
CVE-2019-5096(업로드 핸들러의 UAF) exploit은 서비스 거부(Denial of Service)를 유발합니다.
python TriggerDOS.py ip

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

코드에서 upload.c:370을 찾아보면 다음과 같이 볼 수 있습니다.
wp->currentFile=0
전에 실행된
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;
...
}
여기서 hashEnter 함수는 해시 테이블에 요소를 추가하는데, 이로 인해 wp->currentFile의 여러 번 참조가 발생합니다. wp->files(해시 테이블)의 WebsUpload 구조체는 http 세션이 종료될 때(Webs 수명 주기 종료) termWebs가 호출되면서 free됩니다.
static void termWebs(Webs *wp, int reuse)
{
...
#if ME_GOAHEAD_UPLOAD
if (wp->files >= 0) {
websFreeUpload(wp);//hashtable을 순회하며 WebsUpload 구조체를 꺼내 free합니다.
}
#endif
}
다음으로 또 다른 free 지점을 살펴보겠습니다:
...
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));
...
}
}
}
발견된 바로는, upload 헤더에 filename 필드가 있으면 wp->currentFile을 free하고, 그 다음 walloc으로 WebsUpload를 할당합니다.
sizeof(WebsUpload)가 global_max_fast 크기 이내이므로, 힙 청크는 LIFO(후입선출) 방식으로 할당되어 방금 free된 청크가 곧바로 다시 할당됩니다. 이후 processContentData 함수에서 다시 hash 테이블에 추가됩니다. 이 시점에서 hash 테이블 내에 해당 청크에 대한 두 번의 참조가 존재하게 되어, termWebs 호출 시 double free가 발생하고 abort됩니다.
한 번의 요청에 두 개의 upload 헤더를 추가합니다:
processContentData 함수 이후 다시 processUploadHeader 함수로 진입합니다. 즉, 다음 순서로 호출됩니다:
websProcessUploadData (반복) # 업로드 상태 머신, 각 반복마다 상태 결정 ->initUpload() ->processContentBoundary() ->processUploadHeader() ->processContentData() ->processContentBoundary() ->processUploadHeader() ->processContentData() ->return;
...