Lab-3-Rca
UWE-P564-01: Host header buffer overflow
The Basics
Authors: Samuel Tay, Chloe Claridad
Disclosure Date: 2022-11-22
Product: tinyserv
Reporter(s): CSE P564 staff
Exploit sample: see sploit1.sh
The Exploit
Exploit strategy: The header
struct in tinyserv has two consecutive fields char host[32]
and int is_admin
. When assigning the incoming packet's Host header value, there is no limit on the length of the data copied into host
. The exploit simply sends a request with a Host header value that exceeds 32
chars, thus overwriting the is_admin
flag, allowing the user to access admin-restricted content.
Exploit primitives: This exploit has no limit on the buffer overflow. Thus while the sploit1.sh
example simply overwrites the very next is_admin
field of the header struct, the vulnerability is actually much greater. In particular, the hdr
value is sitting on the serve
function's stack frame, after two other stack variables int id
and int timeout
. Thus by using a host value that exceeds the size of the header
struct and two int
s, the attacker could overwrite the return address of the serve
function and execute arbitrary code in a ret-lib-c style attack.
The Vulnerability
Vulnerability details: The vulnerability is a buffer overflow. Specifically the header struct has a buffer field char host[32]
defined on line main.c:85
. Then on lines main.c:483-488
this field is written to without regard to its 32-len size limit.
Bug class: CWE-787
Severity/priority score: The severity is high; arbitrary code execution is possible with this vulnerability.
Thoughts on how this vulnerability might have been found: Fuzzing probably could have found this, however for the size of this codebase an audit would be a good solution without huge overhead. In particular, for any of the buffers defined at the top of the file, simply search for writes to those variables and verify that length checks are in place.
The Patch
Proposed patch plan: The plan is to define a const HOST_MAX_LEN 32
, use this constant in the host field definition char host[HOST_MAX_LEN]
, and then fix the get_host
function such that it returns the lesser of the found length and HOST_MAX_LEN
.
Killing the bug class: Oh jeez. I don't think there is a general accepted solution for ridding ourselves of buffer overflows in C. If it were up to me, with such a small codebase, I'd just port it to a different language like Rust and avoid unsafe
. Outside of a rewrite, two things come to mind:
- Lesser effort: create consts for each of the defined buffer lengths and put explicit bounds checks on all of the existing buffers. Having this pattern in the codebase goes a long way to others following this pattern in the future.
- More effort: integrate some automated fuzz testing.
UWE-P564-02: Naive equality check for admin filepath
The Basics
Authors: Samuel Tay, Chloe Claridad
Disclosure Date: 2022-11-22
Product: tinyserv
Reporter(s): CSE P564 staff
Exploit sample: see sploit2.sh
The Exploit
Exploit strategy:: When checking to see if a request is for the restricted admin.txt
file, a simple string equality check is performed; that is, the server checks if the requested file path is "admin.txt"
. This is exploited by using a file path that is equivalent to the restricted file, but a different string. For example when the server is started with a root directory ./files
the user requests file "../admin.txt"
. This passes the check which determines the admin request, and the server will dutifully send back the restricted file ./files/../admin.txt
.
Exploit primitives: The vulnerability allows the attacker to read arbitrary files on the server; to be precise, if the server is started by a user $USER
, then the attacker can access any file for which $USER
has read access.
The Vulnerability
Vulnerability details: There are actually two vulnerabilities here.
- The user gains access to the specific restricted
admin.txt
file. This occurs in the functionint packet_is_admin_page(char *packet)
, specifically on linesmain.c:946-949
, which simply performs a string equality check against"admin.txt"
. - The user can access content outside of the directory specified by the CLI argument. This is a check that should occur in the
get_header
function, after checkingpacket_is_admin_page
. The proposed patch will insert an extraelse if
block between linesmain.c:508
andmain.c:510
.
Arguably, (2) is the more dangerous exploit here. (1) does leak potentially sensitive data for the website, but (2) allows users to access local files on the server, which could potentially be used to gain root access and wreak much more havoc (e.g. imagine someone is running tinyserver as root
, attacker request /etc/passwd
or /etc/shadow
, breaks hashes to get root password, etc.).
Also note that these are overlapping in the normal case, but need not be; in the case when the user makes the poor choice of using the tinyserv directory or one of its parent directories as the files argument, the user is not exploiting vulnerability (2) but still exploiting vulnerability (1).
Bug class (CWE):
Severity/priority score: Vulnerability (1) is medium severity; attackers get to see some data on the server usage. It's not good but it's not the end of the world. However vulnerability (2) is high; as explained above, this could in certain cases lead to someone having root access on the server.
Thoughts on how this vulnerability might have been found: The only thing I can think of is a code audit.
The Patch
Proposed patch plan: For (1) the plan is to pass both the requested path and admin path through realpath
first, and then compare equality. Similarly, for (2) we will pass the requested path and the dir
argument through realpath
and check that realpath(dir)
is a prefix of realpath(requested_file)
.
Killing the bug class: I'm not very familiar with C, so this might not be possible, but my thought is to solve this with types. For example in Haskell or Rust I would use a FilePath
type that has lawfully correct Eq
behavior.