Escape untrusted input like the request URL or filesystem paths in HTML
outputs such as the directory listing or 404 error messages.
This fixes certain XSS vulnerabilities which can be leveraged to further
exploit the system.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
const char *type = "directory";
unsigned int mode = S_IXOTH;
struct stat s;
const char *type = "directory";
unsigned int mode = S_IXOTH;
struct stat s;
char *file;
char buf[128];
int i;
char *file;
char buf[128];
int i;
if (!(s.st_mode & mode))
goto next;
if (!(s.st_mode & mode))
goto next;
+ escaped = uh_htmlescape(name);
+
+ if (!escaped)
+ goto next;
+
uh_chunk_printf(cl,
"<li><strong><a href='%s%s%s'>%s</a>%s"
"</strong><br /><small>modified: %s"
"<br />%s - %.02f kbyte<br />"
"<br /></small></li>",
uh_chunk_printf(cl,
"<li><strong><a href='%s%s%s'>%s</a>%s"
"</strong><br /><small>modified: %s"
"<br />%s - %.02f kbyte<br />"
"<br /></small></li>",
- path, name, suffix,
- name, suffix,
+ path, escaped, suffix,
+ escaped, suffix,
uh_file_unix2date(s.st_mtime, buf, sizeof(buf)),
type, s.st_size / 1024.0);
uh_file_unix2date(s.st_mtime, buf, sizeof(buf)),
type, s.st_size / 1024.0);
*file = 0;
next:
free(files[i]);
*file = 0;
next:
free(files[i]);
static void uh_file_dirlist(struct client *cl, struct path_info *pi)
{
struct dirent **files = NULL;
static void uh_file_dirlist(struct client *cl, struct path_info *pi)
{
struct dirent **files = NULL;
+ char *escaped_path = uh_htmlescape(pi->name);
+ if (!escaped_path)
+ {
+ uh_client_error(cl, 500, "Internal Server Error", "Out of memory");
+ return;
+ }
+
uh_file_response_200(cl, NULL);
ustream_printf(cl->us, "Content-Type: text/html\r\n\r\n");
uh_chunk_printf(cl,
"<html><head><title>Index of %s</title></head>"
"<body><h1>Index of %s</h1><hr /><ol>",
uh_file_response_200(cl, NULL);
ustream_printf(cl->us, "Content-Type: text/html\r\n\r\n");
uh_chunk_printf(cl,
"<html><head><title>Index of %s</title></head>"
"<body><h1>Index of %s</h1><hr /><ol>",
+ escaped_path, escaped_path);
count = scandir(pi->phys, &files, NULL, dirent_cmp);
if (count > 0) {
strcpy(uh_buf, pi->phys);
count = scandir(pi->phys, &files, NULL, dirent_cmp);
if (count > 0) {
strcpy(uh_buf, pi->phys);
- list_entries(cl, files, count, pi->name, uh_buf);
+ list_entries(cl, files, count, escaped_path, uh_buf);
free(files);
uh_chunk_printf(cl, "</ol><hr /></body></html>");
free(files);
uh_chunk_printf(cl, "</ol><hr /></body></html>");
{
int fd;
struct http_request *req = &cl->request;
{
int fd;
struct http_request *req = &cl->request;
+ char *error_handler, *escaped_url;
if (!(pi->stat.st_mode & S_IROTH))
goto error;
if (!(pi->stat.st_mode & S_IROTH))
goto error;
+ escaped_url = uh_htmlescape(url);
+
uh_client_error(cl, 403, "Forbidden",
"You don't have permission to access %s on this server.",
uh_client_error(cl, 403, "Forbidden",
"You don't have permission to access %s on this server.",
+ escaped_url ? escaped_url : "the url");
+
+ if (escaped_url)
+ free(escaped_url);
}
void uh_dispatch_add(struct dispatch_handler *d)
}
void uh_dispatch_add(struct dispatch_handler *d)
struct http_request *req = &cl->request;
struct dispatch_handler *d;
char *url = blobmsg_data(blob_data(cl->hdr.head));
struct http_request *req = &cl->request;
struct dispatch_handler *d;
char *url = blobmsg_data(blob_data(cl->hdr.head));
+ char *error_handler, *escaped_url;
blob_buf_init(&cl->hdr_response, 0);
url = uh_handle_alias(url);
blob_buf_init(&cl->hdr_response, 0);
url = uh_handle_alias(url);
- uh_client_error(cl, 404, "Not Found", "The requested URL %s was not found on this server.", url);
+ escaped_url = uh_htmlescape(url);
+
+ uh_client_error(cl, 404, "Not Found", "The requested URL %s was not found on this server.",
+ escaped_url ? escaped_url : "");
+
+ if (escaped_url)
+ free(escaped_url);
char *uh_htmlescape(const char *str)
{
char *uh_htmlescape(const char *str)
{
- for (p = str, len = 1; *p; p++)
- if (is_html_special_char(*p))
+ for (i = 0, len = 1; str[i]; i++)
+ if (is_html_special_char(str[i]))
len += 6; /* &#x??; */
else
len++;
len += 6; /* &#x??; */
else
len++;
- for (p = copy; *str; str++)
- if (is_html_special_char(*str))
- p += sprintf(p, "&#x%02x;", (unsigned int)*str);
+ for (i = 0, p = copy; str[i]; i++)
+ if (is_html_special_char(str[i]))
+ p += sprintf(p, "&#x%02x;", (unsigned int)str[i]);