persistence
Windows Persistence
Notes while working through the excellent Sektor7 Windows persistence course. They’re mainly reminders for me :) The templates, tools and extra context are what make the training valuable; these notes won’t replace them.
Low privilege:
Start folder:
c:\Users\UserName\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup%APPDATA%probably an easier way to go about it. Likecopy myimplant.exe "%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup"
Registry keys:
HKCU\Software\Microsoft\Windows\CurrentVersion\Run(orRunOnce). AddREG_SZ- Note, there is the machine equivalent, but this is the low priv section of the notes. If you had admin rights you could also set
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run - https://attack.mitre.org/techniques/T1060/
Logon Scripts:
- userinit launches the local logon scripts.
HKCU\Environmentwe addUserInitMprLogonScriptas aREG_SZfor a implant.bat that launches an executable.- https://attack.mitre.org/techniques/T1037/
Shortcut Modification:
- Modifying the
.lnkfiles that the user interacts with regularly. - They are not straight up text files and you can’t just modify them directly to point somewhere else.
- The course script provides an example of a shortcut creator that will replace a
lnkon the desktop with one that is the same except for the target. The new target is a script that launches the payload and then the intended shortcut target.
Screensaver:
HKCU\ControlPanel\Desktopcontains the screensaver keys (if configured).- We add
SCRNSAVE.EXEas a string value pointing atourimplant.exe - We also add the timeout before the “screensaver” should execute -
ScreenSaveTimeOut - Keep in mind GPO might override this.
- https://attack.mitre.org/techniques/T1180/
PowerShell Profile:
- Does rely on something PowerShell running on the machine.
- Profile locations vary by PowerShell version, user and host.
$PROFILEshows the current user’s host-specific file; it isn’t always theprofile.ps1underDocuments\WindowsPowerShell. Profiles also don’t load with-NoProfile. Microsoft’s profile reference covers the different scopes. - https://attack.mitre.org/techniques/T1504/
DLL Proxy
- We’re hoping to replace something in the search path with our code.
- dll loader is checking for dll already in memory first, then
HKLM\SYSTEM\CurrentControlSet\Session Manager\KnownDLLs, then the applications folder, then c:\windows\system32 and SysWow64 (depending), then c:\windows\system, c:\windows, current directory and finally things in %PATH%. - You want to be careful here to create a module that can pass off to the real .dll if breaking the application is a concern.
- Procmon is a good way to find out if the application is a good candidate that is calling .dll’s. Result contains ‘NOT FOUND’ and the process name is a good starting filter.
dumpbin(SDK tools) can allow us to inspect the imported functions. We need to be careful though, sometimes there are additional functions required (via getProcAddress). If you wanted to be mega safe you could do all the exported functions from a dll (found using dumpbin).- Sektor7 demo and template for creating the proxy .dll is the way to go here. The quick-but-poor approach is to let the app crash, but if we find a reference to a dll with only a few functions we can proxy to the real dll without too much effort.
- Remember to be careful with 32 bit v 64 bit with the .dll.
- https://attack.mitre.org/techniques/T1038/
COM
- .dll is created in one language but designed to be usable by developers in others
- via Application Binary Interface (ABI)
- Identified by Unique Id (and referenced by Id)
- COM objects can live on a different machine, transparent to the application; appears like a regular local function call.
- For in-process COM, the registered server is a DLL loaded into the caller.
HKCRis a merged view ofHKCU\Software\ClassesandHKLM\Software\Classes, not a separate store. Which user supplies the per-user view matters, especially for services. Microsoft’s HKCR documentation explains the merge. - We may be able to hijack at the HKCU lookup
- For Local COM Loading: Similar, but the COM local proxy inside the process will use RPC to communicate with a separate local process on the machine (still specified in HKCR and referenced via the SCM). We see these as
LocalServerin the registry. - For Network COM Loading: similar, but the SCM on the hosting machine will call out to the remote SCM on the machine hosting the COM Server. The application will call out via RPC.
HKCR\CLSIDis the place to inspect the class registrations. Remember that the entries shown can come from either the machine or user store.- We can find some interesting COM persistence in our scheduled tasks. When we export all the tasks we can inspect for LogonTrigger types.
- We also know that although most of the com objects are in HKLM, we can hijack by adding to HKCU because that location is checked first. Sektor7 provide a template for creating a hijack .dll. (Implementing the
DllGetClassObjectfunction). But to take it even further, they show the proxy technique to make the system function ‘as normal’. - https://attack.mitre.org/techniques/T1122/
Higher privilege:
Scheduled Task
- Standard:
schtasks /create /tn 'Mytasks\go' /sc daily /st 10:00 /tr 'c:\mything\mything.exe' - Standard (created as admin):
schtasks /create /sc onlogon /tn "BonzaiBuddyUpdate" /tr 'c:\mything\mything.exe' - To create admin level task we export the definition via
schtasks /query /tn BonzaiBuddyUpdate /xmlthen edit the principal section we edit theto HighestAvailable. Then we delete the existing with `schtasks /delete /f /tn BonzaiBuddyUpdate` and create again with `schtasks /create /tn BonzaiBuddyUpdate /xml task.xml` with the edited task. (If we don't do this we end up with a task that _could_ run as admin, but won't by default). - It is also possible to configure the task with multiple actions which would allow the original action to happen.
New or Modified Services
- Either create a new one, or modify an existing service.
sc create UpdaterService binpath= "c:\ourImplant.exe" start= auto- Default for this will be local system.
sc query UpdaterServiceto confirm.- We need to make sure our implant is compiled as a service though, else SCM is going to give up on the process reasonably quickly. Sektor7 provide a template. There are SCM related functions that we should have and they’ve provided them. (We just need to implement the RunMe section of the template and optionally include AES Encryption function for payload - also provided)
- We could modify an existing service instead via
sc config UpdaterService binpath= "c:\somethingelse.exe"
Image File Execution Options
- IFEO is around to make debugging easier (attach the debugger or tools to process in various scenarios).
- Debugger, Exit, or Verifier options.
- Debugger allows us to start a process under a debugger (but instead we use our binary)
- Exit allows the same on exit
- The verifier notes here refer to Application Verifier, not the separate Driver Verifier tool (
verifier.exe). HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options- We create a subkey for the process we want to start under a ‘debugger’ (our persistence implant).
- The challenge here is that we are effectively starting a ‘debugger’ now, passing the real process as a parameter to the debugger, but since our implant is not really a debugger the actual process won’t get a chance to start. We’d either have to implement this, or choose a process that wouldn’t be noticed.
- Silent Process Exit has its own configuration;
ReportingModeisn’t an IFEO value in the same location asDebugger. See Microsoft’s Silent Process Exit reference. - To do the same for verifier we use
VerifierDllsbut we need to remember that the .dll needs to live in system32 or syswow AND we need to use a specific dll type that Sektor7 provide a template for (it has aDLL_PROCESS_VERIFIERevent case configured; we use that to create a thread for the persistence module). We also need to setGlobalFlagto make this work. You can play with this stuff with verifier to see legitimate uses. - https://attack.mitre.org/techniques/T1183/
Application Shims
- Windows AppCompat
- Hook address table in the process, patch app code, inject dll’s to make it work across OS.
- More relevant to 32 bit process (limited 64 bit support)
Inject dllis the app compat option from the App Compat toolkit we leverage.- Once we create the shim we need to install it via
sdbinst OurShim.sdb(sdbinst-u OurShim.sdbto remove) - https://attack.mitre.org/techniques/T1138/
WMI Event Subscription
- “Windows Management Instrumentation (WMI) is the Microsoft implementation of Web-Based Enterprise Management (WBEM), which is an industry initiative to develop a standard technology for accessing management information in an enterprise environment. WMI uses the Common Information Model (CIM) industry standard to represent systems, applications, networks, devices, and other managed components. CIM is developed and maintained by the Distributed Management Task Force (DMTF).”
- Made up of filters, consumers and bindings.
- WMI event subscriptions persist over reboot.
wmic /NAMESPACE:"\\root\subscription" PATH __EventFilter GET /format:listto see the current event filters.wmic /NAMESPACE:"\\root\subscription" PATH __EventCOnsumer GET /format:listto see current event consumers.wmic /NAMESPACE:"\\root\subscription" PATH __FilterToConsumerBinding GET /format:listto see bindings- To set up WMI based persistence:
wmic /NAMESPACE:"\\root\subscription" PATH __EventFilter CREATE Name="INFilter", EventNameSpace="root\cimv2",QueryLanguage="WQL", Query="Select * From __InstanceCreationEvent Within 15 Where (TargetInstance Isa 'Win32_Process' And TargetInstance.Name = 'wordpad.exe')"
wmic /NAMESPACE:"\\root\subscription" PATH CommandLineEventConsumer CREATE Name="INConsumer", WorkingDirectory="C:\rto\PERS\implant", CommandLineTemplate="c:\rto\PERS\implant\implant.exe"
wmic /NAMESPACE:"\\root\subscription" PATH __FilterToConsumerBinding CREATE Filter="__EventFilter.Name=\"INFilter\"", Consumer="CommandLineEventConsumer.Name=\"INConsumer\""
- WMI runs as SYSTEM in session 0 by default, so testing implants might not be visible (but you’ll see with procexp)
- remove:
wmic /NAMESPACE:"\\root\subscription" PATH __FilterToConsumerBinding WHERE Filter="__EventFilter.Name='INFilter'" DELETE
wmic /NAMESPACE:"\\root\subscription" PATH __EventFilter WHERE Name="INFilter" DELETE
wmic /NAMESPACE:"\\root\subscription" PATH CommandLineEventConsumer WHERE Name="INConsumer" DELETE
AppCert DLL’s
- Loaded during the first call of any win32 functions that load process like
CreateProcess* - In
HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\AppCertDllswe add a dll toAppCert - It is a special DLL type though (template provided) that has a CreateProcessNotify function.
- Once configured, you can see them in the “AppInit” section of autoruns:
- (we need a reboot for this one to take effect)
- Doesn’t work reliably against GUI applications. Stick to console apps.
- https://attack.mitre.org/techniques/T1182/
AppInit DLL’s
- Very similar to AppCert DLL
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windowsand add a dll toAppInit_DLLs. We also need to modifyLoadAppInit_DLLsto1- This applies to processes that load
user32.dll, not literally every process. It can still cause a nasty recursive process-launch problem if a DLL starts another application which loads the same DLL. Since Windows 8, the AppInit mechanism is disabled when Secure Boot is enabled. Microsoft’s AppInit guidance covers that limitation. - https://attack.mitre.org/techniques/T1103/
Netsh Helper DLLs
- Microsoft added extensibility to NetSh (helper dll)
- Downside: relies on running netsh. You’re looking for enterprise with scripts.
- We need to use a specific DLL type that exports a function called InitHelperDll (but its otherwise similar to standard dll)
netsh.exe add helper c:\temp\nethelp.dllto add the .dll (which adds a registry entry).removeto get rid of it.- https://attack.mitre.org/techniques/T1128/
Winlogon
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogonwe look atshellwhich is the system shell being used;userinitinitializes the user session.- Interestingly, they can store more than one application in the value like
explorer.exe,backdoor.exe(where backdoor is also in system32). - Unlike Shell,
userinitwill take a full path. - https://attack.mitre.org/techniques/T1060/
Time Providers
- Inward (get time) and Outwards (provide time) both controlled by the SCM.
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\W32Time\TimeProviders\TimeProv. You’ll see NTPClient, NTPServer usually, but might also see others for VM software etc on a standard machine. To set up a new one we create a new key and defineDllName(backdoor),Enabled(flag) andInputProvider(flag).- The course provides a template .dll that will provide the three required functions
TimeProvopenetc. - We restart w32tm to get the provider loaded.
- Since this is service based it will run in session 0 (won’t be visible in testing except via procexp etc)
- https://attack.mitre.org/techniques/T1209/
Port Monitors
- Very similar to time providers, but on the printing side of the house.
- dll that can pass commands to the printer.
- Use the template provided by Sektor7 which implements the functions required. It has to export an
InitializePrintMonitor2function at the least, but there’s also other implementation requirements that make the template particularly handy in this case. HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Monitors\PortMonitorjust takes a driver dll value as a string. It needs to live in System32 (can’t be a path).AddMonitorAPI is an alternate method for configuration. [https://docs.microsoft.com/en-us/windows/win32/printdocs/addmonitor]](https://docs.microsoft.com/en-us/windows/win32/printdocs/addmonitor)- https://attack.mitre.org/techniques/T1013/
Local Security Authority (LSA)
- Dangerous one :) We’ll load inside lsass and in addition to being system, we’ll have access to whatever is in the process.
- If LSASS is running protected it should kill this though, because it requires signed (by Microsoft) code. See https://attack.mitre.org/techniques/T1177/
- One approach uses SSPs and authentication packages. My original registry names here contained typos; Microsoft’s SSP/AP registration documentation is the reference for the package type and registration involved.
- The SSP approach will require us to implement specific functions but the template provided by Sektor7 is a perfect start.
- When configuring the registry for multi string type to support this, don’t forget the
\0zero byte delim between packages. - https://attack.mitre.org/techniques/T1131/
- Password Filters are another approach in this space. They show up in the same spot
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsabut underNotification Packageswhich is a multi-string value (remember the\0delim). - Sektor7 provide the template which implements the basic format of a password filter.
- LSASS will load the password filters on reboot and execute the persistence code.
- https://attack.mitre.org/techniques/T1174/