#!/usr/bin/env python3
"""Scan backdoor klinikmetamorf.com dari sisi luar (REST + probe HTTP):
plugin/tema tak dikenal, namespace asing, skrip tersuntik di halaman, file PHP mencurigakan, xmlrpc."""
import base64, html, json, re, time, urllib.request, urllib.error

SITE = "https://klinikmetamorf.com"
UA = {"User-Agent": "Mozilla/5.0"}
AUTH = base64.b64encode(b"bambangbot:whWA hVlW omQk 9FSL 8rkz VMHy").decode()
AUTHH = {"Authorization": f"Basic {AUTH}", **UA}


def wp(path):
    r = urllib.request.Request(SITE + path, headers=AUTHH)
    for _ in range(3):
        try:
            with urllib.request.urlopen(r, timeout=120) as x:
                return json.loads(x.read())
        except urllib.error.HTTPError as e:
            return {"__err": e.code, "pesan": e.read().decode()[:120]}
        except Exception:
            time.sleep(3)
    return {"__err": "gagal"}


print("=== 1. Plugin terpasang ===")
plug = wp("/wp-json/wp/v2/plugins?_fields=plugin,name,status,version")
if isinstance(plug, list):
    for p in sorted(plug, key=lambda x: x.get("status", "")):
        print(f"  [{p.get('status'):<9}] {p.get('name','?')[:38]:<40} v{p.get('version','?'):<10} {p['plugin']}")
else:
    print("  ", plug)

print("\n=== 2. Tema terpasang ===")
th = wp("/wp-json/wp/v2/themes?status=active&_fields=stylesheet,name,version")
print("  aktif:", json.dumps(th, ensure_ascii=False)[:200] if isinstance(th, list) else th)
th_all = wp("/wp-json/wp/v2/themes?_fields=stylesheet,name,status")
if isinstance(th_all, list):
    for t in th_all:
        nm = t.get("name")
        nm = nm.get("rendered") if isinstance(nm, dict) else str(nm)
        print(f"  [{t.get('status','-'):<8}] {nm[:40]:<42} {t.get('stylesheet')}")

print("\n=== 3. Namespace REST (namespace tak dikenal = plugin asing) ===")
root = wp("/wp-json")
if isinstance(root, dict) and "namespaces" in root:
    kenal = ("wp/", "oembed", "yoast", "contact-form", "wp-rocket", "astra", "spectra", "uag", "site-kit",
             "google-site-kit", "akismet", "wpcode", "bdpp", "zipwp", "nps-survey", "one-onboarding")
    for ns in root["namespaces"]:
        tanda = "" if any(ns.startswith(k) for k in kenal) else "   ← PERIKSA"
        print(f"  {ns}{tanda}")

print("\n=== 4. Skrip/iframe tersuntik di 6 halaman ===")
pages = wp("/wp-json/wp/v2/pages?per_page=100&context=edit&_fields=id,title,content")
if isinstance(pages, list):
    for p in pages:
        raw = p["content"]["raw"] if isinstance(p["content"], dict) else ""
        tanda = []
        for pola, label in ((r"<script", "script"), (r"<iframe", "iframe"),
                            (r"base64_decode|eval\(|gzinflate|str_rot13|preg_replace\s*\(\s*['\"]/e", "kode obfuscated"),
                            (r"https?://(?!klinikmetamorf\.com|www\.w3\.org|gmpg\.org|fonts\.|maps\.google)[a-z0-9.-]+", "host luar")):
            m = re.findall(pola, raw, re.I)
            if m:
                tanda.append(f"{label}: {len(m)}")
        host = sorted(set(re.findall(r'href="(https?://[^/"]+)', raw)))
        host = [h for h in host if "klinikmetamorf" not in h and "w3.org" not in h]
        print(f"  #{p['id']:>5} {html.unescape(p['title']['rendered'])[:28]:<30} {'; '.join(tanda) or 'bersih':<28} host luar: {host[:3]}")

print("\n=== 5. Probe file/endpoint mencurigakan (HTTP dari luar) ===")
PROBE = ["/wp-content/uploads/", "/wp-content/uploads/shell.php", "/wp-content/uploads/2026/09/shell.php",
         "/wp-content/uploads/wp-login.php", "/wp-content/uploads/index.php", "/xmlrpc.php",
         "/wp-config.php.bak", "/wp-config.php~", "/.env", "/wp-content/debug.log", "/readme.html",
         "/wp-json/wp/v2/users", "/wp-admin/", "/wp-content/plugins/js_composer/readme.txt"]
for u in PROBE:
    try:
        r = urllib.request.Request(SITE + u, headers=UA)
        resp = urllib.request.urlopen(r, timeout=45)
        b = resp.read()
        kecil = b.decode("utf-8", "replace")[:120].replace("\n", " ")
        print(f"  {resp.status} | {len(b):>7}b | {u:<44} {kecil[:60]}")
    except urllib.error.HTTPError as e:
        print(f"  {e.code} | {u}")
    except Exception as e:
        print(f"  ERR {str(e)[:30]} | {u}")
