Bug #3062
closedServer Aborted due to Malicious Data sent through CGI Sendfile
Description
My configuration file for this is as following.
cgi.assign = ( ".pl" => "/usr/bin/perl",
".cgi" => "/usr/bin/perl" )
$HTTP["url"] =~ "^/cgi/" {
cgi.x-sendfile = "enable"
cgi.upgrade = "enable"
cgi.local-redir = "enable"
}
server.m
My cgi script looks like this:
#!/usr/bin/perl
use CGI;
my $q = CGI->new;
my %headers = map { $_ => $q->http($_) } $q->http();
for my $header ( keys %headers ) {
if ($header = "HTTP_X_SENDFILE") {
print "X-Sendfile: $headers{$header}\n\n";
}
}
Basically, the script takes the data from the X_SENDFILE http header and passes it to the response header.
While testing this functionality, I found a couple crashes. None of them actually crashed the server, they all resulted in an SIGABORT. I read up on some past issues and know that this a security mechanism of lighttpd.
Here is the proof of concept
GET /cgi/sendfile.cgi HTTP/1.1
Host: 172.18.163.75:3000
X-Sendfile: .
This single dot triggers an SIGABORT on the application.
Here is the full backtrace.
stat_cache.c.1257: assertion failed: 0 != len
Thread 1 "lighttpd" received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1 0x00007ffff7d05859 in __GI_abort () at abort.c:79
#2 0x0000000000266477 in log_failed_assert (filename=<optimized out>,
line=<optimized out>, msg=<optimized out>) at buffer.c:1016
#3 0x000000000029e2cf in stat_cache_get_entry (name=<optimized out>)
at stat_cache.c:1257
#4 0x000000000029f302 in stat_cache_get_entry_open (name=0x3f1d80, symlinks=1)
at stat_cache.c:1386
#5 0x00000000002afd56 in http_response_send_file (r=0x3a08c0, path=0x3f1d80)
at http-header-glue.c:566
#6 0x00000000002b7a01 in http_response_parse_headers (r=<optimized out>,
opts=<optimized out>, b=<optimized out>) at http-header-glue.c:765
#7 0x00000000002b8b17 in http_response_read (r=0x3a08c0, opts=0x3ed608, b=0x3ed6c0,
fdn=0x3f1ca0) at http-header-glue.c:1513
#8 0x00007ffff536b4b6 in cgi_recv_response (r=0x3a08c0, hctx=0x3ed5c0)
at mod_cgi.c:433
#9 cgi_handle_fdevent (ctx=0x3ed5c0, revents=1) at mod_cgi.c:459
#10 0x00000000002aa694 in fdevent_linux_sysepoll_poll (ev=0x3964f0,
timeout_ms=<optimized out>) at fdevent_linux_sysepoll.c:43
#11 0x0000000000285c91 in fdevent_poll (ev=0x3964f0, timeout_ms=-11120)
at fdevent.c:436
#12 0x000000000022ad17 in server_main_loop (srv=0x3131b0) at server.c:1902
#13 0x0000000000227108 in main (argc=6, argv=<optimized out>) at server.c:2040
Updated by gstrauss almost 4 years ago
- Status changed from New to Patch Pending
- Target version changed from 1.4.x to 1.4.59
Thanks for the report. Here's a patch.
--- a/src/http-header-glue.c +++ b/src/http-header-glue.c @@ -737,6 +737,10 @@ static void http_response_xsendfile (request_st * const r, buffer * const path, if (r->conf.force_lowercase_filenames) { buffer_to_lower(path); } + if (buffer_string_is_empty(path)) { + r->http_status = 502; + valid = 0; + } /* check that path is under xdocroot(s) * - xdocroot should have trailing slash appended at config time @@ -815,6 +819,10 @@ static void http_response_xsendfile2(request_st * const r, const buffer * const if (r->conf.force_lowercase_filenames) { buffer_to_lower(b); } + if (buffer_string_is_empty(b)) { + r->http_status = 502; + break; + } if (xdocroot) { size_t i, xlen = buffer_string_length(b); for (i = 0; i < xdocroot->used; ++i) {
Please note that this would not have crashed if you had set "x-sendfile-docroot"
to restrict the locations of files that can be sent via X-Sendfile.
If you do not trust your users, you should not enable "x-sendfile"
without also configuring "x-sendfile-docroot"
Updated by stbuehler almost 4 years ago
Also: if you don't trust your CGI scripts you shouldn't use CGI - instead you need to run them via a FastCGI wrapper (e.g. https://redmine.lighttpd.net/projects/fcgi-cgi/wiki) as a different user; a normal CGI script can simply kill -ABRT your webserver anyway.
Updated by gstrauss almost 4 years ago
- Status changed from Patch Pending to Fixed
Applied in changeset 649829f90688e780f1df780035a630d3fc9faa1b.
Updated by axe34 almost 4 years ago
May I file a cve for this bug, and moreover, how many versions does this affect?
Updated by gstrauss almost 4 years ago
I do not think this is CVE-worthy, and if you choose to file one, I will dispute it.
- First,
"x-sendfile"
it is not enabled by default. - Second, as stated above,
"x-sendfile-docroot"
should be configured whenever"x-sendfile"
is configured, especially with untrusted users.
"x-sendfile-docroot"
has been available in lighttpd since lighttpd 1.4.40 (Jul 2016) - Third, since Jan 2010 (yes 2010) lighttpd explicitly documents that
"x-sendfile"
should not be enabled for untrusted users. (This alone disqualifies this bug as a CVE)
https://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModFastCGI/57#X-Sendfile - Fourth, as you already acknowledged, the behavior is intentional. An assertion failure is explicitly triggered by lighttpd. This is not "exploitable" beyond triggering the assertion.
Not every bug is CVE-worthy. Thank you for reporting a minor bug. A brief thanks is included in the commit message for commit 649829f9 if you would like to reference that and this issue (#3062) to record your efforts.
how many versions does this affect?
The call to stat_cache_get_entry_open()
was introduced in lighttpd 1.4.56 (Nov 2020)
However, it bears repeating that any admin who enabled "x-sendfile"
for untrusted users has exposed their system to dangers far worse than triggering an assertion failure. Again, please read the documentation for X-Sendfile (which is referenced from the mod_cgi documentation.
Also available in: Atom