DHCP sous Windows – Callout

Les serveurs DHCP Microsoft, à partir de Windows 2003 Server, disposent d’une fonctionnalité très intéressante et rarement utilisée : le callout

Cette fonctionnalité, très bien documentée (http://msdn.microsoft.com/library/windows/desktop/aa363372.aspx), permet de notifier des librairies externes du traitement de requêtes DHCP.
Une fois n’est pas coutume, Microsoft laisse l’opportunité à ces librairies d’altérer les paquets, requêtes, et même de stopper le traitement d’une requête !

Le besoin

Pour une raison quelconque, j’ai du réfléchir à une problématique : comment ne pas distribuer d’adresses IP à une certaine catégorie de machines pouvant se brancher sur le même réseau physique/logique que des machines légitimes.

Des solutions existent déjà :

  • IpSec
  • NAC

et même d’autres moins efficaces (*) :

  • IP fixe pour tout le réseau
  • Blacklistage des adresses MAC sur les équipements frontaux
  • Réservations DHCP pour tous les postes

…Inapplicables pour diverses raisons sur l’environnement ciblé.
(*) L’on part ici du principe qu’une personne prenant volontairement une IP du réseau d’entreprise ou changeant son adresse MAC, commet une action malveillante. Cela arrive rarement par hasard.

Un début de solution

Quelques recherches Google mènent obligatoirement vers cette entrée Technet : http://blogs.technet.com/b/teamdhcp/archive/2007/10/03/dhcp-server-callout-dll-for-mac-address-based-filtering.aspx

L’on y apprend que le blacklistage d’adresses MAC au niveau DHCP n’est pas un besoin loufoque et que Microsoft a « développé » une librairie pouvant prendre en charge une liste noire ou blanche d’adresses.
A priori celle-ci est maintenant devenue une fonctionnalité native du service DHCP de Windows Server 2008 r2.

Vu le nombre de commentaires exprimant des problématiques de mise en service, et ce genre d’avertissements Microsoft :

The current callout DLL shall no longer be available after December 15, 2010.
[…]
Known Issue:

  1. This callout dll may not work on localized builds (non english builds).

… cela n’encourage guère à son utilisation !

Un peu de code

Grâce au MSDN : http://msdn.microsoft.com/library/windows/desktop/aa363373.aspx, l’on peut rapidement coder sa propre librairie (ici sans fichier de log ou de paramétrages … (pas envie, pas besoin…)

/*	Benjamin DELPY `gentilkiwi`
	http://blog.gentilkiwi.com
	benjamin@gentilkiwi.com
	Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
*/
#include <windows.h>
#include <dhcpssdk.h>

#define MAC_ADDRESS_SIZE			6
#define MAC_SOURCE_ADDRESS_OFFSET	28

const BYTE macToBlack[][MAC_ADDRESS_SIZE] = {
	{0x00, 0x0c, 0x29, 0x00, 0x00, 0x00},
	{0x00, 0x50, 0x56, 0x00, 0x00, 0x00}
};

HMODULE nextLibrary = NULL;
LPDHCP_NEWPKT nextLibraryCalloutNewPkt = NULL;

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
	if(ul_reason_for_call == DLL_PROCESS_DETACH && nextLibrary)
		FreeLibrary(nextLibrary);

	return TRUE;
}

DWORD CALLBACK DhcpNewPktHook(IN OUT LPBYTE *Packet, IN OUT DWORD *PacketSize, IN DWORD IpAddress, IN LPVOID Reserved, IN OUT LPVOID *PktContext, OUT LPBOOL ProcessIt)
{
	DWORD retour = ERROR_SUCCESS, m;
	*ProcessIt = TRUE;

	for(m = 0; m < sizeof(macToBlack) / MAC_ADDRESS_SIZE; m++)
	{
		if(RtlEqualMemory(*Packet + MAC_SOURCE_ADDRESS_OFFSET, macToBlack[m], MAC_ADDRESS_SIZE / 2))
		{
			*ProcessIt = FALSE;
			retour = DHCP_DROP_INVALID;
			break;
		}
	}

	if(*ProcessIt && nextLibraryCalloutNewPkt)
		retour = nextLibraryCalloutNewPkt(Packet, PacketSize, IpAddress, Reserved, PktContext, ProcessIt);
	
	return retour;
}

