前言
学习,用上一篇里的动态调试方法调试一下CVE-2014-6271破壳漏洞。
环境搭建
根据漏洞影响版本和漏洞时间,在Ubuntu Packages里找到合适的版本,在虚拟机中编译安装后进行测试:
env x='() { :;}; echo Pwn' ./bash -c "echo test"
看到漏洞正常触发:
漏洞分析
配置launch.json:
{
"configurations": [
{
"type": "cppdbg",
"request": "launch",
"name": "GDB",
"program": "${workspaceFolder}/run/bin/bash",
"stopAtEntry": false,
"args": ["-c", "echo test"],
"cwd": "${fileDirname}",
"environment": [
{"name": "x", "value": "() { :;}; echo Pwn"},
],
"MIMode": "gdb",
}
]
}
根据漏洞payload猜测,漏洞成因应该是将函数x的内容跟待执行命令拼接在了一起执行,所以函数体外的bash指令在无需函数被调用的情况下也被一起执行了。
一步步调试,找到variables.c文件下的initialize_shell_variables函数,该函数会处理环境变量,当该环境变量为自定义函数时:
/* 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);
if (posixly_correct == 0 || legal_identifier (name))
parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);
...
}
就会将环境变量名作为函数名,拼接成x(){}形式的函数构造,交由parse_and_execute函数通过解析执行的方式导入到环境中,因此函数体外的命令也混入其中被一起执行了。
漏洞修复
简单分析修复补丁,关键点:
if (legal_identifier (name))
parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
if (legal_identifier (temp_name))
parse_and_execute (temp_string, temp_name,
SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
看起来应该是根据SEVAL_FUNCDEF和SEVAL_ONECMD这两个flag阻止了函数体外命令的执行,但还是可以将函数名构造为已知将要执行的命令,这样就能将该命令覆盖掉,从而实现命令注入,利用方法详见参考文章。