1
1
mirror of https://github.com/pterodactyl/panel.git synced 2024-11-22 17:12:30 +01:00

[Security] Address 2FA bypass in password reset functionality

Thanks to Trixter#0001 on Discord for this security report.

There was a two-factor authentication bypass present in all previous versions of Pterodactyl that would allow a user to login without providing a token by going through the password reset process. A person would still have to have access to the targeted account's email, but if they did manage to get a password reset link they would be able to reset the account password and then proceede to login without a token being required.

This logic has since been changed to check if 2FA is enabled on an account, and if so they will NOT be logged in when their password is changed. This will force them to continue through the normal login pathway where a token will be needed.

Overall the impact of this issue is minor, but I am still addressing it and disclosing the mechanism behind it.
This commit is contained in:
Dane Everitt 2018-07-04 11:41:56 -07:00
parent 422e5dd99f
commit 8f5bd214a4
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53

View File

@ -2,8 +2,14 @@
namespace Pterodactyl\Http\Controllers\Auth;
use Illuminate\Support\Str;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\Contracts\Hashing\Hasher;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Contracts\Events\Dispatcher;
use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
class ResetPasswordController extends Controller
{
@ -16,6 +22,47 @@ class ResetPasswordController extends Controller
*/
public $redirectTo = '/';
/**
* @var bool
*/
protected $hasTwoFactor = false;
/**
* @var \Prologue\Alerts\AlertsMessageBag
*/
private $alerts;
/**
* @var \Illuminate\Contracts\Events\Dispatcher
*/
private $dispatcher;
/**
* @var \Illuminate\Contracts\Hashing\Hasher
*/
private $hasher;
/**
* @var \Pterodactyl\Contracts\Repository\UserRepositoryInterface
*/
private $userRepository;
/**
* ResetPasswordController constructor.
*
* @param \Prologue\Alerts\AlertsMessageBag $alerts
* @param \Illuminate\Contracts\Events\Dispatcher $dispatcher
* @param \Illuminate\Contracts\Hashing\Hasher $hasher
* @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $userRepository
*/
public function __construct(AlertsMessageBag $alerts, Dispatcher $dispatcher, Hasher $hasher, UserRepositoryInterface $userRepository)
{
$this->alerts = $alerts;
$this->dispatcher = $dispatcher;
$this->hasher = $hasher;
$this->userRepository = $userRepository;
}
/**
* Return the rules used when validating password reset.
*
@ -29,4 +76,49 @@ class ResetPasswordController extends Controller
'password' => 'required|confirmed|min:8',
];
}
/**
* Reset the given user's password. If the user has two-factor authentication enabled on their
* account do not automatically log them in. In those cases, send the user back to the login
* form with a note telling them their password was changed and to log back in.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword|\Pterodactyl\Models\User $user
* @param string $password
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
protected function resetPassword($user, $password)
{
$user = $this->userRepository->update($user->id, [
'password' => $this->hasher->make($password),
$user->getRememberTokenName() => Str::random(60),
]);
$this->dispatcher->dispatch(new PasswordReset($user));
// If the user is not using 2FA log them in, otherwise skip this step and force a
// fresh login where they'll be prompted to enter a token.
if (! $user->use_totp) {
$this->guard()->login($user);
}
$this->hasTwoFactor = $user->use_totp;
}
/**
* Get the response for a successful password reset.
*
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
protected function sendResetResponse($response)
{
if ($this->hasTwoFactor) {
$this->alerts->success('Your password was successfully updated. Please log in to continue.')->flash();
}
return redirect($this->hasTwoFactor ? route('auth.login') : $this->redirectPath())
->with('status', trans($response));
}
}