Bash
破壳漏洞 解析漏洞
Bash漏洞起因
curl -A "() { :; }; /bin/cat /etc/passwd" http://192.168.0.1/poc.cgi
curl是linux下用于http请求的一个工具,
-A是将User-Agent设置为() { :; }; /bin/cat /etc/passwd字符串
后面的http://192.168.0.1/poc.cgi是
位于服务器192.168.0.1的一个cgi脚本,为什么cat /etc/passwd可以在192.168.0.1执行成功
poc.cgi的源代码
#!/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
/* 这里存在一个BASH的调用,输出环境信息*/
echo '</pre>'
echo '</body>'
echo '</html>'
exit 0
poc.cgi
允许我们远程访问http://192.168.0.1/poc.cgi时
使用HTTP方式对/usr/bin/env进行调用
访问http://192.168.0.1/poc.cgi时可以设置任意的HTTP Header
比如User-Agent、Refer、cookie以及自定义等参数
而 Bash CGI会将客户端发送的HTTP数据包的HTTP头部的字段
作为ENV的参数传入环境变量的设置函数中,
也就是说Bash CGI默认将HTTP头部参数作为环境变量设置源。
“() { :; }; /bin/cat /etc/passwd”
User-Agent : () <-- 作为函数
{ :;}; <-- 函数体
/bin/cat /etc/passwd <-- 注入的代码
当我们的() { :; }; /bin/cat /etc/passwd被传入Bash的环境设置函数之后,
由于Bash使用的环境变量是通过函数名称来调用的,
因此以“(){”开头定义的环境变量在命令ENV中解析成函数后,
Bash会将这段代码这样解释:
“()”当做User-Agent()函数、而“{ :;};” 作为一个空的函数体。
这一Bash对环境进行设置的过程中,“
() { :; }; /bin/cat /etc/passwd”会被当做代码进行“代码执行(可以想象成php的eval)”。
注入的代码被成功解析执行后会以”环境变量”的形式保存在环境变量中,
然后CGI返回的HTTP数据包中会将环境变量一并发送回客户端,
也就是你看到的/bin/cat /etc/passwd执行了的结果。
问题产生的地方就在于Bash对环境进行设置的过程中对传入的参数在未检查其合法性的情况下,即进行了代码执行。
Bash 3.2中对此功能的实现:
evalstring.c
else if (command = global_command)
{ struct fd_bitmap *bitmap;
/*
这里没有对传入的command进行正确的边界检查,引入了代码注入的可能性
*/
bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
begin_unwind_frame ("pe_dispose");
add_unwind_protect (dispose_fd_bitmap, bitmap);
add_unwind_protect (dispose_command, command);
/* XXX */
global_command = (COMMAND *)NULL;
}
variables.c
/*
Initialize the shell variables from the current environment. If PRIVMODE is nonzero, don't import functions from
ENV
or
parse $SHELLOPTS.
*/
void initialize_shell_variables (env, privmode) char **env; int privmode;
{
...
create_variable_tables ();
/*
从ENV环境变量中获取参数
*/
for (string_index = 0; string = env[string_index++]; )
{
char_index = 0;
name = string;
while ((c = *string++) && c != '=') ;
if (string[-1] == '=')
char_index = string - name - 1;
/* If there are weird things in the environment, like `=xxx' or a
string without an `=', just skip them. */
if (char_index == 0)
continue;
/* ASSERT(name[char_index] == '=') */
name[char_index] = '\0';
/*
Now, name = env variable name, string = env variable value, and char_index == strlen (name)
*/
/*
If exported function, define it now. Don't import functions from the environment in privileged mode.
解析环境变量设置中的函数定义
*/
if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4))
{
string_length = strlen (string);
temp_string = (char *)xmalloc (3 + string_length + char_index);
strcpy (temp_string, name);
temp_string[char_index] = ' ';
strcpy (temp_string + char_index + 1, string);
/*
这句是关键,initialize_shell_variables对环境变量中的代码进行了执行,由于它错误的信任的外部发送的数据,形成了和SQL注入类似的场景,这句代码和PHP中的eval是类似的,黑客只要满足2个条件
1. 控制发送的参数,并在其中拼接payload
2. 黑客发送的包含payload的参数会被无条件的执行,而执行方不进行任何的边界检查
这就是典型的数据和代码没有进行正确区分导致的漏洞
*/
parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);
// Ancient backwards compatibility. Old versions of bash exported functions like name()=() {...}
if (name[char_index - 1] == ')' && name[char_index - 2] == '(')
name[char_index - 2] = '\0';
if (temp_var = find_function (name))
{
VSETATTR (temp_var, (att_exported|att_imported));
array_needs_making = 1;
}
else
report_error (_("error importing function definition for `%s'"), name);
/* ( */
if (name[char_index - 1] == ')' && name[char_index - 2] == '\0')
name[char_index - 2] = '('; /* ) */
}
}
}
Bash漏洞的影响范围
Bash漏洞迄今为止影响的系统或应用包括如下:
1 . 调用了Bash并对提交的http参数未作处理的cgi脚本
2 . gitlab (SSH) 对于git、rsync这类远程shell来说,
常常会对用户可以执行的指令进行严格限制,但是这个BASH解析漏洞提供了一个bypass的向量
3.DHCP 客户端
动态主机配置协议客户端被用来通过DHCP自动获取网络配置信息。
该客户端使用不同的环境变量和运行bash来配置网络接口。
连接到一个恶意的DHCP服务器可能允许攻击者在客户机上运行任意代码。
黑客通过在域中的DHCP服务器中对DHCP的回送包进行特定的修改(控制hostname、 domainname等参数),
可以达到污染dhcpclient的环境变量参数的目的,从而进行远程代码执行。
4. Qmail
5. F5
6. SIP
7. Pure-ftpd
8. tmnt