
Exploração em Python para CVE-2019-5096, uma vulnerabilidade de use-after-free no manipulador de upload do servidor web GoAhead, causando negação de serviço via double-free.
python TriggerDOS.py ip

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

Localizando no código upload.c:370, pode-se ver que antes de
wp->currentFile=0
foi executado:
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;
...
}
A função hashEnter adiciona um elemento à tabela hash, causando múltiplas referências a wp->currentFile. A estrutura WebsUpload em wp->files (tabela hash) será liberada quando termWebs for chamado no final da sessão HTTP (fim do ciclo de vida do Webs).
static void termWebs(Webs *wp, int reuse)
{
...
#if ME_GOAHEAD_UPLOAD
if (wp->files >= 0) {
websFreeUpload(wp); //percorre a hashtable e libera a estrutura WebsUpload.
}
#endif
}
A seguir, veja outro ponto de free:
...
processUploadHeader(Webs *wp, char *line)
{
while (key && stok(key, ";\r\n", &nextPair)) { // aqui analisa o cabeçalho upload com ';' como delimitador
...
else if (scaselesscmp(key, "filename") == 0) {
...
freeUploadFile(wp->currentFile);
file = wp->currentFile = walloc(sizeof(WebsUpload));
...
}
}
}
Descobre-se que, se o cabeçalho de upload tiver um campo filename, será liberado wp->currentFile e então alocado um WebsUpload com walloc.
Como sizeof(WebsUpload) está dentro do tamanho de global_max_fast, o heap rápido será alocado em LIFO, então o bloco recém-liberado será imediatamente alocado novamente e, posteriormente, na função processContentData, será adicionado novamente à tabela hash. Nesse momento, a tabela hash já terá duas referências a esse chunk, resultando em um double free quando termWebs for chamado, causando abort.
Adicionando dois cabeçalhos de upload em uma solicitação:
Após a função processContentData, entrar novamente na função processUploadHeader. Ou seja, a seguinte sequência de chamadas:
websProcessUploadData (循环) #上传状态机,每次循环确定一个状态
->initUpload()
->processContentBoundary()
->processUploadHeader()
->processContentData()
->processContentBoundary()
->processUploadHeader()
->processContentData()
->return;
...