Skip to content

Commit 691d2fa

Browse files
committed
Update of docus
1 parent 3fc41ca commit 691d2fa

3 files changed

Lines changed: 35 additions & 7 deletions

File tree

doc/ARCHITECTURE.md

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ non-ASCII byte is unavoidable. Compatibility shims live in `lib/core/compat.py`
1919
|-------|------|---------|
2020
| CLI | `sqlmap.py` -> `main()` | the scanner. Applies runtime patches, parses options, runs a scan. |
2121
| REST API | `sqlmapapi.py` | `-s` server / `-c` client wrappers around `lib/utils/api.py`. |
22+
| Library | `import sqlmap` -> `lib/utils/library.py` | `scan()` / `scanFromRequest()` for programmatic callers; like the API, it drives the engine as a subprocess. |
2223

2324
`main()` (sqlmap.py) does, in order: `dirtyPatches()` (monkey-patches stdlib for
2425
quirks/security - see below), `setPaths()`, `init()` (option parsing + environment
@@ -58,7 +59,7 @@ Identifiers in the codebase are camelCase.
5859
| `lib/core/` | conf/kb model, common helpers, settings, enums, dump, session, agent, option parsing |
5960
| `lib/controller/` | the scan orchestrator (`controller.py`), detection checks (`checks.py`), enumeration dispatch (`action.py`), DBMS handler selection (`handler.py`) |
6061
| `lib/request/` | HTTP layer: `connect.py` (sending), `comparison.py` (the true/false oracle), `inject.py` (value extraction), protocol handlers, response processing |
61-
| `lib/techniques/` | the exploitation engines: `blind/inference.py`, `error/use.py`, `union/{test,use}.py`, `dns/` |
62+
| `lib/techniques/` | the exploitation engines: `blind/{inference,multibit}.py`, `error/use.py`, `union/{test,use}.py`, `dns/`, plus one directory per non-SQL family (`ssti/`, `nosql/`, `xpath/`, ...) |
6263
| `lib/parse/` | parsing of inputs: CLI, config, HTTP request/log files, HTML, sitemap, and the XML payload/boundary loader (`payloads.py`) |
6364
| `lib/utils/` | feature modules: `api.py` (REST), `hashdb.py` (session), `crawler.py`, `hash.py` (cracking), `har.py`, `brute.py`, `search.py`, ... |
6465
| `lib/takeover/` | OS-level takeover: shells, file access, UDF, registry, Metasploit, `xp_cmdshell` |
@@ -130,6 +131,7 @@ Once a parameter is injectable, value extraction is dispatched by
130131
| Technique | Engine | Mechanism |
131132
|-----------|--------|-----------|
132133
| boolean-based blind | `blind/inference.py: bisection()` | binary-search each character via true/false oracle |
134+
| multi-bit blind (`--multi-bit`) | `blind/multibit.py` | opt-in; reads several bits per request out of the rows a listing page renders |
133135
| time-based blind / stacked | `blind/inference.py` (time compare) | same bisection, oracle is a measured delay |
134136
| error-based | `error/use.py: errorUse()` | parse the value straight out of a provoked DB error |
135137
| UNION query | `union/{test,use}.py` | column-count detection then `UNION SELECT` extraction |
@@ -141,6 +143,14 @@ Once a parameter is injectable, value extraction is dispatched by
141143
(intentional). Multi-threaded extraction is coordinated via `kb.locks` and
142144
`getCurrentThreadData()` (`lib/core/threads.py`).
143145

146+
**Non-SQL engines.** `--nosql`, `--xpath`, `--ldap`, `--ssti`, `--graphql`, `--hql`, `--sparql`,
147+
`--odata`, `--xslt`, `--xxe` and `--jwt` do not go through the pipeline above at all. Each one is a
148+
self-contained scanner in `lib/techniques/<family>/inject.py`, dispatched from `controller.py` and
149+
registered once in `NONSQL_TECHNIQUES` (`lib/core/settings.py`) - that tuple is what the rest of the
150+
code tests against, so a new family is declared there and nowhere else. The response comparison,
151+
reflection stripping and blind-bit classification they all need live in `lib/utils/nonsql.py`
152+
instead of being copied per family.
153+
144154
---
145155

146156
## 7. DBMS abstraction
@@ -155,7 +165,10 @@ Enumeration is DBMS-agnostic at the top and specialized underneath:
155165
pieces and supplying dialect specifics.
156166
- **`data/xml/queries.xml`** - per-DBMS SQL query templates (banner, current user, table
157167
enumeration, casting, etc.) keyed by DBMS. The generic code asks for a query by name;
158-
the dialect comes from XML.
168+
the dialect comes from XML. It also carries the per-DBMS `<gadgets>` - side-effecting scalar
169+
expressions (e.g. PostgreSQL `dblink_exec`) that `getGadget()` (`lib/request/inject.py`) probes
170+
once and caches in `kb.gadget`, so `--sql-query` / `--file-write` / `--os-cmd` still work from an
171+
injection point that has no stacked queries.
159172

160173
`conf.dbmsHandler` (set in `handler.py`) is the live object that `action()` calls into.
161174

@@ -180,12 +193,16 @@ Enumeration is DBMS-agnostic at the top and specialized underneath:
180193
`lib/request/connect.py` (`Connect.getPage`) is the single HTTP chokepoint. Around it:
181194
protocol handlers (`httpshandler`, `redirecthandler`, `chunkedhandler`, `rangehandler`,
182195
persistent connections via `lib/request/keepalive.py`), response processing (`basic.py`), and the
183-
comparison oracle (`comparison.py`).
196+
comparison oracle (`comparison.py`). Alternative transports hang off the same chokepoint: the
197+
standard-library HTTP/2 client (`http2.py`, `--http2`, which also carries the `--timeless` oracle in
198+
`timeless.py`) and WebSocket targets (`websocket.py`).
184199

185200
**Tamper scripts** (`tamper/`) mutate the payload just before sending to evade WAF/IPS.
186201
Each file exposes a `tamper(payload, **kwargs)` and a `__priority__`; `--tamper=a,b,c`
187202
chains them in priority order. They are payload-string transforms only (no engine
188-
coupling), which is why they compose freely.
203+
coupling), which is why they compose freely. When a WAF/IPS is identified, `lib/utils/wafbypass.py`
204+
ranks the plausible candidates and `_autoWafBypass()` (`controller.py`) trials them one at a time -
205+
a candidate is adopted only if re-running the detection through it brings the injection back.
189206

