Skip to content

Commit 4910365

Browse files
committed
Fix h1 reports 93809 and 93813
Session Fixation ---------------- The HackerOne users kaviya and Kamini Singh have independendltly reported that Revive Adserver was vulnerable to session fixation, by allowing arbitrary session identifiers to be forced and at the same time by not invalidating the existing session upon a successful authentication. Under some circumstances, that could have been an opportunity for an attacker to steal an authenticated sessions. A CVE-ID has been requested, but not assigned yet. CWE: CWE-384 CVSSv2: 7.8 (AV:N/AC:M/Au:N/C:C/I:P/A:N)
1 parent 8479413 commit 4910365

File tree

6 files changed

+85
-20
lines changed

6 files changed

+85
-20
lines changed

Diff for: lib/OA/Auth.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ function login($redirectCallback = null)
8686
OA_Auth::restart($GLOBALS['strUsernameOrPasswordWrong']);
8787
}
8888

89+
// Regenerate session ID now
90+
phpAds_SessionRegenerateId();
91+
8992
return OA_Auth::getSessionData($doUser);
9093
}
9194

@@ -190,7 +193,7 @@ function getFakeSessionData()
190193
*/
191194
function restart($sMessage = '')
192195
{
193-
$_COOKIE['sessionID'] = phpAds_SessionStart();
196+
$_COOKIE['sessionID'] = phpAds_SessionRegenerateId();
194197
OA_Auth::displayLogin($sMessage, $_COOKIE['sessionID']);
195198
}
196199

