New Benchmark alternative or effective blind SQL-injection

EDB-ID:

13101

CVE:

N/A

Author:

Elekt

Type:

papers

Platform:

Multiple

Published:

2007-04-12

=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-
=-=-=-=-=- New Benchmark alternative or effective blind SQL-injection =-=-=-=-=-=-
=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-

Title: New Benchmark alternative or effective blind SQL-injection
Author: Elekt 
Translate: NeMiNeM
Website: www.antichat.ru
Email: elektronic@antichat.ru
IRC: irc.antichat.ru:7771 #antichat

Original article: http://forum.antichat.ru/thread35207.html
Translate article: http://forum.antichat.ru/thread37726.html

=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-

In this article we describe a new and universal way to work without 
benchmark in blind sql-inj in so-called "unusable" bugged queries like 
UPDATE, DELETE, REPLACE, UPDATE etc. 

Using this new alternative method we can exactly get required 
information from database, not just simply modify entries. 

Here we describe all features of well-known methods of sql-inj attacks, 
which are used towards above-mentioned operators. 

We'll also more comprehensively study the aspects of practical usage of 
BENCHMARK during exploits writing. 

Note: we provide examples for mysql in this article, however the 
description will practically work on all databases (considering the 
queries syntax of course). 

=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-
-[1]- INTRO =-=-=-=-=-=-=-=-==-=-=-=-=-=-
=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-

Programmers become cleverer, there are less and less bugs in 
select-queries, but the problem of injections in 
INSERT,UPDATE,REPLACE,DELETE and others remains important. 

I often see such questions in the forums: "...please, help what to do if 
I see - 'mysql error INSERT INTO table_name VALUES(...'" When a newbie 
sees such an error he'll probably close his browser and the amateur will 
post the same 100th question in the forums. He won't probably receive an 
answer or the answers will be too difficult for him, because the 
promotion of blind sql, considering the ammount of queries, demands the 
implementation of automatization, i.e. the ability to write exploits. 

The methods have been known long ago and described in details by 
1dt.w0lf. on November 14, 2004 and only lazy-bones didn't read it - 
http://www.securitylab.ru/contest/212099.php Our article can be a 
continuation to it. 


=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-
-[2]- INSERT and others =-=-=-=-=-=-=-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-

(known attacks on instert/update etc are described, it can be omitted if you know this)

What's the benefit?


-[A]- 
 (general case)Data modification without a possibility to watch results
Ideal case - sql-inj in table name. Here is possible everything:
Êîä:
INSERT INTO [SQL] VALUES ('stat','stat2');

