Chapardeur de mots de passe

Énoncé :

Un ami vous demande de l'aide pour déterminer si l'email qu'il vient d'ouvrir au sujet du Covid-19 était malveillant et si c'était le cas, ce qu'il risque.

Il prétend avoir essayé d'ouvrir le fichier joint à cet mail sans y parvenir. Peu de temps après, une fenêtre liée à l'anti-virus a indiqué, entre autre, le mot KPOT v2.0 mais rien d'apparent n'est arrivé en dehors de cela.

Après une analyse préliminaire, votre ami vous informe qu'il est probable que ce malware ait été légèrement modifié, étant donné que le contenu potentiellement exfiltré (des parties du format de texte et de fichier avant chiffrement) ne semble plus prédictible. Il vous recommande donc de chercher d'autres éléments pour parvenir à l'aider.

Vous disposez d'une capture réseau de son trafic pour l'aider à déterminer si des données ont bien été volées et lui dire s'il doit rapidement changer ses mots de passe !

pws.pcap.zip ~500Mo

Étape 1 - Recherche sur le malware

Pour commencer, nous téléchargeons la capture de trames de ~500Mo. Cela nous laisse le temps de chercher quelques informations sur le malware KPOT v2.0.

Je tombe sur 2 sites :

  • https://www.proofpoint.com/us/threat-insight/post/new-kpot-v20-stealer-brings-zero-persistence-and-memory-features-silently-steal

  • https://labs.sentinelone.com/info-stealers-how-malware-hacks-private-user-data/

On apprend que le malware contamine les victimes généralement par des attaques phishing à partir de la pièce jointe. Kpot utilise http pour agîr, il communique avec un serveur distant pour l'informer de l'infection d'un poste.

Il envoie une requête GET à destination d'un serveur de ce type: http://lesitemalveillant.ru/lmpUNlwDfoybeulu/gate.php

La réponse du serveur est encodé en base64 et XOR'd avec une clé stocké sous forme de chaîne. Voici un exemple d'échantillon déja analysé :

1111111111111100__DELIMM__A.B.C.D__DELIMM__appdata__GRABBER__*.log,*.txt,__GRABBER__%appdata%__GRABBER__0__GRABBER__1024__DELIMM__desktop_txt__GRABBER__*.txt,__GRABBER__%userprofile%\Desktop__GRABBER__0__GRABBER__150__DELIMM____DELIMM____DELIMM__

Les données contenu dans cette réponse sont délimitées par "DELIMM" et sont réparties selon le type de données suivant :

  • Une chaîne de bit indiquant les commandes à éxécuter

  • L'adresse ip de la victime

  • Les règles GRABBER précisant les fichiers à rechercher et exfiltrer

Le premier composant de la réponse ci dessus est une chaîne de 16 bits. Chaque 1 active une fonctionnalité, 0 la désactive. Voici une liste de quelques fonctionnalités :

  • Voler les cookies, les mots de passe de Chrome

  • Voler les cookies, les mots de passe de Firefox

  • Voler les cookies, les mot de passe d'Internet Explorer

  • Voler les comptes Skype

  • Voler les comptes de Télégram

  • Voler des comptes Discord

  • Volez les comptes Steam

  • Prendre une capture d'écran

  • Voler divers comptes clients FTP

  • Se supprimer lui même

  • Récupérer un fichier en fonction de son extension, sa taille, son path

Enfin ! La capture de trames est téléchargé. Maintenant que nous avons une vision sur le fonctionnement général du malware, commençons à l'analyser !

Étape 2 - La communication post-infection

Vu le contexte du challenge, je commence par chercher des trames en rapport avec la pièce jointe télécharger par notre ami, mais RAS.

Je passe donc à la recherche de la requête GET envoyé au serveur malveillant sur le fichier ciblé "gate.php".

