|
Vulnerability Postaci Affected Postaci Description Berk Demir found following. 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. 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. 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] 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... Solution Will be fixed.