第一题
<?php
error_reporting(0);
show_source(__FILE__);
$flag = 'you_get_me!';
if (isset ($_GET['password'])) {
if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
echo '<p class="alert">You password must bealphanumeric</p>';
else if (strpos ($_GET['password'], '--') !== FALSE)
die($flag);
else
echo '<p class="alert">Invalid password</p>';
}
?>
解题:
1. 知识:isset 函数、strpos函数、ereg函数、die函数
(1)isset函数是检测变量是否设置的函数,若变量不存在或者变量存在但值为NULL,则返回FALSE;若变量存在且值不为NULL,返回TRUE。
(2)ereg函数判断正则表达式,限制变量形式
2. 分析:首先,本题中用GET方式提交password,isset函数监测变量确实被设置则返回TRUE进行下面的操作,否则返回FALSE。接下来用ereg函数判断正则表达式,限制了password的形式只能是一或多个数字、大小写字母,很显然这里面不能有“--”,但是往下看,strpos()对password进行匹配,要求password里面必须有“--”才能输出flag,那么假设我们真的有“--”,接下来执行die,退出程序,所以程序到底是要求我们有“--”还是没有呢?这就很迷啊(无奈脸)。于是我们上网搜索一下ereg这个函数有什么漏洞或者问题。
3. 问题与漏洞:因为ereg函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00截断正则匹配。
Payload:
?password=1234%00--
【注】:最后一定要加上“--”,%00前面的是数字或大小写字母
第二题
<?php
show_source(__FILE__);
$a=0;
$b=0;
$c=0;
if (isset($_GET['x1']))
{
$x1 = $_GET['x1'];
$x1=="1"?die("ha?"):NULL;
switch ($x1)
{
case 0:
case 1:
$a=1;
break;
}
}
$x2=(array)json_decode(@$_GET['x2']);
if(is_array($x2)){
is_numeric(@$x2["x21"])?die("ha?"):NULL;
if(@$x2["x21"]){
($x2["x21"]>2017)?$b=1:NULL;
}
if(is_array(@$x2["x22"])){
if(count($x2["x22"])!==2 OR !is_array($x2["x22"][0])) die("ha?");
$p = array_search("XIPU", $x2["x22"]);
$p===false?die("ha?"):NULL;
foreach($x2["x22"] as $key=>$val){
$val==="XIPU"?die("ha?"):NULL;
}
$c=1;
}
}
if($a && $b && $c ){
echo 'you get flag!';
}else{
echo 'try again!';
}
?>
解题:
1. 知识:isset 函数、switch-case语句、json_decode函数、is_array函数、is_numeric函数、count函数、array_search函数
(1)isset()函数是检测变量是否设置的函数,若变量不存在或者变量存在但值为NULL,则返回FALSE;若变量存在且值不为NULL,返回TRUE。
(2)json_decode()函数是对 JSON 格式的字符串进行解码,接受一个 JSON 编码的字符串并且把它转换为 PHP 变量,参数是待解码的字符串。
(3)is_numeric()函数是检测变量是否为数字或数字字符串的,如果参数是数字和数字字符串则返回 TRUE,否则返回 FALSE。
(4)array_search()函数是在数组中搜索某个键值,并返回对应的键名。如果找到了该值,匹配元素的键名会被返回。如果没找到,则返回FALSE。在PHP 4.2.0 之前,函数在失败时返回NULL而不是 FALSE。
2. 分析:首先通读代码,可以看出最后只有使a,b,c都赋值了才能得到flag。
(1)利用代码的逻辑漏洞可绕过x1
(2)上网可以查到JSON的标准格式
(3)字符串比较0=0,0='aaa'都是可以的,所以x2的x21只要是一个大于2017的数+字母就可以绕过,注意是大于2017
(4)x2的x22要求有两个元素,继续分析,又出现了和第一个题中类似的问题,到底是应该有“XIPU”还是没有没呢?
(5)我想问题应该出在array_search这个函数上,那么上网搜索一下这个函数的漏洞。
3. 问题与漏洞:array_search函数先判断传入的是不是数组,然后循环遍历数组中的每个值,没有的话,每个值转化为int类型,再判断传入的数组有没有。
Payload:
?x1=0&x2={"x21":"2018k","x22":[[4],0]}
第三题
<?php
error_reporting(0);
$pass = "xxxxxxxx";
$password = $_GET['password'];
if(strcmp($password,$pass) == 0)
{
echo "flag";
}else{
echo"try again";
}
?>
解题:
1. 知识:strcmp 函数
strcmp函数是二进制安全字符串的比较,如果 str1 小于 str2 返回 < 0; 如果 str1 大于 str2 返回 > 0;如果两者相等,返回 0。
2. 分析:这道题……毫无疑问问题出在字符串比较的函数上,查一下这个函数的漏洞吧
3.问题与漏洞:使用strcmp函数比较会返回0,0==0,那么就会得到flag了
Payload:
?password[]=1