
CVE-2019-5096(アップロードハンドラ内のUAF)エクスプロイトがサービス拒否を引き起こす
python TriggerDOS.py ip

[https://github.com/embedthis/goahead.git] GoAhead GitHubリンク

コード内でupload.c:370 を特定すると、以下の処理の前に
wp->currentFile=0
次のコードが実行される
typedef struct WebsUpload {
char *filename; /**< ファイルのローカル(一時)名 */
char *clientFilename; /**< クライアント側のファイル名 */
char *contentType; /**< コンテンツタイプ */
ssize 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 が呼ばれて解放されます
static void termWebs(Webs *wp, int reuse)
{
...
#if ME_GOAHEAD_UPLOAD
if (wp->files >= 0) {
websFreeUpload(wp);//ハッシュテーブルを走査し、WebsUpload 構造体を取り出して解放
}
#endif
}
次に別の解放箇所を見てみます:
...
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 が解放され、続いて walloc で WebsUpload が割り当てられることがわかります。
sizeof(WebsUpload) は global_max_fast サイズ以内であるため、ヒープチャンクは LIFO(後入れ先出し)で割り当てられます。すると解放された直後のチャンクがすぐに再割り当てされ、その後の processContentData 関数で再びハッシュテーブルに追加されます。この時点でハッシュテーブル内に同じチャンクへの参照が 2 つ存在するため、termWebs で double free が発生し、abort します。
1 回のリクエストに 2 つの upload ヘッダーを追加する:
processContentData 関数の後に再び processUploadHeader 関数に入る。すなわち以下の順序で呼び出されます:
websProcessUploadData (ループ) #アップロードステートマシン、ループごとに状態を決定
->initUpload()
->processContentBoundary()
->processUploadHeader()
->processContentData()
->processContentBoundary()
->processUploadHeader()
->processContentData()
->return;