Megosztás:


Ajánlott eljárások a magas jogosultsági szintű viselkedés korlátozásához a kernel módú illesztőprogramokban

Ez a témakör összefoglalja azokat a nem biztonságos fejlesztési mintákat, amelyek a Windows kernel illesztőprogram-kódjának kihasználásához és visszaéléséhez vezethetnek. Ez a témakör fejlesztési javaslatokat és kódmintákat tartalmaz a kiemelt viselkedés korlátozásához. Ezeknek az ajánlott eljárásoknak a követéséval javíthatja a kiemelt viselkedés windowsos kernelben való végrehajtásának biztonságát.

Nem biztonságos illesztőprogramok viselkedésének áttekintése

Bár elvárás, hogy a Windows-illesztőprogramok magas jogosultsági szintű viselkedést hajtsanak végre kernel módban, a biztonsági ellenőrzések elmulasztása és a kiemelt viselkedés korlátozásának hiánya elfogadhatatlan. A Korábban WHQL-ként használt Windows hardverkompatibilitási program (WHCP) új illesztőprogram-beküldéseket igényel, hogy megfeleljenek ennek a követelménynek.

A nem biztonságos és veszélyes viselkedés többek között a következőket foglalja magában, de nem korlátozódik a következőkre:

Az MSR-ek olvasási és írási képességének biztosítása

Az MSR-ek olvasási biztonságának növelése

Ebben a ReadMsr-példában az illesztő lehetővé teszi a nem biztonságos viselkedést azáltal, hogy lehetővé teszi bármely és minden regisztrátor tetszőleges olvasását a __readmsr modellspecifikus regiszter belső használatával. Ez felhasználói módban rosszindulatú folyamatokkal való visszaéléshez vezethet.

Func ReadMsr(int dwMsrIdx) 
{
	int value = __readmsr(dwMsrIdx); // Unsafe, can read from any MSR
	return value;
}

Ha a forgatókönyv olvasást igényel az MSRs-ekből, az illesztőnek mindig ellenőriznie kell, hogy az olvasni kívánt regiszter a várt indexre vagy tartományra van-e korlátozva. Két példa a biztonságos olvasási művelet implementálására.

Func ConstrainedReadMsr(int dwMsrIdx) 
{
    int value = 0;
    if (dwMsrIdx == expected_index) // Blocks from reading anything
    {
        value = __readmsr(dwMsrIdx); // Can only read the expected MSR
    }
    else
    {
        return error;
    }
    return value;
}

// OR

Func ConstrainedReadMsr(int dwMsrIdx) 
{
    int value = 0;
    if (min_range <= dwMsrIdx <= max_range) // Blocks from reading anything
    {
        value = __readmsr(dwMsrIdx); // Can only from the expected range of MSRs
    }
    else
    {
        return error;
    }
    return value;
}

Az MSR-eknek való írás biztonságának növelése

Az első WriteMsr-példában az illesztőprogram nem biztonságos viselkedést tesz lehetővé azáltal, hogy lehetővé teszi bármely és minden regisztráció tetszőleges írását. Ez olyan rosszindulatú folyamatok általi visszaélést eredményezhet, amelyek felhasználói módban emelik a jogosultságot, és minden MSR-be írnak.

Func WriteMsr(int dwMsrIdx) 
{
	int value = __writemsr(dwMsrIdx); // Unsafe, can write to any MSR
	return value;
}

Ha a forgatókönyv írást igényel az MSRs-be, az illesztőnek mindig ellenőriznie kell, hogy az íráshoz használt regiszter a várt indexre vagy tartományra van-e korlátozva. Két példa a biztonságos írási művelet implementálására.

Func ConstrainedWriteMsr(int dwMsrIdx) 
{
    int value = 0;
    if (dwMsrIdx == expected_index) // Blocks from reading anything
    {
        value = __writemsr(dwMsrIdx); // Can only write to the expected constrained MSR
    }
    else
    {
        return error;
    }
    return value;
}

// OR

Func ConstrainedWriteMSR(int dwMsrIdx) 
{
    int value = 0;
    if (min_range <= dwMsrIdx <= max_range) // Blocks from reading anything
    {
        value = __writemsr(dwMsrIdx); // Can only write to the expected constrained MSR
    }
    else
    {
        return error;
    }
    return value;
}

Folyamatok leállításának lehetősége

Rendkívül óvatosnak kell lennie az illesztőprogram funkcióinak megvalósításakor, ami lehetővé teszi a folyamatok leállítását. A védett folyamatokat és a védett folyamat light (PPL) folyamatokat, mint például a kártevőirtó és vírusvédelmi megoldások által használtakat, nem lehet leállítani. Ennek a funkciónak a felfedése lehetővé teszi a támadók számára a biztonsági védelem leállítását a rendszeren.

Ha a forgatókönyv folyamatvégzítést igényel, a következő ellenőrzéseket kell végrehajtani az tetszőleges folyamatvégzítés elleni védelem érdekében PsLookupProcessByProcessId és PsIsProtectedProcesshasználatával:

Func ConstrainedProcessTermination(DWORD dwProcessId)
{
	// Function to check if a process is a Protected Process Light (PPL)
    NTSTATUS status;
    BOOLEAN isPPL = FALSE;
    PEPROCESS process;
    HANDLE hProcess;

    // Open the process
    status = PsLookupProcessByProcessId(processId, &process);
    if (!NT_SUCCESS(status)) {
        return FALSE;
    }

    // Check if the process is a PPL
    if (PsIsProtectedProcess(process)) {
        isPPL = TRUE;
    }

    // Dereference the process
    ObDereferenceObject(process);
    return isPPL;
}

