比赛 10:00 开始,下午 18:00 结束。开始时平台很卡,pwn 远程也是,后面好多了。flag 居然是大括号里面的部分。。。一共放出了四题,只做了两道,分别是关于 mmap
和 chroot
的。
fruitpie
程序分析
主要逻辑都在主函数中。申请 chunk 的大小没有限制,且给了 chunk 的地址。然后可以在偏移 chunk 可控位置处读入 0x10 任意字节。最后 malloc
了一次。
漏洞利用
初看感觉没有头绪。后面回想起了有题的考点是用 mmap
的地址求 libc 地址(虽然在不同机器上、用不同的链接器偏移会不一样),之后就可以覆盖 __realloc_hook
和 __malloc_hook
了。
注意。如果申请的 chunk 地址比较小(比如 0x30000),chunk 会被分配到相对 libc 高地址处,此时远程打不通。更大的话(比如 0x517000),chunk 会被分配到低地址处,此时远程也能打通。
还有不要用自己编译的 ld。(这次我记住了)
exp
1 | from pwn import * |
ParentSimulator
程序分析
堆题。64位ELF,保护全开,libc 为 2.31。
- 程序必须以 root 权限执行,开头调用 seccomp 禁用了 system,
open
了 /tmp 目录,chroot 到了 /tmp/ohohoho 目录,降低进程权限为 1 (显示为 daemon) - 有 add、delete、edit_name、edit_description、show 等功能
- add 的大小只能为 0x100
- 用 bss 段的一篇空间记录 chunk 使用情况
- chunk 的 bk 域只能为 “boy” 或 “girl” 字符串
- delete 有 UAF 漏洞,且不会检查 chunk 使用情况。其它的功能都会检查。
- 有一次泄漏和修改一个 chunk 的 bk 的机会
漏洞利用
堆利用
如果忽略掉程序开头的操作,这道题的利用流程是:
- 用 tcache chunk 进行 double free(因为 libc-2.32,中途要修改一次 chunk 的 fd),同时泄漏堆地址
- 然后控制堆上的 tcache_perthread 结构体(这样可以多次向任意地址申请 chunk)
- 把一个 chunk free 进 unsortedbin,利用 show 泄漏 libc 地址
- 修改 __free_hook,然后 orw 获得 flag。
但我们必须先逃出 chroot jail。因为此题有 edit_name,可以多次修改 __free_hook
,因此可以多次调用一些函数。
chroot jail escape
当时我先 man 了一下 chroot
,发现里面提到两种可以逃出的情况:
- 权限为 root,可以
mkdir foo; chroot foo; cd ..
chdir
到某个目录中,然后该目录被移出到chroot
的目录之外
值得注意的是 man page 中提到调用 chroot
的条件:
Only a privileged process (Linux: one with the CAP_SYS_CHROOT capability) may call chroot().
尝试 chroot
我尝试了第一种,调试时查看 errno 后发现因为权限不足失败了(大概只有 root 才有 CAP_SYS_CHROOT capability?)
之后我又想弄明白 open("/tmp", 0)
到底是用来干嘛的(因为在我的印象中 open
一个文件夹没什么用)。写了个 C 程序 test_read_write_folder.c 测试,发现读写都会失败(错误信息是该 fd 为一个目录)。
chdir(“/bin/“)
然后我就傻眼了,开始乱试。试了一下 chdir("/bin/")
,然后 getcwd
获得所在目录,发觉在远程环境下居然到了 “/usr/bin”,逃出了 chroot jail!
然而本地环境却失败了,依然在根目录下。我还搞不懂成功和失败的原因。。。(因为有链接?还是有别名之类的机制?)
最后 chdir("../../")
,orw 得到 flag。但提交始终不过,当时我以为 escape 失败了,读到了一个别人写的假 flag,然后开始寻找新的方法。(实际上是成功了的,提交不过的原因在文章的最上方)
fchdir(fd)
我想不出来办法,就到处查资料。当我 man chroot 时,我找到了突破口:
CHDIR(2) Linux Programmer’s Manual CHDIR(2)
NAME
chdir, fchdir - change working directorySYNOPSIS
#include <unistd.h>
1
2 int chdir(const char *path);
int fchdir(int fd);
原来还能根据 fd 切换目录!这说明我们可以利用程序开头 chroot("/tmp/ohohoho")
前 open("/tmp", 0)
得到的 fd(值为 3)来逃出 chroot jail!google 一下后发现确实有这种方法:http://www.unixwiz.net/techtips/mirror/chroot-break.html
exp
1 | ''' |
该程序对 chunk 的控制力较强,帮我在构建 rop 链时省了很多时间。
总结
打得还是很爽的。不过还是经验不足,做得很慢。
我想如果其他人看 pwn 手的虚拟机,一定会察觉在一些奇奇怪怪的地方(比如根目录,home 目录,/home/ctf 目录) ,有 flag、flag.txt 之类的文件吧。这么想想还是挺好玩的。