lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20040424155303.24514.qmail@www.securityfocus.com>
Date: 24 Apr 2004 15:53:03 -0000
From: Adam Zabrocki <pi3ki31ny@...pl>
To: bugtraq@...urityfocus.com
Subject: Apache - all versions vulnerability in OLD procesors.




Apache - all versions vulnerability in OLD procesors.

I.  Entry.

    Vulnerability in probably all versions of apache web server, default
install (as of version 1.3.29).

II. Vulnerability details.

	There are few scenarios, few calls leading to that bug. 
The first call is in mod_auth, mod_auth3 and mod_auth4. As follows:

"src/modules/standard/mod_auth.c"
and
"src/modules/standard/mod_aut3.c"
and
"src/modules/standard/mod_aut4.c"
static int authenticate_basic_user(request_rec *r)
{
...
...
    const char *sent_pw;
    char *real_pw;
...
...
    if ((res = ap_get_basic_auth_pw(r, &sent_pw)))
        return res;
...
...
    if (!(real_pw = get_pw(r, c->user, sec->auth_pwfile))) {
       ...
       ...
    }
...
...
    invalid_pw = ap_validate_password(sent_pw, real_pw);
...
...
}

request_rec structure is declared in "src/include/httpd.h".

Now look at ap_validate_password() function in "src/ap/ap_check.c":

API_EXPORT(char *) ap_validate_password(const char *passwd, const char *hash)
{
    char sample[120];
...
...
    /* Netscape / SHA1 ldap style strng
     */
    else if (strncmp(hash, AP_SHA1PW_ID, AP_SHA1PW_IDLEN) == 0) {

        ap_sha1_base64(passwd, strlen(passwd), sample);
    }
...
...
}

AP_SHA1PW_ID in "src/include/ap_sha1.h" is defined as:
...
...
#define AP_SHA1PW_ID "{SHA}"
...
...

Ok. So to the heart of problem. So for strncmp hash to be zero, above must be
passwd to ap_get_basic_auth_pw() function:

"src/main/http_pro.c"
API_EXPORT(int) ap_get_basic_auth_pw(request_rec *r, const char **pw)
{
...
...
}

The second argument, pw is evaluated inside ap_validate_password that is called
from inside get_pw():

"src/modules/standard/mod_auth.c"
static char *get_pw(request_rec *r, char *user, char *auth_pwfile)
{
...
...
}

Ok function ap_validate_password calls ap_sha1_base64(). Take a closer look:

"src/ap/ap_sha1.c"
API_EXPORT(void) ap_sha1_base64(const char *clear, int len, char *out)
{
...
...
    AP_SHA1_CTX context;
...
...
    ap_SHA1Init(&context);
    ap_SHA1Update(&context, clear, len);
...
...
}

AP_SHA1_CTX:

"src/ap/ap_sha1.c"
typedef struct {
    AP_LONG digest[5];             /* message digest */
    AP_LONG count_lo, count_hi;    /* 64-bit bit count */
    AP_LONG data[16];              /* SHA data buffer */
    int local;                     /* unprocessed amount in data */
} AP_SHA1_CTX;

ok, now ap_SHA1Init():

"src/ap/ap_sha1.c"
API_EXPORT(void) ap_SHA1Init(AP_SHA1_CTX *sha_info)
{
    sha_info->digest[0] = 0x67452301L;
    sha_info->digest[1] = 0xefcdab89L;
    sha_info->digest[2] = 0x98badcfeL;
    sha_info->digest[3] = 0x10325476L;
    sha_info->digest[4] = 0xc3d2e1f0L;
    sha_info->count_lo = 0L;
    sha_info->count_hi = 0L;
    sha_info->local = 0;
}

"src/ap/ap_sha1.c"
API_EXPORT(void) ap_SHA1Update(AP_SHA1_CTX *sha_info, const char *buf,
                               unsigned int count)
{
...
...
    const AP_BYTE *buffer = (const AP_BYTE *) buf;
...
...
    while (count >= SHA_BLOCKSIZE) {
        ebcdic2ascii((AP_BYTE *)sha_info->data, buffer, SHA_BLOCKSIZE);
        buffer += SHA_BLOCKSIZE;
        count -= SHA_BLOCKSIZE;
        maybe_byte_reverse(sha_info->data, SHA_BLOCKSIZE);
        sha_transform(sha_info);
    }
    ebcdic2ascii((AP_BYTE *)sha_info->data, buffer, count);
...
...
}

Aha... good, while count is bigger or equal following constant:

"src/ap/ap_sha1.c"
...
...
#define SHA_BLOCKSIZE           64
...
...

Hm... ok, this get's evaluated further more in ebcdic2ascii() ?

"src/ap/ap_ebcdi.c"
API_EXPORT(void *)
ebcdic2ascii(void *dest, const void *srce, size_t count)
{
    unsigned char *udest = dest;
    const unsigned char *usrce = srce;

    while (count-- != 0) {
        *udest++ = os_toascii[*usrce++];
    }

    return dest;
}

Above function copies 64 bytes, structre AP_SHA1_CTX is an array of 16 elements.
Take a look at structure element declaration :

"src/include/ap_sha1.h"
typedef unsigned long AP_LONG;     /* a 32-bit quantity */

This is fine, assuming that we have 32 bits CPU, and sizeof(unsigned long) equals 4. So 4*16=64.
There is no guarantee that on some archs unsigned long is going to stay 32 bit width. When it's
either longer or shorter (I am not sure if long can be 16 bits long, but possibly ANSI C standart
doesn't say anythin about it's length in bits). Ie. on 64bit platforms, depending on compiler
options, and compiler it self long can be either 64 (default) or 32 bits. 
Take a look at that:

siusiak% uname -a; cat a.c; cc a.c; ./a.out
 OSF1 sirppi V4.0 1229 alpha
 int main(void) { 
 	printf("%d\n",sizeof(unsigned long)); 
	return 0; 
	}
 8
siusiak%

When sizeof( unsigned long )!=4 it can lead to memory corruption in function ebcdic2ascii(),
which will either copy too much, copyied in this example 32 bytes more than he should and
that situaction do this bug! To bypass this not popular vulnerability we should only
resolution is quite simple, SHA_BLOCKSIZE should be declared as sizeof(unsigned long)*16.
Possibly SHA_BLOCKSIZE must stay 64 bytes long, than obviously author should take care more
about single elements size.


III. Exploit.

	I no time to have a very close look on it, so no proof of concept is provided this time.
Thanks for attention for read this shit.

--
pi3 (pi3ki31ny) - pi3ki31ny@...pl (BIG thx for appelast and giejot)
http://www.pi3.int.pl

"MJINKS, swanky pijemy w czerwcu no nie? ;-)"


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