LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS
Basic Info
With an LFI, PHP’s upload-progress feature can create a session file even when the application did not otherwise start a session and session.auto_start=Off. This requires session.upload_progress.enabled=On, a multipart upload containing the configured progress field (normally PHP_SESSION_UPLOAD_PROGRESS), and a controllable session identifier.[4]
$ curl http://127.0.0.1/ -H 'Cookie: PHPSESSID=iamorange'
$ ls -a /var/lib/php/sessions/
. ..
$ curl http://127.0.0.1/ -H 'Cookie: PHPSESSID=iamorange' -d 'PHP_SESSION_UPLOAD_PROGRESS=blahblahblah'
$ ls -a /var/lib/php/sessions/
. ..
$ curl http://127.0.0.1/ -H 'Cookie: PHPSESSID=iamorange' -F 'PHP_SESSION_UPLOAD_PROGRESS=blahblahblah' -F 'file=@/etc/passwd'
$ ls -a /var/lib/php/sessions/
. .. sess_iamorange
In the last example the session will contain the string blahblahblah
The progress value becomes part of serialized session data. If the LFI can include that session file while it exists, attacker-controlled PHP code in the value may execute.
[!TIP] PHP defaults
session.upload_progress.cleanuptoOn, so progress data is removed as soon as the upload is processed. Exploitation is therefore a race unless cleanup has been disabled.[4]
The CTF
In the original CTF where this technique is described, winning the race was not enough: the loaded content also needed to start with the string @<?php.[1]
The default session.upload_progress.prefix adds upload_progress_ before the attacker-controlled key in the serialized session data, producing content such as upload_progress_controlledcontentbyattacker.
The trick to remove the initial prefix was to base64encode the payload 3 times and then decode it via convert.base64-decode filters, this is because when base64 decoding PHP will remove the weird characters, so after 3 times only the payload sent by the attacker will remain (and then the attacker can control the initial part).[1]
More information is available in the original writeup and the final exploit.[1][2]
Another writeup in https://spyclub.tech/2018/12/21/one-line-and-return-of-one-line-php-writeup/[3]