Ronaldo100's avatar

PHAR Deserialization Vulnerability

Hello! :)

Please tell me, what the best practice is when it comes to file upload.

I want my Laravel projects to be very secure, however, I haven't managed to find any resource online that clearly tells me, how to avoid the so-called "PHAR Deserialization Vulnerability"

What I am talking about is people hiding PHAR code inside an uploaded file which then gets executed on the server, for example as a web shell or whatever kind of code.

Thanks, Ronaldo

0 likes
18 replies
Ronaldo100's avatar

@Sinnbeck

Hello again, Sinnbeck :)

Thank you very much for the link!

The exact video that you linked is the video that got me thinking about this very vulnerability in the first place (so, I already knew this video and have watched it just a few days ago)

Even though this amazing speaker points out said vulnerability, he did not explain how to prevent it.

At least I wasn't able to extract the information, and I am next to totally sure that he really did not tell the viewers as to how to prevent it.

But it could be owed to my lack of understanding.

However, I am really pretty sure he only explained it, but did not show how to fix it.

Ronaldo100's avatar

UPDATE to everyone who reads this:

Here, this is a website also explaining the problem:

https://pentest-tools.com/blog/exploit-phar-deserialization-vulnerability

Unfortunately, the only solution they tell the reader about is to "sanitize user input" and to randomize the file name stored on the server.

However, this leaves two key issues:

  1. Simply sanitizing won't help, because a picture would still qualify as a JPG even if PHAR code were inside

  2. No matter what filename I save the picture under on the server, the user will still know if I use the picture for example as their profile picture (Right Click, open image in new tab, and there you have the file name)

Also, to prove that I am not afraid about nothing, please allow me to point y'all to a specific part of the video that has been linked by @sinnbeck above.

https://youtu.be/kKGGVGiq2y8?t=646

^ this link should bring you to 10:48 in the video.

Please give the video a chance, it's really interesting how the speaker manages to hack the server using a picture.

If you really have no time to watch the video from the position linked above, you can skip to 16:27 to get closer to "the live action"

https://youtu.be/kKGGVGiq2y8?t=988

Sinnbeck's avatar

@Ronaldo100 a good point is made in tip 2. This specific hack is patched in guzzle so if you update, at least you are safe from that.

Regarding validation I think he is talking about the get route. 19:53 in the video. Ensure that it's a clean filename and not phar://

Also you can reencode the image on save to clean it up

But in the end it's only a problem if you allow accessing the image using php (file size etc). In most cases you never do that at all. You just embed a direct link using the direct url to the image

Ronaldo100's avatar

Thank you for responding again, @sinnbeck!

I am answering your message by quoting your lines:

a good point is made in tip 2

Which "tip 2" are you referring to? Do you mean on the pentest-tools website the section "2. Core concepts to understand PHAR Deserialization" ? That was a bit unclear for me.

Ensure that it's a clean filename and not phar://

Do you mean like: phar://day_on_the_beach.jpg ?

That is something I would not allow anyway!

Also you can reencode the image on save to clean it up

a) Would re-encoding really get rid of all of the malicious phar code?

b) Do you mean like: system("convert uploaded-pic.jpg uploaded-pic.png"); ?

c) Wouldn't that command (see b) also somehow execute the code?

But in the end it's only a problem if you allow accessing the image using php (file size etc). In most cases you never do that at all. You just embed a direct link using the direct url to the image

Wouldn't I want to check the user does not upload a 400 MB large picture?

Also, I might need to check the file dimensions to make sure it will work as an e.g. profile picture.

Sinnbeck's avatar

@Ronaldo100 the tip 2 is in the video and states that the hack is patched in guzzle so if you update it to the latest version the hack won't work. Until the next security hole is found

Be aware that the hack isn't in the upload of the file. That part isn't a problem, even if you run file size checks. For the hack to work, you need to prefix the filename with phar:// So the hack is only possible because he passes the filename directly to the file size check

So accessing the image directly in the browser does not execute the hack

The conversion can be done using imagick or similar. But it isn't necessary if you already guard the image using the above methods

Snapey's avatar

@Ronaldo100 I routinely resize images so that the original data is no more. Maybe it's not completely bulletproof ( if say my code is open source and available for reverse engineering) but it probably makes the risk many times lower

Ronaldo100's avatar

Dear @Sinnbeck,

thank you very much for responding again!

I think I've understood you now, but just to be sure that I am not mistaken, please kindly allow me to repeat the information I've gathered so far:

Presumption: A user uploads a JPG file containing malicious PHAR code

  1. I will rename the picture to something only containing [a-Z] and [0-9] so that the file will NOT start with phar://

  2. I will only perform file size checks and dimension checks AFTER having renamed the file as described in step 1)

But, according to what I also understood from you, is, that because of the now patched "guzzle", I would NOT need to even care about 1) and 2)

QUESTION A:

Is everything I wrote above correct? If not, please kindly correct me.

QUESTION B:

How can I make sure, a user does not upload multiple, let's say, 500 GB files which will cause my server to run out of space?

I ask this, because I am NOT allowed to check for anything before renaming the file.

QUESTION C:

Can I even use Laravel form validation on file uploads?

Laravel allows for form validation out of the box, but if I used it on pictures, I would probably again expose my server to PHAR attacks, wouldn't I ?

Ronaldo100's avatar

Hello @Snapey :)

I saw your name on the Leaderboard before :))

Resizing the images sounds good, but how can we be sure this will really remove all malicious code?

