mirror of
				https://github.com/HackTricks-wiki/hacktricks.git
				synced 2025-10-10 18:36:50 +00:00 
			
		
		
		
	Merge pull request #1439 from HackTricks-wiki/update_ReDisclosure__New_technique_for_exploiting_Full-Te_20250925_184639
ReDisclosure New technique for exploiting Full-Text Search i...
This commit is contained in:
		
						commit
						5a81e0b2d5
					
				| @ -198,6 +198,55 @@ mysql> select @@version; | ||||
| mysql> select version(); | ||||
| ``` | ||||
| 
 | ||||
| ## MySQL Full-Text Search (FTS) BOOLEAN MODE operator abuse (WOR) | ||||
| 
 | ||||
| This is not a classic SQL injection. When developers pass user input into `MATCH(col) AGAINST('...' IN BOOLEAN MODE)`, MySQL executes a rich set of Boolean search operators inside the quoted string. Many WAF/SAST rules only focus on quote breaking and miss this surface. | ||||
| 
 | ||||
| Key points: | ||||
| - Operators are evaluated inside the quotes: `+` (must include), `-` (must not include), `*` (trailing wildcard), `"..."` (exact phrase), `()` (grouping), `<`/`>`/`~` (weights). See MySQL docs. | ||||
| - This allows presence/absence and prefix tests without breaking out of the string literal, e.g. `AGAINST('+admin*' IN BOOLEAN MODE)` to check for any term starting with `admin`. | ||||
| - Useful to build oracles such as “does any row contain a term with prefix X?” and to enumerate hidden strings via prefix expansion. | ||||
| 
 | ||||
| Example query built by the backend: | ||||
| 
 | ||||
| ```sql | ||||
| SELECT tid, firstpost | ||||
| FROM threads | ||||
| WHERE MATCH(subject) AGAINST('+jack*' IN BOOLEAN MODE); | ||||
| ``` | ||||
| 
 | ||||
| If the application returns different responses depending on whether the result set is empty (e.g., redirect vs. error message), that behavior becomes a Boolean oracle that can be used to enumerate private data such as hidden/deleted titles. | ||||
| 
 | ||||
| Sanitizer bypass patterns (generic): | ||||
| - Boundary-trim preserving wildcard: if the backend trims 1–2 trailing characters per word via a regex like `(\b.{1,2})(\s)|(\b.{1,2}$)`, submit `prefix*ZZ`. The cleaner trims the `ZZ` but leaves the `*`, so `prefix*` survives. | ||||
| - Early-break stripping: if the code strips operators per word but stops processing when it finds any token with length ≥ min length, send two tokens: the first is a junk token that meets the length threshold, the second carries the operator payload. For example: `&&&&& +jack*ZZ` → after cleaning: `+&&&&& +jack*`. | ||||
| 
 | ||||
| Payload template (URL-encoded): | ||||
| 
 | ||||
| ``` | ||||
| keywords=%26%26%26%26%26+%2B{FUZZ}*xD | ||||
| ``` | ||||
| 
 | ||||
| - `%26` is `&`, `%2B` is `+`. The trailing `xD` (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: | ||||
| 1) Start with `{FUZZ} = a…z,0…9` to find first-letter matches via `+a*`, `+b*`, … | ||||
| 2) For each positive prefix, branch: `a* → aa* / ab* / …`. Repeat to recover the whole string. | ||||
| 3) 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 MODE` or 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/Db2 `CONTAINS` also parse operators inside quoted arguments. | ||||
| 
 | ||||
| Notes: | ||||
| - Prepared statements do not protect against semantic abuse of `REGEXP` or search operators. An input like `.*` remains a permissive regex even inside a quoted `REGEXP '.*'`. Use allow-lists or explicit guards. | ||||
| 
 | ||||
| ## Other MYSQL injection guides | ||||
| 
 | ||||
| - [PayloadsAllTheThings – MySQL Injection cheatsheet](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md) | ||||
| @ -206,9 +255,10 @@ mysql> select version(); | ||||
| 
 | ||||
| - [PayloadsAllTheThings – MySQL Injection cheatsheet](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md) | ||||
| - [Pre-auth SQLi to RCE in Fortinet FortiWeb (watchTowr Labs)](https://labs.watchtowr.com/pre-auth-sql-injection-to-rce-fortinet-fortiweb-fabric-connector-cve-2025-25257/) | ||||
| - [MySQL Full-Text Search – Boolean mode](https://dev.mysql.com/doc/refman/8.4/en/fulltext-boolean.html) | ||||
| - [MySQL Full-Text Search – Overview](https://dev.mysql.com/doc/refman/8.4/en/fulltext-search.html) | ||||
| - [MySQL REGEXP documentation](https://dev.mysql.com/doc/refman/8.4/en/regexp.html) | ||||
| - [ReDisclosure: New technique for exploiting Full-Text Search in MySQL (myBB case study)](https://exploit.az/posts/wor/) | ||||
| 
 | ||||
| 
 | ||||
| {{#include ../../../banners/hacktricks-training.md}} | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user