DWORD CALLBACK DhcpServerCalloutEntry(IN LPWSTR ChainDlls, IN DWORD CalloutVersion, IN OUT LPDHCP_CALLOUT_TABLE CalloutTbl)
{
	LPDHCP_ENTRY_POINT_FUNC nextEntry;

	RtlZeroMemory(CalloutTbl, sizeof(DHCP_CALLOUT_TABLE));

	if(nextLibrary = LoadLibrary(ChainDlls))
		if(nextEntry = (LPDHCP_ENTRY_POINT_FUNC) GetProcAddress(nextLibrary, DHCP_CALLOUT_ENTRY_POINT))
			nextEntry(ChainDlls + wcslen(ChainDlls) + 1, CalloutVersion, CalloutTbl);

	if(CalloutTbl->DhcpNewPktHook)
		nextLibraryCalloutNewPkt = CalloutTbl->DhcpNewPktHook;
	CalloutTbl->DhcpNewPktHook = DhcpNewPktHook;

	return ERROR_SUCCESS;
}

Sans oublier notre export C d’un __stdcall

LIBRARY
EXPORTS
	DhcpServerCalloutEntry = DhcpServerCalloutEntry

Cette librairie rejette ainsi les demandes émanant d’adresse MAC commençant par 00:0c:29 ou 00:50:56, soit provenant de machines virtuelles VMware.

Installation

Sous HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\DHCPServer\Parameters

  • CalloutEnabled de type DWORD, à 1 pour activer les Callouts, 0 pour les désactiver
  • CalloutDlls de type REG_MULTI_SZ, contenant la liste des librairies de Callouts (séparées par un saut de ligne)

dhcp_callout

Le service DHCP (DHCPServer) doit être redémarré pour prendre en charge ces modifications.

Test

C:\Documents and Settings\Administrateur>ipconfig /renew

Configuration IP de Windows

Une erreur s'est produite lors du renouvellement de l'interface Connexion au réseau local : impossible de contacter votre serveur DHC. Le délai d'attente de la demande est dépassé.

Diaboliquement efficace pour quelques lignes :)

Surveillance des routes par Juniper (7.1)

