New SQL Injection Concept (Comments, 9e999, MySQL Specific)
26 Feb. 2004
Currently all penetration testers efforts seem to be focused on "blind hacking". Penetration tester can get free access to SQL subsystem and execute any commands but not able to get any other result back than error messages (or even not them). There are many publications describing how to fingerprint databases in blind. This posting just adds one more way.
The information has been provided by Tonu Samuel.
The examples below use MySQL because it seems to be most used database on the web. Meanwhile similar techniques can apply to others. In every SQL there is a one "feature" that is unique to that product. MySQL allows usage of comments in SQL clauses: SELECT * FROM table /* foo */
In MySQL, there is a extension to it which allows to insert MySQL specific code in way: SELECT /*! SQL_NO_CACHE */ FROM table
Comments shown above are treated as comments in every database except MySQL. MySQL takes a look inside of comments and may change his behavior. For example, this gets executed only if MySQL is version 4.0.0 or higher: SELECT /*!40000 SQL_NO_CACHE */ FROM table
This can be extremely useful for penetration tester to find out database in use and his version in blind:
Just trying http://foo/web.php?table=38 - We get normal screen http://foo/web.php?table=38/*%20s*/ - We get normal screen http://foo/web.php?table=38/*!%20s*/ - We get a different screen because syntax error in comments - MySQL is in use http://foo/web.php?table=38/*!30000%20s*/ - We get a different screen, MySQL is at least 3.x.x http://foo/web.php?table=38/*!40000%20s*/ - We get a different screen, MySQL is at least 4.x.x http://foo/web.php?table=38/*!50000%20s*/ - We get normal screen, MySQL is below 5.x.x http://foo/web.php?table=38/*!40020%20s*/ - We get normal screen, MySQL is below 4.0.20 http://foo/web.php?table=38/*!40017%20s*/ - We get a different screen, MySQL is at least 4.0.17 http://foo/web.php?table=38/*!40018%20s*/ - We get normal screen, MySQL is below 4.0.18
We can conclude that MySQL running on site is 4.0.17.
This is useful information because then we may know which exploits/vulnerabilities to try next. In MySQL for example each series 3.x.x,4.x.x and 5.x.x have different functionality.
Another, independent idea. This works on most systems without change. Look at default behavior of MySQL database engine: mysql> select 9e0;
| 9e0 |
| 9 |
1 row in set (0.02 sec)
mysql> select 9e2;
| 9e2 |
| 900 |
1 row in set (0.00 sec)
Most language interpreters are trying to guess something about their input. This input gets validated against length and passed. So we can freely pass 9e9 to some database query in backend. PHP guys often suggest using functions like is_int($_GET['foo']). This doesn't block this method as it is still an int, and it is only 3 characters long. But it may take your database server down.
Tonu had nice penetration testing case when there was nearly impossible to get any error message from the system. Finally Tonu managed to send some 9e999 somewhere as input which leaded message similar "PHP timeout of 30 seconds in something.inc". Who works for penetration testing knows how important is any information about system internals. Tonu was able to download this INC file which leaded to data leak.