2012-12-21 5 views
5

Ich studiere für meine letzte Prüfung (yey!), Und bin auf ein Problem gestoßen, das mir schwer fällt herauszufinden. Es ist eine alte Prüfungsfrage, wo Sie mindestens zwei Sicherheitslücken finden sollten, die in einer Funktion ausgenutzt werden können, die eine ppm-Bilddatei liest. Das einzige Problem, das ich identifizieren kann, ist, wenn Spalten und/oder Zeilen unerwartete Werte erhalten, entweder zu groß (verursacht einen Integer-Überlauf) oder negativ, was dazu führt, dass im-> Raster eine falsche Größe hat, was die Möglichkeit eines Heap-basierten eröffnet Pufferüberlauf-Angriff.Sicherheitslücken in ziemlich einfachem c code

Soweit ich kann, sollte das ungeprüfte Malloc nicht ausnutzbar sein.

struct image *read_ppm(FILE *fp) 
{ 
    int version; 
    int rows, cols, maxval; 
    int pixBytes=0, rowBytes=0, rasterBytes; 
    uint8_t *p; 
    struct image *img; 
    /* Read the magic number from the file */ 
    if ((fscanf(fp, " P%d ", &version) < 1) || (version != 6)) { 
     return NULL; 
    } 
    /* Read the image dimensions and color depth from the file */ 
    if (fscanf(fp, " %d %d %d ", &cols, &rows, &maxval) < 3) { 
     return NULL; 
    } 
    /* Calculate some sizes */ 
    pixBytes = (maxval > 255) ? 6 : 3; // Bytes per pixel 
    rowBytes = pixBytes * cols; // Bytes per row 
    rasterBytes = rowBytes * rows; // Bytes for the whole image 
    /* Allocate the image structure and initialize its fields */ 
    img = malloc(sizeof(*img)); 
    if (img == NULL) return NULL; 
    img->rows = rows; 
    img->cols = cols; 
    img->depth = (maxval > 255) ? 2 : 1; 
    img->raster = (void*)malloc(rasterBytes); 
    /* Get a pointer to the first pixel in the raster data. */ 
    /* It is to this pointer that all image data will be written. */ 
    p = img->raster; 
    /* Iterate over the rows in the file */ 
    while (rows--) { 
     /* Iterate over the columns in the file */ 
     cols = img->cols; 
     while (cols--) { 
      /* Try to read a single pixel from the file */ 
      if (fread(p, pixBytes, 1, fp) < 1) { 
       /* If the read fails, free memory and return */ 
       free(img->raster); 
       free(img); 
       return NULL; 
      } 
      /* Advance the pointer to the next location to which we 
      should read a single pixel. */ 
      p += pixBytes; 
     } 
    } 
    /* Return the image */ 
    return img; 
} 

Original (die letzte Frage): http://www.ida.liu.se/~TDDC90/exam/old/TDDC90%20TEN1%202009-12-22.pdf

Vielen Dank für jede Hilfe.

+0

Dies erinnert mich an das (2008 gewinnende) Beispiel von [The Underhanded C Contest] (http://underhanded.xcott.com/), könnte einige Hinweise dort geben. –

Antwort

3

Erstellen Sie eine große Datei, so dass beide Negative row und cols sind zu lesen. rasterBytes = pixBytes * rows * cols ist positiv so wird alles in Ordnung sein, bis p = img->raster;. Aber an dieser Stelle haben Sie zwei Endlosschleifen, und das Programm überschreibt möglicherweise den Heap.

Ein weiterer Angriff ist, row und cols so einzurichten, dass sie unterschiedliche Vorzeichen haben. Sie können einen Wert als -1 auswählen, während der andere groß genug ist, um die gewünschten Daten zu lesen. Die Zuordnung

wird fehlschlagen, die img-> Raster auf NULL zeigen. Das bedeutet

fread(p, pixBytes, 1, fp) < 1 

wird versuchen, den Inhalt der Datei Kernel-Speicher zu lesen. Wenn dieser Code abhängig vom System im Kernelmodus ausgeführt wird (sagen wir altes Unix, das kein Speichersegment verwendet), überschreiben Sie den Inhalt des Kernelspeichers mit dem Inhalt der Datei. Ein Kernel, der kein Speichersegment verwendet, beruht nicht auf Segmentierungsfehlern, sondern auf Seitenfehlern (einer virtuellen Adresse, der keine reale Seite zugeordnet ist). Das Problem besteht darin, dass es virtuelle Speicherdesigns gibt, bei denen die ersten realen Seiten direkt den Kernelseiten zugewiesen werden. Dh die virtuelle Kernel-Adresse 0x0 entspricht dem realen Speicher bei 0x0 und ist absolut gültig (innerhalb des Kernels).

EDIT: In beiden Fällen besteht das Ziel des Angreifers darin, den Inhalt der Eingabedatei (die vollständig unter seiner Kontrolle steht) in eine Speicherregion zu injizieren, auf die er keinen Zugriff haben sollte in der Lage sein, die Funktion read_ppm() zu modifizieren.

+0

Also im Grunde, je nach Plattform und Privilegien, kann das ungeprüfte malloc tatsächlich ausgenutzt werden? Ich denke, es ist nicht etwas, was Sie heutzutage tun können, aber es ist wahrscheinlich die erwartete Antwort, da das andere malloc im Code überprüft wird. – Cesar

+0

ja, aber der Angreifer hat bereits seinen Job gemacht, um den Inhalt der Datei in den Haufen notieren – UmNyobe

+0

@Cesar Ich bin nicht gut in der modernen Architektur, aber wir hatten einen OS-Kurs, der Design auf Paginierung basiert folgte. Debugging innerhalb des Kernels war nicht einfach, weil man einfach eine Zahl zufällig auswählen, anfangen konnte, hineinzuschreiben und alles lief gut. – UmNyobe

0

Es gibt auch die Tatsache, dass diese Zuordnung nicht auf Erfolg überprüft wird. Könnte zu einem DoS führen.

img->raster = (void*)malloc(rasterBytes); 
0

Wenn Zuteilung nicht an:

img->raster = (void*)malloc(rasterBytes); 

Sie durch einige Speicher zu schreiben konnte man nicht die Absicht hatte.

Und die Größe dieser Zuordnung wird durch Daten in der Datei gesteuert.

Verwandte Themen