La nouvelle version de Juniper Network Connect (7.1) ne change pas grand chose à la surveillance des routes :(
Ainsi, la nouvelle version du patch anti-surveillance de routes est incorporée à mimikatz (et ne prend plus en charge la version 7.0)

Pour plus de précisions dans le service dsNcService :

  • Remplacer {0x83, 0xec, 0x1c, 0x55, 0x8b, 0xe9}; // 7.0 // 83 ec 1c 55 8b e9
  • ou bien {0x83, 0xec, 0x14, 0x53, 0x8b, 0xd9}; // 7.1 // 83 ec 14 53 8b d9
  • par : {0xb0, 0x01, 0xc2, 0x04, 0x00}

nc71

Juniper Secure Virtual Workspace, hooks userland

Le mode « Secure Virtual Workspace » ou « Bureau Virtuel » de Juniper fais appel à un vrai petit HIPS en mode user.
Ce dernier repose sur une librairie dsjvd.dll, systématiquement chargé dans les processus de la bulle.

Cet article ne le détaillera pas, mais il est tout à fais possible d’alterner une fonction hookée et une plus personnelle afin de sortir des fichiers de la bulle, d’en faire rentrer ou exécuter des programmes non autorisés.

  • Registre (advapi32), via InterceptRegistryFunctions :
    • RegCreateKeyExW
    • RegCreateKeyExA
    • RegOpenKeyExW
    • RegOpenKeyExA
    • RegCloseKey
    • RegSetValueExW
    • RegDeleteKeyW
    • RegDeleteKeyA
    • RegDeleteValueW
    • RegEnumKeyExW
    • RegEnumValueW
    • RegQueryInfoKeyW
    • RegQueryMultipleValuesW
    • RegQueryValueExW
    • RegQueryValueW
    • RegReplaceKeyW
    • RegRestoreKeyW
    • RegSaveKeyW
    • RegSetKeySecurity
    • RegOpenCurrentUser
    • SetNamedSecurityInfoW
    • GetNamedSecurityInfoW
  • Appels noyau (ntdll), via InterceptNativeFunctions :
    • NtCreateFile
    • NtOpenFile
    • NtClose
    • NtQueryInformationFile
    • NtSetInformationFile
    • NtQueryDirectoryFile
    • NtQueryAttributesFile
    • NtQueryFullAttributesFile
    • NtReadFile
    • NtWriteFile
    • NtMapViewOfSection
    • NtUnmapViewOfSection
    • NtCreateSection
    • NtOpenSection
    • NtQuerySection
  • Fichier et mémoire (kernel32/user32), via InterceptFileFunctions
    • FindFirstFileExW
    • FindFirstFileW
    • FindNextFileW
    • FindClose
    • SetFileAttributesW
    • GetFileAttributesW
    • GetFileAttributesExW
    • DeleteFileW
    • MoveFileW
    • MoveFileExW
    • MoveFileWithProgressW
    • CreateHardLinkW
    • CopyFileW
    • CopyFileExW
    • CreateDirectoryW
    • CreateDirectoryExW
    • RemoveDirectoryW
    • CreateFileW
    • SetEndOfFile
    • CloseHandle
    • FindFirstChangeNotificationW
    • ReadDirectoryChangesW
    • WriteProcessMemory
    • ReadProcessMemory
    • LoadLibraryExW
    • DuplicateHandle
    • FlushViewOfFile
    • VirtualAlloc
    • SwitchDesktop
  • Impression (gdi32/winspool), via InterceptDeviceFunctions
    • CreateDCW
    • OpenPrinterW
    • EnumPrintersW
    • GetDefaultPrinterW
    • AddPrinterDriverW
    • AddPrinterDriverExW
    • WritePrinter
  • Presse-papier (user32), via InterceptClipboardFunctions
    • OpenClipboard
    • CloseClipboard
    • EmptyClipboard
    • ChangeClipboardChain
    • CountClipboardFormats
    • GetClipboardOwner
    • EnumClipboardFormats
    • GetClipboardData
    • GetClipboardFormatNameA
    • GetClipboardFormatNameW
    • GetClipboardSequenceNumber
    • GetClipboardViewer
    • GetOpenClipboardWindow
    • GetPriorityClipboardFormat
    • IsClipboardFormatAvailable
    • RegisterClipboardFormatA
    • RegisterClipboardFormatW
    • SetClipboardData
    • SetClipboardViewer
  • Processus (kernel32/advapi32/ole32), via InterceptProcessFunctions
    • CreateProcessA
    • CreateProcessW
    • CreateProcessAsUserA
    • CreateProcessAsUserW
    • WinExec
    • ExitWindowsEx
    • ShellExecuteExW
    • CoGetClassObject
    • CoCreateInstanceEx
    • CreateProcessWithLogonW
    • OleRun

Surveillance des routes par Juniper

Le composant Juniper Network Connect est fréquemment utilisé pour se connecter, via VPN, au système d’information de son organisation.
Ce dernier offre une multitude de fonctionnalités, dont une très pratique : la redirection du réseau du poste vers le SI.

La redirection peut se faire en plusieurs points, mais le principal reste la table de routage modifiée à la connexion :

Ce que Juniper peut nous imposer suite à une connexion

===========================================================================
Liste d'Interfaces
0x1 ........................... MS TCP Loopback interface
0x2 ...00 03 ff 91 17 83 ...... Carte Fast Ethernet PCI à base de Intel 21140 (Générique) - Miniport d'ordonnancement de paquets
0x3 ...00 ff 98 8c 03 82 ...... Juniper Network Connect Virtual Adapter - Miniport d'ordonnancement de paquets
===========================================================================
===========================================================================
Itinéraires actifs :
Destination réseau    Masque réseau  Adr. passerelle   Adr. interface Métrique
          0.0.0.0          0.0.0.0   [ip attribuée]  [ip attribuée]	  1
          0.0.0.0          0.0.0.0    192.168.0.254   192.168.0.246	  20
   [ip attribuée]  255.255.255.255        127.0.0.1       127.0.0.1	  10
   10.255.255.255  255.255.255.255   [ip attribuée]  [ip attribuée]	  10
   [ip organisme]  255.255.255.255    192.168.0.254   192.168.0.246	  1
        127.0.0.0        255.0.0.0        127.0.0.1       127.0.0.1	  1
      192.168.0.0    255.255.255.0    192.168.0.246   192.168.0.246	  20
      192.168.0.0    255.255.255.0   [ip attribuée]  [ip attribuée]	  1
    192.168.0.246  255.255.255.255        127.0.0.1       127.0.0.1	  20
    192.168.0.255  255.255.255.255    192.168.0.246   192.168.0.246	  20
        224.0.0.0        240.0.0.0    192.168.0.246   192.168.0.246	  20
        224.0.0.0        240.0.0.0   [ip attribuée]  [ip attribuée]	  1
  255.255.255.255  255.255.255.255   [ip attribuée]  [ip attribuée]	  1
  255.255.255.255  255.255.255.255    192.168.0.246   192.168.0.246	  1
Passerelle par défaut :     [ip attribuée]
===========================================================================
Itinéraires persistants :
  Aucun

Il est important de visualiser :

  • les rajouts de routes vers la passerelle Juniper (via l’ip attribuée) avec une métrique plus faible que la route originale
  • la conservation de la connexion avec la passerelle de l’organisme (notre entreprise) via une route unique et explicite vers l’ip de l’organisme (c’est la seule connexion passant encore en dehors du VPN)
  • l’impossibilité de se connecter à son réseau interne ou à internet

La solution trop évidente…

route add 10.0.0.0 mask 255.0.0.0 [ip attribuée]
route delete 0.0.0.0 mask 0.0.0.0 [ip attribuée]
route delete 192.168.0.0 mask 255.0.0.0 [ip attribuée]
  1. rajout d’une route vers le réseau de notre organisme via le VPN.
  2. suppression de la passerelle par défaut passant par le VPN, l’on récupère celle d’origine.
  3. suppression de la route vers le réseau interne qui voulait passer par le VPN, l’on récupère celle d’origine.

Surveillé…

Le service Juniper surveille (par boucle d’environ 5s) la table de routage courante et peut couper la connexion dès détection d’une modification :
nc_routemon
loin d’être un bogue, c’est une mesure de sécurité décrite par Juniper : http://kb.juniper.net/InfoCenter/KB15829

Le code

Grâce à un import bien particulier du service :

00475110     GetIpForwardTable                                    IPHLPAPI

… et aux belles traces pouvant être remontées :

.rdata:0047AAA8 00000075 C Route to destination %u.%u.%u.%u is missing mask %u.%u.%u.%u with gw %u.%u.%u.%u, metric %d, if_id %d, disconnecting
.rdata:0047AB20 0000007A C Unauthorized new route to %u.%u.%u.%u/%u.%u.%u.%u has been added (conflicts with our route to %u.%u.%u.%u), disconnecting

…l’on retrouve facilement la routine de vérification appelée périodiquement :

0415D30 sub_415D30      proc near               ; DATA XREF: .rdata:0047A838o
.text:00415D30
.text:00415D30 var_1C          = dword ptr -1Ch
.text:00415D30 var_18          = dword ptr -18h
.text:00415D30 var_14          = dword ptr -14h
.text:00415D30 var_10          = dword ptr -10h
.text:00415D30 var_C           = dword ptr -0Ch
.text:00415D30 var_8           = dword ptr -8
.text:00415D30 var_4           = dword ptr -4
.text:00415D30
.text:00415D30                 sub     esp, 1Ch
.text:00415D33                 push    ebp
.text:00415D34                 mov     ebp, ecx
.text:00415D36                 cmp     dword ptr [ebp+40h], 0
.text:00415D3A                 mov     [esp+20h+var_14], ebp
.text:00415D3E                 mov     byte ptr [esp+20h+var_1C+3], 0
.text:00415D43                 jnz     short loc_415D7F
.text:00415D45                 push    offset aNoRoutesToMoni ; "no routes to monitor"
.text:00415D4A                 push    offset aRmon    ; "rmon"
.text:00415D4F                 push    199h
.text:00415D54                 push    offset a_Routemon_cpp ; ".\\routemon.cpp"
...

Évitons cette routine après tout ?

nc_noroutemon

Cette fois-ci, après modifications de la table de routage sans déconnexions, les communications fonctionnent vers tous les réseaux :)