190207
---
191208

@@ -227,6 +244,7 @@ Two complementary layers:
227244
| a constant/threshold | `lib/core/settings.py` |
228245
| how injection is *detected* | `data/xml/boundaries.xml` + `data/xml/payloads/*.xml`, then `lib/controller/checks.py` |
229246
| how a value is *extracted* | `lib/request/inject.py` + the relevant `lib/techniques/` engine |
247+
| a non-SQL technique (SSTI, NoSQL, XPath, ...) | `lib/techniques/<family>/inject.py` (+ `NONSQL_TECHNIQUES` in `settings.py`) |
230248
| the true/false decision | `lib/request/comparison.py` |
231249
| a per-DBMS query/dialect | `data/xml/queries.xml` + `plugins/dbms/<dbms>/` |
232250
| enumeration behavior | `plugins/generic/*.py` |

doc/CHANGELOG.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
* Added the switch `--xslt`. It tests for XSLT injection. The engine names itself in the response. sqlmap then dumps the XML document that the stylesheet transforms. It also reads the files that the engine can reach. When the engine exposes an extension bridge (PHP `php:function` or the Xalan `java:` namespace), sqlmap reads any file through it, and with `--os-cmd` or `--os-shell` it runs operating system commands.
1616
* Added the switch `--xxe`. It tests for XML External Entity injection. It uses in-band, error-based, and out-of-band channels.
1717
* Added the switch `--jwt`. It examines JSON Web Tokens for weak keys and for injection in the claims.
18+
* sqlmap now offers to get around a WAF/IPS on its own. Once it identifies one and the ordinary payloads come back blocked, it drops the scanner fingerprint and tries the tamper scripts that suit that WAF, and it keeps the first one that brings the injection back.
1819

1920
## Speed
2021

