Skip to content

Commit c294098

Browse files
committed
Minor style changes for Esperanto DBMS engine
1 parent 272d144 commit c294098

4 files changed

Lines changed: 34 additions & 12 deletions

File tree

extra/esperanto/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ python run.py --self-test
4141
```
4242

4343
The `*` (or an explicit `[INFERENCE]`) marks the injection point; without one it defaults to the end
44-
of the URL. The true/false oracle is taken from `--string` / `--not-string` / `--code`, or
44+
of the URL. The true/false oracle is taken from `--string` / `--code`, or
4545
auto-calibrated from the response when none is given.
4646

4747
## How it works

extra/esperanto/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
for a built-in self-test against an in-memory SQLite oracle.
2020
"""
2121

22+
__version__ = "1.0.0"
23+
2224
from .engine import Esperanto
2325
from .engine import hostExtract
2426
from .handler import buildHandler
2527
from .records import Cap, ExtractResult, BulkResult, Dialect, InferenceStrategy, Integrity
2628
from .records import OracleUndecided, QueryBudgetExceeded
2729

28-
__all__ = ["Esperanto", "hostExtract", "buildHandler", "Cap", "ExtractResult", "BulkResult", "Dialect", "InferenceStrategy", "Integrity", "OracleUndecided", "QueryBudgetExceeded"]
30+
__all__ = ["Esperanto", "hostExtract", "buildHandler", "Cap", "ExtractResult", "BulkResult", "Dialect", "InferenceStrategy", "Integrity", "OracleUndecided", "QueryBudgetExceeded", "__version__"]

extra/esperanto/__main__.py

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@
55
See the file 'LICENSE' for copying permission
66
"""
77

8+
from . import __version__
89
from .atlas import _REPL
910
from .engine import Esperanto, hostExtract
1011
from .records import (
1112
OracleUndecided, ExtractResult, QueryBudgetExceeded)
1213

14+
_SITE = "https://sqlmap.org"
15+
1316
# ratio-mode confidence margin: if the true/false similarity scores are within this of each
1417
# other the page can't be classified, so the oracle returns UNDECIDED rather than guessing.
1518
_RATIO_MARGIN = 0.05
@@ -331,14 +334,14 @@ def mssql():
331334
return ok
332335

333336

334-
def _httpOracle(url, data=None, cookie=None, headers=None, string=None, notString=None, code=None):
337+
def _httpOracle(url, data=None, cookie=None, headers=None, string=None, code=None):
335338
"""A boolean oracle over a real HTTP target, for standalone use. The condition is
336339
substituted at the injection marker: '[INFERENCE]' is replaced verbatim (you supply
337340
the context, e.g. `id=1 AND [INFERENCE]`), else a single '*' is replaced with
338341
` AND (<condition>)`.
339342
340343
True/false is decided by a reduced port of sqlmap's response differentiation - the
341-
Pareto 80%: explicit --string/--not-string/--code win; otherwise it CALIBRATES from
344+
Pareto 80%: explicit --string/--code win; otherwise it CALIBRATES from
342345
two true (1=1) baselines + one false (1=2) and auto-picks the cheapest reliable
343346
signal - HTTP status code, else a stable text line present in true but not false,
344347
else a difflib similarity ratio. Two noise-killers borrowed from sqlmap make it
@@ -428,8 +431,6 @@ def _clean(body, cond):
428431
mode, wanted, base = None, None, {}
429432
if string is not None:
430433
mode = "string"
431-
elif notString is not None:
432-
mode = "notstring"
433434
elif code is not None:
434435
mode, wanted = "code", int(code)
435436
else: # auto-calibrate
@@ -456,7 +457,7 @@ def _clean(body, cond):
456457
break
457458
if wanted is None: # (3) similarity ratio floor
458459
mode, base = "ratio", {"t": tc, "f": fc}
459-
if not string and not notString:
460+
if string is None:
460461
print("[*] calibrated oracle: %s%s" % (mode, (" (%r)" % wanted) if mode in ("code", "autostring") else ""))
461462

462463
def classify(cond):
@@ -465,8 +466,6 @@ def classify(cond):
465466
return None # let the engine retry/degrade, never a fake bool
466467
if mode == "string":
467468
return string in body
468-
if mode == "notstring":
469-
return notString not in body
470469
if mode == "code":
471470
return status == wanted
472471
if mode == "autostring":
@@ -647,6 +646,25 @@ def _report(esp, args):
647646
_printTable(result["columns"], result["rows"])
648647

649648

649+
def _banner():
650+
# modest CLI identity, sqlmap-styled: a small globe (DBMS-agnostic/universal) + the Esperanto
651+
# green star. Colored only on a TTY; pure-ASCII (no coding header on this file); text columns
652+
# aligned at a fixed offset so the escape codes (zero display width) don't skew them.
653+
import sys as _sys
654+
tty = _sys.stdout.isatty()
655+
G = "\033[0;32m" if tty else "" # esperanto green (the globe)
656+
S = "\033[1;32m" if tty else "" # bright green (the star)
657+
W = "\033[1;37m" if tty else "" # bold white (the name)
658+
U = "\033[4;37m" if tty else "" # underline (the site)
659+
R = "\033[0m" if tty else ""
660+
return (
661+
" %(G)s___%(R)s\n"
662+
" %(G)s/ _ \\%(R)s %(W)sesperanto%(R)s {%(ver)s}\n"
663+
" %(G)s| (_) |%(R)s\n"
664+
" %(G)s\\___/ %(S)s*%(R)s %(U)s%(site)s%(R)s\n"
665+
) % dict(G=G, S=S, W=W, U=U, R=R, ver=__version__, site=_SITE)
666+
667+
650668
def main(argv=None):
651669
"""Standalone entry point: drive the engine against a live HTTP target."""
652670
import argparse
@@ -665,13 +683,14 @@ def _format_action_invocation(self, action):
665683

666684
parser = argparse.ArgumentParser(
667685
prog="esperanto", formatter_class=_Formatter,
686+
usage="esperanto -u URL [options]", # short synopsis, not an auto-listing of every flag
668687
description="DBMS-agnostic blind-SQLi enumeration engine (standalone)")
688+
parser.add_argument("--version", action="version", version="esperanto %s (%s)" % (__version__, _SITE))
669689
parser.add_argument("-u", "--url", help="target URL (with a '*'/'[INFERENCE]' marker)")
670690
parser.add_argument("--data", help="POST data string")
671691
parser.add_argument("--cookie", help="HTTP Cookie header")
672692
parser.add_argument("-H", "--header", action="append", help="extra HTTP header (repeatable)")
673693
parser.add_argument("--string", help="match string for a True response")
674-
parser.add_argument("--not-string", dest="not_string", help="match string for a False response")
675694
parser.add_argument("--code", type=int, help="HTTP code for a True response")
676695
parser.add_argument("--banner", action="store_true", help="retrieve DBMS banner")
677696
parser.add_argument("--current-user", action="store_true", dest="current_user", help="retrieve current user")
@@ -697,13 +716,14 @@ def _format_action_invocation(self, action):
697716
if args.selftest: # self-test only on EXPLICIT request
698717
_selftest()
699718
return 0
719+
print(_banner()) # CLI identity (after the dev-harness paths above)
700720
if not args.url: # no target and nothing to do -> show help, don't surprise
701721
parser.print_help()
702722
return 1
703723

704724
target = args.url if "://" in args.url else ("http://" + args.url) # tolerate a scheme-less URL
705725
esp = Esperanto(_httpOracle(target, args.data, args.cookie, args.header,
706-
args.string, args.not_string, args.code))
726+
args.string, args.code))
707727
import sys as _sys
708728
_tty = _sys.stdout.isatty()
709729
def _charLive(partial, total):

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.7.174"
23+
VERSION = "1.10.7.175"
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)