-
Notifications
You must be signed in to change notification settings - Fork 439
Strategy
💉jSQL is checking for the slowest to the fastest strategy in order to identify the best usable and to get rows efficiently.
The slowest strategy gets a single character bit-by-bit with 7 requests, the fastest strategy gets large chunks of text with a single query.
The simplest strategy shows the rows directly in the source page, the worst usable strategy does not even display anything.
Note
Create an issue to share additional strategies you know.
Tip
Switch to any confirmed strategy from the menu in the address bar, and compare the process behavior in the logs.
The following pseudo-code describes the extraction methods from the simplest to the most convoluted.
Union-based is the standard strategy that extracts the most chars with the least amount of queries.
Response from the target contains directly the SQL result so the process is really fast.
select row then show row
↘️ ~100k chars in 1 requestStrategy is basically identical and as efficient as Union, though Stack feature is not proposed by all engines thus less frequently encountered.
select row then show row
↘️ ~100k chars in 1 requestDatabase engines may contain buggy syntax processor which can be triggered by a specific forged SQL query. The result appears directly in the error message returned by the database, however with a size reduced significantly.
Error strategy gets the SQL results directly in the response so it's still really efficient, particularly useful when Union strategy is not working, even for query whose purpose is not to return any result like INSERT, UPDATE and DELETE.
select row then show row in internal error message
↘️ ~100 chars in 1 requestYou may not get the result directly in the response for various reasons, nevertheless the target may still answer back to your query and display a specific given text for a specific query.
It means you can query the database and confirm or infirm any statement and receive the answer Yes or No depending on the text in the response.
Given that each letter can be translated into its ASCII integer code, which in turn can be split into its binary components :
char:'a' ➡️ ascii:97 ➡️ bin:1100001
Then it means you can query the entire results bit-by-bit and char-by-char, even when the target does not return anything directly. It's significantly slower than Union or Error, though also faster than Blind bin as every bits can be fetched in parallel.
if Nth bit of ascii char X in the row is 1
then 🟢 show page A
else 🔴 show page B
↘️ Nth bit of ascii(X in the row) from 1 to 7 is 🟢 or 🔴 ?
➡️ pages:🟢;🟢;🔴;🔴;🔴;🔴;🟢 ➡️ bin:1100001 ➡️ ascii:97 ➡️ char:'a' in 7 requestsAs any letter can be translated into its ASCII integer code from a range between 32 and 127, you can apply algorithm binary search instead of Blind bit for example when database does not provide bitwise feature.
You check that char is up or below the mid range boundary, then continue until the mid boundary is reduced to its minimum and finally identify the char :
char:'a' ➡️ ascii:97 ➡️ bin search 97 in range 32 and 127 ?
32> 🟢mid>=79? >127 ➡️ 79> 🔴mid>=103? >127 ➡️ ... ➡️ 97> 🟢mid>=97? >97
So you query char-by-char but you need to wait for each boundary checks in sequence as it prevents parallel execution.
if char X in range between low and high boundaries
then 🟢 show page A
else 🔴 show page B
↘️ ascii(X in the row) between low and high boundaries is 🟢 or 🔴 ?
➡️ pages:🟢➡️🔴➡️🟢➡️... ➡️ ascii:97 ➡️ char:'a' in 7 requestsWhen the target does not even return anything in the page, no SQL result, no specific text related to the query, you can still create statement confirmation for Yes or No with the delay required by the target to answer.
Like Blind the entire results can be built either bit-by-bit or by mid boundary. And it's also even slower than Blind and depends strongly on the network quality and on the target reliability, consequently you may get corrupted chars as the loading time is not strictly reliable.
if Nth bit of ascii char X in the row is 1
then 🟢 sleep 5s
else 🔴 no sleepif char X in range between low and high boundaries
then 🟢 sleep 5s
else 🔴 no sleepBitwise representation of chars can be processed more efficiently than Blind if you can get groups of bits, yet the target requires a set of 7 distinct responses to match any of the possible groups of triple Yes and No combination.
Typical use case is a market site loading a page by id and returning a distinct content for each id (eg. ?id=1, ?id=2, etc).
if Nth bit-group of char X in row is 000 then 🔴🔴🔴 show page A
else if Nth bit-group of char X in row is 001 then 🔴🔴🟢 show page B
...
else if Nth bit-group of char X in row is 110 then 🟢🟢🔴 show page F
else if Nth bit-group of char X in row is 111 then 🟢🟢🟢 show page G
↘️ Nth bits-group of ascii(X in row) from 1 to 3 ?
➡️ pages:🔴🔴🟢;🟢🔴🔴;🔴🔴🟢 ➡️ bin:1100001 ➡️ ascii:97 ➡️ char:'a' in 3 requestsThis definitive out-of-band strategy runs a query that calls your web domain with the SQL results as a subdomain, your domain then forward the Dns query to your machine that runs a local Dns server embedded into jSQL.
Multiple factors limit the content like the domain length and chars but aggregating all the chunks is still faster than querying all bits.
To test it locally just set your system Dns address to your computer address instead of the usual box address.
graph
subgraph Registrar
registrar([bob.com ➡️ 1.2.3.4])
end
subgraph "Apache PHP"
mysql[(MySQL)]
end
subgraph jSQL Injection on 1.2.3.4
gui(GUI)
direction TB
model("💉Model")
dns("Dns on :53")
end
gui -.-> model
mysql -. "2️⃣ call<br>mysql-v8.bob.com" .-> registrar
registrar -. 3️⃣ forward .-> dns
model -. "1️⃣ select version().bob.com" .-> mysql
dns -.-> model
| Speed | Read bits |
Page Diff |
Show rows |
Show onINSERT
|
Show onUPDATE
|
Show onDELETE
|
Show onORDER BY
|
|
|---|---|---|---|---|---|---|---|---|
Time bin |
🐌🐌🐌 | ❌ | ❌ | ❌ | ❌ | ❌ | ||
Time bit |
🐌🐌🐌 | ✔ | ❌ | ❌ | ❌ | ❌ | ❌ | |
Blind bin |
🐌🐌 | ✔ | ❌ | ❌ | ❌ | ❌ | ❌ | |
Blind bit |
🐌🐌 | ✔ | ✔ | ❌ | ❌ | ❌ | ❌ | ❌ |
Multibit |
🐌 | ✔ | ✔ | ❌ | ❌ | ❌ | ❌ | ❌ |
Dns |
⚡ | ✔ | ✔ | ✔ | ✔ | ✔ | ||
Error |
⚡⚡ | ✔ | ✔ | ✔ | ✔ | ✔ | ||
Stack |
⚡⚡⚡ | (✔) | ❌ | ❌ | ❌ | ❌ | ||
Union |
⚡⚡⚡ | ✔ | ❌ | ❌ | ❌ | ❌ |
- Position: get
Booleanresult from a limited chars map, reducing from 7 to 3 queries - Duality: combine
TimewithBlindto extract 2 bits directly - Ascii: convert each char to ASCII code and open matching page id similarly to
Multibit