
Python-Exploit für CVE-2019-5096, eine Use-after-Free-Schwachstelle im Upload-Handler des GoAhead-Webservers, die einen Denial-of-Service durch Double-Free verursacht.
python TriggerDOS.py ip

[https://github.com/embedthis/goahead.git] GoAhead GitHub-Link

Im Code finden Sie upload.c:370. Sie sehen, dass vor
wp->currentFile=0
Folgendes ausgeführt wird:
typedef struct WebsUpload {
char *filename; /**< Local (temp) name of the file */
char *clientFilename; /**< Client side name of the file */
char *contentType; /**< Content type */
ssize size; /**< Uploaded file size */
} WebsUpload;
...
typedef struct Webs {
...
WebsUpload *currentFile;
...
}Webs;
...
processContentData(Webs *wp){
...
file = wp->currentFile;
...
hashEnter(wp->files, wp->uploadVar, valueSymbol(file), 0);
defineUploadVars(wp);
wp->currentFile=0;
...
}
Die Funktion hashEnter fügt der Hash-Tabelle ein Element hinzu; dadurch wird wp-currentFile mehrfach referenziert. Die WebsUpload-Struktur in wp->files (der Hash-Tabelle) wird beim Aufruf von termWebs am Ende der HTTP-Sitzung (am Ende des Webs-Lebenszyklus) freigegeben.
static void termWebs(Webs *wp, int reuse)
{
...
#if ME_GOAHEAD_UPLOAD
if (wp->files >= 0) {
websFreeUpload(wp);//遍历hashtable 取出WebsUpload结构体free掉。
}
#endif
}
Als Nächstes betrachten wir eine weitere Stelle, an der free aufgerufen wird:
...
processUploadHeader(Webs *wp, char *line)
{
while (key && stok(key, ";\r\n", &nextPair)) {// 这是以 ; 为分割符解析 upload 头部
...
else if (scaselesscmp(key, "filename") == 0) {
...
freeUploadFile(wp->currentFile);
file = wp->currentFile = walloc(sizeof(WebsUpload));
...
}
}
}
Man sieht: Wenn der Upload-Header ein filename-Feld enthält, wird wp->currentFile freigegeben und anschließend mit walloc eine WebsUpload-Struktur allokiert. Da sizeof(WebsUpload) innerhalb von global_max_fast liegt, wird der Heap-Chunk nach dem LIFO-Prinzip (Last-In-First-Out) vergeben. Der gerade freigegebene Chunk wird also sofort wieder allokiert und später in der Funktion processContentData erneut in die Hash-Tabelle eingefügt. Die Hash-Tabelle enthält zu diesem Zeitpunkt bereits zwei Referenzen auf diesen Chunk. Beim Aufruf von termWebs kommt es zu einem Double-Free und das Programm bricht mit abort ab.
Eine einzelne Anfrage mit zwei Upload-Headern:
Nach der Funktion processContentData wird erneut die Funktion processUploadHeader aufgerufen. Der Ablauf ist also folgender:
websProcessUploadData (Schleife) # Upload-Zustandsmaschine; jeder Schleifendurchlauf bestimmt einen Zustand
->initUpload()
->processContentBoundary()
->processUploadHeader()
->processContentData()
->processContentBoundary()
->processUploadHeader()
->processContentData()
->return();
...