Skip to content

Commit

Permalink
Fix insecure persistent login token
Browse files Browse the repository at this point in the history
Signed-off-by: 4n4nk3 <47717886+4n4nk3@users.noreply.github.com>
  • Loading branch information
4n4nk3 authored and 4n4nk3 committed Jan 22, 2023
1 parent 8a139d6 commit d31cf9d
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 7 deletions.
8 changes: 7 additions & 1 deletion logout.php
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
<?php

require_once 'scripts/pi-hole/php/persistentlogin_token.php';

// If the user wants to log out, we free all session variables currently registered
// and delete any persistent cookie.
session_start();
session_unset();
setcookie('persistentlogin', '', 1);

if (isset($_COOKIE['persistentlogin'])) {
logoutPersistentLoginToken($_COOKIE['persistentlogin']);
}

header('Location: login.php');
exit;
14 changes: 8 additions & 6 deletions scripts/pi-hole/php/password.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

require_once 'func.php';
require_once 'persistentlogin_token.php';

// Start a new PHP session (or continue an existing one)
start_php_session();
Expand All @@ -29,11 +30,8 @@ function verifyPassword($pwhash, $use_api = false)
if (strlen($pwhash) > 0) {
// Check for and authorize from persistent cookie
if (isset($_COOKIE['persistentlogin'])) {
if (hash_equals($pwhash, $_COOKIE['persistentlogin'])) {
if (checkValidityPersistentLoginToken($_COOKIE['persistentlogin'])) {
$_SESSION['auth'] = true;
// Refresh cookie with new expiry
// setcookie( $name, $value, $expire, $path, $domain, $secure, $httponly )
setcookie('persistentlogin', $pwhash, time() + 60 * 60 * 24 * 7, null, null, null, true);
} else {
// Invalid cookie
$_SESSION['auth'] = false;
Expand Down Expand Up @@ -61,8 +59,12 @@ function verifyPassword($pwhash, $use_api = false)

// Set persistent cookie if selected
if (isset($_POST['persistentlogin'])) {
// setcookie( $name, $value, $expire, $path, $domain, $secure, $httponly )
setcookie('persistentlogin', $pwhash, time() + 60 * 60 * 24 * 7, null, null, null, true);
// Generate cookie with new expiry
$token = genPersistentLoginToken();
$time = time() + 60 * 60 * 24 * 7; // 7 days
writePersistentLoginToken($token, $time);
// setcookie($name, $value, $expire, $path, $domain, $secure, $httponly)
setcookie('persistentlogin', $token, $time, null, null, null, true);
}

$_SESSION['auth'] = true;
Expand Down
83 changes: 83 additions & 0 deletions scripts/pi-hole/php/persistentlogin_token.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php
/* Pi-hole: A black hole for Internet advertisements
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license.
*/


function genPersistentLoginToken()
{
return bin2hex(openssl_random_pseudo_bytes(16));
}

function checkSafetyPersistentLoginToken($token)
{
// return true only if the token is and alphanumeric string of 32 chars, else return false
if (ctype_alnum($token) and strlen($token) == 32) {
return true;
}
error_log("Security alert: presented \"persistentlogin\" token did not pass safety check!", 0);
return false;
}

function getPathPersistentLoginToken($token)
{
// safely return the path of the persistentlogin token file, if token is not safe return false
$session_path = session_save_path();

if ($session_path and checkSafetyPersistentLoginToken($token)) {
$token_file = $session_path . '/ph_plt_' . $token . '.txt';
return $token_file;
}
return false;
}

function checkValidityPersistentLoginToken($token)
{
// return true if persistentlogin token is safe, valid and not expired
$token_file = getPathPersistentLoginToken($token);

if ($token_file and file_exists($token_file) and is_readable($token_file)) {
$t_file = fopen($token_file, "r");
if ($t_file) {
$time = fread($t_file, filesize($token_file));
fclose($t_file);
// make sure that token is not expired
if ($time && intval($time) >= time()) {
return true;
}
}
}
return false;
}

function writePersistentLoginToken($token, $time)
{
$token_file = getPathPersistentLoginToken($token);

if ($token_file and !file_exists($token_file)) {
$t_file = fopen($token_file, "w");
if ($t_file) {
// make sure persistent login token file is not readable by other users
chmod($token_file, 0600);

fwrite($t_file, $time);
fclose($t_file);
return true;
}
}
return false;
}

function logoutPersistentLoginToken($token)
{
setcookie('persistentlogin', '', 1);

$token_file = getPathPersistentLoginToken($token);
if ($token_file and file_exists($token_file) and is_writable($token_file)) {
unlink($token_file);
}
}

1 comment on commit d31cf9d

@pralor-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit has been mentioned on Pi-hole Userspace. There might be relevant details there:

https://discourse.pi-hole.net/t/pi-hole-web-v5-18-2-and-core-v5-15-1-released/60695/1

Please sign in to comment.