Megosztás:


Hálózati illesztőprogramok biztonsági problémái

A biztonságos illesztőprogramok írásáról a Megbízható Kernel-Mode illesztőprogramok létrehozása című témakörben olvashat bővebben.

A biztonságos kódolási eljárásokon és az általános eszközillesztő-útmutatáson túl a hálózati illesztőprogramoknak a következőkre van szükség a biztonság javítása érdekében:

  • Minden hálózati illesztőprogramnak ellenőriznie kell a beállításjegyzékből beolvasott értékeket. A NdisReadConfiguration vagy a NdisReadNetworkAddress hívójának nem szabad feltételeznie a beállításjegyzékből beolvasott értékekre vonatkozó feltételezéseket, és ellenőriznie kell az összes beolvasott beállításjegyzék-értéket. Ha a NdisReadConfiguration hívója azt állapítja meg, hogy egy érték túllépi a határokat, akkor ehelyett egy alapértelmezett értéket kell használnia. Ha a NdisReadNetworkAddress hívója azt állapítja meg, hogy egy érték kívül esik a határokon, akkor az állandó médium hozzáférés-vezérlő (MAC) címet vagy egy alapértelmezett címet kell használnia.

OID-specifikus problémák

Az OID lekérdezési biztonsági irányelvei

A legtöbb lekérdezési azonosítót a rendszeren található bármely usermode-alkalmazás kibocsáthatja. Kövesse a lekérdezési azonosítókra vonatkozó alábbi irányelveket.

  1. Mindig ellenőrizze, hogy a puffer mérete elég nagy-e a kimenethez. A kimeneti pufferméret-ellenőrzés nélküli lekérdezési OID-kezelő biztonsági hibával rendelkezik.

    if (oid->DATA.QUERY_INFORMATION.InformationBufferLength < sizeof(ULONG)) {
        oid->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(ULONG);
        return NDIS_STATUS_INVALID_LENGTH;
    }
    
  2. Mindig írjon helyes és minimális értéket a BytesWritten fájlba. Ez egy piros jelölő, amelyet az alábbi példához hasonlóan kell hozzárendelni oid->BytesWritten = oid->InformationBufferLength .

    // ALWAYS WRONG
    oid->DATA.QUERY_INFORMATION.BytesWritten = DATA.QUERY_INFORMATION.InformationBufferLength; 
    

    Az operációs rendszer a BytesWritten bájtokat visszamásolja egy usermode alkalmazásba. Ha a BytesWritten nagyobb, mint az illesztőprogram által ténylegesen írt bájtok száma, akkor előfordulhat, hogy az operációs rendszer visszamásolja a nem inicializált kernelmemóriát a usermode-ba, ami információfeltárási biztonsági rés lenne. Ehelyett használja a következőhöz hasonló kódot:

    oid->DATA.QUERY_INFORMATION.BytesWritten = sizeof(ULONG);
    
  3. Soha ne olvasson vissza értékeket a pufferből. Bizonyos esetekben az OID kimeneti puffere közvetlenül egy ellenséges felhasználói mód folyamatba van leképezve. A rosszindulatú folyamat megváltoztathatja a kimeneti puffert, miután írtál rá. Az alábbi kód például megtámadható, mert a támadó a megírás után módosíthatja a NumElements parancsot:

    output->NumElements = 4;
    for (i = 0 ; i < output->NumElements ; i++) {
        output->Element[i] = . . .;
    }
    

    A pufferből való visszaolvasás elkerülése érdekében őrizze meg a helyi másolatot. A fenti példa kijavításához például vezessen be egy új veremváltozót:

    ULONG num = 4;
    output->NumElements = num;
    for (i = 0 ; i < num; i++) {
        output->Element[i] = . . .;
    }
    

    Ezzel a módszerrel a for loop visszaolvassa az illesztőprogram veremváltozóját num, és nem a kimeneti pufferből. Az illesztőnek meg kell jelölnie a kimeneti puffert a volatile kulcsszóval, hogy a fordító ne vonja vissza a javítást csendesen.

Az OID biztonsági irányelveinek beállítása