Diff for: lib/OA/Upgrade/Login.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class OA_Upgrade_Login
2525
function checkLogin()
2626
{
2727
// Clean up session
28-
$GLOBALS['session'] = array();
28+
phpAds_clearSession();
2929

3030
// Detection needs to happen every time to make sure that database parameters are
3131
$oUpgrader = new OA_Upgrade();
@@ -93,6 +93,7 @@ function autoLogin()
9393
$doUser->joinAdd($doAUA);
9494
$doUser->find();
9595
if ($doUser->fetch()) {
96+
phpAds_SessionRegenerateId();
9697
phpAds_SessionDataRegister(OA_Auth::getSessionData($doUser));
9798
phpAds_SessionDataStore();
9899
}
@@ -106,6 +107,8 @@ function _checkLoginNew()
106107
$aCredentials = $oPlugin->_getCredentials(false);
107108

108109
if (!PEAR::isError($aCredentials)) {
110+
phpAds_SessionRegenerateId();
111+
109112
$doUser = $oPlugin->checkPassword($aCredentials['username'], $aCredentials['password']);
110113

111114
if ($doUser) {
@@ -140,6 +143,8 @@ function _checkLoginOld($tableName, $agencySupport)
140143
$aCredentials = $oPlugin->_getCredentials(false);
141144

142145
if (!PEAR::isError($aCredentials)) {
146+
phpAds_SessionRegenerateId();
147+
143148
if (strtolower($aPref['admin']) == strtolower($aCredentials['username']) &&
144149
$aPref['admin_pw'] == md5($aCredentials['password']))
145150
{

Diff for: lib/max/Dal/Admin/Session.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,10 @@ function storeSerializedSession($serialized_session_data, $session_id)
7676
if ($doSession) {
7777
$doSession->sessiondata = $serialized_session_data;
7878
$doSession->update();
79-
}
80-
else {
79+
} else {
8180
$doSession = OA_Dal::factoryDO('session');
82-
$doSession->sessionid = $session_id;
81+
// It's an md5, so 32 chars max
82+
$doSession->sessionid = substr($session_id, 0, 32);
8383
$doSession->sessiondata = $serialized_session_data;
8484
$doSession->insert();
8585
}

Diff for: www/admin/lib-sessions.inc.php

+68-13
Original file line numberDiff line numberDiff line change
@@ -30,28 +30,29 @@
3030
function phpAds_SessionDataFetch()
3131
{
3232
global $session;
33-
$dal = new MAX_Dal_Admin_Session();
3433

3534
// Guard clause: Can't fetch a session without an ID
36-
if (empty($_COOKIE['sessionID'])) {
35+
if (empty($_COOKIE['sessionID']) || !preg_match('#^[0-9a-f]{32}$#D', $_COOKIE['sessionID'])) {
3736
return;
3837
}
3938

39+
$dal = new MAX_Dal_Admin_Session();
4040
$serialized_session = $dal->getSerializedSession($_COOKIE['sessionID']);
4141

42-
// This is required because 'sessionID' cookie is set to new during logout.
43-
// According to comments in the file it is because some servers do not
44-
// support setting cookies during redirect.
45-
if (empty($serialized_session)) {
42+
// Return if the session was not found (expired or forged)
43+
if (!$serialized_session) {
4644
return;
4745
}
4846

4947
$loaded_session = unserialize($serialized_session);
50-
if (!$loaded_session) {
51-
// XXX: Consider raising an error
48+
49+
// Or if it can't be unserialized and/or is not a session we started
50+
if (empty($loaded_session['__authentic__'])) {
5251
return;
5352
}
54-
$session = $loaded_session;
53+
54+
$session = $loaded_session;
55+
5556
$dal->refreshSession($_COOKIE['sessionID']);
5657
}
5758

@@ -75,21 +76,75 @@ function phpAds_SessionSetAdminCookie($name, $value)
7576
}
7677

7778
/*-------------------------------------------------------*/
78-
/* Create a new sessionid */
79+
/* Start a new session */
7980
/*-------------------------------------------------------*/
8081

8182
function phpAds_SessionStart()
8283
{
8384
global $session;
85+
8486
if (empty($_COOKIE['sessionID'])) {
85-
$session = array();
86-
$_COOKIE['sessionID'] = md5(uniqid('phpads', 1));
87+
phpAds_clearSession();
88+
89+
$sessionId = phpAds_SessionGenerateId();
8790

88-
phpAds_SessionSetAdminCookie('sessionID', $_COOKIE['sessionID']);
91+
$dal = new MAX_Dal_Admin_Session();
92+
$dal->storeSerializedSession(serialize($session), $sessionId);
8993
}
94+
9095
return $_COOKIE['sessionID'];
9196
}
9297

98+
/*-------------------------------------------------------*/
99+
/* Generate a sessionid */
100+
/*-------------------------------------------------------*/
101+
102+
function phpAds_SessionGenerateId()
103+
{
104+
$_COOKIE['sessionID'] = md5(uniqid('phpads', 1));
105+
106+
phpAds_SessionSetAdminCookie('sessionID', $_COOKIE['sessionID']);
107+
108+
return $_COOKIE['sessionID'];
109+
}
110+
111+
/*-------------------------------------------------------*/
112+
/* Re-generate the sessionid */
113+
/*-------------------------------------------------------*/
114+
115+
function phpAds_SessionRegenerateId()
116+
{
117+
global $session;
118+
119+
$dal = new MAX_Dal_Admin_Session();
120+
121+
if (!empty($_COOKIE['sessionID'])) {
122+
$dal->deleteSession($_COOKIE['sessionID']);
123+
}
124+
125+
if (!empty($session['__authentic__'])) {
126+
$sessionId = phpAds_SessionGenerateId();
127+
$dal->storeSerializedSession(serialize($session), $sessionId);
128+
129+
return $sessionId;
130+
}
131+
132+
unset($_COOKIE['sessionID']);
133+
134+
return phpAds_SessionStart();
135+
}
136+
137+
/*-------------------------------------------------------*/
138+
/* Clear the session and mark it as authentic */
139+
/*-------------------------------------------------------*/
140+
141+
function phpAds_clearSession()
142+
{
143+
$GLOBALS['session'] = array(
144+
'__authentic__' => true,
145+
);
146+
}
147+
93148
/*-------------------------------------------------------*/
94149
/* Register the data in the session array */
95150
/*-------------------------------------------------------*/

Diff for: www/api/v1/xmlrpc/LogonServiceImpl.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ function logon($username, $password, &$sessionId)
9393

9494
$_POST['login'] = 'Login';
9595

96-
$_COOKIE['sessionID'] = uniqid('phpads', 1);
96+
unset($_COOKIE['sessionID']);
97+
phpAds_SessionStart();
9798
$_POST['phpAds_cookiecheck'] = $_COOKIE['sessionID'];
9899

99100
$this->preInitSession();

Diff for: www/api/v2/xmlrpc/LogonServiceImpl.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ function logon($username, $password, &$sessionId)
9393

9494
$_POST['login'] = 'Login';
9595

96-
$_COOKIE['sessionID'] = uniqid('phpads', 1);
96+
unset($_COOKIE['sessionID']);
97+
phpAds_SessionStart();
9798
$_POST['phpAds_cookiecheck'] = $_COOKIE['sessionID'];
9899

99100
$this->preInitSession();

0 commit comments

Comments
 (0)