php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #74192 Inappropriate URL parsing may cause security risk
Submitted: 2017-03-01 18:56 UTC Modified: 2017-10-24 23:52 UTC
From: orange dot 8361 at gmail dot com Assigned: pollita (profile)
Status: Assigned Package: URL related
PHP Version: 7.0.16 OS: Ubuntu 16.04
Private report: No CVE-ID: 2017-7189
Have you experienced this issue?
Rate the importance of this bug to you:

 [2017-03-01 18:56 UTC] orange dot 8361 at gmail dot com
Description:
------------
Hi, PHP Security Team:

The behaviors in parse_url and http_wrap/cURL are different. This may cause a security risk on web application.

https://3v4l.org/ADXSe

The port of parse_url("http://0:11211:80/") is 80.

But file_get_content("http://0:11211:80/") or curl_exec(...). It will connect to localhost:11211

So if a programmer use the result of parse_url to check whether attacker access the port out of 80. The check will be bypassed.

For a example: 
I use this bug to bypass the patch of CVE-2016-6483.
vBulletin use parse_url to limit the port in 80 and 443. But I can use http://0:11211:80/ to access the local Memcached service.



Test script:
---------------
<?php

parse_url("http://0:11211:80/");


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-03-02 09:18 UTC] orange at chroot dot org
Small update:
cURL is safe. But PHP's http_wrapper is actually affected by this vulnerability.
 [2017-03-04 11:40 UTC] orange at chroot dot org
ping?

I just fuzzed and found a work PoC on cURL.

<?php
var_dump(parse_url('http://[127.0.0.1]:11211:80'));
// Output port is 80

https://3v4l.org/ouuZH


But 
<?php
$url = $argv[1];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'http://[127.0.0.1]:11211:80');
curl_exec($ch);
curl_close($ch);
// connect 127.0.0.1:11211
 [2017-03-08 18:35 UTC] orange dot 8361 at gmail dot com
-: orange at chroot dot org +: orange dot 8361 at gmail dot com
 [2017-03-08 18:35 UTC] orange dot 8361 at gmail dot com
Hi, did you see this mail? :)
 [2017-03-08 20:51 UTC] pollita@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: pollita
 [2017-03-08 20:51 UTC] pollita@php.net
This actually got fixed yesterday while working on a very similar bug in fsockopen()

https://github.com/php/php-src/commit/bab0b99f376dac9170ac81382a5ed526938d595a

For reference, the builtin http wrapper turns requests for http(s)://(host:ip)/path into a transport open to (tcp|ssl)://(host:ip) which make it through to the same parse_ip method that was fixed for the fsockopen() bug.
 [2017-03-08 20:53 UTC] pollita@php.net
-Status: Closed +Status: Re-Opened
 [2017-03-08 20:53 UTC] pollita@php.net
Actually, I'll reopen this.   The transport uri used by the http wrapper is reconstructed from the url decomposer shared by parse_url() and that probably still is broken in this circumstance.

I'll take another look.
 [2017-03-08 21:13 UTC] pollita@php.net
Clarification: Broken in the sense that parse_url() on a malformed URL provides an answer as though the URL were valid.  Not, broken in the sense that it'll allow the bypass you described.  The aforementioned fix from yesterday *does* block that particular vulnerability.

That's not to say there isn't room for parse_url() giving a "successful parse" response to cause other vulnerabilities.
 [2017-03-08 21:15 UTC] pollita@php.net
-Assigned To: pollita +Assigned To:
 [2017-03-08 22:04 UTC] stas@php.net
I think parse_url has always been more lenient and allowed parsing partial URLs. However, something like two ports probably shouldn't pass if there's no valid interpretation of it. I don't think we can guarantee that every function would treat broken URLs the same way parse_url does, but at least having PHP streams and parse_url agree would be a good idea.
 [2017-03-09 02:40 UTC] orange dot 8361 at gmail dot com
The URL seems not valid in RFC. So the best way I think is return nothing in parse_url() part.
The cURL part I have reported to them. They fixed the issue by return an error.
 [2017-03-09 02:43 UTC] orange dot 8361 at gmail dot com
But I agree that "at least having PHP streams and parse_url agree would be a good idea."
 [2017-03-09 04:30 UTC] orange dot 8361 at gmail dot com
Right, the patch yesterday seem fixed the issue :)
 [2017-04-04 23:05 UTC] orange dot 8361 at gmail dot com
-Status: Re-Opened +Status: Closed
 [2017-04-04 23:05 UTC] orange dot 8361 at gmail dot com
Fixed
 [2017-04-04 23:09 UTC] orange dot 8361 at gmail dot com
Please use CVE-2017-7189 for this issue.
 [2017-04-04 23:11 UTC] kaplan@php.net
-Assigned To: +Assigned To: kaplan -CVE-ID: +CVE-ID: 2017-7189
 [2017-05-12 07:17 UTC] orange dot 8361 at gmail dot com
Please disclose it(set to public)

Thanks! :)
 [2017-10-24 06:21 UTC] stas@php.net
-Status: Closed +Status: Re-Opened
 [2017-10-24 06:21 UTC] stas@php.net
Reopening since bug #74429 reverted the fix.
 [2017-10-24 06:22 UTC] stas@php.net
-Assigned To: kaplan +Assigned To: pollita
 [2017-10-24 23:52 UTC] kalle@php.net
-Status: Re-Opened +Status: Assigned
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Sun Nov 19 01:31:42 2017 UTC