Relative Path Traversal in laravel/framework
Reported on
Jun 12th 2021
✍️ Description
The active_url
rule for validation in input fails to correctly check dns record with dns_get_record
resulting in bypassing the validation.
🕵️♂️ Proof of Concept
For a laravel installation having the following validation on route:
Route::get('/', function () {
$urlValidator = Validator::make(request()->toArray(), [
'url' => 'required|active_url',
]);
if ($urlValidator->fails()) {
return "[FAILED] ".request()->input('url');
} else {
echo "[PASSED] ".request()->input('url');
return file_get_contents(request()->input('url'));
}
});
Provide url
parameter as http://example.com/?url=file://localhost/etc/passwd
The dns_get_record
will try to resolve A record for localhost
. If there is no record, it tries to check for localhost.example.com
treating localhost
as a subdomain. As a result, if localhost.example.com
resolves for A (which is affirmative for wildcard subdomain routing), the file://localhost/etc/passwd
will pass the validation check for active_url
.
PoC || gtfo
http://laravel.example.com/?url=file://localhost/etc/passwd (POC taken down)
💥 Impact
This vulnerability is capable of bypassing validation checks and if the provided file://
url is passed to functions like file_get_contents
, fopen
etc., we can traverse the local paths on the server.
Mitigation
In src/Illuminate/Validation/Concerns/ValidatesAttributes.php:59
append a .
to $url
while using dns_get_record
:
return count(dns_get_record($url . '.', DNS_A | DNS_AAAA)) > 0;