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

From: guysv <sviryguy_AT_gmail.com>
Date: Mon, 16 Mar 2020 12:55:42 +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 | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)
diff --git a/resp.c b/resp.c
index 3075c28..e461a5d 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,29 @@ suffix(int t)
 	return "";
 }
 
+void
+htmlescape(char *src, char *dst)
+{
+	for (; *src; src++) {
+		switch (*src) {
+		case '<': strcpy(dst, "&lt;"); dst += sizeof("&lt;")-1; break;
+		case '>': strcpy(dst, "&gt;"); dst += sizeof("&gt;")-1; break;
+		case '&': strcpy(dst, "&amp;"); dst += sizeof("&amp;")-1; break;
+		case '"': strcpy(dst, "&quot;"); dst += sizeof("&quot;")-1; break;
+		case '\'': strcpy(dst, "&#39;"); dst += sizeof("&#39;")-1; break;
+		default: *dst++ = *src; *dst = '\0'; break;
+		}
+	}
+}
+
 enum status
 resp_dir(int fd, char *name, 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 +82,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_@ -81,11 +100,12 @@ resp_dir(int fd, char *name, struct request *r)
 				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 Mon Mar 16 2020 - 11:55:42 CET

This archive was generated by hypermail 2.3.0 : Mon Mar 16 2020 - 12:12:35 CET