Simovits

Applocker vs Rundll och .NET Assemblies

Applocker introducerades under tidseran Windows 7 och Windows Server 2008 R2 som ett sätt att kontrollera vilka applikationer som exekverar på datorn. Tanken är att man kan använda vitlistning av applikationer för att på så sätt undvika att skadlig kod exekveras. Denna artikel beskriver hur man kan använda rundll32 för att gå runt Applocker-skyddet.

Ponera exempelvis att man utför ett penetrationstest vid en organisation och genom detta har lyckats få en användare (kanske vars flash-komponenter är sårbara https://github.com/SecurityObscurity/cve-2015-0313 ) att ladda en webbsida som man kontrollerar. Om man kan ladda in kod i webbläsaren och exekvera den under dess webbläsarens kontext (likt diverse exploit kits exempelvis Angler exploit kit) har man en bra början för persistens. Om man behöver en mer långvarig relation target-datorn för en djupare penetration i målsystemet så vill man antagligen skapa en persistent bakdörr som finns kvar även efter att datorn startats om.

Om Applocker är installerat och konfigurerat att hindra att användare exekverar okända filer så vill man som angripare ha en pålitlig metod att komma runt detta. Det finns en mängd sätt att göra detta på. Vissa har fungerat bra länge men har byggt på buggar i Microsofts mjukvara och därmed lagats av Microsoft (https://support.microsoft.com/en-us/kb/2532445 ). Om man gör ett penetrationstest är enkelhet alltid önskvärt. Man vill exempelvis inte gärna förlita sig på att en måldater saknar en specifik patch så att en bypass av Applocker eller annan säkerhetsmekanism ska lyckas. Man vill gärna slippa systemkrascher som drar till sig onödig uppmärksamhet. Om det finns enkla sätt som funkar utan att utnyttja en oavsiktlig sårbarhet i mjukvaran så är det att föredra.

Ofta är powershell inte nedlåst och kan därför användas som en fullgod plattform för en persistent bakdörr. Det är en populär aktivitet nuförtiden att skriva om diverse hackverktyg i powershell så att man ska kunna använda det under penetrationstest. Det kan dock hända att även powershell har låsts ned. Därför kan man vara tvungen att använda andra sätt för att anropa sin egen kod.

Ett enkelt sätt är att starta sin kod genom rundll32.exe. Rundll32.exe vill man inte gärna låsa ned eftersom den används för diverse uppgifter i Windows och av andra applikationer som kan tänkas sluta fungera ifall man låser den. Dessutom kan dll-regler i Applocker ge negativa prestandaeffekter (performance-hits) (https://technet.microsoft.com/en-us/library/ee460947.aspx).

Ifall man kan exekvera godtycklig kod behöver man ju förstås inte Powershell men eftersom powershell ändå är en bra kommandorad så kan det vara ett trevligt verktyg att ha när man letar runt i nätverket. Man kan starta powershell genom att ladda in den som ett .NET-objekt och anropa den från .NET. Rundll32.exe stödjer dock inte att kunna ladda .NET-objekt direkt varvid man behöver ett sätt att komma runt detta. Ett sätt är att använda projektet ”Unmanaged Exports” (https://www.nuget.org/packages/UnmanagedExports). Jag har använt UnmanagedExports-projektet och det har alltid fungerat men jag är inte helt säker på att det alltid kommer att fungera i alla lägen. Man vill gärna inte ha massa beroenden av tredjeparts-dll:er eftersom det är lätt att tappa kontrollen över vad som egentligen händer.

Det är dock möjligt för rundll32.exe att ladda en dll kompilerad i managed C++ och det är i sin tur möjligt för managed c++ att ladda en dll skapad i C# eller något annat .NET-språk. Detta kräver inte många kodrader och exempel visas nedan (koden finns i sin helhet vid https://github.com/jamesrep/loadnetdll ).

using namespace System;
using namespace System::Reflection;
using namespace System::Runtime::InteropServices;
extern "C" __declspec( dllexport )
void _cdecl load(long hwnd, long hinst, char *lpszCmdLine, int nCmdShow)
{
String^ delimStr = " ";
String^ strPath = gcnew String(lpszCmdLine);
array <Char>^ delimiter = delimStr->ToCharArray();
array <String^>^ parameters = strPath->Split(delimiter);
System::Reflection::Assembly ^assembly = System::Reflection::Assembly::LoadFile(parameters[0]);
System::Type ^type = assembly->GetType(parameters[1]);
ConstructorInfo^ mConstructor = type->GetConstructor(Type::EmptyTypes);
Object^ mObject = mConstructor->Invoke(gcnew array<Object^>(0));
MethodInfo ^minf = type->GetMethod(parameters[2]);
if(parameters->Length <= 3)
{
minf->Invoke(mObject, gcnew array<Object^>(1){""});
}
else
{
array<String^>^ parameters2 = gcnew array <String ^>(parameters->Length -3);
Array::Copy(parameters, 3, parameters2, 0, parameters->Length -3);
minf->Invoke(mObject, parameters2);
}
}

Genom detta åstadkommer man att Rundll32 laddar in UnmanagedLoader som i sin tur laddar in LoadNetDll som i sin tur laddar in Powershell-tolken som ett .net-objekt (System.Management.Automation.Powershell). Därefter ligger powershell-tolken öppen för att användas för diverse andra penetrationstest-ändamål utan att behöva störas av AppLocker.

Eftersom det är rundll32.exe som laddar in alla DLL:er så syns inte heller någon annan del av processen än just rundll32.exe i Task Manager.

Om man vill att just powershells System.Management.Automation eller någon annan .NET-assembly inte ska kunna laddas in av rundll32.exe så behöver man då använda sig av Applockers DLL-regler. Det är inte någon bugg i Applocker som gör detta möjligt. Det är bara så som Applocker är designat. Det är just därför det är ett trevligt alternativ att använda för att exekvera bakdörrar.

Trots att det är möjligt att för vissa användningsområden (typ persistenta bakdörrar eller processgömning) gå runt Applocker är det ändå rekommenderat att man använder Applocker för att begränsa användarnas möjligheter att exekvera egna applikationer på datorn. Att behöva använda rundll32.exe eller något annat sätt för att exekvera applikationer är ytterligare ett hinder för en angripare. Se https://technet.microsoft.com/en-us/library/ee449496(v=ws.10).aspx för mer information kring Applocker och hur det är tänkt att användas. Sen finns det förstås andra sätt än just rundll32 att gå runt Applocker. Exempelvis genom regsvr32 … men det är en annan historia.