按照个人的习惯,先走一下程序的流程,它有几点好处,
1、可以快速浏览完系统运行的代码顺序、
2、了解系统各文件功能、
3、了解系统整个目录的分布情况。
很明显,首页加载了common.inc.php,这个文件的存在与否,定性了系统是否是安装过的,当然还有其他的判断条件,这仅仅是初步判断安装的状态,这个文件是安装过程生成的MySQL的配置文件,其次还加载了common.php文件,core.class.php文件,定义了网站状态、检查了Ip配置,调用了index方法,输出了首页内容。下面介绍下另外的一个文件、common.php
文件描述:文件加载了webscan.php文件、定义了系统路径、加载了common.func.php文件、执行了外部参数过滤转义,加载了数据库类【sql.class.php】,图片类【image.class.php】、计划任务类等。
注意三个重点:
1、外部变量的检测和转义
2、webscan.php文件【做了二次过滤后续分析】
3、sql.class.php文件【数据库操作文件,做了SQL语句完整性校验】
这张图就是对外界参数的整体过滤!从上面函数可以看出来,键值对的键不能是cfg_和GLOBALS的字样,并且使用了addslashes的转义,但是如果cookie里有cfg_和GLOBALS的设置,就可以绕过这两个的限制,下面分析webscan.php
过滤的规则是黑客常用的函数、union、load_file、sleep、concat、group_xxx、js的事件函数防止xss的一些规则,下面分析sql.class.php文件
Sql.class.php这一小节,校验了敏感函数,这些函数一般为黑客常用的函数,所以这里做了验证
Sql.class.php这一小节,通过匹配单引号的位置,对SQL语句进行了重装,整体替换完的效果是,把单引号包裹的部分,用$s$
这样的字符串进行替换。并保存在$clean的变量中,后面在SQL注入中会有所体现。到此,我们流程算是走完了,其他加载的文件,就不做重要分析了,下面我们进行漏洞复现和修复。
代码执行
通过全局的搜索eval函数,我们找到项目中所包含该函数的文件,core.class.php。在该文件中,有两个方法包含了eval的使用,一个是上图中parseIf的方法,一个是parseSubIf方法,后面的方法是通过前面的方法调用的,所以我们这里就只分析parseIf方法,这个方法简单分析下,程序中定义了三个正则,1、{if:(.?)}(.?){end if}。2、{elseif。3、{else},通过preg_match_all函数,用第一个表达式的匹配,结果赋值给$iar的变量,这是含有三个单元的二维数组,后续通过替换,完成对模板的解析过程,分析完过程,然后通过猜想,这是对前台模板解析if标签使用的方法,项目全局搜索该方法的调用位置,就可以找到search.php的文件,其他文件也有,选这个是因为这个文件被搞了。下面来分析这个文件。
这个文件包含三处关键点:
1、程序在接受搜索关键词参数的时候,检测了xss,限制了字符串的长度为20。
2、程序使用接受的参数,替换了模板中的{searchpage:page}的字符。
3、调用了parseIf的方法,完成了代码执行的结果。
值得注意的是,payload只能用{if:这样的字符,上一图对这个有判断。Example:{if:phpinfo()},所以到这里我们可以断定,除去固有的字符外,程序只允许我们执行15个字节的payload。然后比较好的,你不用写shell,就可以直接得到shell,这个地方有点像是变形的一句话木马。url:search.php?searchword={if:eval($_POST[x])}
修复方式:过滤括号
$svar = str_replace(array('(',')','[',']','{','}'),array('','','','','',''),$svar);
foreach(Array('_GET','_POST','_COOKIE') as $_request)
{
foreach($$_request as $_k => $_v) ${$_k} = _RunMagicQuotes($_v);
}
Sql注入
SQL注入,直接看存在的漏洞文件,这个文件参数,有id/score/uid,分析这三个参数,第一参数id、在文件的上部做了数据类型的验证,pass掉,第二个参数score,这个参数是在SQL语句的中间部分,需要结合注释符进行注入,但是前面在说流程的时候,系统过滤了注释符,所以这里也pass。最后一个uid。这个参数在SQL语句的最后,并且没有做类型判断转换,没有单引号、双引号的包裹,所以这里是最好的利用点。
我们直接访问这个方法,讲uid加上点引号做下测试。访问:
加单引号。直接报错,这样单引号被带入执行了运算。这边没有回显,在sql.class.php文件中,又过滤了常用的union,sleep,select子句,还有注释符。所以这里要出成果需要绕绕路。
知识点扩充
注释
1、--+空格
2、#
3、/*!数字 xxxxx*/ 第一位是主版本号,第二位是0,剩余是次版本号,大于这个数字没回显
字段表示
1、column=xxx[正常表示]
2、`任意符号`.``.column=xxx
显错注入
extractvalue('anything'【目标xml文档】,concat【xml路径】)能查询字符串的 最大长度为32
updatexml('anything'【目标xml文档】,concat【xml路径】,'anything'【更新的内容】)
concat('str1【0x7e|0x3A】','str2【查询数据库的语句】')
concat_ws('str1【连接符0x7e|0x3A】','str2【0x7e|0x3A】','str3【查询数据库的语句】')
group_concat(column)函数返回一个字符串结果。
通过上面的payload,这样就获得了SQL的版本号,如果要获取其他的信息,只需要改动version()这个为的SQL语句即可【理论值】。比如说,获取admin的密码,就可以写成下面的select语句。url:duomiphp/ajax.php?action=addfav&id=1&uid=1%20and%20extractvalue(1,concat_ws(0x7e,0x7e,(select password from duomi_admin where id=1)))
显然不对,程序给拦截了,因为这里有websan.php的正则匹配,上面说流程的时候说了这个点,上面这个是具体的细节,这个正则有点长,通过写的SQL语句,可以快速的分析,应该是倒数第二行正好匹配了,满足了要求,就给拦截了请求,这你需要细心的分析下,这一行表达了什么意思,大致意思是select+空格+任意字符+空格+from+空格+一位除换行符以外的任意字符,所以绕过这个地方的方法,就是减少一处查询字段左右两边的空格,如果两个空格都去掉,就被后面的匹配到。然后我们调整后看结果。
显然不对,程序还是给拦截了,因为这里有sql.class.php的正则匹配,上面说流程的时候说了这个点,上面这个是具体的细节,这个正则大致意思是(select,所以绕过这个地方的方法,最初想的是去除payload中的左括号,变成url:duomiphp/ajax.php?action=addfav&id=1&uid=1%20and%20extractvalue(1,concat_ws(0x7e,0x7e,select password from duomi_admin where id=1)),
但是还是能匹配的到,因为extractvalue这个函数还有个左括号,所以去括号的路线丢弃了,就有了后来的'..vid这种字段的表示方式,它的诞生是为了利用上面流程中说到的这段代码,简单一回顾。有了单引号替换以后,就可以绕过这个限制了。修改
为duomiphp/ajax.php?action=addfav&id=1&uid=1 and `'`..vid and extractvalue(1,concat_ws(0x7e,0x7e,(selectname from duomi_admin where id =1))) and '.``.vid
到这里就完成了SQL注入的过程。那么怎么打补丁呢。
1、把这个参数强转成数字。
2、加上引号
至此就完成整个漏洞的复现和修复。
E
N
D
关
于
我
们
Tide安全团队正式成立于2019年1月,是新潮信息旗下以互联网攻防技术研究为目标的安全团队,团队致力于分享高质量原创文章、开源安全工具、交流安全技术,研究方向覆盖网络攻防、系统安全、Web安全、移动终端、安全开发、物联网/工控安全/AI安全等多个领域。
团队作为“省级等保关键技术实验室”先后与哈工大、齐鲁银行、聊城大学、交通学院等多个高校名企建立联合技术实验室,近三年来在网络安全技术方面开展研发项目60余项,获得各类自主知识产权30余项,省市级科技项目立项20余项,研究成果应用于产品核心技术研究、国家重点科技项目攻关、专业安全服务等。对安全感兴趣的小伙伴可以加入或关注我们。
我知道你在看哟