php high concurrency post writes webshell, local reproduction
The most recent real emergency scenario, background as follows: php temporary files
- Host security alert detected a webshell.
- The malware file was named php. Additionally, there were numerous php temporary files in the /tmp directory.
- Nginx access logs showed a significant amount of scanner traffic, but no corresponding abnormal requests were found at the time the malware file was generated.
- The machine had WAF enabled, but the scanner’s IP was whitelisted (not malicious external scanning).
Host security alert isolated the malware
Emergency investigation process analysis
Preliminary assessment
The uploaded malware is a simple webshell. Theoretically, such an unencoded webshell would be directly intercepted by the WAF and would not be successfully uploaded. It is highly likely that the webshell was uploaded by the scanner.

Since the webshell was written through php temporary files (as seen in the isolated file above), and there were numerous php temporary files in the /tmp directory.

The logs showed a significant amount of scanner characteristics, so the next step is to find out which interface was used to upload the webshell, focusing only on post requests.
Emergency difficulties?
After the preliminary assessment, the investigation direction was outlined. However, there were still challenges.
- The log volume is enormous, with normal business requests mixed with scanner traffic. Each minute’s log volume can reach thousands of entries.
- There are no key characteristics, and Nginx logs do not record the body content of post requests.
- The malware file has been isolated, but the isolation time of the file may not be the actual write time of the file.
Investigating php configuration files

The php.ini
did not specify the path for upload_tmp_dir
, so php temporary files would default to the system’s temporary directory /tmp. It was confirmed that the files in /tmp were generated by php.
Investigating Nginx access logs
Since the malware file had already been isolated by host security, but the isolation time of the file may not be the actual write time of the file, investigating Nginx access logs based on the malware isolation time may not be accurate.
On the contrary, there were other numerous php temporary files in the /tmp directory, and the write times of these files were accurate.
The investigation found normal business requests, so no screenshots were provided.
Ultimately, investigating the generation times of multiple php temporary files corresponding to access logs did not reveal any abnormal requests.
Turning point – local reproduction
How are php temporary files generated?
Since normal investigation yielded no results, a different approach was taken. How can php generate these temporary files?
When we send an upload data packet to any PHP file, regardless of whether the PHP service backend has logic to handle $_FILES, PHP will first save the user’s uploaded data to a temporary file. This file is generally located in the system’s temporary directory, with a filename starting with php followed by 6 random characters; after the entire PHP file execution is complete, these uploaded temporary files will be cleaned up.
PHP’s POST temporary file mechanism
- The file is stored by default in the /tmp directory (can be specified by php.ini’s upload_tmp_dir)
- The filename is php[6 random characters], e.g., phpG4ef0q
- If the request ends normally, the temporary file will be automatically deleted
- If it ends abnormally, such as a crash, the temporary file may be permanently retained
Therefore, constructing abnormal requests, such as causing php to crash and ultimately failing to delete the temporary files, can generate php temporary files.
Monitoring file changes in the /tmp directory
Use the inotifywait command for monitoring, which can be installed via yum.
yum -y install inotify-tools inotifywait -m --timefmt "%Y-%m-%d %H:%M:%S" --format "[%T] : [%e] : %w%f" /tmp

Enabling real-time host security monitoring

Constructing high concurrency requests
Since php generates temporary files for post request content, high concurrency post requests can be manually constructed to make the server generate numerous php temporary files or even errors.
Here, 500 concurrent requests are simulated, with the post content being eval.php.
root@VM-8-15-ubuntu:/root# cat eval.php root@VM-8-15-ubuntu:/root# for i in `seq 1 500`;do curl "http://target.com/" -F "[email protected]" -o /dev/null -s & done

The final process result matched the video at the beginning of the article, successfully writing the webshell under high concurrency requests. Numerous host security alert messages were received.

Process chain analysis

Ultimately, comparing the process chain of the webshell file generated by the simulated concurrent requests with the emergency investigation host information confirmed my initial hypothesis.
Summary
Although the trick of writing webshells through php temporary files has been around for a long time, it was the first time encountering it in an emergency real-world scenario.
Not all emergency cases are caused by intrusions. For example, in this case, high concurrency requests caused the scanner’s post content to be written into php temporary files, but due to high concurrency, php crashed and failed to delete the temporary files, leading to host security alert isolation. Although it may be a rare event, this case is still very interesting!