3

I know you need prepared statements and such to avoid SQL injection, and I've seen that there are different questions about exploits for SELECT, INSERT, UPDATE injectable queries.

But I couldn't come up with an exploit sample for USE statement. Suppose I have an injectable single statement that looks like this:

USE `data_from_attacker`; 

What data could the attacker use if they can put anything in place of the data_from_attacker, considering I'm looking for an exploit example that is not just selecting a DB (ie: selecting information_schema or mysql DB seems harmless, as the next queries won't work because tables won't exist; and selecting a DB that do not exists seems also harmless).

Also, consider that mysql will only interpret the 1st query, so attacker cannot inject:

mysql`; SELECT * FROM `users 

Can you find such exploit for MySQL? The USE syntax seems very "poor" for such injection...

    2 Answers 2

    4

    Quote Xenos
    Can you find such exploit for MySQL? The USE syntax seems very "poor" for such injection

    Lets track down how USE works in MySQL and which files MySQL in the source code needs to access.

    --- **Query #1** SET PROFILING = 1; There are no results to be displayed. --- **Query #2** USE test; There are no results to be displayed. --- **Query #3** SHOW PROFILES; | Query_ID | Duration | Query | | -------- | ---------- | -------- | | 1 | 0.00006425 | USE test | --- **Query #4** SHOW PROFILE ALL FOR QUERY 1; | Status | Duration | CPU_user | CPU_system | Context_voluntary | Context_involuntary | Block_ops_in | Block_ops_out | Messages_sent | Messages_received | Page_faults_major | Page_faults_minor | Swaps | Source_function | Source_file | Source_line | | -------------- | -------- | -------- | ---------- | ----------------- | ------------------- | ------------ | ------------- | ------------- | ----------------- | ----------------- | ----------------- | ----- | --------------------- | ------------ | ----------- | | starting | 0.000038 | 0.000019 | 0.000012 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | | | | query end | 0.000003 | 0.000002 | 0.000001 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | mysql_execute_command | sql_parse.cc | 4310 | | closing tables | 0.000003 | 0.000001 | 0.000001 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | mysql_execute_command | sql_parse.cc | 4356 | | freeing items | 0.000009 | 0.000006 | 0.000003 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | mysql_parse | sql_parse.cc | 4968 | | cleaning up | 0.000012 | 0.000007 | 0.000005 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | dispatch_command | sql_parse.cc | 1978 | --- 

    see demo

    MySQL basic lexer works with yacc so we check file sql_yacc.yy first.
    Below is the USE keyword defined.

    /* change database */ use: USE_SYM ident { LEX *lex=Lex; lex->sql_command=SQLCOM_CHANGE_DB; lex->select_lex->db= $2.str; } ; 

    When we check sql_parse.cc and within the function mysql_execute_command() we find

    case SQLCOM_CHANGE_DB: { const LEX_CSTRING db_str = {select_lex->db, strlen(select_lex->db)}; if (!mysql_change_db(thd, db_str, false)) my_ok(thd); break; } 

    To answer the question.
    No i could not find a possible exploit as it is very clear in the source code the <database> part in the USE <database> statement expects a "string" and does not parse and or execute a SQL statement futher.

    With string i mean database_name in the format of USE database_name or with backticks.

    2
    • 1
      Excellent, that's the type of answer I was looking for : ) I've digged even a bit further in the mysql_change_db code and it's sub-called functions, but I also saw nothing attackable there (even tho I'm not expert in MySQL source code). Thanks again ! :)
      – Xenos
      CommentedAug 7, 2019 at 8:36
    • @Xenos in some cases character encoding mixing injections might work if the client not explicitly uses a connection charset or the server does not enforce the client to use one but you will also not gain much from it... Also as C/C++ strings are NULL terminated lets test that case aswell, well also no gain here..CommentedAug 7, 2019 at 14:01
    2

    If any of the elements of the schema in your database have names in common with other databases on the SQL engine, it might be possible to cross queries to produce undesirable results.

    Let’s say the expected database has a name of ‘PROD _DB’, but your developers have another database on the same SQL server named ‘TEST_DB’. They use the test database for testing the app, so it has the identical schema, but is filled with junk data that is used only for testing and nobody cares about; things like UserName == ‘test1’, PassWord == ‘abc’, AdminFlag == 1. By changing the USE statement at will, from PROD_DB to TEST_DB and back again, they could authenticate using the ‘test1’ credentials and set their status to Admin, then flip back and use their admin status to do whatever they want inside your production application.

    2
    • Indeed, the prod/test example is neat. I'm still less impressed than other usual DML injection. Do you have any other idea how to read or alter data in the tables through that single injection (without relying on other queries from the normal process flow being fired on the "wrong" database)?
      – Xenos
      CommentedAug 1, 2019 at 15:55
    • Certainly it’s not as generically useful as an exploit that lets you break out of the existing SQL. If I was attacking the system, I’d be trying to find a way to escape the restrictions preventing that. Regardless, it probably should be fixed now, even if there isn’t a visible exploit. Consider that in the future someone else may migrate the database to a prod/test type of configuration, at which point it would become vulnerable. Or maybe they migrate it to Postgres, which could be vulnerable. Too many possibilities for the future.CommentedAug 1, 2019 at 20:54

    You must log in to answer this question.

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.