大田后生仔之playSMS1.4版代码审计

0x00

关于playSMSv1.4,sendfromfile位置文件RCE漏洞的代码审计。
首先根据代码逻辑找到用户输入的位置:
大田后生仔之playSMS1.4版代码审计
大田后生仔之playSMS1.4版代码审计
可以看到系统首先加载程序的主文件app\main.php,然后根据用户请求的url进行分解找到功能代码位置,用户输入的位置ROOT\plugin\feature\sendfromfile\sendfromfile.php。
大田后生仔之playSMS1.4版代码审计
找到上传文件的除了模块。

0x01

对该模块进行测试,发现53行输入的filename存到filename122filename变量,然后在122行添加到content变量当中直接返回,然后在167行使用函数输出:
大田后生仔之playSMS1.4版代码审计
大田后生仔之playSMS1.4版代码审计
大田后生仔之playSMS1.4版代码审计
关于_p()函数跟进一下,看看是否有重写,然后发现首先调用core_print()函数:
大田后生仔之playSMS1.4版代码审计
再跟进:发现core_print()是普通的输出函数:
大田后生仔之playSMS1.4版代码审计

重新会到sendfromfile.php,通过_p打印的$content变量没有异常,但是为什么里面的恶意代码会被当成代码执行?
之后又在其他地方多次echo恶意代码,最后发现在此php文件中输出的全部恶意代码都是可以执行的,那么漏洞产生原因肯定不在这个页面。测试形如下图。
大田后生仔之playSMS1.4版代码审计

0x02

之后重新回到main.php,发现此处存在一个未接触的点:
大田后生仔之playSMS1.4版代码审计
程序中使用了ob_get_clean()函数来获取缓冲区的数据,关于这个函数:
大田后生仔之playSMS1.4版代码审计
大田后生仔之playSMS1.4版代码审计
也就是说,我们在sendfromfile.php中的所有输出,全部都是存在缓冲区当中,现在使用ob_get_clean()函数就能够获取到缓冲区当中的所有输出,包括恶意代码。
之后继续跟进,在程序输出缓冲区内容之前,经历了themes_apply()函数,漏洞形成原因应该在这个函数当中。
函数如下:
大田后生仔之playSMS1.4版代码审计
在这个函数中会调用一个core_thems_get()函数,这个函数是是用来获取当前主题的,然后将主题当成参数传递给core_hook(()函数:
大田后生仔之playSMS1.4版代码审计
可以看到core_hook()函数获取到三个参数之后会将前两个参数拼接,组成一个字符串,然后调用call_user_func_array()回调函数调用这个字符串所表示的函数,回调函数主要将第一个参数当成函数名,第二个参数当成要调用函数的参数,然后调用该函数。此处回调的函数是从前一个函数拼接的,获取到的主题为default,但是拼接后的回调函数名不存在,所以返回false,然后使用common当成主题名继续尝试回调:common_hook_themes_apply函数存在,执行回调函数。
大田后生仔之playSMS1.4版代码审计
0x04
回调函数成功,接下来就要跟进到回调函数的位置。我们从缓冲区获取的输出已经变成了回调函数的参数。
大田后生仔之playSMS1.4版代码审计
在此处将$content变量的内容相应的添加,然后传递参数,调用tpl_apply()函数:
大田后生仔之playSMS1.4版代码审计
这个函数会根据你访问的不同模块探测是否在文件夹下面会存在对应的html文件,如果没有的话就应用一个公共的,之后又将html文件路径当成参数和其他变量一起传递给_tpl_apply()函数:
大田后生仔之playSMS1.4版代码审计

返回值是$t对象的getCompiled()方法返回值,进入Tpl类审计getCompiled()函数:
_compiled是个私有变量:
大田后生仔之playSMS1.4版代码审计
通过getCompiled()函数返回,
大田后生仔之playSMS1.4版代码审计
那么之后就要查看这个私有变量的值是如何获取的:可以返回上一步看到先执行了compile函数,查看这个函数逻辑:
大田后生仔之playSMS1.4版代码审计
调用了_compile函数。
大田后生仔之playSMS1.4版代码审计
关于_compile函数,可以看到虽然对传进去的数据存在过滤,但是并没有对危险的函数等等进行过滤。
大田后生仔之playSMS1.4版代码审计
之后将数据写入缓存文件:
大田后生仔之playSMS1.4版代码审计
可以看到缓存文件的数据就是我们在sendfromdfile文件输出的内容:
大田后生仔之playSMS1.4版代码审计
最后通过文件包含的形式,获取到缓存文件的内容,还是通过缓冲区的方式传递给返回值,最后清空缓冲区。然后回到main.php中,打印输出。而此时,输出的其实是一段html代码,但是其中包含了用户可控的各种输入,然后造成了漏洞的产生。
如果是这个亚子的话其实所有的用户输入都没有进行过滤,那么就存在多种利用方法了。

0x05
这个流程简化一下就是下面这个亚子的:
大田后生仔之playSMS1.4版代码审计
大田后生仔之playSMS1.4版代码审计
大田后生仔之playSMS1.4版代码审计