mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-13 10:15:00 +00:00
Improved CGI disclosure protection
This commit is contained in:
1 parent
0470e813a9
commit
eecf24b20c
1 file changed
+23
-24
+23
-24
@@ -1032,31 +1032,14 @@ static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len) {
|
||||
// Point p to the end of the file name
|
||||
p = buf + strlen(buf) - 1;
|
||||
|
||||
// Trim trailing backslash character
|
||||
while (p > buf && *p == '\\' && p[-1] != ':') {
|
||||
*p-- = '\0';
|
||||
}
|
||||
|
||||
// Protect from CGI code disclosure.
|
||||
// This is very nasty hole. Windows happily opens files with
|
||||
// some garbage in the end of file name. So fopen("a.cgi ", "r")
|
||||
// actually opens "a.cgi", and does not return an error!
|
||||
if (*p == 0x20 || // No space at the end
|
||||
(*p == 0x2e && p > buf) || // No '.' but allow '.' as full path
|
||||
*p == 0x2b || // No '+'
|
||||
(*p & ~0x7f)) { // And generally no non-ASCII chars
|
||||
(void) fprintf(stderr, "Rejecting suspicious path: [%s]", buf);
|
||||
// Convert to Unicode and back. If doubly-converted string does not
|
||||
// match the original, something is fishy, reject.
|
||||
memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
|
||||
MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
|
||||
NULL, NULL);
|
||||
if (strcmp(buf, buf2) != 0) {
|
||||
wbuf[0] = L'\0';
|
||||
} else {
|
||||
// Convert to Unicode and back. If doubly-converted string does not
|
||||
// match the original, something is fishy, reject.
|
||||
memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
|
||||
MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
|
||||
NULL, NULL);
|
||||
if (strcmp(buf, buf2) != 0) {
|
||||
wbuf[0] = L'\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1126,6 +1109,16 @@ static int mg_rename(const char* oldname, const char* newname) {
|
||||
return MoveFileW(woldbuf, wnewbuf) ? 0 : -1;
|
||||
}
|
||||
|
||||
// Windows happily opens files with some garbage at the end of file name.
|
||||
// For example, fopen("a.cgi ", "r") on Windows successfully opens
|
||||
// "a.cgi", despite one would expect an error back.
|
||||
// This function returns non-0 if path ends with some garbage.
|
||||
static int path_cannot_disclose_cgi(const char *path) {
|
||||
static const char *allowed_last_characters = "_-";
|
||||
int last = path[strlen(path) - 1];
|
||||
return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
|
||||
}
|
||||
|
||||
static int mg_stat(struct mg_connection *conn, const char *path,
|
||||
struct file *filep) {
|
||||
wchar_t wbuf[PATH_MAX];
|
||||
@@ -1139,6 +1132,12 @@ static int mg_stat(struct mg_connection *conn, const char *path,
|
||||
info.ftLastWriteTime.dwLowDateTime,
|
||||
info.ftLastWriteTime.dwHighDateTime);
|
||||
filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||
// If file name is fishy, reset the file structure and return error.
|
||||
// Note it is important to reset, not just return the error, cause
|
||||
// functions like is_file_opened() check the struct.
|
||||
if (!filep->is_directory && !path_cannot_disclose_cgi(path)) {
|
||||
memset(filep, 0, sizeof(*filep));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user