hacking contest

hacking exploits security forum
hacking
compliance articles
upgrade backup exec
information security consultant

Help - Search - Member List - Calendar
Full Version: Apache Memory Corruption In Various Architectures
GovernmentSecurity.org > The Archives > Exploit Articles
qcred11
Apr 26 2004, 06:48 PM
QUOTE

The Apache Software Foundation's HTTP Server is "an effort to develop and maintain an open-source HTTP server for modern operating systems including UNIX and Windows NT. The goal of this project is to provide a secure, efficient and extensible server that provides HTTP services in sync with the current HTTP standards".

The Apache HTTP server contains a bug in the way it handles SHA (Secure Hash) contexts. In various processor architectures the possibility exists that memory corruption can occur.




Vulnerable Systems:
* Apache HTTP server, all versions as of 1.3.29

The problem lies in the fact that while copying a SHA context, the program calculates the number of bytes to copy based on the size of the unsigned long integer type. In effect, on architectures where the size of an unsigned long is not 32-bit, possible memory corruption can occur. There are several places in the code that lead to the same vulnerable section of code:
"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);
...
...
}

While the request_rec structure is declared in "src/include/httpd.h". Taking a closer look at the ap_validate_password() in the "src/ap/ap_check.c" file:
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);
}
...
...
}

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

In order for the strncmp hash to be zero, the above should be the password for the 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)
{
...
...
}

Now, the function ap_validate_password calls ap_sha1_base64(). Taking a closer look shows:
"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;

Taking note of the type of AP_LONG and looking at 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);
...
...
}

Notice the loop with the condition that count has to be greater or equal to the following contant:
"src/ap/ap_sha1.c"
...
...
#define SHA_BLOCKSIZE 64
...
...

And what happens 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;
}

The above function copies 64 bytes, but the AP_SHA1_CTX structure is an array of 16 elements. Take a look at the structure's element declaration:
"src/include/ap_sha1.h"
typedef unsigned long AP_LONG; /* a 32-bit quantity */

Assuming that an unsigned long is indeed 32-bit (4 bytes), the function will indeed copy only 64 bytes of data into the context structure. However on architectures other than, 80x86, there is no guarantee that the size of unsigned long would be 32-bit. On 64-bit platforms it could very well be possible with some compiler options. When the sizeof(unsigned long) is not 4 bytes, memory corruption can occur in the ebcdic2ascii() function.

This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.

 
Invision Power Board © 2001-2005 Invision Power Services, Inc.