
CVE-2019-5096(UAF in upload handler) exploit cause Denial of Service
python TriggerDOS.py ip

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

In the code, locate upload.c:370. It can be seen that before
wp->currentFile=0
the following is executed:
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;
...
}
The hashEnter function adds an element to the hash table, which causes multiple references to wp->currentFile. The WebsUpload structure in wp->files (hash table) will be freed when termWebs is called at the end of the HTTP session (end of Webs lifecycle).
static void termWebs(Webs *wp, int reuse)
{
...
#if ME_GOAHEAD_UPLOAD
if (wp->files >= 0) {
websFreeUpload(wp);//遍历hashtable 取出WebsUpload结构体free掉。
}
#endif
}
Next, look at another free point:
...
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));
...
}
}
}
It is found that if the upload header has a filename field, then wp->currentFile is freed, followed by walloc for a WebsUpload.
Since sizeof(WebsUpload) falls within the size of global_max_fast, the heap chunk will be allocated in a LIFO manner, so the just-freed heap chunk is immediately allocated again, and later in the processContentData function, it will be added to the hash table again. At this point, the hash table already has two references to that chunk, and when termWebs is called, a double free occurs and aborts.
One request adds two upload headers:
After the processContentData function, it re-enters the processUploadHeader function. That is, the following order of calls:
websProcessUploadData (循环) #上传状态机,每次循环确定一个状态 ->initUpload() ->processContentBoundary() ->processUploadHeader() ->processContentData() ->processContentBoundary() ->processUploadHeader() ->processContentData() ->return;
...