onosh@kali:/home/onosh/FCSC/FORENSIC/CHAPARDEUR# tshark -r pws.pcap http.request.method == "GET" |grep -iH 'gate.php'
2656  37.377541 192.168.4.129 → 198.54.117.197 HTTP 217 GET /lmpUNlwDfoybeulu/gate.php HTTP/1.1 
3251  39.543285 192.168.4.129 → 104.27.140.49 HTTP 218 GET /o96xEVtEmxfoYNxf/gate.php HTTP/1.1 
6138  41.601461 192.168.4.129 → 185.25.51.81 HTTP 217 GET /WjXxdpfqDyEE45gr/gate.php HTTP/1.1 
7174  44.655584 192.168.4.129 → 203.0.113.42 HTTP 230 GET /Ym9ubmVfcGlzdGVf/gate.php HTTP/1.1

On tombe sur 4 requêtes, voyons voir la quelle à répondu par OK à cette demande !

onosh@kali:/home/onosh/FCSC/FORENSIC/CHAPARDEUR# tshark -r pws.pcap http.response |egrep '(198.54.117.197|104.27.140.49|185.25.51.81|203.0.113.42)'
 2658  37.533943 198.54.117.197 → 192.168.4.129 HTTP 380 HTTP/1.1 403 Forbidden  (text/html)
 3253  39.548535 104.27.140.49 → 192.168.4.129 HTTP 530 HTTP/1.1 403 Forbidden  (text/plain)
 6186  41.650472 185.25.51.81 → 192.168.4.129 HTTP 1460 HTTP/1.1 404 Not Found  (text/html)
 7176  44.656395 203.0.113.42 → 192.168.4.129 HTTP 603 HTTP/1.1 200 OK  (text/html)
11616  47.662486 203.0.113.42 → 192.168.4.129 HTTP 267 HTTP/1.1 200 OK  (text/html)

Le serveur en 203.0.113.42 a l'air d'être le bon candidat.

Récupérons le contenu de sa réponse :

onosh@kali:/home/onosh/FCSC/FORENSIC/CHAPARDEUR# tshark -r pws.pcap -T fields -e http.file_data frame.number eq 7176
RHVdQ1V8BFVHAgRSAGNZRisbKDYoBXgpKW0HUgl8WUZMal1HXWIGU0Vtaid0HiE7ORszEhQ8UQUCU2o8dgApNDYBPiw7ZhsIGVUZSR8mEAJYGzM0Ng13JjNgajwUMxgGECUYEkETaiMkc3chdAA3KUQbMzQ2DXcmM2BqPABiWkIrGyg2KAV4KSltUQZCORwZBBsYCxATaiMkc3chdAA3KV5qGAsQYGo7MWB0IXMXOikrYRkAAT5FFhlUXA9UdzQyETcHBws8ajsxYHQhcxc6KSt0MywjHnQmNHdnPG5iNykwASA6KQFqOyltcSZ9GyU7KxszLCAJeS07f2o8

D'après la documentation sur le malware, les données ont été encodé en base64 puis XOR'd à l'aide d'une clé, cependant nous n'avons pas cette clé...

Étape 3 - La clé XOR

Quelques types d'attaques sont connues avec XOR :

  • plaintext ⊕ key = encrypted_text

  • encrypted_text ⊕ plaintext = key

  • encrypted_text ⊕ key = plaintext

Ici nous avons des données chiffrées, pas de clé, mais nous connaissons les potentiels données qui pourraient se trouver à l'intérieur (GRABBER, DELIM etc...).

Après quelque recherche je trouve un tool capable de gérer cette attaque :

  • https://blog.didierstevens.com/2017/06/06/update-xor-kpa-py-version-0-0-5/.

La description de son fonctionnement est ici :

  • https://isc.sans.edu/forums/diary/Malware+and+XOR+Part+1/22486/

  • https://isc.sans.edu/forums/diary/Malware+and+XOR+Part+2/22490/

Il ne reste plus qu'à tester !

L'outil xor-kpa.py prend 2 fichiers en entrée :

Le premier fichier contient le texte en clair, et le second le fichier encodé.

Dans son exemple, Monsieur Didier Stevens recherche la chaîne "This program cannot be run in DOS mode" contenu généralement dans les éxécutables.

Son programme est d'ailleurs adaptés pour travailler avec cette chaîne, mais nous cela ne nous intéresse pas.

Notre texte en clair est composé de :

