CVE-2019–19576 (Arbitrary file upload in class.upload.php)

Jinny Ramsmark
Dec 5, 2019 · 3 min read

class.upload.php <= 2.0.3 Arbitrary file upload

Vendor: https://www.verot.net/

Product: class.upload.php

PoC github: https://github.com/jra89/CVE-2019-19576

CVE: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-19576

This is a filter bypass exploit that results in arbitrary file upload and remote code execution. The class.upload.php script filters “dangerous files and content” and renames them to the txt file extension. It also does different type of transformation on the uploaded image, which would normally destroy any injected payload, even if the file extension filter could be bypassed.

The file extension filter is a blacklist, so any time a new extension is introduced (in this case phar), or any has been missed, a PHP file can be uploaded. The content must still be a valid image however and will still go through the imagecreatefromjpeg and similar functions. For this purpose I wrote the inject.php script which will essentially bruteforce its way through different images until it finds one where the payload will not be destroyed by the process done in class.upload.php. This effectively gives us an arbitrary file upload and a very stealthy code execution since it’s still a valid image and will be displayed like one on pages where uploaded.

An interesting note is that not all installations of web server with PHP are vulnerable, and requires the phar extension to be enabled and handled. Default installed Ubuntu 19.10 with apache and php has this however.

I had to write a script that essentially brute forces different images to find a valid injection point that will survive the php-gd process in the library. This can be found in the git repository, but an example of the output can be seen below. The script is nothing really new and is something I started writing years ago for another project, but realized I could make use of it here as well.

user@ayu:/var/www/html# php inject.php 
-=Imagejpeg injector 1.7=-
[+] Fetching image (100 X 100) from http://lorempixel.com/100/100/
[+] Jumping to end byte
[+] Searching for valid injection point
[!] Temp solution, if you get a 'recoverable parse error' here, it means it probably failed
[+] It seems like it worked!
[+] Result file: image.jpg.phar

When uploaded using the example code from verot.net’s github page, it results in code execution.

user@ayu:/var/www/html# curl -v -o - http://localhost/images/image_resized.phar?c=uname%20-a | grep -aPo "(Linux.*GNU)"
Linux ayu 5.0.0-36-generic #39-Ubuntu SMP Tue Nov 12 09:46:06 UTC 2019 x86_64 x86_64 x86_64 GNU

Joomla K2 test

The Joomla K2 extension was also tested for this and was found to be vulnerable since it uses this library. This was tested on version 2.10.1 of K2, but older version are probably also vulnerable.

The below picture shows a regular registered user in Joomla K2 that has uploaded a profile picture that has been run through my script and contains the payload. It will appear as a regular profile picture that is slightly distorted.

In the next picture you can see the picture being used to execute a command on the server.

Solution

The implemented solution for class.upload.php has been to simply add the phar extension to the list of blacklisted extensions. My suggestion for a more permanent solution would be to switch from a blacklist to a whitelist, since with the blacklist this issue may come back in the future if new extensions are introduced. With whitelisting one would specify all allowed extensions instead, and the library could even have a long list of default ones since the idea behind the library is to allow upload of all kinds of files.

Reference: https://github.com/verot/class.upload.php/blob/2.0.4/src/class.upload.php#L3068

Jinny Ramsmark

Written by

I program, hack, and write odd stories. I currently work for an IT-security company called Defensify.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade