前言

学习,用上一篇里的动态调试方法调试一下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阻止了函数体外命令的执行,但还是可以将函数名构造为已知将要执行的命令,这样就能将该命令覆盖掉,从而实现命令注入,利用方法详见参考文章。


参考

Bash远程代码执行漏洞“破壳”(CVE-2014-6271)分析

我是如何利用环境变量注入执行任意命令


复现 Linux

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!

tai-e学习(1)
学习调试Linux命令程序