New user adding:
INSERT INTO [mysql.user (user, host, password) VALUES ('newadmin', 'localhost', PASSWORD('passwd'))/*] VALUES ('stat');


-[B]-
 DoS-attack 
But similar sql-injections exist in most cases in column name and it 
doesn't allow us to change the upgradable table to the one we need. 

INSERT INTO table VALUES ('stat','[SQL]');


So besides database breaking\littering\dos we won't get anything with data modifying.
SQL: 
INSERT INTO table VALUES ('stat','bla['),('test', 'demo]');

DoS: 
INSERT INTO table VALUES ('stat','bla[' and BENCHMARK(10000000,BENCHMARK(10000000,md5(now())))   ) /*]');


-[C]-
 Queries separating in MSSQL, PostgreSql, Oracle
But what does combine these three popular DBMS?
Such wonderful thing as queries separating support, using semicolon, carriage return etc.
Thus we can add absolutely ANY sql-query, using ";","%0A","%0D" to separate it from the main. 
What useful can we add? - Search in google for concrete db.


-[D]-
 Data modification with a possibility to watch results.
It's not important here where the injection is - in table or in column 
name. We can see the result of query, though marginally. So it's not a 
problem to make an attack - purely technical details of result 
clarification. Example: let web-application OPENLY conduct the 
attendance statistics and there is a vulnerability in a column with 
User-Agent. Then, the result of sql-inj realization will be the 
attendance statistics output on a page. 


-[E]-
 BENCHMARK use
We use BENCHMARK, which helps us to determine the result of query 
execution depending on the server response time. This query will be 
positive for if and server response will come at once. 

INSERT INTO table VALUES ('stat','1' and 1=if(ascii(lower(substring((select users from mysql.user limit 1),1,1)))>=1,1,benchmark(999999,md5(now()))) )/* ,'stat2');


And this one is negative and a lot of time will pass for BENCHMARK execution, thus we'll not get the server's response at once: 
INSERT INTO table VALUES ('stat','1' and 1=if(ascii(lower(substring((select users from mysql.user limit 1),1,1)))>=254,1,benchmark(999999,md5(now()))) )/* ,'stat2');


It's obvious that instead of INSERT we can put any other operator, 
including SELECT, because there are also some complicated cases of 
injections in it. 


=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-
-[3]- Bencmark for hackers =-=-=-=-=-=-=-
=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-
(benchmark operation features, it can be omitted if you know this) 

The use of BENCHMARK is like a moving to another dimension. From 
received information difference measuring to the measuring of query 
execution time difference. 

If anyone has any doubts if exploits for BENCHMARK are written, please, 
look through the bugtraqs and make sure in the opposite - there are some 
exploits really. 

BENCHMARK exploits realization is more complicated than simple 
character-oriented bruteforce. 

Benchmark features: 

-[A]- perhaps the most important detail is that benchmark creates a 
serious load on server's processor. And this load lasts during the whole 
time of exploit working. The administator may not look through the 
access\error logs, but he could be quite interested why the server is 
lagging and in top->P "mysqld" takes the first place... 

-[B]- action period of exploit is bigger depending on the record length 
we want to get. (more length = more action period) In my practice I 
needed more than an hour for 32-symbols hash searching. Sometimes more 
hours - it depends, the conditions are listed below. 

-[C]- A hacker and a server will need a wide and reliable channel. These 
things are important for bruteforcing quality and stability. I don't say 
that everything will fail if you use dial-up connection, but there will 
be much more lags, especially if you decide to save time and choose too 
small parameter. 

-[D]- performance measurement parameter, i.e. the ammount of iterations, 
in our example - 999999 benchmark(999999,md5(user()) From my first-hand 
experience, since 1dt.w0lf''s article this number has changed together 
with the growth of performance of modern servers. It's recommended to 
make self-tuning of this parameter for universality, trying to get the 
acceptable response time. 

-[E]- and accordingly, having found the number in benchmark we must set 
the response timeout. This will be arithmetic mean value from the time 
of true\false execution query. 

-[F]- Note: while making an exploit take into account that according to 
the statistics the number of false queries is bigger than a number of 
true, that means you should set benchmark delay in the way it works when 
the response is correct. This way: if( ?, true, false ) 1 = if( 1=1 , 
benchmark(999999,md5(user()), 1 ) 

Thus we save our time and reduce the load on the server. 

Don't forget that server needs rest after each benchmark, to recover so 
to say. Otherwise the next query may have an unexpectable execution time 
and will give us wrong data. Many people forget about this small detail, 
because they either test locally or don't think at all, releasing their 
code without former testing. I was really surprised and didn't know why 
during the bruteforce the first symbol was correct, but then I got 
garbage - the server was just overload with benchmark. It's recommended 
to set the delay time 1-1,5 more than benchmark execution time. Yes, it 
will essentially slow down bruteforce but the effect will be better. 

If we look at the code we can easily modify 1dt.w0lf's 
character-oriented bruteforcer, taking into account benchmark. We need.. 

-[A]-
 change sql according to benchmark
$http_query = $path."?Cat=&page=1&like=".$username."' AND 1=if(ascii(substring(CONCAT(U_LoginName,CHAR(58),U  _Password),".$s_num.",1))".$ccheck.",benchmark(999999,md5(user()),1)/*";

-[B]-
 timeout
But sub check($) should return the result depending on whether the server has given the response in time or not.
Êîä:
$mcb_reguest = LWP::UserAgent->new(timeout=>$timeout) or die;

-[C]-
 sleep()
After each false query let's give N seconds rest to the server. Let it recover. 

That's it.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-
-[4]- Benchmark alternative -=-=-=-=-=-=-
=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-
 
Here is, in fact, the most delicious thing!

Dealing with benchmark I wished to find a substitution to this 
troublemaking, but the only method. And I've found it! 

Actually the difference of output data and time aren't the only factors. 

Let's look at the beginning again and remember how each sql-inj starts. 
Certainly from the quotation mark in request! ... and error message of 
course. But let's think logically - we put quotation mark, mysql checks 
our query, finds a mistake in it and tells us. 

Follow my thought: mysql first checks if it's correct, then either makes 
a query and shows a result or an error message. 

And now let's think if there is another way. Certainly, maybe that's 
just the point. There may be such case when the query will successfully 
pass verification, execute,.. but in result we'll get an error message. 

So our task is simply to PROVOKE such query + we should join parameteres 
in our request in the way we are be able to manipulate with a result of 
query and get a useful data. 

Here is a task: Query failure frustration and as a result - intentional 
error call which will help to distinguish true\false query. 

I realized it and began to remember different db errors. 

First, I tried to wreck the request with a help of IF, trying to put 
false table\column\datatype names: 

select if(1=1,null,blaaaah); 

But damn mysql is clever and checks datatype before execution. So it has 
failed. "You have an error in your SQL syntax" 

An attempt to change not column but table didn't work out as well. 

select null from if(1=1,users,blaaaah); 

By the way, the algorithm of query parsing in mysql is probably 
expecting the name of a table to be a constant and here it's obviously 
not a constant. It checks the existance of a column in already known 
table and if the table is not defined, e.g. I specify it through if, 
mysql will just send me away. 

I didn't check verification principle in other databases, so maybe such 
simple but universal tricks will work out there. 

What other mistakes can occur during the query execution? The most 
popular after "You have an error in your SQL syntax" is perhaps "The 
used SELECT statements have a different number of columns". But here 
verification also passes before executing. 

"Operand should contain 1 column(s)" - fails because of the same reason. 
"warning: mysql_fetch_array..." - it may be, but php-error is specific 
according to the engine. 

.. the next thing in my errors' chart is "Subquery returns more than 1 
row"... Yes yes, that ubiquitous limit! 

Here is what we need! MySQL checks data correctness, but can't check the 
number of returned responses, haven't made a response itself. 

The question is how to formulate a query to be sure to get such error? 

You'll need to provoke two conditions: when you are 100% sure that 
you'll get an error and 100% sure that there won't be any errors. 

Let's say we know beforehand table and column names in vulnerable 
application. Let the password hash with md5. Then the length of any 
password = 32 symbols. ID and login length will probably be shorter, 
won't it? length(id)=(1-5..) and length(password)=(32) Then our exploit 
will be like this: 


false:

...123' and 1=(select null from users where length(if(ascii(substring((select password from users where uid=1),1,1))>254,password,uid))>5)/* 


First password symbol is probably smaller than ascii(254).. It means if 
will return length(id)>5 and so there are not so many users (though we 
can set a bigger number), SELECT will return NULL. In the result we 
won't see anything as if there is no injection at all. 


true:

...123' and 1=(select null from users where length(if(ascii(substring((select password from users where uid=1),1,1))>1,password,uid))>5)/*


As a first password symbol is probably bigger than ascii(1), the condition is true.
So if will return length(password)>5 which will cause the N results output in SELECT query.
But in condition only one result 1=(*) can be compared... which will provoke "Subquery returns more than 1 row" !!!

It's so simple, isn't it? =) 

I'm sure that more similar mistakes, shown right after query execution, 
can be found. 

"more than 1 row" features: 

1) the main: the standard speed of characters bruteforce with a full 
benchmark substitution, time saved and no server load. 

2) At the cost of this performance - a lot of errors in mysql logs, 
which can attract administrator's attention. 

3)The only thing you should know is some data, like table and column 
names in order to provoke "more than 1 row" error. 

Maybe you'll find more perfect and universal way than mine! Good luck! 


=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-
-[5]- UNIVERSAL "more than 1 row"  EXPLOIT -=-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-

My friend podkashey proposed universal version exploits:

EXPLOIT:

true: 1=if(ascii(substring((select users from mysql.user limit 1),1,1))>1,1,(select 1 union select 5))
false: 1=if(ascii(substring((select users from mysql.user limit 1),1,1))>254,1,(select 1 union select 5))

Match: "Subquery returns more than 1 row"

INSERT INTO table VALUES ('stat','bla[' and 1=if(ascii(substring((select users from mysql.user limit 1),1,1))>1,1,(select 1 union select 5))   ) /*]');


=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-[6]- Mybb <= 1.2.2 (CLIENT_IP) Remote SQL Injecton Exploit  EXPLOIT -=-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Date: 23.01.2007

backup: http://www.milw0rm.com/exploits/3719

Enjoy!

=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-
-[the end]=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-
=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-
Translation by NeMiNeM - 
Please, feel free to show and correct my mistakes in the translation. No flame please. 

Thank you.

(c) for www.antichat.ru
=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-

# milw0rm.com [2007-04-12]