CVE-2016-9125 (PHP, published 2017-03-28T02:59Z)
Description: value: Revive Adserver before 3.2.3 suffers from 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 session.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-384 \u2014 Session Fixation
Authenticating a user, or otherwise establishing a new user session, without invalidating any existing session identifier gives an attacker the opportunity to steal authenticated sessions.
Repository: https://github.com/revive-adserver/revive-adserver
Files changed:
lib/OA/Auth.php
lib/OA/Upgrade/Login.php
lib/max/Dal/Admin/Session.php
www/admin/lib-sessions.inc.php
www/api/v1/xmlrpc/LogonServiceImpl.php
www/api/v2/xmlrpc/LogonServiceImpl.php
Commit message: 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)


Vulnerable code:
        $_COOKIE['sessionID'] = phpAds_SessionStart();
        $GLOBALS['session'] = array();
        }
        else {
            $doSession->sessionid = $session_id;
    $dal = new MAX_Dal_Admin_Session();
	if (empty($_COOKIE['sessionID'])) {
    // This is required because 'sessionID' cookie is set to new during logout.
    // According to comments in the file it is because some servers do not
    // support setting cookies during redirect.
    if (empty($serialized_session)) {
	if (!$loaded_session) {
        // XXX: Consider raising an error
	$session = $loaded_session;
/* Create a new sessionid                                */
		$session = array();
		$_COOKIE['sessionID'] = md5(uniqid('phpads', 1));
        phpAds_SessionSetAdminCookie('sessionID', $_COOKIE['sessionID']);
        $_COOKIE['sessionID'] = uniqid('phpads', 1);
        $_COOKIE['sessionID'] = uniqid('phpads', 1);

Fixed code:
            // Regenerate session ID now
            phpAds_SessionRegenerateId();

        $_COOKIE['sessionID'] = phpAds_SessionRegenerateId();
        phpAds_clearSession();
                phpAds_SessionRegenerateId();
            phpAds_SessionRegenerateId();

                    phpAds_SessionRegenerateId();

        } else {
            // It's an md5, so 32 chars max
            $doSession->sessionid = substr($session_id, 0, 32);
    if (empty($_COOKIE['sessionID']) || !preg_match('#^[0-9a-f]{32}$#D', $_COOKIE['sessionID'])) {
    $dal = new MAX_Dal_Admin_Session();
    // Return if the session was not found (expired or forged)
    if (!$serialized_session) {

    // Or if it can't be unserialized and/or is not a session we started
    if (empty($loaded_session['__authentic__'])) {

    $session = $loaded_session;

/* Start a new session                                   */

		phpAds_clearSession();

        $sessionId = phpAds_SessionGenerateId();
        $dal = new MAX_Dal_Admin_Session();
        $dal->storeSerializedSession(serialize($session), $sessionId);

/*-------------------------------------------------------*/
/* Generate a sessionid                                  */
/*-------------------------------------------------------*/

function phpAds_SessionGenerateId()
{
    $_COOKIE['sessionID'] = md5(uniqid('phpads', 1));

    phpAds_SessionSetAdminCookie('sessionID', $_COOKIE['sessionID']);

    return $_COOKIE['sessionID'];
}

/*-------------------------------------------------------*/
/* Re-generate the sessionid                             */
/*-------------------------------------------------------*/

function phpAds_SessionRegenerateId()
{
    global $session;

    $dal = new MAX_Dal_Admin_Session();

    if (!empty($_COOKIE['sessionID'])) {
        $dal->deleteSession($_COOKIE['sessionID']);
    }

    if (!empty($session['__authentic__'])) {
        $sessionId = phpAds_SessionGenerateId();
        $dal->storeSerializedSession(serialize($session), $sessionId);

        return $sessionId;
    }

    unset($_COOKIE['sessionID']);

    return phpAds_SessionStart();
}

/*-------------------------------------------------------*/
/* Clear the session and mark it as authentic            */
/*-------------------------------------------------------*/

function phpAds_clearSession()
{
    $GLOBALS['session'] = array(
        '__authentic__' => true,
    );
}

        unset($_COOKIE['sessionID']);
        phpAds_SessionStart();
        unset($_COOKIE['sessionID']);
        phpAds_SessionStart();