很久没有在BUU做题了,偶然发现上了一批羊城杯的题目,唯一一道0解题做了下,好题!
我自己的主虚拟机是Virtualbox的Debian Buster,然后在运行程序的时候就报错没有libasan.so.2文件,用Ubuntu16就不会报错,但顺藤摸瓜找了找这个libasan是干啥的:google/sanitizers。那大致的意思就看第一句
AddressSanitizer (aka ASan) is a memory error detector for C/C++
回到题目,先分析下程序,看到反编译出来的代码非常难看,因为asan的缘故,因此就先手工看下程序的功能。一开始会登录,有三个选项:匿名,认证和管理员。匿名登录后任何事情都做不了,管理员不给输入账号密码。认证登录也比较简单,用户名是guest,密码在经过处理后需要等于”2100122107654100”,处理也比较简单,就是简单的异或3。
登录后有几个功能:创建文件,删除文件,打印文件,切换用户,后门。移动文件这个选项无效,然后后门的选项并不是menu里打印出来的6,而是反编译出来的666。
创建文件功能很简单明了,删除文件使用的是unlink实现,修改用户是让你输入账号密码,打印文件比较特殊,是创建了一个线程运行的这个函数,暂时还不知道为什么要这么做。作为普通用户,后门函数是没法触发的,打印文件也是。其中,判断权限的语句是if (*(char *)(_cred + 8) != '\x03')
,然后_cred的地址在bss段。这里可以盲猜是通过某种方法覆盖掉这个cred为\x03,甚至可以盲猜是通过修改用户函数。
XREF[14]: print_file:555555556cf4(R),
setup:5555555570fc(W),
create_file:55555555732a(R),
delete_file:555555557721(R),
backdoor:555555557980(R),
change_user:555555557b34(R),
change_user:555555557bc6(R),
login:555555557d22(R),
login:555555557de7(R),
login:555555557eb2(R),
login:555555557f42(R),
login:5555555580b0(R),
login:5555555580e8(R),
login:555555558170(R)
然后修改用户这个函数中,基本上就两个输入点:用户名和密码。懒得去分析源码的漏洞,直接测试了下,发现确实在密码处有个1字节的溢出,那也就意味着我们可以成为admin。
回到后门函数,虽然可以绕过了(*(char *)(_cred + 8) == '\x03')
,但是后面还有个(*(char *)(_cred + 9) == '\x01')
。先放在一边不管,看到如果绕过了限制,后门函数实际上做的是一个symlink,也就是软链接,可以理解为快捷方式,你可以试试ls -la /lib/libc.so.6
,这就是libc文件的一个软链接。
其实到这里的时候漏洞有点呼之欲出了,软链接+多线程,但我先卖个关子,先继续看看打印文件函数做了什么。
打印函数的文件名不能包含flag,其次打印的文件必须是你自己的(通过strcmp比较)。这里我一开始试图绕过,比如说用..来穿越目录,但是很明显不可以。最后就是非常可疑的两行:
*(undefined *)(lVar4 + 9) = 1;
sleep(2);
首先是这个+9的偏移,我之前在找控制后门函数的第二个约束时一直没有找到+9的偏移,这里就非常可能是我们要找的约束了。接着,程序sleep了2秒,但是其实是在线程内sleep两秒。如果你手动试一下,会发现程序不会僵住,因为主线程main函数依旧在运行。
到这里解法就很明显了,我们调用完打印函数后,2秒内立刻调用后门函数将某个文件变成flag的软连接,2秒后打印线程才打开文件并且打印出来,因为exp比较简单,这里就不贴了。但是这题在BUU上是无法获取flag的,程序是使用fopen(fn, “a+”)打开的文件,而我记得BUU的环境一般flag都是不可写的,因此打开文件不会成功。
之后我搜了一下这一题的writeup,只找到这一篇:2020 羊城杯 部分PWN WrieUp。作者说这里是一个TOCTTOU漏洞,Time-of-check to time-of-use指的是利用程序在检测和使用时的时间差,维基百科的这个例子非常好理解:
// victim
if (access("file", W_OK) != 0) {
exit(1);
}
fd = open("file", O_WRONLY);
// Actually writing over /etc/passwd
write(fd, buffer, sizeof(buffer));
// attacker
symlink("/etc/passwd", "file");
如果一个程序首先检测file文件可不可写,之后又打开file文件做写操作,那么就存在TOCTOU漏洞。攻击者可以在程序检测完可写性之后,将file变成/etc/passwd的软链接(软链接本身不可写,指向的文件可写),那么目标程序最终打开的就是passwd文件。
关于TOCTOU还有一个非常棒的视频,这里面liveoverflow也解释了一个条件竞争的漏洞,以及