首页 -> 安全研究

安全研究

安全漏洞
Apache Web Server ETag头远程信息泄露漏洞

发布日期:2003-02-25
更新日期:2003-03-04

受影响系统:
Apache Software Foundation Apache 1.3.27
Apache Software Foundation Apache 1.3.26
Apache Software Foundation Apache 1.3.25
Apache Software Foundation Apache 1.3.24
Apache Software Foundation Apache 1.3.23
Apache Software Foundation Apache 1.3.22
    - Caldera OpenLinux Server 3.1.1
    - Caldera OpenLinux Server 3.1
    - Caldera OpenLinux Workstation 3.1.1
    - Caldera OpenLinux Workstation 3.1
    - Conectiva Linux 8.0
    - Conectiva Linux 7.0
    - Conectiva Linux 6.0
    - Mandrake Linux Corporate Server 1.0.1
    - Mandrake Linux 8.1
    - Mandrake Linux 8.0
    - Mandrake Linux 7.2
    - RedHat Linux 7.2
    - RedHat Linux 7.1
    - RedHat Linux 7.0
    - RedHat Linux 6.2
    - Sun Solaris 9.0
    - Sun Solaris 8.0
描述:
BUGTRAQ  ID: 6939

Apache是一款流行的开放源代码httpd服务程序。

Apache Web服务程序在生成Etag应答头时处理存在问题,远程攻击者可以利用这个漏洞获得服务器敏感信息,如文件节点号。

Apache的ETag用于缓冲管理也节约网络带宽,可以由FileETag指示进行设置。如果Apache Web服务器配置使用了FileETag指示,攻击者可以提交恶意请求,使Apache生成包含文件节点号的ETag头字段的应答返回给客户端。攻击者可以根据此信息对目标网络进一步进行攻击。

<*链接:http://www.openbsd.org/errata.html
*>

建议:
临时解决方法:

如果您不能立刻安装补丁或者升级,NSFOCUS建议您采取以下措施以降低威胁:

* Apache 1.3.23及以后版本可以使用'FileETag -INode'配置就不会有inode信息。
* 使用OpenBSD发布的安全补丁:

ftp://ftp.openbsd.org/pub/OpenBSD/patches/3.2/common/008_httpd.patch

Apply by doing:
    cd /usr/src
    patch -p0 < 008_httpd.patch

And then rebuild and install httpd and it's modules:
    cd usr.sbin/httpd
    make -f Makefile.bsd-wrapper obj
    make -f Makefile.bsd-wrapper depend
    make -f Makefile.bsd-wrapper
    make -f Makefile.bsd-wrapper install

If httpd had been started, you might want to run
    apachectl stop
    apachectl start
afterwards.

Index: usr.sbin/httpd/src/main/http_main.c
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/src/main/http_main.c,v
retrieving revision 1.25.2.1
retrieving revision 1.25.2.2
diff -u -p -r1.25.2.1 -r1.25.2.2
--- usr.sbin/httpd/src/main/http_main.c    8 Nov 2002 00:04:04 -0000    1.25.2.1
+++ usr.sbin/httpd/src/main/http_main.c    24 Feb 2003 02:09:38 -0000    1.25.2.2
@@ -1,4 +1,4 @@
-/* $OpenBSD: http_main.c,v 1.25.2.1 2002/11/08 00:04:04 jason Exp $ */
+/* $OpenBSD: http_main.c,v 1.25.2.2 2003/02/24 02:09:38 margarida Exp $ */

/* ====================================================================
  * The Apache Software License, Version 1.1
@@ -5176,6 +5176,7 @@ static void standalone_main(int argc, ch
    }
    ap_set_version();    /* create our server_version string */
    ap_init_modules(pconf, server_conf);
+    ap_init_etag(pconf);
    version_locked++;    /* no more changes to server_version */

    if(!is_graceful && !is_chrooted)
