xBlubbs Website Exploit Fix

02/17/2020 06:53 Alexsh#1
So for the majority of the community out there using xBlubb's website and all of the scripts, there's an exploit that can be done using the login function. It's done by modifying the User-Agent header and then injecting code into the database.

I'm here to publicly release a fix to prevent anyone selling it and to ensure the community is safe. Not patching this exploit leaves you wide open to SQL Injection attacks.

There are two ways to patch this exploit.

1. Stop collecting the User-Agent data.

The proper way to do this would be to modify the LOG_LOGIN table and remove the "browser" field, then go into xinc_login and change the INSERT query to look like this:
PHP Code:
                    INSERT INTO WEBSITE_DBF.dbo.[LOG_LOGIN] (
                        [
account],
                        [
ip],
                        [
host],
                        [
timestamp]
                    ) 
VALUES (
                        \
'' $strPostAccount '\',
                        \'' 
$ServerIPAddr '\',
                        \'' 
gethostbyaddr($_SERVER['REMOTE_HOST']) . '\',
                        ' 
time() . 
2. Check the integrity of the data coming from User-Agent by running it through a filter and checking for key words like UPDATE, SHUTDOWN, DROP, INSERT, DELETE.

For my method, I used a function.

xinc_function.php
PHP Code:
function checkdata($data) {                  
        
$badchars = array("DROP""DELETE""TRUNCATE""TABLE""UPDATE""SELECT""INSERT");
        foreach (
$badchars as $key => $value
        {          
            if (
strpos(strtoupper($data), $value$offset 0) !== FALSE
            {
                
$detection $value;
            } 
            else
            {
                
$detection 0;
            }
        }      
        
        return 
$detection;                  
  } 
xinc_login.php Under
PHP Code:
            if(md5($_CONFIG['allg_svr_salt'].$strPostPassword) != [MENTION=311501]ODB[/MENTION]c_result($intValidateLoginInformation'password')) {
                
$strOutputErrorArray[] = $_LANG['error_wrong_password'];
            } 
Add this:
PHP Code:
            if(checkdata($_SERVER['HTTP_USER_AGENT']) !== 0){
                
$strOutputErrorArray[] = 'SQL INJECTION ATTEMPT!';
            } 
Enjoy! :)
02/17/2020 07:14 Burdenz2007#2
Thank you for the support for the FlyFF Community. You have my best respect. :handsdown:
02/17/2020 14:28 xTwiLightx#3
What about...

- use filter_var or filter_input:
Code:
$userAgent = $_SERVER['HTTP_USER_AGENT'];
$userAgent = filter_var($userAgent, FILTER_SANITIZE_SPECIAL_CHARS);
Code:
$userAgent = filter_input(INPUT_SERVER, 'HTTP_USER_AGENT', FILTER_SANITIZE_SPECIAL_CHARS);
- use prepared statements with PDO, mysqli or odbc_prepare and combine it with filter_ functions?
Code:
$qryLogLogin = 'INSERT INTO ' . $_CONFIG['db_databases']['web'] . '.dbo.LOG_LOGIN'
                . ' ([account], [ip], [host], [browser], [timestamp])'
                . ' VALUES (:account, :ip, :host, :browser, :logintime)';

$strPostAccount = filter_input(INPUT_POST, 'loginAccount', FILTER_SANITIZE_SPECIAL_CHARS);
$userAgent = filter_input(INPUT_SERVER, 'HTTP_USER_AGENT', FILTER_SANITIZE_SPECIAL_CHARS);

try {
                $stmt = $dbCon->prepare($qryLogLogin);
                $stmt->bindValue(':account', $strPostAccount);
                $stmt->bindValue(':ip', $ServerIPAddr);
                $stmt->bindValue(':host', gethostbyaddr($ServerIPAddr));
                $stmt->bindValue(':browser', $userAgent);
                $stmt->bindValue(':logintime', time(), PDO::PARAM_INT);
                $stmt->execute();
            } catch (\Exception $e) {
                error_log($e->getMessage());
                error_log($e->getTraceAsString());
            }
Nonetheless, great job sharing this exploit and a potential fix here.
02/17/2020 14:37 netHoxInc#4
Was an amusing thing to use xD

Also im not quite sure why u need to log the HTTP user agent at all anyways, removing it would be a simple enough fix in my eyes. xD
02/17/2020 15:46 Alexsh#5
Quote:
Originally Posted by xTwiLightx View Post
What about...

- use filter_var or filter_input:
Code:
$userAgent = $_SERVER['HTTP_USER_AGENT'];
$userAgent = filter_var($userAgent, FILTER_SANITIZE_SPECIAL_CHARS);
Code:
$userAgent = filter_input(INPUT_SERVER, 'HTTP_USER_AGENT', FILTER_SANITIZE_SPECIAL_CHARS);
- use prepared statements with PDO, mysqli or odbc_prepare and combine it with filter_ functions?
Code:
$qryLogLogin = 'INSERT INTO ' . $_CONFIG['db_databases']['web'] . '.dbo.LOG_LOGIN'
                . ' ([account], [ip], [host], [browser], [timestamp])'
                . ' VALUES (:account, :ip, :host, :browser, :logintime)';

$strPostAccount = filter_input(INPUT_POST, 'loginAccount', FILTER_SANITIZE_SPECIAL_CHARS);
$userAgent = filter_input(INPUT_SERVER, 'HTTP_USER_AGENT', FILTER_SANITIZE_SPECIAL_CHARS);

try {
                $stmt = $dbCon->prepare($qryLogLogin);
                $stmt->bindValue(':account', $strPostAccount);
                $stmt->bindValue(':ip', $ServerIPAddr);
                $stmt->bindValue(':host', gethostbyaddr($ServerIPAddr));
                $stmt->bindValue(':browser', $userAgent);
                $stmt->bindValue(':logintime', time(), PDO::PARAM_INT);
                $stmt->execute();
            } catch (\Exception $e) {
                error_log($e->getMessage());
                error_log($e->getTraceAsString());
            }
Nonetheless, great job sharing this exploit and a potential fix here.
Yeah, there's a bunch of ways to go about it. Preparing and binding works as well, but most people don't go that route. Thanks for the added input and contribution. :)