作者:会上树的猪合天智汇
0x00 写点废话
在渗透测试中,获取一个webshell应该是我们不屑的追求,今天要通过这个CMS从代码的角度看一下可利用的getshell的方法。这一次的代码审计需要借助工具来定位可能存在的漏洞点,选择Seay源代码审计系统。步入正题。
0x01文件上传getshell:
1、/kindupload.php:通过获取文件最后一个扩展名进行白名单匹配,且添加随机数命名新文件名,应该不存在文件上传漏洞
2、/upload.php:此文件属于测试文件
3、include/function/common.php:关于$image变量的来源有两个,为null时强制转换jpg格式,当对有图片项目进行编辑时,$image变量就是之前上传的文件地址,这样的话想进行任意文件上传应该就没有可能了。。。。。。
0x02 文件写入+文件包含getshll:
在进行任意文件删除/读取/修改漏洞审计时发现支付日志位置可以向日志文件写入任意内容:漏洞位置:/alifast/alipay.function.php
根据定位,可以找到logResult函数:
可以看到其中的$word变量未经过任何check便写入到log.txt文件中(此处写入文件可能比较鸡肋,但如果可以找到任意文件包含,便可以直接getshell)而其中$word变量来源于对函数的引用,我们全局搜索一下看有哪些地方调用了logResult函数:
可以找到一处调用,在/alifast/lib/alipay_notify_class.php文件中:
通过verifyNotify函数,当POST数据不为空时就会调用logResult函数进行日志写入,那之后就转到查找何处调用了verifyNotify函数,找到一处调用:/alifast/returnadd_url.php
而且可以发现此处文件应该不需要登录便可以直接访问:
之后我们传入一个payload,然后开启DEBUG调试一下,看一下参数传递:
最后可以看一下log.txt文件,成功写入payload:
这需要结合文件读取漏洞才能利用,否则写入到txt文件属于鸡肋,之后便通过对扫描到的可能存在文件包含漏洞的点进行验证,未发现可利用的文件包含漏洞,上面这个任意写入真的鸡肋了。
不过作为一个搞信息安全的弱鸡,我是不会放弃的。
0x03后台通过修改模板getshell:
感觉模板渲染位置最容易存在代码执行漏洞了,之前审计一些其他的CMS也在类似模板渲染位置发现了漏洞,导致getshell。因为系统存在很多模板,便只举一个模板当作栗子。
此处漏洞位置:/include/function/template.php
在__parse函数中存在preg_replace函数通过e参数进行代码执行。
我们先看在哪些地方对__parse函数进行了调用:
在同文件下58行,通过__tempate函数进行调用。
再搜索有哪些地方对__template函数进行了调用:
在/include/function/common.php文件下存在对__template函数的调用:
最后就是看有哪些地方调用了template函数:
这些调用基本都是进行模板加载的位置,我们先随便找一处:(团购信息提交)
接下来还是要开启debug,然后跟踪一下程序执行的逻辑:
- 访问链接,触发模板解析函数:注意此处采用的include的方式进行模板加载。
2、进入template函数之后,会根据传递的参数加载不同的模板。
3、当进入__template函数之后要先根据传递的参数加载模板的绝对位置,这里注意,存在一个模板和一个编译后的模板,模板是.html文件,而编译后的模板是.php文件,程序在此处将模板文件路径存在变量$tfile,编译后的模板文件路径存在变量$cFile,之后会利用filemtime函数来比较两个文件的修改时间,如果模板的修改时间小于编译后的模板文件,那说明已经对模板进行过编译,直接返回编译后的模板文件路径。反之才会调用__parse函数对模板进行重新编译。
根据上面的分析,我们要找到可以修改模板的功能点,不然此处漏洞便无法利用,因为无法满足文件修改时间的检查,除非站长刚好改了模板文件。不过一般站点都提供了模板修改功能,这个CMS也不例外:
既然后台可以修改模板文件,那就保证模板文件修改时间大于编译后的模板文件,这样就会进入重新编译环节。
我们通过第20行的preg_replace来进行分析:
preg_replace("/<!--s*${(.+?)}s*-->/ies", "__replace('<?php 1; ?>')", $fileContent);
这个正则表达式会怎么匹配不太好说,直接举一下编译前和编译后的栗子出来就能明白了:
上面那个正则是如何处理的应该就清楚了。接下来还是继续debug,跟踪模板渲染的具体逻辑:
通过正则表达式将模板进行渲染,然后通过file_put_content函数将内容全部写入到渲染后的模板,写入成功则返回true。
值得注意的是最后返回的是渲染后的模板的物理路径,然后通过include方式加载模板,此时可以看到模板已经通过正则全部替换为php代码。
在这个地方存在一个之前的想法错误,其实并不是通过preg_replace来进行代码执行,因为通过/e参数调用的函数是__replace方法,只进行了简单的替换,最后还是通过文件包含的方法来包含存在恶意代码的模板。
既然已经清楚模板渲染的流程,接下来尝试getshell操作,首先将模板修改成如下形式:记得闭合双引号,括号等等。
通过编译函数之后模板应该是下面这个样子的:
最后通过include包含这个含有恶意代码的模板:
0x04数据库备份getshell:
在一般系统中通常会存在数据库备份的功能,在渗透测试中利用数据库备份getshell也是常用操作,在这个CMS系统中同样发现了数据库备份与还原功能。
但是此处数据库备份的文件是默认的用户不可控的,未发现将恶意代码备份到.php文件当中的操作:
但是在之后对从本地文件恢复数据库的功能进行审计发现,此处存在任意SQL语句执行,相当于给我们提供了一个执行任意SQL语句的接口,那么便可以尝试通过SQL命令导出文件getshell和MySQL日志getshell。先来看一下程序逻辑:
在数据库恢复功能提供了从本地文件恢复的功能:
当本地文件上传到服务器,会通过一个backup_import的函数执行文件内的SQL语句:
我们跟踪一下这个函数:
可以看到从文件中读取到SQL语句之后只去掉了几个特殊符号,便通过DB::Query方法直接执行,其中可以再看一下Query方法:未经过任何处理,直接执行SQL语句。
已经明白程序的运行逻辑,那么我们便只要构造可以getshell的SQL语句,然后通过备份还原的功能执行SQL语句便能够成功getshell。
上面说MySQL有两种常用的方法getshell:文件导出和日志记录。因为新版的MySQL添加了secure_file_priv参数对文件导入导出进行了限制,这个参数需要修改数据库配置文件,利用困难。
所以为了提高成功率优先选择利用日志功能getshell。这里还是先介绍一下利用log日志getshell。在MySQL日志功能中:
- General_log 指的是日志保存状态,一共有两个值(ON/OFF)ON代表开启 OFF代表关闭。
- General_log_file 指的是日志的保存路径。
- 关于开启general_log参数的作用:
- 开启它可以记录用户输入的每条命令,会把其保存再general_log_file指定的目录下,就是日志文件。这个参数是可以直接通过mysqld进行设置。
- 我们的利用的思路是开启general_log之后把general_log_file的值修改为我们网站默认路径下一个自定义的php文件中,然后我们通过log日志进行写入一句话后门到上面去,然后再进一步利用。
通过上面的介绍我们知道要实现日志getshell,要做的以下三步:开启日志功能,重定义日志输出文件(需要绝对路径),执行恶意SQL语句写入日志,具体SQL语句如下:
之后上传文件执行SQL语句,然后在之前设置的日志路径下便可以看到带有恶意payload的日志文件了:
访问一下链接,成功getshell
0x05 收尾:
还是来点骚话收尾,上述只是我找到的一些getshell的操作,肯定还会有其他getshll的操作没有被我发现。但是用代码审计的方式从代码角度去看待漏洞形成的原因对漏洞的理解还是有很大帮助的,还是那句话,代码审计一时爽,一直审计一直爽,大家也可以加入代码审计的大军,有兴趣和我这个菜鸡一起成长进步。
声明:笔者初衷用于分享与普及网络知识,若读者因此作出任何危害网络安全行为后果自负,与合天智汇及原作者无关!