Index: usr.sbin/httpd/src/main/http_protocol.c
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/src/main/http_protocol.c,v
retrieving revision 1.13
retrieving revision 1.13.2.1
diff -u -p -r1.13 -r1.13.2.1
--- usr.sbin/httpd/src/main/http_protocol.c    19 Jul 2002 21:31:16 -0000    1.13
+++ usr.sbin/httpd/src/main/http_protocol.c    24 Feb 2003 02:09:39 -0000    1.13.2.1
@@ -1,3 +1,4 @@
+/*    $OpenBSD: http_protocol.c,v 1.13.2.1 2003/02/24 02:09:39 margarida Exp $ */
/* ====================================================================
  * The Apache Software License, Version 1.1
  *
@@ -76,6 +77,7 @@
#include "util_date.h"          /* For parseHTTPdate and BAD_DATE */
#include <stdarg.h>
#include "http_conf_globals.h"
+#include "ap_sha1.h"

#define SET_BYTES_SENT(r) \
   do { if (r->sent_bodyct) \
@@ -276,7 +278,10 @@ static int byterange_boundary(request_re
API_EXPORT(int) ap_set_byterange(request_rec *r)
{
     const char *range, *if_range, *match;
+    char *bbuf, *b;
+    u_int32_t rbuf[12]; /* 48 bytes yields 64 base64 chars */
     long length, start, end, one_start = 0, one_end = 0;
+    size_t u;
     int ranges, empty;
    
     if (!r->clength || r->assbackwards)
@@ -322,8 +327,20 @@ API_EXPORT(int) ap_set_byterange(request
      * caller will perform if we return 1.
      */
     r->range = range;
-    r->boundary = ap_psprintf(r->pool, "%lx%lx",
-                  r->request_time, (long) getpid());
+    for (u = 0; u < sizeof(rbuf)/sizeof(rbuf[0]); u++)
+        rbuf[u] = htonl(arc4random());
+
+    bbuf = ap_palloc(r->pool, ap_base64encode_len(sizeof(rbuf)));
+    ap_base64encode(bbuf, (const unsigned char *)rbuf, sizeof(rbuf));
+    for (b = bbuf; *b != '\0'; b++) {
+        if (((b - bbuf) + 1) % 7 == 0)
+            *b = '-';
+        else if (!isalnum(*b))
+            *b = 'a';
+    }
+
+    r->boundary = bbuf;
+
     length = 0;
     ranges = 0;
     empty = 1;
@@ -646,7 +663,7 @@ API_EXPORT(int) ap_meets_conditions(requ
  * could be modified again in as short an interval.  We rationalize the
  * modification time we're given to keep it from being in the future.
  */
-API_EXPORT(char *) ap_make_etag(request_rec *r, int force_weak)
+API_EXPORT(char *) ap_make_etag_orig(request_rec *r, int force_weak)
{
     char *etag;
     char *weak;
@@ -3106,4 +3123,164 @@ API_EXPORT(void) ap_send_error_response(
     ap_kill_timeout(r);
     ap_finalize_request_protocol(r);
     ap_rflush(r);
+}
+
+/*
+ * The shared hash context, copies of which are used by all children for
+ * etag generation.  ap_init_etag() must be called once before all the
+ * children are created.  We use a secret hash initialization value
+ * so that people can't brute-force inode numbers.
+ */
+static AP_SHA1_CTX baseCtx;
+
+int ap_create_etag_state(pool *pconf)
+{
+    u_int32_t rnd;
+    unsigned int u;
+    int fd;
+    const char* filename;
+
+    filename = ap_server_root_relative(pconf, "logs/etag-state");
+    ap_server_strip_chroot(filename, 0);
+
+    if ((fd = open(filename, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW, 0640)) ==
+      -1) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+          "could not create %s", filename);
+        exit(-1);
+    }
+
+    if (fchown(fd, -1, ap_group_id) == -1) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+          "could not chown %s", filename);
+        exit(-1);
+    }
+
+    /* generate random bytes and write them */
+    for (u = 0; u < 4; u++) {
+        rnd = arc4random();
+        if (write(fd, &rnd, sizeof(rnd)) == -1) {
+            ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+              "could not write to %s", filename);
+            exit(-1);
+        }
+    }
+
+    close (fd);
+}
+
+API_EXPORT(void) ap_init_etag(pool *pconf)
+{
+    if (ap_read_etag_state(pconf) == -1) {
+        ap_create_etag_state(pconf);
+        if (ap_read_etag_state(pconf) == -1) {
+            ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+              "could not initialize etag state");
+            exit(-1);
+        }
+    }            
+}
+
+int ap_read_etag_state(pool *pconf)
+{
+    struct stat st;
+    u_int32_t rnd;
+    unsigned int u;
+    int fd;
+    const char* filename;
+
+    ap_SHA1Init(&baseCtx);
+
+    filename = ap_server_root_relative(pconf, "logs/etag-state");
+    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, NULL,
+      "Initializing etag from %s", filename);
+
+    ap_server_strip_chroot(filename, 0);
+
+    if ((fd = open(filename, O_RDONLY|O_NOFOLLOW, 0640)) == -1)
+    return (-1);
+
+    fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP);
+    fchown(fd, -1, ap_group_id);
+
+    if (fstat(fd, &st) == -1) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+          "could not fstat %s", filename);
+        exit(-1);
+    }
+
+    if (st.st_size != sizeof(rnd)*4) {
+    return (-1);
+    }
+
+    /* read 4 random 32-bit uints from file and update the hash context */
+    for (u = 0; u < 4; u++) {
+        if (read(fd, &rnd, sizeof(rnd)) < sizeof(rnd))
+            return (-1);
+
+        ap_SHA1Update_binary(&baseCtx, (const unsigned char *)&rnd,
+          sizeof(rnd));
+    }
+
+    if (close(fd) == -1) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+          "could not properly close %s", filename);
+        exit(-1);
+    }
+}
+
+API_EXPORT(char *) ap_make_etag(request_rec *r, int force_weak)
+{
+    AP_SHA1_CTX hashCtx;
+    core_dir_config *cfg;
+    etag_components_t etag_bits;
+    int weak;
+    unsigned char md[SHA_DIGESTSIZE];
+    unsigned int i;
+    
+    memcpy(&hashCtx, &baseCtx, sizeof(hashCtx));
+    
+    cfg = (core_dir_config *)ap_get_module_config(r->per_dir_config,
+      &core_module);
+    etag_bits = (cfg->etag_bits & (~ cfg->etag_remove)) | cfg->etag_add;
+    if (etag_bits == ETAG_UNSET)
+        etag_bits = ETAG_BACKWARD;
+    
+    weak = ((r->request_time - r->mtime <= 1) || force_weak);
+    
+    if (r->finfo.st_mode != 0) {
+        if (etag_bits & ETAG_NONE) {
+            ap_table_setn(r->notes, "no-etag", "omit");
+            return "";
+        }
+        if (etag_bits & ETAG_INODE) {
+            ap_SHA1Update_binary(&hashCtx,
+              (const unsigned char *)&r->finfo.st_dev,
+              sizeof(r->finfo.st_dev));
+            ap_SHA1Update_binary(&hashCtx,
+              (const unsigned char *)&r->finfo.st_ino,
+              sizeof(r->finfo.st_ino));
+        }
+        if (etag_bits & ETAG_SIZE)
+            ap_SHA1Update_binary(&hashCtx,
+              (const unsigned char *)&r->finfo.st_size,
+              sizeof(r->finfo.st_size));
+        if (etag_bits & ETAG_MTIME)
+            ap_SHA1Update_binary(&hashCtx,
+              (const unsigned char *)&r->mtime,
+              sizeof(r->mtime));
+    }
+    else {
+        weak = 1;
+        ap_SHA1Update_binary(&hashCtx, (const unsigned char *)&r->mtime,
+          sizeof(r->mtime));
+    }
+    ap_SHA1Final(md, &hashCtx);
+    return ap_psprintf(r->pool, "%s\""
+      "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+        "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+        "\"", weak ? "W/" : "",
+      md[0], md[1], md[2], md[3], md[4], md[5], md[6], md[7],
+      md[8], md[9], md[10], md[11], md[12], md[13], md[14], md[15],
+      md[16], md[17], md[18], md[19]);
}

厂商补丁:

Apache Software Foundation
--------------------------
目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:

http://www.apache.org/

浏览次数:5201
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障