1111111111111100__DELIMM__A.B.C.D__DELIMM__appdata__GRABBER__*.log,*.txt,__GRABBER__%appdata%__GRABBER__0__GRABBER__1024__DELIMM__desktop_txt__GRABBER__*.txt,__GRABBER__%userprofile%\Desktop__GRABBER__0__GRABBER__150__DELIMM____DELIMM____DELIMM__

Prenons un échantillon !

Je décide de modifier le script xor-kpa.py :

onosh@kali:/home/onosh/FCSC/FORENSIC/CHAPARDEUR# grep -inH --color 'dos' xor-kpa.py 
xor-kpa.py:42:dPlaintext = {'dos': 'This program cannot be run in DOS mode'}

Je remplace This program cannot be run in DOS mode par GRABBER__0__GRABBER__1024

Le script ne prend pas en compte l'encodage base64, je décode donc la chaîne

onosh@kali#:/home/onosh/FCSC/FORENSIC/CHAPARDEUR# base64 -d enc.b64 >ciph.txt

Je lance le script en indiquant que nous recherchons le plaintext contenu dans la variable dos dans le contenu du fichier cipher.txt

onosh@kali:/home/onosh/FCSC/FORENSIC/CHAPARDEUR# ./custom.py -n dos ciph.txt 
Key:       '!\x053s2Uxly>F0^a\x02DX\x16\x1eJ\x06(k\x03'
Key (hex): 0x210533733255786c793e46305e61024458161e4a06286b03
Extra:     1
Divide:    1
Counts:    1
Keystream: '3s2Uxly>F0^a\x02DX\x16\x1eJ\x06(k\x03!\x053'

Key:       'f+lMSn\x10G@\x168c)1\x19\x06\x02?+e6[sd'
Key (hex): 0x662b6c4d536e10474016386329311906023f2b65365b7364
Extra:     1
Divide:    1
Counts:    1
Keystream: '\x02?+e6[sdf+lMSn\x10G@\x168c)1\x19\x06\x02'

Key:       tDlsdL5dv25c1Rhv
Key (hex): 0x74446c73644c35647632356331526876
Extra:     9
Divide:    1
Counts:    1
Keystream: dv25c1RhvtDlsdL5dv25c1Rhv

Nous voilà maintenant avec 3 clés !

D'après les deux sites que l'on a vu au début expliquant le fonctionnement du malware, la clé fait généralement 16 bits, oh ! comme la dernière :)

La clé XOR serait donc : tDlsdL5dv25c1Rhv 🍀

Nous retrouvons donc bien le texte en clair en utilisant cette clé :

0110101110111110__DELIMM__218.108.149.373__DELIMM__appdata__GRABBER__*.log,*.txt,__GRABBER__%appdata%__GRABBER__0__GRABBER__1024__DELIMM__desktop_txt__GRABBER__*.txt,__GRABBER__%userprofile%\Desktop__GRABBER__0__GRABBER__0__DELIMM____DELIMM____DELIMM__

Maintenant analysons la requête POST envoyé au serveur, cette requête exfiltre les données en utilisant la clé XOR.

onosh@kali:/home/onosh/FCSC/FORENSIC/CHAPARDEUR# tshark -r pws.pcap http.request |egrep '203.0.113.42'
11614  47.662486 192.168.4.129 → 203.0.113.42 HTTP 267 HTTP/1.1 200 POST  (text/html)
onosh@kali:/home/onosh/FCSC/FORENSIC/CHAPARDEUR# tshark -r pws.pcap -T fields -e http.file_data frame.number eq 11614

Nous récupérons le résultat en hexa :

2b003e3234097431296249164260181301363d06017e78501a13154363661b0501365f09491a5a10045718225c63453300691a1c552f04321946470655205c061125192c220f66277c49015508375047427c5b425c750c5213510d50506b5a1717205a15017a575d1502060007310d1246255f125329020544020d5a53675b4216250d165d7b54530b386a2763133833351133

Même manipulation que toute à l'heure pour déchiffrer les données

_DRAPEAU_P|us2peurQue2M4l!  R4ssur3z-Votre-Am1-Et-vo1c1Votredr4peau_FCSC
{469e8168718996ec83a92acd6fe6b9c03c6ced2a3a7e7a2089b534baae97a7}
_DRAPEAU_

Dernière mise à jour