Présentation d’un write-up de résolution du challenge « Reverse – SoStealthy » des qualifications du CTF de la Nuit du Hack 2018.
Le weekend du 31/03/2018 se déroulait les pré-qualifications pour la Nuit du Hack 2018 sous forme d’un CTF Jeopardy. Ayant eu l’occasion et le temps d’y participer avec quelques collègues et amis, voici un write-up de résolution d’un des challenges auquel nous avons pu participer.
- Catégorie : Reverse
- Nom : SoStealthy
- Description : During an incident response, we captured the network traffic from a suspected compromised host. Could you help us reverse the installed malware?
- File : suspicious.pcap (5.80MB – 7b34f24ad1a87204bc5b1aa4044013c270e171d89d07c1eab0f24e9e2cc5498b)
- Points : 150
Pour ce challenge, une fichier PCAP suspicieux est fourni. Celui-ci comprend de nombreuses requêtes HTTP. Nous débutons pas l’extraction des objets HTTP depuis Wireshark :
Ces objets sont nombreux, il va falloir analyser cet export :
Parmi les différents fichiers exportés, l’un d’eux attire l’attention. Un fichier « favicon » contenant du code :
Ce fichier dispose d’un en-tête XML puis d’un code JavaScript chargeant un ActiveX. La charge utile de cet ActiveX est encodée en base64, difficile de faire plus suspicieux.
En nettoyant l’en-tête XML et le footer XML associé, nous nous retrouvons avec un script JScript exploitable via les binaires Windows « cscript.exe » ou « wscript.exe » :
A l’exécution de celui-ci, une fenêtre GUI avec un formulaire nous est proposée :
Clairement, il nous faut à présent désosser ce binaire pour découvrir le « magic word » souhaité.
La décompilation de la version JScript avec IDA et le debugging de ce script avec la commande « cscript //X » avec Visual Studio ne donnent rien. La piste de faire un dump à chaud du process « cscript.exe » ou encore de la VM pour une analyse par volatility n’ont pas été concluantes non-plus.
Le nom de James Forshaw et DotNetToJscript nous révèle la manière dont ce binaire a été converti / embarqué dans du JScript : le projet Github DotNetToJscript permet de convertir un code .NET en JScript.
D’après les observations, le code semble en conséquence être du .NET, et très certainement une version « Portable Executable » (PE), creusons cette piste.
Les PE disposent généralement d’un header reconnaissable « MZ », header que l’on trouve mais pas à l’offset « 0 » si l’on décode le base64 :
On nettoie le début du code base64 décodée pour débuter avec le header « MZ » valide, et enregistrons le binaire résultant en tant que « .exe ».
Ce binaire peut à présent être chargé dans « dnSpy« , pour dé-compiler le code .NET de manière intelligible.
On repère rapidement les fonctions du formulaire .NET, et notamment une opération XOR :
// Token: 0x06000005 RID: 5 RVA: 0x0000226C File Offset: 0x0000046C private bool MeeBish0iotho9biBuJi(string magicWord) { for (int i = 0; i < this.Tai8Aip0ua3ULi6zo1je.Length; i++) { uint num = (uint)(magicWord[i] ^ this.Tai8Aip0ua3ULi6zo1je[i]); bool flag = (ulong)num != (ulong)((long)this.az5nieghahj0Iekah0ph[i]); if (flag) { return false; } } return true; }
La clé du XOR est stockée en décimal dans le code dé-compilé :
private int[] az5nieghahj0Iekah0ph = new int[] { 21, 91, 20, 0, 126, 0, 61, 24, 2, 82, 7, 17, 88, 22, 18, 21, 114, 117, 15, 80, 59, 24 };
La chaîne entrée dans le formulaire GUI est XORée avec les 22 derniers bytes du payload base64 lui-même :
Les 22 derniers caractères sont donc :
FkKEJ5dGVbXSkIAAAACgsA
La clé XOR est en décimal :
key = [21,91,20,0,126,0,61,24,2,82,7,17,88,22,18,21,114,117,15,80,59,24]
Pour trouver l’inconnue « magic word », il nous suffit donc de XORer les deux :
def xor_strings(xs, ys): return "".join(chr(ord(x) ^ ord(y)) for x, y in zip(xs, ys)) last22bytes = "FkKEJ5dGVbXSkIAAAACgsA" xorKey = [21,91,20,0,126,0,61,24,2,82,7,17,88,22,18,21,114,117,15,80,59,24] xorKeyStr = "" for c in xorKey: xorKeyStr = xorKeyStr + str(unichr(c)) print "Magic Word : NDH{" + xor_strings(last22bytes, xorKeyStr) + "}"
Exécution :
Flag : NDH{S0_E45Y_T0_B3_ST34L7HY}
Ce challenge nous aura résisté une bonne partie de la nuit ! Chapeau à Estelle, Martin, Georges et Timothée pour celui-ci 🙂
Salutations à toute l’équipe, on remet ça quand vous voulez 😉 // Gr3etZ