Security context
Critical· 9.9GHSA-qm5c-m76r-2hfr Published May 15, 2024

Laravel RCE vulnerability in "cookie" session driver

Research this vulnerability

Research is free — Hunters explains how the bug works, the root-cause code pattern, how the fix addresses it, and how to test whether a target is affected, in chat. Investigate & write exploit is a paid run — the engine reads the advisory and fix commits, then builds and validates a working proof-of-concept exploit with reproduction steps.

Affected versions

4.1.0 → fixed in 6.18.317.0.0 → fixed in 7.22.4

Details

Applications using the "cookie" session driver that were also exposing an encryption oracle via their application were vulnerable to remote code execution. An encryption oracle is a mechanism where arbitrary user input is encrypted and the encrypted string is later displayed or exposed to the user. This combination of scenarios lets the user generate valid Laravel signed encryption strings for any plain-text string, thus allowing them to craft Laravel session payloads when an application is using the "cookie" driver.

The fix

Release delta 7.0.0 → 7.22.4 (contains the fix)

· Mar 3, 2020, 02:19 PM+981350compare
src/Illuminate/Http/Client/PendingRequest.php+5 3
@@ -3,6 +3,7 @@
namespace Illuminate\Http\Client;
use GuzzleHttp\Client;
+use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\HandlerStack;
use Illuminate\Support\Traits\Macroable;
@@ -285,13 +286,14 @@ public function withToken($token, $type = 'Bearer')
* Specify the cookies that should be included with the request.
*
* @param array $cookies
+ * @param string $domain
* @return $this
*/
- public function withCookies(array $cookies)
+ public function withCookies(array $cookies, string $domain)
{
- return tap($this, function ($request) use ($cookies) {
+ return tap($this, function ($request) use ($cookies, $domain) {
return $this->options = array_merge_recursive($this->options, [
- 'cookies' => $cookies,
+ 'cookies' => CookieJar::fromArray($cookies, $domain),
]);
});
}
tests/Http/HttpClientTest.php+18 0
@@ -193,4 +193,22 @@ public function testFakeSequence()
$this->assertSame(201, $this->factory->get('https://example.com')->status());
$this->assertSame(301, $this->factory->get('https://example.com')->status());
}
+
+ public function testWithCookies()
+ {
+ $this->factory->fakeSequence()->pushStatus(200);
+
+ $response = $this->factory->withCookies(
+ ['foo' => 'bar'], 'https://laravel.com'
+ )->get('https://laravel.com');
+
+ $this->assertCount(1, $response->cookies()->toArray());
+
+ /** @var CookieJarInterface $responseCookies */
+ $responseCookie = $response->cookies()->toArray()[0];
+
+ $this->assertSame('foo', $responseCookie['Name']);
+ $this->assertSame('bar', $responseCookie['Value']);
+ $this->assertSame('https://laravel.com', $responseCookie['Domain']);
+ }
}
src/Illuminate/Support/Facades/Cache.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
src/Illuminate/Support/Facades/Http.php+1 1
@@ -18,7 +18,7 @@
* @method static \Illuminate\Http\Client\PendingRequest withBasicAuth(string $username, string $password)
* @method static \Illuminate\Http\Client\PendingRequest withDigestAuth(string $username, string $password)
* @method static \Illuminate\Http\Client\PendingRequest withToken(string $token, string $type = 'Bearer')
- * @method static \Illuminate\Http\Client\PendingRequest withCookies(array $cookies)
+ * @method static \Illuminate\Http\Client\PendingRequest withCookies(array $cookies, string $domain)
* @method static \Illuminate\Http\Client\PendingRequest withoutRedirecting()
* @method static \Illuminate\Http\Client\PendingRequest withoutVerifying()
* @method static \Illuminate\Http\Client\PendingRequest timeout(int $seconds)
matcher (#31762)
src/Illuminate/Routing/CompiledRouteCollection.php | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
src/Illuminate/Encryption/Encrypter.php+1 1
@@ -100,7 +100,7 @@ public function encrypt($value, $serialize = true)
// its authenticity. Then, we'll JSON the data into the "payload" array.
$mac = $this->hash($iv = base64_encode($iv), $value);
- $json = json_encode(compact('iv', 'value', 'mac'));
+ $json = json_encode(compact('iv', 'value', 'mac'), JSON_UNESCAPED_SLASHES);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new EncryptException('Could not encrypt the data.');
CHANGELOG-7.x.md+43 1
@@ -1,6 +1,48 @@
# Release Notes for 7.x
-## [Unreleased](https://github.com/laravel/framework/compare/v7.0.3...7.x)
+## [Unreleased](https://github.com/laravel/framework/compare/v7.0.7...7.x)
+
+
+## [v7.0.7 (2020-03-07)](https://github.com/laravel/framework/compare/v7.0.6...v7.0.7)
+
+### Fixed
+- Fixed type hint for `Request::get()` method ([#31826](https://github.com/laravel/framework/pull/31826))
+- Add missing public methods to `Illuminate\Routing\RouteCollectionInterface` ([e4f477c](https://github.com/laravel/framework/commit/e4f477c42d3e24f6cdf44a45801c0db476ad2b91))
+
+
+## [v7.0.6 (2020-03-06)](https://github.com/laravel/framework/compare/v7.0.5...v7.0.6)
+
+### Added
+- Added queue suffix for SQS driver ([#31784](https://github.com/laravel/framework/pull/31784))
+
+### Fixed
+- Fixed model binding when route cached ([af80685](https://github.com/laravel/framework/commit/af806851931700e8dd8de0ac0333efd853b19f3d))
+- Fixed incompatible `Factory` contract for `MailFacade` ([#31809](https://github.com/laravel/framework/pull/31809))
+
+### Changed
+- Fixed typehints in `Illuminate\Foundation\Application::handle()` ([#31806](https://github.com/laravel/framework/pull/31806))
+
+
+## [v7.0.5 (2020-03-06)](https://github.com/laravel/framework/compare/v7.0.4...v7.0.5)
+
+### Fixed
+- Fixed `Illuminate\Http\Client\PendingRequest::withCookies()` method ([36d783c](https://github.com/laravel/framework/commit/36d783ce8dbd8736e694ff60ae66e542c62411c3))
+- Catch Symfony `MethodNotAllowedException` exception in `CompiledRouteCollection::match()` method ([#31762](https://github.com/laravel/framework/pull/31762))
+- Fixed a bug with slash prefix in the route ([#31760](https://github.com/laravel/framework/pull/31760))
+- Fixed root URI not showing in the `route:list` ([#31771](https://github.com/laravel/framework/pull/31771))
+- Fixed model restoring right after soft deleting it ([#31719](https://github.com/laravel/framework/pull/31719))
+
+### Changed
+- Throw exception for duplicate route names in `Illuminate\Routing\AbstractRouteCollection::addToSymfonyRoutesCollection()` method ([#31755](https://github.com/laravel/framework/pull/31755))
+- Changed `Illuminate\Support\Str::slug()` method ([e4f22d8](https://github.com/laravel/framework/commit/e4f22d855b429e4141885d542438c859f84bfe49))
+- Check if an array lock exists before releasing it in `Illuminate\Cache\ArrayLock::release()` ([#31795](https://github.com/laravel/framework/pull/31795))
+- Revert disabling expired views checks ([#31798](https://github.com/laravel/framework/pull/31798))
+
+
+## [v7.0.4 (2020-03-05)](https://github.com/laravel/framework/compare/v7.0.3...v7.0.4)
+
+### Changed
+- Changed of route prefix parameter parsing ([b38e179](https://github.com/laravel/framework/commit/b38e179642d6a76a7713ced1fddde841900ac3ad))
## [v7.0.3 (2020-03-04)](https://github.com/laravel/framework/compare/v7.0.2...v7.0.3)
HTTP client for when array doesnt make snese (#31858)
src/Illuminate/Http/Client/PendingRequest.php | 22 ++++++-------------
1 file changed, 7 insertions(+), 15 deletions(-)
composer.json+1 1
@@ -124,7 +124,7 @@
"doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6).",
"filp/whoops": "Required for friendly error pages in development (^2.4).",
"fzaninotto/faker": "Required to use the eloquent factory builder (^1.9.1).",
- "guzzlehttp/guzzle": "Required to use the Mailgun mail driver and the ping methods on schedules (^6.3|^7.0).",
+ "guzzlehttp/guzzle": "Required to use the HTTP Client, Mailgun mail driver and the ping methods on schedules (^6.3|^7.0).",
"laravel/tinker": "Required to use the tinker console command (^2.0).",
"league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^1.0).",
"league/flysystem-cached-adapter": "Required to use the Flysystem cache (^1.0).",
src/Illuminate/Http/Client/RequestException.php | 2 ++
1 file changed, 2 insertions(+)
composer.json+2 2
@@ -79,7 +79,7 @@
"aws/aws-sdk-php": "^3.0",
"doctrine/dbal": "^2.6",
"filp/whoops": "^2.4",
- "guzzlehttp/guzzle": "^6.3|^7.0",
+ "guzzlehttp/guzzle": "^6.3.1|^7.0",
"league/flysystem-cached-adapter": "^1.0",
"mockery/mockery": "^1.3.1",
"moontoast/math": "^1.1",
@@ -124,7 +124,7 @@
"doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6).",
"filp/whoops": "Required for friendly error pages in development (^2.4).",
"fzaninotto/faker": "Required to use the eloquent factory builder (^1.9.1).",
- "guzzlehttp/guzzle": "Required to use the HTTP Client, Mailgun mail driver and the ping methods on schedules (^6.3|^7.0).",
+ "guzzlehttp/guzzle": "Required to use the HTTP Client, Mailgun mail driver and the ping methods on schedules (^6.3.1|^7.0).",
"laravel/tinker": "Required to use the tinker console command (^2.0).",
"league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^1.0).",
"league/flysystem-cached-adapter": "Required to use the Flysystem cache (^1.0).",
src/Illuminate/Mail/composer.json+1 1
@@ -36,7 +36,7 @@
},
"suggest": {
"aws/aws-sdk-php": "Required to use the SES mail driver (^3.0).",
- "guzzlehttp/guzzle": "Required to use the Mailgun mail driver (^6.3|^7.0).",
+ "guzzlehttp/guzzle": "Required to use the Mailgun mail driver (^6.3.1|^7.0).",
"wildbit/swiftmailer-postmark": "Required to use Postmark mail driver (^3.0)."
},
"config": {
src/Illuminate/Http/Client/RequestException.php+1 1
@@ -21,7 +21,7 @@ class RequestException extends Exception
*/
public function __construct(Response $response)
{
- parent::__construct("{$response->effectiveUri()} returned status code {$response->status()}.", $response->status());
+ parent::__construct("HTTP request returned status code {$response->status()}.", $response->status());
$this->response = $response;
}
src/Illuminate/Support/Str.php | 18 ++++++++++++++++--
tests/Support/SupportStrTest.php | 2 +-
tests/Support/SupportStringableTest.php | 2 +-
3 files changed, 18 insertions(+), 4 deletions(-)
src/Illuminate/Routing/CompiledRouteCollection.php+1 1
@@ -29,7 +29,7 @@ class CompiledRouteCollection extends AbstractRouteCollection
protected $attributes = [];
/**
- * An array of the routes that were added after loading the compiled routes.
+ * The dynamically added routes that were added after loading the cached, compiled routes.
*
* @var \Illuminate\Routing\RouteCollection|null
*/
in json to provide deterministic encryption sizes. (#31721)
src/Illuminate/Encryption/Encrypter.php | 2 +-
tests/Encryption/EncrypterTest.php | 10 ++++++++++
2 files changed, 11 insertions(+), 1 deletion(-)
src/Illuminate/Foundation/Application.php+1 1
@@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig
*
* @var string
*/
- const VERSION = '7.0.0';
+ const VERSION = '7.0.1';
/**
* The base path for the Laravel installation.
src/Illuminate/Routing/Route.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
src/Illuminate/Foundation/Application.php+1 1
@@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig
*
* @var string
*/
- const VERSION = '7.0.1';
+ const VERSION = '7.0.2';
/**
* The base path for the Laravel installation.
src/Illuminate/Support/Traits/EnumeratesValues.php | 1 +
1 file changed, 1 insertion(+)
src/Illuminate/Http/Client/RequestException.php+2 0
@@ -21,6 +21,8 @@ class RequestException extends Exception
*/
public function __construct(Response $response)
{
+ parent::__construct("{$response->effectiveUri()} returned status code {$response->status()}.", $response->status());
+
$this->response = $response;
}
}
src/Illuminate/Routing/CompiledRouteCollection.php | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
src/Illuminate/Foundation/Application.php+1 1
@@ -33,7 +33,7 @@ class Application extends Container implements ApplicationContract, CachesConfig
*
* @var string
*/
- const VERSION = '7.0.2';
+ const VERSION = '7.0.3';
/**
* The base path for the Laravel installation.
CHANGELOG-6.x.md | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
CHANGELOG-7.x.md+36 0
@@ -0,0 +1,36 @@
+# Release Notes for 7.x
+
+## [Unreleased](https://github.com/laravel/framework/compare/v7.0.3...7.x)
+
+
+## [v7.0.3 (2020-03-04)](https://github.com/laravel/framework/compare/v7.0.2...v7.0.3)
+
+### Fixed
+- Fixed route caching attempt in `Illuminate\Routing\CompiledRouteCollection::newRoute()` ([90b0167](https://github.com/laravel/framework/commit/90b0167d97e61eb06fce9cfc58527f4e09cd2a5e))
+- Catch Symfony exception in `CompiledRouteCollection::match()` method ([#31738](https://github.com/laravel/framework/pull/31738))
+- Fixed Eloquent model casting ([2b395cd](https://github.com/laravel/framework/commit/2b395cd1f2fe95b67edf97684f09b7c5c4a55152))
+- Fixed `UrlGenerator` constructor ([#31740](https://github.com/laravel/framework/pull/31740))
+
+### Changed
+- Added message to `Illuminate\Http\Client\RequestException` ([#31720](https://github.com/laravel/framework/pull/31720))
+
+
+## [v7.0.2 (2020-03-04)](https://github.com/laravel/framework/compare/v7.0.1...v7.0.2)
+
+### Fixed
+- Fixed `ascii()` \ `isAscii()` \ `slug()` methods on the `Str` class with null value in the methods ([#31717](https://github.com/laravel/framework/pull/31717))
+- Fixed `trim` of the prefix in the `CompiledRouteCollection::newRoute()` ([ce0355c](https://github.com/laravel/framework/commit/ce0355c72bf4defb93ae80c7bf7812bd6532031a), [b842c65](https://github.com/laravel/framework/commit/b842c65ecfe1ea7839d61a46b177b6b5887fd4d2))
+
+### Changed
+- remove comments before compiling components in the `BladeCompiler` ([2964d2d](https://github.com/laravel/framework/commit/2964d2dfd3cc50f7a709effee0af671c86587915))
+
+
+## [v7.0.1 (2020-03-03)](https://github.com/laravel/framework/compare/v7.0.0...v7.0.1)
+
+### Fixed
+- Fixed `Illuminate\View\Component::withAttributes()` method ([c81ffad](https://github.com/laravel/framework/commit/c81ffad7ef8d74ebd109f399abbdc5c7ebabff88))
+
+
+## [v7.0.0 (2020-03-03)](https://github.com/laravel/framework/compare/v6.18.0...v7.0.0)
+
+Check the upgrade guide in the [Official Laravel Upgrade Documentation](https://laravel.com/docs/7.x/upgrade). Also you can see some release notes in the [Official Laravel Release Documentation](https://laravel.com/docs/7.x/releases).
prefix and accounts for bindings
src/Illuminate/Routing/Route.php | 40 ++++++++++++++----------------
tests/Routing/RoutingRouteTest.php | 9 +++++++
2 files changed, 28 insertions(+), 21 deletions(-)
More files changed — see the full commit.

References