…une fois de plus, ça sera dans mimikatz 1.0.

Bureau à distance en trio (limitation des sessions RDP)

Les versions serveurs de Windows 2003 et 2008 permettent aux administrateurs zélés de se connecter, via RDP, à leurs serveurs pour certaines taches d’administration.
Ce mode de fonctionnement de Terminal Server est le mode « Bureau à distance », qui ne permet pas plus de 2 connexions RDP simultanées.

Frustration du troisième administrateur

rdp_frustration
ou en 2008…
rdp_frustration6
Déjà trop de sessions ouvertes en RDP sur le serveur… (2)

Faux réglage du mode « Bureau à distance »

rdp_fakeset
Quoi que cette fenêtre puisse laisser penser, en mode « Bureau à distance », ce réglage graphique ne sert strictement à rien ; il n’y a que deux licences de disponible

Explication

plongé dans termsrv.dll@TermService

.text:760BB42D         lea     esi, [ecx+0Ch]
.text:760BB430         push    esi             ; lpAddend
.text:760BB431         call    ds:__imp__InterlockedIncrement@4 ; InterlockedIncrement(x)
.text:760BB437         cmp     eax, 2
.text:760BB43A         jg      short @@loc_noLicence

Finalement il ne faudrait donc que remplacer un malicieux jg par un nop
Pour les versions 6 de Windows, cela demande un peu plus de subtilité au vu du nombre de vérifications faites autour d’un objet instancié…, un remplacement du nombre de sessions maximales par 0x7fffffff est tout aussi efficace ;)

Il est ici intéressant de manipuler directement ces données dans le service Terminal Server, cela permet d’éviter tout redémarrage et remplacement de fichier.

Résultat

rdp_2k3x64_happy
ou en 2008…
rdp_2k8r2x64_happy

…en plus, ça sera dans mimikatz 1.0, tout administrateur impatient que tu sois.