/*
 * dumbpass.c
 * nitrous<at>vulnfact<d0t>com
 * 31/12/2005 - Yeah! Happy new Year!
 *
 * Just for check DUMB PASSWORDS (same username and password) under
 * three supported application protocols, FTP, TELNET and POP3.
 *
 * First of all, open an userlist (each line must contain ONLY an
 * username that will be used to try login)
 *
 * Then, connect to server and wait for server's banner. E.g.:
 * 220 ProFTPD 1.2.10 Server (ProFTPD)
 * +OK POP3 dallas [cppop 20.0]
 * Welcome to telnet server
 *
 * Whaterver!
 * 
 * After that, send the login string, wait for two seconds and finally
 * send the password string (login == password), and then, check the
 * server's response for a specific pattern (protocol dependent).
 * If the pattern match it means that the password is equal with the
 * username.
 * Although my method to find a pattern is POOR, it may be useful.
 *
 * Coded for a Pen-test... It's useful when you have permissions
 * for read the /etc/passwd file. So, you can generate an userlist
 * with these usernames and run this program with that userlist.
 *
 * Tested under SGI IRIX 6.4, SunOS 5.9, OpenBSD 3.7, Ubuntu Linux 5.04
 * Compilation:
 * Under Linux|*BSD|IRIX = $gcc dumbpass.c -o dumbpass -O2 -funroll-loops
 * Under Solaris = $gcc dumbpass.c -o dumbpass -lsocket -lnsl
 *
 * Greetz 2 Sophie, my sweety and kinky honey ;).
 */
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#if !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__sun) && !defined(__sgi)
	#include<stdint.h>
#endif
#include<signal.h>
#include<unistd.h>
#include<sys/time.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<netdb.h>

#ifdef	__sgi
	#define	SHUT_RDWR	2
#endif

#define MAXLEN	32
#define DEFAULTDELAY	3	/* Seconds between each connection*/
#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__sun) || defined(__sgi)
	#define IPPORT_FTP	21
	#define IPPORT_TELNET	23
#endif
#define IPPORT_POP3	110
//#define MYPORT_FTP	0xfee1
//#define MYPORT_TELNET	0xdead
//#define MYPORT_POP3	0x1337
#define FOO	(sizeof(struct sockaddr))

#define USER_STR	"\x55\x53\x45\x52"
#define PASS_STR	"\x50\x41\x53\x53"
#define FAIL_STR	"\x46\x41\x49\x4c"
#define LOGGED_STR	"\x4c\x4f\x47\x47\x45\x44"

struct sockaddr_in socktarget;
FILE *userlist;
char currentuser[MAXLEN];
int sock;

/* When CTRL+C is pressed it handle the SIGINT */
void exitforced()
{
	close(sock);
	fclose(userlist);
	fprintf(stderr, "Exiting...\n");
	exit(-1);
}

void usage(const char *pname)
{
	fprintf(stderr, "Usage: %s <protocolnumber> <hostname> <userlist> [delaysecs]\n\n", pname);
	fprintf(stderr, "\tProtocols supported (Application level):\n" \
			"\t1  -  FTP\t(21/tcp)\n"\
			"\t2  -  TELNET\t(23/tcp)\n"\
			"\t3  -  POP3\t(110/tcp)\n");
	exit(EXIT_SUCCESS);
}

uint16_t getportbyproto(uint32_t arg1)
{
	switch(arg1){
		case 1:
#ifndef MYPORT_FTP
			return (IPPORT_FTP);
#else
			return (MYPORT_FTP);
#endif
		case 2:
#ifndef MYPORT_TELNET
			return (IPPORT_TELNET);
#else
			return (MYPORT_TELNET);
#endif
		case 3:
#ifndef MYPORT_POP3
			return (IPPORT_POP3);
#else
			return (MYPORT_POP3);
#endif
	}
}

void socket_error(const char *socketcall)
{
	perror(socketcall);
	fclose(userlist);
	close(sock);
	exit(EXIT_FAILURE);
}

/* It is sooooo poooor :( */
uint32_t check_response(int32_t proto, const char *response)
{
	switch(proto){
		case 1: /* FTP */
			if(strstr(response, "230") != NULL) /* Server's response: 230 User blah logged in */
				return 1;
			return 0;
		case 2: /* TELNET */
			/* Possible prompts */ 
			if(strstr(response, "$") != NULL)
				return 1;
			else if(strstr(response, "#") != NULL)
				return 1;
			else if(strstr(response, ">") != NULL)
				return 1;
			else if(strstr(response, "%") != NULL)
				return 1;
			else
				return 0;
		case 3: /* POP3 */
			if(strstr(response, "+OK") != NULL) /* Server's response: +OK logged in. */
				return 1;
			return 0;
	}
}

