@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Mostly defuse DNS rebinding attack for outbound requests

Summary: Ref T6755. I'll add some notes there about specifics.

Test Plan:
- Made connections to HTTP and HTTPS URIs.
- Added some debugging code to verify that HTTP URIs were pre-resolved.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T6755

Differential Revision: https://secure.phabricator.com/D12169

+32 -5
+26 -4
src/applications/files/storage/PhabricatorFile.php
··· 471 471 pht('Too many redirects trying to fetch remote URI.')); 472 472 } 473 473 474 - PhabricatorEnv::requireValidRemoteURIForFetch( 474 + $resolved = PhabricatorEnv::requireValidRemoteURIForFetch( 475 475 $current, 476 476 array( 477 477 'http', 478 478 'https', 479 479 )); 480 480 481 - list($status, $body, $headers) = id(new HTTPSFuture($current)) 481 + list($resolved_uri, $resolved_domain) = $resolved; 482 + 483 + $current = new PhutilURI($current); 484 + if ($current->getProtocol() == 'http') { 485 + // For HTTP, we can use a pre-resolved URI to defuse DNS rebinding. 486 + $fetch_uri = $resolved_uri; 487 + $fetch_host = $resolved_domain; 488 + } else { 489 + // For HTTPS, we can't: cURL won't verify the SSL certificate if 490 + // the domain has been replaced with an IP. But internal services 491 + // presumably will not have valid certificates for rebindable 492 + // domain names on attacker-controlled domains, so the DNS rebinding 493 + // attack should generally not be possible anyway. 494 + $fetch_uri = $current; 495 + $fetch_host = null; 496 + } 497 + 498 + $future = id(new HTTPSFuture($fetch_uri)) 482 499 ->setFollowLocation(false) 483 - ->setTimeout($timeout) 484 - ->resolve(); 500 + ->setTimeout($timeout); 501 + 502 + if ($fetch_host !== null) { 503 + $future->addHeader('Host', $fetch_host); 504 + } 505 + 506 + list($status, $body, $headers) = $future->resolve(); 485 507 486 508 if ($status->isRedirect()) { 487 509 // This is an HTTP 3XX status, so look for a "Location" header.
+6 -1
src/infrastructure/env/PhabricatorEnv.php
··· 717 717 * 718 718 * @param string URI to test. 719 719 * @param list<string> Allowed protocols. 720 - * @return void 720 + * @return pair<string, string> Pre-resolved URI and domain. 721 721 * @task uri 722 722 */ 723 723 public static function requireValidRemoteURIForFetch( ··· 776 776 $address)); 777 777 } 778 778 } 779 + 780 + $resolved_uri = clone $uri; 781 + $resolved_uri->setDomain(head($addresses)); 782 + 783 + return array($resolved_uri, $domain); 779 784 } 780 785 781 786