quark

quark web server
git clone git://git.suckless.org/quark
Log | Files | Refs | LICENSE

commit 48e74a598247f4b81e09a0f652faf15163f9f525
parent 5ee8c07e7e3e601fce49fbc2b170227924be3804
Author: Laslo Hunhold <dev@frign.de>
Date:   Wed, 25 Mar 2020 14:07:17 +0100

Properly HTML-escape names in dirlistings

Based on a patch by guysv. We now make sure that the valid
path-characters ", ', <, >, & can not be used for XSS on a target, for
example with a file called

   "><img src="blabla" onerror="alert(1)"

by properly HTML-escaping these characters.

Signed-off-by: Laslo Hunhold <dev@frign.de>

Diffstat:
Mresp.c | 54+++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 51 insertions(+), 3 deletions(-)

diff --git a/resp.c b/resp.c @@ -38,6 +38,51 @@ suffix(int t) return ""; } +static void +html_escape(char *src, char *dst, size_t dst_siz) +{ + const struct { + char c; + char *s; + } escape[] = { + { '&', "&amp;" }, + { '<', "&lt;" }, + { '>', "&gt;" }, + { '"', "&quot;" }, + { '\'', "&#x27;" }, + }; + size_t i, j, k, esclen; + + for (i = 0, j = 0; src[i] != '\0'; i++) { + for (k = 0; k < LEN(escape); k++) { + if (src[i] == escape[k].c) { + break; + } + } + if (k == LEN(escape)) { + /* no escape char at src[i] */ + if (j == dst_siz - 1) { + /* silent truncation */ + break; + } else { + dst[j++] = src[i]; + } + } else { + /* escape char at src[i] */ + esclen = strlen(escape[k].s); + + if (j >= dst_siz - esclen) { + /* silent truncation */ + break; + } else { + memcpy(&dst[j], escape[k].s, esclen); + j += esclen; + } + } + } + dst[j] = '\0'; +} + enum status resp_dir(int fd, char *name, struct request *r) { @@ -45,6 +90,7 @@ resp_dir(int fd, char *name, struct request *r) size_t i; int dirlen, s; static char t[TIMESTAMP_LEN]; + char esc[PATH_MAX /* > NAME_MAX */ * 6]; /* strlen("&...;") <= 6 */ /* read directory */ if ((dirlen = scandir(name, &e, NULL, compareent)) < 0) { @@ -65,11 +111,12 @@ resp_dir(int fd, char *name, struct request *r) if (r->method == M_GET) { /* listing header */ + html_escape(name, esc, sizeof(esc)); 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) { + esc) < 0) { s = S_REQUEST_TIMEOUT; goto cleanup; } @@ -82,10 +129,11 @@ resp_dir(int fd, char *name, struct request *r) } /* entry line */ + html_escape(e[i]->d_name, esc, sizeof(esc)); if (dprintf(fd, "<br />\n\t\t<a href=\"%s%s\">%s%s</a>", - e[i]->d_name, + esc, (e[i]->d_type == DT_DIR) ? "/" : "", - e[i]->d_name, + esc, suffix(e[i]->d_type)) < 0) { s = S_REQUEST_TIMEOUT; goto cleanup;