Bug 1218599 - AUDIT-1: darkhttpd: check up on small http web server written in C
Summary: AUDIT-1: darkhttpd: check up on small http web server written in C
Status: RESOLVED FIXED
Alias: None
Product: SUSE Security Incidents
Classification: Novell Products
Component: Audits (show other bugs)
Version: unspecified
Hardware: Other Other
: P5 - None : Normal
Target Milestone: ---
Assignee: Matthias Gerstner
QA Contact: Security Team bot
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2024-01-08 09:46 UTC by Matthias Gerstner
Modified: 2024-01-25 10:31 UTC (History)
3 users (show)

See Also:
Found By: ---
Services Priority:
Business Priority:
Blocker: ---
Marketing QA Status: ---
IT Deployment: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Matthias Gerstner 2024-01-08 09:46:24 UTC
The systemd monitoring reported this new service:

```
1 new services detected
=======================

RPM: darkhttpd-1.14-1.1.x86_64.rpm on x86_64
Package: darkhttpd
Service path: /usr/lib/systemd/system/darkhttpd.service
Runs as: root:root
Exec lines:
    ExecStart=/usr/bin/darkhttpd $DARKHTTPD_PARAMS
```

This is a ~3.000 lines C code http web server. Given that it is network faced
and rather small we can do a small dedicated review here.
Comment 1 Matthias Gerstner 2024-01-10 12:52:37 UTC
I'll look into it
Comment 2 Matthias Gerstner 2024-01-12 13:26:41 UTC
I'm through with the code review. This is a self-sufficient C coding style
that I mostly like. It won't get much better than this when using C
programming.

There are a couple of areas that seemed brittle:

- the possibility of log spoofing by passing control characters
- the possibility to cause out of bound memory accesses by passing bad byte
  range values

Log spoofing is actively prevent though by escaping anything that is not
alphanumerical.

The byte range worry stems from the fact that a cast from "long long" to
"off_t" is performed in one spot. If sizeof(long long) > sizeof(off_t) then
this could result in a negative off_t value being used for reaching into
memory.

By default when compiling on Linux for 32-bit then off_t has only 4 bytes and
the problem would arise. The code defines `_FILE_OFFSET_BITS 64`, though, thus
off_t becomes 8 bytes wide.

In all other constellations both data types are always 8 bytes these days
though, even on i386. I even checked some BSDs, but none are affected.

All that remains is that there is a weak http basic auth password comparison
that could be used for timing attacks. I will approach upstream privately
about this.
Comment 3 Matthias Gerstner 2024-01-15 09:20:02 UTC
I approached the upstream author about two security problems in the web
server's code base:

- strcmp() is used to check HTTP basic auth. This is subject to timing
  attacks.
- the `--auth` command line switch leaks the HTTP basic auth credentials in
  the process list of the local system.

The upstream author does not want an embargo so we can publish immediately. I
will also request CVEs from Mitre. Until this is all done let's keep this
private for a couple of days longer.
Comment 4 Matthias Gerstner 2024-01-15 10:52:52 UTC
This is the formal report that I shared with upstream.

Basic Auth Timing Attack
========================

The issue is found in darkhttpd.c line 2272 [4]. Here the HTTP basic
authentication string supplied by a client is compared against the
secret configured via the `--auth` command line parameter. For this
comparison a regular `strcmp()` function call is used.

Since `strcmp()` performs an efficient linear comparison it will
terminate earlier if the first bytes of the supplied authentication
string don't match compared to if they do match. This difference in
runtime can be used for timing attacks to try and find out the correct
authentication parameter to access the web server.

To fix this, a constant-time string comparison function needs to be used
that always takes the same amount of computation time for the comparison
independently of how many bytes of the provided data match the actual
authentication secret. An example for such a function is the
`CRYPTO_memcmp()` function provided by the openSSL library [5].

If darkhttpd is used for unencrypted http:// over the Internet then one
could argue that the authentication data will be sent unencrypted over
an untrusted channel anyway. If darkhttpd is used behind a reverse proxy
that uses SSL and thus uses a secure channel, then a major security
property will be violated by this issue though.

Local Leak of Authentication Parameter in Process List
======================================================

The only way to configure the HTTP basic auth string is to pass it via
the `--auth` command line parameter. On Linux all local users can view
the parameters of other programs running on the system. This means if
there are other users or programs running in different security domains
then these can obtain the authentication credentials for the web server.

To fix this an alternative mechanism needs to be provided to pass the
authentication credentials in a safe way. Typically this can be solved
by using an environment variable or a protected configuration file. If
the existing `--auth` command line switch is kept around then the fact
that this leaks the authentication credentials on Linux systems should
be documented.

Review Summary
==============

Apart from these basic authentication related issues I have not found
any problematic spots in the code base of darkhttpd. I focused on the
potential for log file spoofing, escaping the web root via crafted URLs
and memory corruption e.g. through specifying bad byte ranges. The code
is robust in these areas.

References
==========

[1]: https://github.com/emikulic/darkhttpd
[2]: https://en.opensuse.org/openSUSE:Security_disclosure_policy
[3]: https://www.openwall.com/lists/oss-security/
[4]: https://github.com/emikulic/darkhttpd/blob/v1.14/darkhttpd.c#L2272
[5]: https://www.openssl.org/docs/man1.1.1/man3/CRYPTO_memcmp.html
Comment 5 Smith 2024-01-18 13:32:40 UTC
This seems to be fixed upstream with 1.15, to which Dominik has already submitted to Factory.
I'd have personally preferred to see auth supporting an environment variable. However, it does now warn about --auth's security shortcomings, so that may be enough to consider this resolved.

Thanks as usual Matthias :)
Comment 6 Matthias Gerstner 2024-01-18 14:10:16 UTC
Yes, there was quite some back and forth between us and the upstream author.
For some reason he was not too eager to implement this as an environment
variable.

I'm still keeping this bug private for a bit longer until I get CVE references
from Mitre and then I will publish on multiple channels.
Comment 7 Matthias Gerstner 2024-01-23 10:42:32 UTC
I now published the full report on the oss-security mailing list and on our
blog:

https://security.opensuse.org/2024/01/22/darkhttpd-basic-auth-issues.html

Mitre still did not respond to my CVE requests.

Since we package this only in openSUSE:Factory, and the version has already
been bumped to the fixed v1.15 we can close this review bug.
Comment 8 Matthias Gerstner 2024-01-25 10:31:24 UTC
Mitre finally assigned the CVEs for these issues:

> darkhttpd through 1.15 allows local users to discover credentials (for --auth) by listing processes and their arguments:

Use CVE-2024-23770

> darkhttpd before 1.15 uses strcmp (which is not constant time) to verify authentication, which makes it easier for remote attackers to bypass authentication via a timing side channel.

Use CVE-2024-23771