Olvasási és írási képesség biztosítása a port bemenetére és kimenetére

A port IO-ból történő olvasás biztonságának növelése

Körültekintően kell eljárni, ha lehetővé teszi a porton keresztüli bemenethez/kimenethez (I/O) való olvasási hozzáférést. Ez a __indword használó példakód nem biztonságos.

Func ArbitraryInputPort(int inPort) 
{
	dwResult = __indword(inPort); // Unsafe, allows for arbitrary reading from Input Port
	return dwResult; 
}

Az illesztőprogrammal való visszaélés és kihasználás megakadályozása érdekében a várt bemeneti portot a szükséges használati határra kell korlátozni.

Func ConstrainedInputPort(int inPort) 
{
	// The expected input port must be constrained to the required usage boundary to prevent abuse
	if(inPort == expected_InPort)
	{
		dwResult = __indword(inPort);
	}
	else
	{
		return error; 
	}
	return dwResult; 
}

A port IO-ba történő írás biztonságának növelése

Körültekintően kell eljárni, ha lehetővé teszi a port bemenetére/kimenetére (I/O) való írást. Ez a __outword használó példakód nem biztonságos.

Func ArbitraryOutputPort(int outPort, DWORD dwValue) 
{
	__outdword(OutPort, dwValue); // Unsafe, allows for arbitrary writing to Output Port
}

Az illesztőprogrammal való visszaélés és kihasználás megakadályozása érdekében a várt bemeneti portot a szükséges használati határra kell korlátozni.

Func ConstrainedOutputPort(int outPort, DWORD dwValue) 
{
	// The expected output port must be constrained to the required usage boundary to prevent abuse
	if(outPort == expected_OutputPort)
	{
		__outdword(OutPort, dwValue); // checks on InputPort
	}
	else
	{
		return error; 
	}
}

Kernel, fizikai vagy eszközmemória olvasásának és írásának képessége

A Memcpy biztonságának növelése

Ez a mintakód a fizikai memória biztonságos használatának korlátozás nélküli és nem biztonságos használatát mutatja be.

Func ArbitraryMemoryCopy(src, dst, length) 
{
	memcpy(dst, src, length); // Unsafe, can read and write anything from physical memory
}

Ha a forgatókönyvben kernel, fizikai vagy eszközmemória olvasása és írása szükséges, az illesztőprogramnak mindig ellenőriznie kell, hogy a forrás és a célhely a várt indexekhez vagy tartományokhoz van-e korlátozva.

Func ConstrainedMemoryCopy(src, dst, length) 
{
	// valid_src and valid_dst must be constrained to required usage boundary to prevent abuse
	if(src == valid_Src && dst == valid_Dst)
	{
		memcpy(dst, src, length); 
	}
	else
	{
		return error;
	}
}

A ZwMapViewOfSection biztonságának növelése

Az alábbi példa azt a nem biztonságos és nem megfelelő módszert mutatja be, a ZwOpenSection és ZwMapViewOfSection API-kat használó felhasználói módból történő fizikai memória olvasására és írására.

Func ArbitraryMap(PHYSICAL_ADDRESS Address)
{
	ZwOpenSection(&hSection, ... ,"\Device\PhysicalMemory");
	ZwMapViewOfSection(hSection, -1, 0, 0, 0, Address, ...);
}

Annak érdekében, hogy az illesztőprogram olvasási/írási viselkedését rosszindulatú felhasználói módú folyamatok ne használják ki, az illesztőprogramnak ellenőriznie kell a bemeneti címet, és a memórialeképezést csak a forgatókönyvhöz szükséges használati határig kell korlátoznia.

Func ConstrainedMap(PHYSICAL_ADDRESS paAddress)
{
	// expected_Address must be constrained to required usage boundary to prevent abuse
	if(paAddress == expected_Address)
	{
		ZwOpenSection(&hSection, ... ,"\Device\PhysicalMemory");
		ZwMapViewOfSection(hSection, -1, 0, 0, 0, paAddress, ...);
	}
	else
	{
		return error;
	}
}

Az MmMapLockedPagesSpecifyCache biztonságának növelése

Az alábbi példa illusztrálja a nem biztonságos és nem megfelelő módszert a fizikai memória olvasására és írására felhasználói módban, a MmMapIoSpace, IoAllocateMdl és MmMapLockedPagesSpecifyCache API-k használatával.

Func ArbitraryMap(PHYSICAL_ADDRESS paAddress)
{
	lpAddress = MmMapIoSpace(paAddress, qwSize, ...);
	pMdl = IoAllocateMdl( lpAddress, ...);
	MmMapLockedPagesSpecifyCache(pMdl, UserMode, ... );
}

Annak érdekében, hogy az illesztőprogram olvasási/írási viselkedését rosszindulatú felhasználói módú folyamatok ne használják ki, az illesztőprogramnak ellenőriznie kell a bemeneti címet, és a memórialeképezést csak a forgatókönyvhöz szükséges használati határig kell korlátoznia.

Func ConstrainedMap(PHYSICAL_ADDRESS paAddress)
{
	// expected_Address must be constrained to required usage boundary to prevent abuse
	if(paAddress == expected_Address && qwSize == valid_Size) 
	{
		lpAddress = MmMapIoSpace(paAddress, qwSize, ...);
		pMdl = IoAllocateMdl( lpAddress, ...);
		MmMapLockedPagesSpecifyCache(pMdl, UserMode, ... );
	}
	else
	{
		return error;
	}
}

Lásd még:

Járművezetői biztonsági ellenőrzőlista