php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #72053 Multipart request is parsed differently for nearly equal "Content-Disposition"
Submitted: 2016-04-18 21:17 UTC Modified: 2021-03-10 13:05 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: mail at michael-kaufmann dot ch Assigned:
Status: Verified Package: *General Issues
PHP Version: 7.4 OS: Linux
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: mail at michael-kaufmann dot ch
New email:
PHP Version: OS:

 

 [2016-04-18 21:17 UTC] mail at michael-kaufmann dot ch
Description:
------------
Fuzz testing revealed that this multipart request is parsed differently, depending on the number of 'a' characters:

--BOUNDARY
Content-Disposition: form-data; name="test"; aaaaaaaaa...aaaaaaaaaa:; filename="test.txt"

This is a test
--BOUNDARY--

For up to 5074 'a' characters, PHP parses this as a file upload: _FILES["test"] contains an array.

For 5075 'a' characters and more, PHP parses this as a POST parameter: _POST["test"] contains the string "This is a test".


This is very strange behavior. I expect that PHP parses these requests the same way, regardless of the number of 'a' characters.

Test script:
---------------
#!/bin/bash
(
	printf -- "--BOUNDARY\r\n"
	printf -- "Content-Disposition: form-data; name=\"test\"; "
	printf -- "a%.0s" {1..5074}
	printf -- ":; filename=\"test.txt\"\r\n"
	printf -- "\r\n"
	printf -- "This is a test\r\n"
	printf -- "--BOUNDARY--"
) > /tmp/test.dat

curl -H "Content-Type: multipart/form-data; boundary=BOUNDARY" --data-binary @/tmp/test.dat http://.../phpinfo.php


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-06-12 18:19 UTC] mail at michael-kaufmann dot ch
-PHP Version: 5.6.20 +PHP Version: 7.0.7
 [2016-06-12 18:19 UTC] mail at michael-kaufmann dot ch
This is what happens:

next_line() in rfc1867.c returns a partial (truncated) header line for very long headers. multipart_buffer_headers() processes this partial header line like a complete header line if it contains a colon (":"). The remaining part of the header line is then processed as a separate header.

In the example, the "Content-Disposition" header is split like this:

First header:
- name: Content-Disposition
- value: form-data; name="test"; aaaaaaaaa...aaaaaaaaaa

Second header:
- name: (empty)
- value: ; filename="test.txt"
 [2021-03-10 13:05 UTC] cmb@php.net
-Status: Open +Status: Verified -PHP Version: 7.0.7 +PHP Version: 7.4
 [2021-03-10 13:05 UTC] cmb@php.net
Thanks, you're analysis looks right.  A possible solution might be
to add a flag to multipart_buffer which signals the partial line,
and to catch that like we already catch lines beginning with
whitespace (to support line folding)[1].

[1] <https://github.com/php/php-src/blob/php-7.4.16/main/rfc1867.c#L423-L426>
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Dec 26 20:01:29 2024 UTC