2122
* Added the switch `--timeless`. It reads each blind bit from the HTTP/2 response order. It does not use a delay. sqlmap calibrates the target first, and it uses the usual time-based technique if the target is not applicable.
23+
* Added the switch `--multi-bit`. On a page that renders rows, one request reads a bit from each row that comes back instead of a single bit altogether.
2224
* Added set-membership (Huffman) retrieval for blind dumps. It needs fewer requests for each character. Use `--no-huffman` to stop it.
2325
* Added keyset (seek) pagination for blind table dumps. Use `--no-keyset` to stop it.
2426
* Added parallel retrieval of values in blind mode. Each thread retrieves a different value.
@@ -53,10 +55,13 @@
5355
* Added time-based payloads for CUBRID.
5456
* Added out-of-band DNS channels for H2 and ClickHouse.
5557
* Added PostgreSQL command execution through a PL extension.
56-
* Added the running of non-query statements without stacked queries through a gadget. On PostgreSQL, when the `dblink` extension is present, `--sql-query`, `--file-write`, `--os-cmd`, and `--os-shell` now work from a plain (e.g. boolean-based) injection point.
58+
* Added the running of non-query statements without stacked queries through a gadget. On PostgreSQL, when the `dblink` extension is there and the current user can run it, `--sql-query`, `--file-write`, `--os-cmd`, and `--os-shell` now work from a plain (e.g. boolean-based) injection point.
5759
* Added file read and file write support for SQLite through the `fileio` extension functions `readfile` and `writefile`.
5860
* Added the data access and the security type of a routine to the output of `--procs` on MySQL and PostgreSQL, so a routine that runs as its definer or that modifies data stands out.
59-
* Added the tamper scripts `blindbinary`, `dollarquote`, `infoschema2innodb`, `oraclequote`, and `sign`.
61+
* Added stacked query payloads for Microsoft SQL Server and Sybase that carry no semicolon, so a filtered semicolon alone no longer hides the technique.
62+
* Added the error signatures that tell the MySQL and the PostgreSQL forks apart: Doris, StarRocks, CockroachDB, YugabyteDB, OpenGauss, DuckDB, and Trino. These forks keep the wording of the engine that they come from, so only a leaked driver package or an engine-internal source reference gives them away.
63+
* Made the fingerprinting payloads friendlier to a WAF, so the version detection survives where it used to get blocked.
64+
* Added the tamper scripts `blindbinary`, `castprefix`, `dollarquote`, `infoschema2innodb`, `mid2leftright`, `mssqlnosemicolon`, `odbcbrace`, `oraclequote`, `quote2ltat`, `sign`, `sleep2hex`, and `uniontable`.
6065

6166
## Fewer dependencies
6267

@@ -93,6 +98,11 @@
9398
* Made the heuristic hints of the non-SQL switches exclusive. A signature no longer matches the errors of a different engine, an ordinary SQL error, or a page that only contains the name of a template engine.
9499
* Corrected the GraphQL validation signatures. They now match the quotes in the way that the JSON body escapes them.
95100
* Added the error signatures of Mako and of DynamoDB. sqlmap did not recognise the errors of these two back-ends.
101+
* sqlmap no longer stops with an exception on a JWT whose signature is not valid base64url. Such a signature can not be an HMAC that sqlmap could verify, so it is reported as not crackable instead.
102+
* Corrected the uppercasing of the keywords in the shown queries. A word that merely contains a keyword (e.g. a table named `selected`) and a keyword inside a quoted string are now left alone.
103+
* Corrected the cracking of the old Oracle password hashes when the user name or the password does not come in as text.
104+
* sqlmap now skips a UNION test whose request holds no character instead of stopping with an exception. Only a hand-edited `payloads/union_query.xml` can hold such a test.
105+
* The gadget check now runs the gadget itself instead of only looking for the extension. A user that can not use it no longer gets a false success.
96106

97107
## Quality
98108

lib/core/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from thirdparty import six
2121

2222
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
23-
VERSION = "1.10.9.1"
23+
VERSION = "1.10.9.2"
2424
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
2525
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
2626
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)

0 commit comments

Comments
 (0)