FirstBlood-#939Remote Code Execution via insecure deserialization on /api/checkproof.php
This issue was discovered on FirstBlood v2

On 2021-10-30, 0xblackbird Level 5 reported:

Hello! I was able to execute commands via an insecure deserialization on /api/checkproof.php (and /vaccination-manager/pub/submit-vaccination-proof.php).


When we try to be like a normal user and try uploading an (normal) image that contains nothing special, we can see that we first upload it via POST request on /vaccination-manager/pub/submit-vaccination-proof.php and then that the file extension gets checked by /api/checkproof.php via the proof GET parameter. The thing here is that a malicious user can use this to get remote code execution by uploading a malicious image and calling it via the phar stream wrapper (phar deserialization).

Steps to reproduce

  • First of all, we need to identify the technology that's being used. In this case, we can see that there is a /composer.json file in the root directory. Opening this file gives us the following: Monolog v2.1.1.

  • Next, we can generate a malicious file containing our payload. We can use a tool like phpggc to generate and include it in our image. To do so, download the tool from Github and execute the following command: sudo phpggc Monolog/RCE1 'system' 'whoami' -pj /home/user/picture.jpg -o /home/user/payload.jpg. (In this command, we first specify the custom gadget (which we identified from the composer.json) and also the PHP function including the parameters of the function, in this case we'll be executing system("id").) This will take the picture.jpg file and generate another image in your home directory called payload.jpg which contains the payload (the file we're going to upload).

  • Now we have to upload it, start up firstblood v2 if you haven't already and navigate to /vaccination-manager/pub/upload-vaccination-proof.php. Enter any email-address in the email-address field, it has to be valid but not your personal one: [email protected] will do fine. And finally, click on "Browse" to select the previously generated "image" (picture.jpg). Once you've done so, click on "Upload".

  • We'll have to intercept the request of the checkproof API endpoint. So forward the POST request to /vaccination-manager/pub/submit-vaccination-proof.php and send the GET request to /api/checkproof.php to Repeater.

  • In the Repeater tab, add the phar stream wrapper in the proof GET parameter (so that your value looks like the following phar:///app/firstblood/upload/{HASH}.jpg) and resend the request. It'll take a bit before you get a response back, but as you can see, the function (system('id')) was successfully executed! We got remote code execution! A malicious user can now for example upload a shell (backdoor) and make it easier for him to execute commands and/or escalate his/her privileges.

Thanks for the fun challenge!

Kind regards,


Endpoint: /api/checkproof.php

This report contains multiple vulnerabilities:

  • Deserialization
  • Information leak/disclosure

FirstBlood ID: 34
Vulnerability Type: Deserialization

This endpoint calls filesize() on the path provided in the 'proof' param with no filtering or sanitisation. By adding the phar:// stream handler to the path, an attacker can force a previously uploaded file to be sent through deserialisation. Coupled with the fact that a gadget-chain vulnerable version of monolog is being used, this allows for RCE.

FirstBlood ID: 36
Vulnerability Type: Information leak/disclosure

It is possible to use the composer.json to aid with another vulnerability and gaining information/knowledge on versions used.