Skip to content

Strategy

ron190 edited this page Apr 16, 2025 · 13 revisions

💉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.

1. Union — union [select]

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 request

2. Stack — ; [select]

Strategy 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 request

3. Error — cast([select] as numeric)

Database 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.

select row then show row in internal error message

↘️ ~100 chars in 1 request

4. Blind — and [select]=true

You 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.

4.a Blind bit — in parallel

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 requests

4.a Blind bin — in sequence

As 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 requests

5. Time — and if([select], sleep())

When 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 bit the entire results is built bit-by-bit. 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 char X in the row is 1
then 🟢 sleep 5s
else 🔴 do-nothing

↘️ Nth bit of ascii(X in the row) from 1 to 7 is 🟢 or 🔴 ?
➡️ pages:🟢;🟢;🔴;🔴;🔴;🔴;🟢 ➡️ bin:1100001 ➡️ ascii:97 ➡️ char:'a' in 7 requests

6. Multibit — and id=[select]

Bitwise 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 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 requests

Other strategies (not implemented yet)

  • DNS: mount a DNS server, inject target with calls to the DNS server subdomain then get result from DNS logs
  • Position: get Boolean result from a limited chars map, reducing from 7 to 3 queries
  • Duality: combine Time with Blind to extract 2 bits directly
  • Ascii: convert each char to ASCII code and open matching page id similarly to Multibit

Summary

Speed Read
bits
Page
Diff
Show
rows
Show on
INSERT
Show on
UPDATE
Show on
DELETE
Time bit 🐌🐌🐌
Blind bin 🐌🐌
Blind bit 🐌🐌
Multibit 🐌
Error
Stack ⚡⚡⚡ (✔)
Union ⚡⚡⚡

Previous topic: General, Next topic: Insight