From fee3f56f009105df1d171961b7e5b506dbc1df1b Mon Sep 17 00:00:00 2001 From: swirl Date: Thu, 10 Feb 2022 22:40:41 -0500 Subject: [PATCH] VULN: fix directory listing upon requesting /.%2f --- mongoose.c | 114 ++--------------------------------------------------- mongoose.h | 1 - 2 files changed, 3 insertions(+), 112 deletions(-) diff --git a/mongoose.c b/mongoose.c index 6b20b43..f0f8b46 100644 --- a/mongoose.c +++ b/mongoose.c @@ -83,27 +83,6 @@ static int packed_stat(const char *path, size_t *size, time_t *mtime) { return 0; } -static void packed_list(const char *dir, void (*fn)(const char *, void *), - void *userdata) { - char buf[256], tmp[sizeof(buf)]; - const char *path, *begin, *end; - size_t i, n = strlen(dir); - tmp[0] = '\0'; // Previously listed entry - for (i = 0; (path = mg_unlist(i)) != NULL; i++) { - if (!is_dir_prefix(dir, n, path)) continue; - begin = &path[n + 1]; - end = strchr(begin, '/'); - if (end == NULL) end = begin + strlen(begin); - snprintf(buf, sizeof(buf), "%.*s", (int) (end - begin), begin); - buf[sizeof(buf) - 1] = '\0'; - // If this entry has been already listed, skip - // NOTE: we're assuming that file list is sorted alphabetically - if (strcmp(buf, tmp) == 0) continue; - fn(buf, userdata); // Not yet listed, call user function - strcpy(tmp, buf); // And save this entry as listed - } -} - static struct mg_fd *packed_open(const char *path, int flags) { size_t size = 0; const char *data = mg_unpack(path, &size, NULL); @@ -144,7 +123,7 @@ static size_t packed_seek(void *fd, size_t offset) { return fp->pos; } -struct mg_fs mg_fs_packed = {packed_stat, packed_list, packed_open, +struct mg_fs mg_fs_packed = {packed_stat, packed_open, packed_close, packed_read, packed_write, packed_seek}; @@ -277,22 +256,6 @@ struct dirent *readdir(DIR *d) { } #endif -static void p_list(const char *dir, void (*fn)(const char *, void *), - void *userdata) { -#if MG_ENABLE_DIRLIST - struct dirent *dp; - DIR *dirp; - if ((dirp = (opendir(dir))) == NULL) return; - while ((dp = readdir(dirp)) != NULL) { - if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; - fn(dp->d_name, userdata); - } - closedir(dirp); -#else - (void) dir, (void) fn, (void) userdata; -#endif -} - static struct mg_fd *p_open(const char *path, int flags) { const char *mode = flags == (MG_FS_READ | MG_FS_WRITE) ? "r+b" : flags & MG_FS_READ ? "rb" @@ -347,11 +310,6 @@ static int p_stat(const char *path, size_t *size, time_t *mtime) { return 0; } -static void p_list(const char *path, void (*fn)(const char *, void *), - void *userdata) { - (void) path, (void) fn, (void) userdata; -} - static struct mg_fd *p_open(const char *path, int flags) { (void) path, (void) flags; return NULL; @@ -377,7 +335,7 @@ static size_t p_seek(void *fd, size_t offset) { } #endif -struct mg_fs mg_fs_posix = {p_stat, p_list, p_open, p_close, +struct mg_fs mg_fs_posix = {p_stat, p_open, p_close, p_read, p_write, p_seek}; #ifdef MG_ENABLE_LINES @@ -973,68 +931,6 @@ static void printdirentry(const char *name, void *userdata) { } } -static void listdir(struct mg_connection *c, struct mg_http_message *hm, - struct mg_http_serve_opts *opts, char *dir) { - static const char *sort_js_code = - ""; - struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs; - struct printdirentrydata d = {c, hm, opts, dir}; - char tmp[10]; - size_t off, n; - - mg_printf(c, - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html; charset=utf-8\r\n" - "%s" - "Content-Length: \r\n\r\n", - opts->extra_headers == NULL ? "" : opts->extra_headers); - off = c->send.len; // Start of body - mg_printf(c, - "Index of %.*s%s%s" - "" - "

Index of %.*s

" - "" - "" - "" - "" - "\n", - (int) hm->uri.len, hm->uri.ptr, sort_js_code, sort_js_code2, - (int) hm->uri.len, hm->uri.ptr); - - fs->list(dir, printdirentry, &d); - mg_printf(c, - "" - "
Name" - "ModifiedSize


Mongoose v.%s
\n", - MG_VERSION); - n = (size_t) snprintf(tmp, sizeof(tmp), "%lu", - (unsigned long) (c->send.len - off)); - if (n > sizeof(tmp)) n = 0; - memcpy(c->send.buf + off - 10, tmp, n); // Set content length -} - static void remove_double_dots(char *s) { char *p = s; while (*s != '\0') { @@ -1094,11 +990,7 @@ void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm, int flags = uri_to_path(c, hm, opts, path, sizeof(path)); if (flags == 0) return; LOG(LL_DEBUG, ("%.*s %s %d", (int) hm->uri.len, hm->uri.ptr, path, flags)); - if (flags & MG_FS_DIR) { - listdir(c, hm, opts, path); - } else { - mg_http_serve_file(c, hm, path, opts); - } + mg_http_serve_file(c, hm, path, opts); } } diff --git a/mongoose.h b/mongoose.h index ddd88ce..ca570d6 100644 --- a/mongoose.h +++ b/mongoose.h @@ -556,7 +556,6 @@ enum { MG_FS_READ = 1, MG_FS_WRITE = 2, MG_FS_DIR = 4 }; // list() calls fn() for every directory entry, allowing to list a directory struct mg_fs { int (*stat)(const char *path, size_t *size, time_t *mtime); - void (*list)(const char *path, void (*fn)(const char *, void *), void *); struct mg_fd *(*open)(const char *path, int flags); // Open file void (*close)(struct mg_fd *fd); // Close file size_t (*read)(void *fd, void *buf, size_t len); // Read file