Jegyzet
Az oldalhoz való hozzáférés engedélyezést igényel. Próbálhatod be jelentkezni vagy könyvtárat váltani.
Az oldalhoz való hozzáférés engedélyezést igényel. Megpróbálhatod a könyvtár váltását.
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:
- Lehetőséget biztosít az olvasáshoz és íráshoz tetszőleges gépspecifikus regiszterekben (MSR-ek)
- Tetszőleges folyamatok leállításának lehetősége
- A portbemenet és -kimenet olvasási és írási képességének biztosítása
- A kernel, fizikai vagy eszközmemória olvasási és írási képesség biztosítása
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;
}
}