php_bugs代码审计
条评论简单的php_bugs代码审计。
所有代码均来自:https://github.com/bowu678/php_bugs
0x01 extract变量覆盖
1 |
|
当$shiyan==$content
时输出flag
,$flag
赋给$content
,这里不知道$flag
的值,所以可以get
一个flag
变量覆盖$flag
,当get
的flag
等于get
的shiyan
时即可输出flag
。
构造payload
:?shiyan=&flag=
0x02 绕过过滤的空白字符
代码挺长的,就不放了,自行在github
原项目上看。
主要满足四个点:
1 | is_numeric($_REQUEST['number']) == false |
即可输出flag
,构造如下:
- 第一点
is_numeric()
判断变量是否为数字
或数字字符串
,可以检查10进制
或16进制
,is_numeric()
可以用空字符绕过,%00
放在数值前、后
都可以判断为非数值,而%20
空字符只能放在数值后。 - 第三点该
整数值
等于其反转整数值
,第四点不为回文数
,这两者看似矛盾,实则有多种绕过方法。
法一
来自php_bugs,先满足第三点
回文数再Fuzzing
绕过第四点
,简化后端代码:
1 |
|
将数值
转成2位16进制
加在回文数
191
前面,Fuzzing
如下:
1 | import requests |
输出结果如下:
%0C
%2B
即可构成payload
:?number=%00%2C191
法二
仅限于32位操作系统
,利用intval()
函数的溢出,Intval()
最大的值取决于操作系统
。 32 位系统
最大带符号的 integer
范围是 -2147483648
到 2147483647
。举例,在这样的系统上, intval('1000000000000')
会返回 2147483647
。64 位系统
上,最大带符号的 integer
值是 9223372036854775807
。
如果在32位操作系统
上我们可以构造payload
:?number=%002147483647
2147483647
经过strrev()
反转函数后为7463847412
,又经过intval
函数值又变为2147483647
,故满足第三点
条件,可以输出flag
。
64位操作系统
最大integer
值是 9223372036854775807
,经strrev()
反转函数后为7085774586302733229
反而变小了,未满足溢出条件,故不适用。
法三
因为要求不能为回文数,但又要满足intval($req["number"])=intval(strrev($req["number"]))
所以我们采用科学计数法构造payload
为?number=0e-0%00
,这样的话我们就可以绕过。
参考:
0x03 多重加密
源码
中给出:
1 | $login = unserialize(gzuncompress(base64_decode($requset['token']))); |
有了加密
方式,我们解密
一下即可
1 |
|
eJxLtDK0qs60MrBOAuJaAB5uBBQ=
0x04 SQL注入_WITH ROLLUP绕过
这个题来自实验吧因缺思汀的绕过
1 | $filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)"; |
$_POST
输入通过定义的AttackFilter()
函数过滤导致不能使用常规sql注入
,这里的思路是select
过程中用group by with rollup
方法进行插入查询。
先来看看group by with rollup
统计方法有什么作用
1 | MariaDB [test]> select * from test; |
limit 1
是指只查询一行
,offset 1
指查询某一行的内容,不同的数字出现的是不同行的内容
当用with rollup
方法的时候,会在数据库的最后一行生成一个密码
为NULL
的字段,在查询的时候就可以想想办法让pwd
为空,而user
也是存在的,又有mysql_num_rows($query) == 1
,所以可以构造payload
:
admin' or 1=1 group by pwd with rollup limit 1 offset x #
查询语句就是:
SELECT * FROM interest WHERE uname = 'admin' or 1=1 group by pwd with rollup limit 1 offset x #'
然后一个个试就行了。
参考:
实验吧 因缺思汀的绕过 By Assassin(with rollup统计)
0x05 ereg正则%00截断
直接看关键点审计
1 | ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE |
第二点
可以利用科学计数法
的方式表示。
第三点
GET密码
中要包括*-*
,但是前面的ereg()
过滤了特殊字符,这时候可以用%00
截断,ereg()
读到%00
的时候就截止了,所以构造payload
:
1e9%00*-*
0x06 strcmp比较字符串
1 |
|
strcmp()
期望传入类型是字符串类型,在5.3
之前的php
版本中若传入其他类型将会报错并返回0
,5.3
之后报错不返回任何值,但如果传入数组
的话,就会返回NULL
,这里的判断是弱等于
,NULL==0
是 bool(true)
,所以有构造payload
:
?a[]=1
0x07 sha()函数比较绕过
1 |
|
$_GET['name'] != $_GET['password']
同时满足sha1($_GET['name']) === sha1($_GET['password']
sha1()
默认的传入类型是字符串
类型,若传入数组
会返回false
,这里的判断是强等
,需要构造username
和password
既不相等,又同样要是数组类型
,构造payload:
?name[]=a&password[]=b
0x08 SESSION验证绕过
1 |
|
重点在于$_GET['password'] == $_SESSION['password']
,这就很简单了,只需要GET
值与SESSION
相等,
构造payload
:
?password=
然后将cookies
清空即可。
本文标题:php_bugs代码审计
文章作者:zjun
发布时间:2020-03-12
原始链接:https://blog.zjun.info/2020/php-bugs-code-audit.html
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!
分享