Wouldn't that remain somewhere in the file?

Is there some kind of software to remove it? It's not EXIF information, I guess?

So "exiftool -all=" will probably not help either.

Okay, so back to resizing...

a) The user uploads the picture. b) I rename the picture. c) Then I resize the picture d) And finally I can use it as a profile picture.

Like this?

But again, I won't even be able to use Laravel's built-in form validation upon uploading in order to avoid the PHAR vulnerability.

Best Regards, Ronaldo

Sinnbeck's avatar

@Ronaldo100 it's not detectable in php generally. But just resizing will remove the code as it isn't image data and will be ignored

Ronaldo100's avatar

@Sinnbeck - As resizing will cause the image to significantly lose quality, do you have any thoughts on the message I wrote above the last message? (maybe it got overlooked as I responded to you first, and then to Snapey)

Snapey's avatar

@Ronaldo100 you are validating the file with the temporary name given to it by php, not the one supplied by the user

resizing will affect the image quality only in so much as you resize it.

Ronaldo100's avatar

@Snapey so I should use imagemagick's "resize" command with the SAME dimensions as the user uploaded the picture?

So if the user uploaded a 1000 * 500 px picture, I will go with:

resize input.jpg --resize:1000x500 --quality 100 output.jpg

?

Sinnbeck's avatar

@Ronaldo100 use php. But are you planning to use php for letting the user get file size for an arbitrary image? See the video at 19:53. The get method for getting file size etc. That's the vulnerable code

Ronaldo100's avatar

Dear @Sinnbeck and @Snapey,

Thank you again for both of your replies!

I have given myself a full day to keep re-reading about the so-called "Phar Deserialization Vulnerability" online over and over again, and I have also re-read the entire forum thread here multiple times.

But, I still don't quite get it.

Please forgive me in case I bother y'all, but I still did not quite understand it. I am truly sorry.

QUOTE - @Sinnbeck

But are you planning to use php for letting the user get file size for an arbitrary image? See the video at 19:53. The get method for getting file size etc. That's the vulnerable code

My response:

I thought with all the preceding steps, I could then use PHP to process the picture without risks?

The steps would be:

a) The user uploads the picture.
b) make sure, the filename does NOT start with  phar://,  e.g.  not   phar://picture.jpg
c) I rename the picture.
d) Then I resize the picture
e) And finally I can use it as a profile picture under an address known by the user

Question 1)

What is missing in the steps above in order to turn the arbitrary image into a 100% safe image?

Question 2)

Is setting "upload_max_filesize" and "post_max_size" in the "php.ini" file dangerous? I assume, that even in this case, PHP would check for the file size and, by doing so, turn the arbitrary image into a web shell.

Question 3)

Could the user exploit the arbitrary image if the location of the picture is UNKNOWN to the user?

For example, if I saved the picture OUTSIDE the public directory (so the user can't access it, e.g. in /tmp/)?

So, let's say the arbitrary image is in /tmp/ where the visitor (hacker) cannot access it from the web.

Could I then check for the file size and file dimensions WITHOUT causing a security risk?

Or would there still be a risk if I ran a filesize() check on an arbitrary picture outside Apache's public web-directory?

Please forgive me for asking this all, but it's really not clear yet, and this so-called "PHAR Deserialization Vulnerability" sounds extremely dangerous (web shell access!).

Regards, Ronaldo

Sinnbeck's avatar

@Ronaldo100 ok let's take them one by one

  1. If you follow those steps it should be safe. I also don't think b is a real problem as the file name would be invalid. Try renaming a file yourself and upload it. To remove the exploit, all you need is d. But if the user cannot call the image path, it's not going to work anyways
  2. If that was the case, then php would never be safe. These are built in php functions used under the hood and no matter what you set these values to, the size is still checked. But it would require the attacker to somehow specify that the file is a phar. If this ever is found to be an issue, it can only be fixed in php itself and not by you
  3. Again it would require the hacker to find a way to tell your code to prepend phar:// to the file path. Just checking the size is not a risk unless the file path is prepended with phar://.

But if you still feel unsafe, try to hack your own website. First allow it in your code and then try to close the security hole

Ronaldo100's avatar

@Sinnbeck and @Snapey

May I kindly ask you to please provide me with a working code for PHP / Laravel to resize pictures in a way that...

a) the PHAR deserialization vulnerability is gone for good

b) the pictures don't lose quality

I know the imagemagick resizing:

system('convert input.jpg -quality 100 -resize 1000x output.jpg');

But I am NOT sure if...

a) ...this helps to get rid of the PHAR deserialization vulnerability

b) ...this is the best way of doing it at all (maybe there is a better PHP way?)

c) ...if the can get rid of the PHAR deserialization vulnerability WITHOUT actually RESIZING the picture (maybe it's just in-out without any changes)

ADDITIONAL QUESTION

What do I do about PDF and PNG and WEBP and whatever other file types users might need to upload? (which can be many in a corporate environment)

Sinnbeck's avatar

@Ronaldo100 Use a library if it actually is a problem. You still havent said if it is. As I dont know what packages you plan to use, it is hard to say. Personally I would use intervension: https://packagist.org/packages/intervention/image

$img = Image::make('public/foo.jpg');

// resize image instance
$img->resize($img->width(), $img->height());
$img->save('public/bar.jpg');

And you will need to test it yourself with other formats. The hack he shows is for any image file, but that does not guarantee similar cannot be found for others.

Please or to participate in this conversation.