6.1.20 pwn 33C3CTF2016 babyfengshui

下载文件

题目复现

$ file babyfengshui
babyfengshui: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=cecdaee24200fe5bbd3d34b30404961ca49067c6, stripped
$ checksec -f babyfengshui
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FORTIFY Fortified Fortifiable  FILE
Partial RELRO   Canary found      NX enabled    No PIE          No RPATH   No RUNPATH   Yes     0               3       babyfengshui
$ strings libc-2.19.so | grep "GNU C"
GNU C Library (Debian GLIBC 2.19-18+deb8u6) stable release version 2.19, by Roland McGrath et al.
Compiled by GNU CC version 4.8.4.

32 位程序,开启了 canary 和 NX。

在 Ubuntu-14.04 上玩一下,添加 user 和显示 user:

$ ./babyfengshui
0: Add a user
1: Delete a user
2: Display a user
3: Update a user description
4: Exit
Action: 0
size of description: 10     # description 最大长度(desc_size)
name: AAAA
text length: 5              # description 实际长度(text_size)
text: aaaa
0: Add a user
1: Delete a user
2: Display a user
3: Update a user description
4: Exit
Action: 2
index: 0
name: AAAA
description: aaaa

对于 description 的调整只能在最大长度的范围内,否则程序退出:

题目解析

Add a user

函数首先分配一个 description 的最大空间,然后分配 user 结构体空间,并将 user 放到 store 数组中,最后调用更新 description 的函数。

user 结构体和 store 数组如下:

store 放在 0x804b080,当前 user 个数 user_num 放在 0x804b069

Delete a user

删除的过程将 description 和 user 依次释放,并将 store[i] 置为 0。

但是 user->desc 没有被置为 0,user_num 也没有减 1,似乎可能导致 UAF,但不知道怎么用。

Display a user

函数首先判断 store[i] 是否存在,如果是,就打印出 name 和 description。

Update a user description

该函数读入新的 text_size,并使用 (store[i]->desc + test_size) < (store[i] - 4) 的条件来防止堆溢出,最后读入新的 description。

然而这种检查方式是有问题的,它基于 description 正好位于 user 前面这种设定。根据我们对堆分配器的理解,这个设定不一定成立,它们之间可能会包含其他已分配的堆块,从而绕过检查。

漏洞利用

所以我们首先添加两个 user,用于绕过检查。第 3 个 user 存放 "/bin/sh"。然后删掉第 1 个 user,并创建一个 description 很长的 user,其长度是第 1 个 user 的 description 长度加上 user 结构体长度。这时候检查就绕过了,我们可以在添加新 user 的时候修改 description 大小,造成堆溢出,并修改第 2 个 user 的 user->desc 为 free@got.plt,从而泄漏出 libc 地址。得到 system 地址后,此时修改第 2 个 user 的 description,其实是修改 free 的 GOT,所以我们将其改成 system@got.plt。最后删除第 3 个 user,触发 system('/bin/sh'),得到 shell。

开启 ASLR。Bingo!!!

exploit

完整的 exp 如下:

参考资料

Last updated

Was this helpful?