do_conections(int32_t proto, uint32_t delay)
{
	int32_t foo, tries = 0, wait4banner = 8;
	uint16_t prt;
	char *senduser, *sendpass, *recvstr;

	fd_set readbanner;
	struct timeval tv;

	tv.tv_sec = wait4banner; /* Wait 'wait4banner' seconds for server's banner */
	tv.tv_usec = 0;

	senduser = (char *) malloc(MAXLEN + 5);
	sendpass = (char *) malloc(MAXLEN + 5);
	recvstr = (char *) malloc(1024);

#if	__BYTE_ORDER == __BIG_ENDIAN
	prt = socktarget.sin_port;
#else	/* __LITTLE_ENDIAN */
	prt = htons(socktarget.sin_port);
#endif

	while(fgets(currentuser, MAXLEN, userlist)){
		memset(senduser, 0x00, sizeof(senduser));
		memset(sendpass, 0x00, sizeof(sendpass));
		memset(recvstr, 0x00, sizeof(recvstr));

		if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
			socket_error("socket()");

		if(connect(sock, (struct sockaddr *)&socktarget, FOO) == -1)
			socket_error("connect()");

		if(proto == 2){	/* Proto = TELNET */
			strcat(senduser, currentuser); /* senduser = "currentuser\n" */
			strcat(sendpass, currentuser); /* sendpass = "currentuser\n" */
		}
		else{	/* Proto = FTP or POP3 */
			strcat(senduser, USER_STR);
			strcat(senduser, " ");
			strcat(senduser, currentuser); /* senduser = "USER currentuser\n" */
			strcat(sendpass, PASS_STR);
			strcat(sendpass, " ");
			strcat(sendpass, currentuser); /* sendpass = "PASS currentuser\n" */
		}

		FD_ZERO(&readbanner);
		FD_SET(sock, &readbanner);

		select(sock + 1, &readbanner, NULL, NULL, &tv);

		if(!FD_ISSET(sock, &readbanner)){
			fprintf(stderr, "Time out!: Banner not found in %d seconds!\n", wait4banner);
			fclose(userlist);
			close(sock);
			exit(EXIT_FAILURE);
		}

		if(send(sock, senduser, strlen(senduser), 0) == -1)
			socket_error("send() user");

		sleep(1); /* Wait 1 second for "password: " string */

		recv(sock, recvstr, 1023, 0); /* Read something...To flush the data in server's side*/

		if(send(sock, sendpass, strlen(sendpass), 0) == -1)
			socket_error("send() pass");

		sleep(1); /* Wait 1 second for Authentication response */

		if((foo = recv(sock, recvstr, 1023, 0)) == -1)
			socket_error("recv()");

		recvstr[foo] = '\0';
		currentuser[strlen(currentuser) - 1] = '\0';

		shutdown(sock, SHUT_RDWR);

		tries++;

		printf("%d\t%s:%s@%s:%d\t%s\n\n", tries, currentuser, currentuser, \
				inet_ntoa(socktarget.sin_addr), \
				prt, \
				check_response(proto, recvstr)?LOGGED_STR:FAIL_STR);

		memset(currentuser, 0x00, sizeof(currentuser));

		sleep(delay);
	}
}

int main(int argc, char **argv)
{
	struct hostent	*hosttarget;
	uint16_t port;
	uint32_t delay = (argv[4] != NULL)?atoi(argv[4]):DEFAULTDELAY;

	if(argc < 4)	usage(*argv);

	if(atoi(argv[1]) < 1 || atoi(argv[1]) > 3){
		fprintf(stderr, "\nInvalid protocol number asshole!\n\n");
		usage(*argv);
	}

	if((hosttarget = gethostbyname(argv[2])) == NULL){
		perror("gethostbyname");
		exit(EXIT_FAILURE);
	}

	if((userlist = fopen(argv[3], "r")) == NULL){
		perror("fopen");
		exit(EXIT_FAILURE);
	}

	port = getportbyproto(atoi(argv[1]));

	memset(&socktarget, 0x00, sizeof(struct sockaddr_in));
	socktarget.sin_family = AF_INET;
	socktarget.sin_addr = *((struct in_addr *)hosttarget->h_addr);
#if	__BYTE_ORDER == __BIG_ENDIAN
	socktarget.sin_port = port;
#else	/* __LITTLE_ENDIAN */
	socktarget.sin_port = htons(port);
#endif

	signal(SIGINT, exitforced);

	printf("TRIES\tUSER:PASS@HOST\t\tSTATUS\n\n");

	do_conections(atoi(argv[1]), delay);

	fclose(userlist);

	return 0;
}

