[hackers] [quark][PATCH] HTML-escape dirlist dynamic content

From: guysv <sviryguy_AT_gmail.com>
Date: Wed, 11 Mar 2020 23:10:38 +0200

Because ",',<,>,& are all valid unix filename characters,
filenames containing those characters can glitch-out a dirlist
response.

A funny example would be:
"><img src="blabla" onerror="alert(1)"

This commit escapes dynamic input, and fixes the bug.
---
 resp.c | 31 ++++++++++++++++++++++++++-----
 1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/resp.c b/resp.c
index 3075c28..3bd4c16 100644
--- a/resp.c
+++ b/resp.c
_AT_@ -1,5 +1,6 @@
 /* See LICENSE file for copyright and license details. */
 #include <dirent.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
_AT_@ -38,12 +39,31 @@ suffix(int t)
 	return "";
 }
 
+void
+htmlescape(char *src, char *dst)
+{
+	*dst = '\0';
+	for (; *src; src++) {
+		switch (*src) {
+		case '<': strcat(dst, "&lt;"); dst += sizeof("&lt;")-1; break;
+		case '>': strcat(dst, "&gt;"); dst += sizeof("&gt;")-1; break;
+		case '&': strcat(dst, "&amp;"); dst += sizeof("&amp;")-1; break;
+		case '"': strcat(dst, "&quot;"); dst += sizeof("&quot;")-1; break;
+		case '\'': strcat(dst, "&#39;"); dst += sizeof("&#39;")-1; break;
+		default: *dst++ = *src; break;
+		}
+	}
+	*dst = '\0';
+}
+
 enum status
-resp_dir(int fd, char *name, struct request *r)
+resp_dir(int fd, char name[PATH_MAX], struct request *r)
 {
 	struct dirent **e;
 	size_t i;
 	int dirlen, s;
+	/* 6 - strlen("&quot;"), largest escape */
+	char escapebuf[PATH_MAX*6];
 	static char t[TIMESTAMP_LEN];
 
 	/* read directory */
_AT_@ -64,12 +84,13 @@ resp_dir(int fd, char *name, struct request *r)
 	}
 
 	if (r->method == M_GET) {
+		htmlescape(name, escapebuf);
 		/* listing header */
 		if (dprintf(fd,
 		            "<!DOCTYPE html>\n<html>\n\t<head>"
 		            "<title>Index of %s</title></head>\n"
 		            "\t<body>\n\t\t<a href=\"..\">..</a>",
-		            name) < 0) {
+		            escapebuf) < 0) {
 			s = S_REQUEST_TIMEOUT;
 			goto cleanup;
 		}
_AT_@ -80,12 +101,12 @@ resp_dir(int fd, char *name, struct request *r)
 			if (e[i]->d_name[0] == '.') {
 				continue;
 			}
-
+			htmlescape(e[i]->d_name, escapebuf);
 			/* entry line */
 			if (dprintf(fd, "<br />\n\t\t<a href=\"%s%s\">%s%s</a>",
-			            e[i]->d_name,
+			            escapebuf,
 			            (e[i]->d_type == DT_DIR) ? "/" : "",
-			            e[i]->d_name,
+			            escapebuf,
 			            suffix(e[i]->d_type)) < 0) {
 				s = S_REQUEST_TIMEOUT;
 				goto cleanup;
-- 
2.25.1
Received on Wed Mar 11 2020 - 22:10:38 CET

This archive was generated by hypermail 2.3.0 : Wed Mar 11 2020 - 23:48:36 CET