前言
学习,用上一篇里的动态调试方法调试一下CVE-2014-6271破壳漏洞。
环境搭建
根据漏洞影响版本和漏洞时间,在Ubuntu Packages里找到合适的版本,在虚拟机中编译安装后进行测试:
1
| env x='() { :;}; echo Pwn' ./bash -c "echo test"
|
看到漏洞正常触发:

漏洞分析
配置launch.json:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| { "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函数,该函数会处理环境变量,当该环境变量为自定义函数时:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
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函数通过解析执行的方式导入到环境中,因此函数体外的命令也混入其中被一起执行了。
漏洞修复
简单分析修复补丁,关键点:
1 2 3 4 5
| 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阻止了函数体外命令的执行,但还是可以将函数名构造为已知将要执行的命令,这样就能将该命令覆盖掉,从而实现命令注入,利用方法详见参考文章。
参考
Bash远程代码执行漏洞“破壳”(CVE-2014-6271)分析
我是如何利用环境变量注入执行任意命令