
Une implémentation VBA de la technique RunPE ou comment contourner la liste blanche d'applications.
Une implémentation simple mais efficace de la technique RunPE en VBA. Ce code peut être utilisé pour exécuter des exécutables depuis la mémoire de Word ou Excel. Il est compatible avec les versions 32 bits et 64 bits de Microsoft Office 2010 et versions ultérieures.
Plus d'informations ici :
https://itm4n.github.io/vba-runpe-part1/
https://itm4n.github.io/vba-runpe-part2/

Exploit à la fin du code, définissez le chemin du fichier que vous souhaitez exécuter.strSrcFile = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
/!\ Si vous utilisez une version 32 bits de Microsoft Office sur un OS 64 bits, vous devez spécifier des binaires 32 bits.
strSrcFile = "C:\Windows\SysWOW64\cmd.exe"
strSrcFile = "C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe"
strArguments = "-exec Bypass"
Cela sera utilisé pour former une ligne de commande équivalente à :
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -exec Bypass
(Optionnel) Activez Affichage > Fenêtre Exécution (Ctrl+G) pour vérifier les logs d'exécution et d'erreurs.
Exécutez la macro Exploit !
pe2vba.py pour convertir un fichier PE en VBA. Ainsi, il peut être directement incorporé dans la macro.user@host:~/Tools/VBA-RunPE$ ./pe2vba.py meterpreter.exe
[+] Created file 'meterpreter.exe.vba'.
RunPE.vba par le contenu du fichier .vba généré à l'étape précédente.' ================================================================================
' ~~~ EMBEDDED PE ~~~
' ================================================================================
' CODE GENRATED BY PE2VBA
' ===== BEGIN PE2VBA =====
Private Function PE() As String
Dim strPE As String
strPE = ""
PE = strPE
End Function
' ===== END PE2VBA =====
(Optionnel) Activez Affichage > Fenêtre Exécution (Ctrl+G) pour vérifier les logs d'exécution et d'erreurs.
Exécutez la macro Exploit !
/!\ Lors de l'utilisation d'un PE incorporé, la macro basculera automatiquement dans ce mode car la méthode PE() renverra une chaîne non vide.
GetThreadContext() échoue avec le code d'erreur 998.Vous pouvez rencontrer cette erreur si vous exécutez cette macro à partir d'une version 64 bits d'Office. Comme solution de contournement, vous pouvez déplacer le code vers un module plutôt que de l'exécuter depuis les références d'objets Word. Merci @joeminicucci pour l'astuce.
================================================================================
[*] Source file: 'C:\Windows\System32\cmd.exe'
[*] Checking source PE...
[*] Creating new process in suspended state...
[*] Retrieving the context of the main thread...
|__ GetThreadContext() failed (Err: 998)
Je n'ai aucune idée de pourquoi cette solution fonctionne pour le moment. J'ai un peu enquêté cependant. Cette erreur semble être causée par la structure CONTEXT qui n'est pas correctement alignée dans la version 64 bits. J'ai remarqué que la taille de la structure est également incorrecte ([VBA] LenB(CONTEXT) != [C++] sizeof(CONTEXT)) alors qu'elle est correcte dans la version 32 bits. J'ai une solution fonctionnelle qui permet à GetThreadContext() de retourner correctement, mais cela casse d'autres choses plus loin dans l'exécution.
Modification 2019-12-15 : la définition de la version 64 bits de la structure CONTEXT était effectivement incorrecte mais la corriger n'a pas résolu le bug. J'ai donc implémenté une solution de contournement pour la version 64 bits. J'ai remplacé l'argument de structure CONTEXT des fonctions GetThreadContext() et SetThreadContext() par un tableau Byte de la même taille.
Modification 2019-12-17 : j'ai finalement trouvé le problème. Ma première hypothèse était correcte, la structure CONTEXT doit être alignée sur 16 octets en mémoire. C'est quelque chose que l'on peut contrôler en C en utilisant align(16) dans la définition de la structure mais on ne peut pas le contrôler en VBA. Par conséquent, GetThreadContext() et SetThreadContext() peuvent échouer "aléatoirement". Les tableaux Byte en revanche semblent toujours être alignés sur 16 octets, c'est pourquoi cette solution de contournement est efficace mais il n'y a aucune garantie, à moins que je ne fasse du reverse engineering de l'interpréteur/compilateur VBA et que je ne le comprenne ?!
LongPtr - Type défini par l'utilisateur non définiSi vous obtenez cette erreur, cela signifie que vous exécutez la macro à partir d'une ancienne version d'Office (<=2007). Le type LongPtr a été introduit dans VBA7 (Office 2010) avec le support de l'API Windows 64 bits. Il est très utile pour manipuler des pointeurs sans avoir à se soucier de l'architecture (32 bits / 64 bits).
Comme solution de contournement, vous pouvez remplacer toutes les occurrences de LongPtr par Long (32 bits) ou LongLong (64 bits). Utilisez Ctrl+H dans votre éditeur de texte préféré.
@hasherezade - Implémentation complète de RunPE (https://github.com/hasherezade/)
@Zer0Mem0ry - RunPE 32 bits écrit en C++ (https://github.com/Zer0Mem0ry/RunPE)
@DidierStevens - Incorporation de PE en VBA
Ce code a été testé sur les plateformes suivantes :
Voici un tableau de correspondance entre certains types Win32 et VBA :
(*) LongPtr est un type "dynamique", il fait 4 octets dans Office 32 bits et 8 octets dans Office 64 bits. https://msdn.microsoft.com/fr-fr/library/office/ee691831(v=office.14).aspx
| C++ | VBA | Arch |
|---|
| BYTE | Byte | 32 & 64 |
| WORD | Integer | 32 & 64 |
| DWORD, ULONG, LONG | Long | 32 & 64 |
| DWORD64 | LongLong | 64 |
| HANDLE | LongPtr(*) | 32 & 64 |
| LPSTR | String | 32 & 64 |
| LPBYTE | LongPtr(*) | 32 & 64 |