A legtöbb set OID-t a Rendszergazdák vagy a Rendszer biztonsági csoportokban futó usermode-alkalmazás állíthatja ki. Bár ezek általában megbízható alkalmazások, a miniport-illesztőnek továbbra sem szabad engedélyeznie a memória sérülését vagy a kernelkód injektálását. Kövesse az alábbi szabályokat az azonosítók beállításához:

  1. Mindig ellenőrizze, hogy a bemenet elég nagy-e. A bemeneti pufferméret-ellenőrzés nélküli OID-készletkezelő biztonsági rést tartalmaz.

    if (oid->DATA.SET_INFORMATION.InformationBufferLength < sizeof(ULONG)) {
        return NDIS_STATUS_INVALID_LENGTH;
    }
    
  2. Amikor beágyazott eltolással érvényesít egy OID-t, ellenőriznie kell, hogy a beágyazott puffer az OID terhelésen belül van-e. Ehhez több ellenőrzésre van szükség. Előfordulhat például, hogy OID_PM_ADD_WOL_PATTERN egy beágyazott mintát eredményez, amelyet ellenőrizni kell. A helyes ellenőrzéshez ellenőrizni kell:

    1. InformationBufferSize >= sizeof(NDIS_PM_PACKET_PATTERN)

      PmPattern = (PNDIS_PM_PACKET_PATTERN) InformationBuffer;
      if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN))
      {
          Status = NDIS_STATUS_BUFFER_TOO_SHORT;
          *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN);
          break;
      }
      
    2. Pattern->PatternOffset + Pattern->PatternSize nem eredményez túlcsordulást

      ULONG TotalSize = 0;
      if (!NT_SUCCESS(RtlUlongAdd(Pattern->PatternOffset, Pattern->PatternSize, &TotalSize) ||
          TotalSize > InformationBufferLength) 
      {
          return NDIS_STATUS_INVALID_LENGTH;
      }
      

      Ez a két ellenőrzés a következő példához hasonló kóddal kombinálható:

      ULONG TotalSize = 0;
      if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN) ||
          !NT_SUCCESS(RtlUlongAdd(Pattern->PatternSize, Pattern->PatternOffset, &TotalSize) ||
          TotalSize > InformationBufferLength) 
      {
          return NDIS_STATUS_INVALID_LENGTH;
      }
      
    3. InformationBuffer + Pattern->PatternOffset + Pattern->PatternLength nem okoz túlcsordulást

      ULONG TotalSize = 0;
      if (!NT_SUCCESS(RtlUlongAdd(Pattern->PatternOffset, Pattern->PatternLength, &TotalSize) ||
          (!NT_SUCCESS(RtlUlongAdd(TotalSize, InformationBuffer, &TotalSize) ||
          TotalSize > InformationBufferLength) 
      {
          return NDIS_STATUS_INVALID_LENGTH;
      }
      
    4. Pattern->PatternOffset + Pattern->PatternLength = InformationBufferSize<

      ULONG TotalSize = 0;
      if(!NT_SUCCESS(RtlUlongAdd(Pattern->PatternOffset, Pattern->PatternLength, &TotalSize) ||
          TotalSize > InformationBufferLength)) 
      {
          return NDIS_STATUS_INVALID_LENGTH;
      }
      

Az OID metódus biztonsági irányelvei

A metódusazonosítókat a Rendszergazdák vagy a Rendszer biztonsági csoportokban futó felhasználómódú alkalmazások adhatják ki. Ezek egy halmaz és egy lekérdezés kombinációját képezik, így a fenti útmutatási listák a metódusazonosítókra is érvényesek.

Egyéb hálózati illesztőprogramokkal kapcsolatos biztonsági problémák

  • Számos NDIS miniport-illesztőprogram tesz elérhetővé egy vezérlőeszközt a NdisRegisterDeviceEx használatával. Az ezt végzőknek a WDM-illesztőprogramokkal megegyező biztonsági szabályokkal kell naplózást végezniük az IOCTL-kezelőiken. További információ: I/O-vezérlőkódok biztonsági problémái.

  • A jól megtervezett NDIS miniportillesztők nem támaszkodhatnak arra, hogy egy adott folyamatkörnyezetben hívják meg őket, és nem állhatnak szoros kapcsolatban a felhasználói móddal (kivételt képeznek az IOCTL-k és az OID-k). Figyelmeztető jel lenne, ha egy miniportot látna, amely megnyitott felhasználói módú leírókat, használta a felhasználói módú várakozásokat, vagy memóriát foglalt le felhasználói módú kvóta terhére. Ezt a kódot meg kell vizsgálni.

  • A legtöbb NDIS-miniportillesztőnek nem szabad részt vennie a csomagok hasznos adatainak elemzésében. Bizonyos esetekben azonban szükség lehet rá. Ha igen, ezt a kódot nagyon óvatosan kell naplózni, mivel az illesztőprogram nem megbízható forrásból elemzi az adatokat.

  • Ahogy a kernel módú memória kiosztásakor szokásos, az NDIS-illesztőprogramoknak a megfelelő NX-készlet Opt-In mechanizmusokat kell használniuk. A WDK 8 és újabb verzióiban a NdisAllocate* függvénycsalád megfelelően van engedélyezve.