Skip to content

Commit 7e917ee

Browse files
Merge branch 'master' into feature/add-SAP-HANA-support
2 parents 3307bab + 63b1b59 commit 7e917ee

68 files changed

Lines changed: 34903 additions & 2588 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/tests.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,14 @@ on:
44
pull_request:
55
branches: [ master ]
66

7+
permissions:
8+
contents: read
9+
710
jobs:
811
build:
912
runs-on: ${{ matrix.os }}
13+
timeout-minutes: 30
14+
1015
strategy:
1116
matrix:
1217
include:
@@ -22,12 +27,16 @@ jobs:
2227
uses: actions/checkout@v4
2328
with:
2429
fetch-depth: 1
30+
persist-credentials: false
2531

2632
- name: Set up Python ${{ matrix.python-version }}
2733
uses: actions/setup-python@v5
2834
with:
2935
python-version: ${{ matrix.python-version }}
3036

37+
- name: Python sanity
38+
run: python -VV
39+
3140
- name: Basic import test
3241
run: python -c "import sqlmap; import sqlmapapi"
3342

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,10 @@ traffic.txt
77
req*.txt
88
.idea/
99
.aider*
10+
.DS_Store
11+
.github/.DS_Store
12+
data/.DS_Store
13+
extra/.DS_Store
14+
lib/.DS_Store
15+
plugins/.DS_Store
16+
thirdparty/.DS_Store

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# sqlmap ![](https://i.imgur.com/fe85aVR.png)
1+
# sqlmap ![](https://raw.githubusercontent.com/sqlmapproject/sqlmap/refs/heads/gh-pages/favicon-32.png)
22

33
[![.github/workflows/tests.yml](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml/badge.svg)](https://github.com/sqlmapproject/sqlmap/actions/workflows/tests.yml) [![Python 2.7|3.x](https://img.shields.io/badge/python-2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![x](https://img.shields.io/badge/x-@sqlmap-blue.svg)](https://x.com/sqlmap)
44

data/txt/sha256sums.txt

Lines changed: 58 additions & 58 deletions
Large diffs are not rendered by default.

doc/THANKS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ Ivan Giacomelli, <truemilk(at)insiberia.net>
175175
* for reviewing the documentation
176176

177177
Dimitris Giannitsaros, <daremon(at)gmail.com>
178-
* for contributing a REST-JSON API client
178+
* for contributing a REST API client
179179

180180
Nico Golde, <nico(at)ngolde.de>
181181
* for reporting a couple of bugs

doc/THIRD-PARTY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ This file lists bundled packages and their associated licensing terms.
1515
Copyright (C) 2013, Jonathan Hartley.
1616
* The `Fcrypt` library located under `thirdparty/fcrypt/`.
1717
Copyright (C) 2000, 2001, 2004 Carey Evans.
18-
* The `SocksiPy` library located under `thirdparty/socks/`.
18+
* The `PySocks` library located under `thirdparty/socks/`.
1919
Copyright (C) 2006, Dan-Haim.
2020

2121
````

doc/translations/README-ar-AR.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
----
5959

6060
* الصفحة الرئيسية: https://sqlmap.org
61-
* التحميل: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) أو [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master)
61+
* التحميل: [&#x202A;.tar.gz&#x202C;](https://github.com/sqlmapproject/sqlmap/tarball/master) أو [&#x202A;.zip&#x202C;](https://github.com/sqlmapproject/sqlmap/zipball/master)
6262
* تغذية التحديثات RSS: https://github.com/sqlmapproject/sqlmap/commits/master.atom
6363
* تتبع المشكلات: https://github.com/sqlmapproject/sqlmap/issues
6464
* دليل المستخدم: https://github.com/sqlmapproject/sqlmap/wiki

lib/controller/checks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,7 +1088,7 @@ def _(page):
10881088
if casting:
10891089
errMsg = "possible %s casting detected (e.g. '" % ("integer" if origValue.isdigit() else "type")
10901090

1091-
platform = conf.url.split('.')[-1].lower()
1091+
platform = (extractRegexResult(r"\.(?P<result>\w+)(?:\?|\Z)", conf.url) or conf.url.split('.')[-1]).lower()
10921092
if platform == WEB_PLATFORM.ASP:
10931093
errMsg += "%s=CInt(request.querystring(\"%s\"))" % (parameter, parameter)
10941094
elif platform == WEB_PLATFORM.ASPX:
@@ -1238,7 +1238,7 @@ def checkDynamicContent(firstPage, secondPage):
12381238
kb.heavilyDynamic = True
12391239

12401240
secondPage, _, _ = Request.queryPage(content=True)
1241-
findDynamicContent(firstPage, secondPage)
1241+
findDynamicContent(firstPage, secondPage, merge=True)
12421242

12431243
def checkStability():
12441244
"""

lib/core/agent.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,13 +1229,19 @@ def addPayloadDelimiters(self, value):
12291229
def removePayloadDelimiters(self, value):
12301230
"""
12311231
Removes payload delimiters from inside the input string
1232+
1233+
>>> agent.removePayloadDelimiters(agent.addPayloadDelimiters("1 AND 1=1")) == "1 AND 1=1"
1234+
True
12321235
"""
12331236

12341237
return value.replace(PAYLOAD_DELIMITER, "") if value else value
12351238

12361239
def extractPayload(self, value):
12371240
"""
12381241
Extracts payload from inside of the input string
1242+
1243+
>>> agent.extractPayload("prefix" + agent.addPayloadDelimiters("1 AND 1=1") + "suffix") == "1 AND 1=1"
1244+
True
12391245
"""
12401246

12411247
_ = re.escape(PAYLOAD_DELIMITER)

lib/core/common.py

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ def paramToDict(place, parameters=None):
655655
kb.base64Originals[parameter] = oldValue = value
656656
value = urldecode(value, convall=True)
657657
value = decodeBase64(value, binary=False, encoding=conf.encoding or UNICODE_ENCODING)
658-
parameters = re.sub(r"\b%s(\b|\Z)" % re.escape(oldValue), value, parameters)
658+
parameters = re.sub(r"\b%s(\b|\Z)" % re.escape(oldValue), value.replace('\\', r'\\'), parameters)
659659
except:
660660
errMsg = "parameter '%s' does not contain " % parameter
661661
errMsg += "valid Base64 encoded value ('%s')" % value
@@ -2467,7 +2467,7 @@ def getSQLSnippet(dbms, sfile, **variables):
24672467
retVal = retVal.replace(_, randomStr())
24682468

24692469
for _ in re.findall(r"%RANDINT\d+%", retVal, re.I):
2470-
retVal = retVal.replace(_, randomInt())
2470+
retVal = retVal.replace(_, getText(randomInt()))
24712471

24722472
variables = re.findall(r"(?<!\bLIKE ')%(\w+)%", retVal, re.I)
24732473

@@ -3237,11 +3237,15 @@ def aliasToDbmsEnum(dbms):
32373237

32383238
return retVal
32393239

3240-
def findDynamicContent(firstPage, secondPage):
3240+
def findDynamicContent(firstPage, secondPage, merge=False):
32413241
"""
32423242
This function checks if the provided pages have dynamic content. If they
32433243
are dynamic, proper markings will be made
32443244
3245+
Note: with merge=True the newly found markings are accumulated into the
3246+
existing ones (e.g. when refining across multiple original-page samples)
3247+
instead of replacing them
3248+
32453249
>>> findDynamicContent("Lorem ipsum dolor sit amet, congue tation referrentur ei sed. Ne nec legimus habemus recusabo, natum reque et per. Facer tritani reprehendunt eos id, modus constituam est te. Usu sumo indoctum ad, pri paulo molestiae complectitur no.", "Lorem ipsum dolor sit amet, congue tation referrentur ei sed. Ne nec legimus habemus recusabo, natum reque et per. <script src='ads.js'></script>Facer tritani reprehendunt eos id, modus constituam est te. Usu sumo indoctum ad, pri paulo molestiae complectitur no.")
32463250
>>> kb.dynamicMarkings
32473251
[('natum reque et per. ', 'Facer tritani repreh')]
@@ -3254,7 +3258,9 @@ def findDynamicContent(firstPage, secondPage):
32543258
singleTimeLogMessage(infoMsg)
32553259

32563260
blocks = list(SequenceMatcher(None, firstPage, secondPage).get_matching_blocks())
3257-
kb.dynamicMarkings = []
3261+
3262+
if not merge:
3263+
kb.dynamicMarkings = []
32583264

32593265
# Removing too small matching blocks
32603266
for block in blocks[:]:
@@ -3283,7 +3289,7 @@ def findDynamicContent(firstPage, secondPage):
32833289
suffix = suffix[:DYNAMICITY_BOUNDARY_LENGTH]
32843290

32853291
for _ in (firstPage, secondPage):
3286-
match = re.search(r"(?s)%s(.+)%s" % (re.escape(prefix), re.escape(suffix)), _)
3292+
match = re.search(r"(?s)%s(.+?)%s" % (re.escape(prefix), re.escape(suffix)), _)
32873293
if match:
32883294
infix = match.group(1)
32893295
if infix[0].isalnum():
@@ -3292,7 +3298,9 @@ def findDynamicContent(firstPage, secondPage):
32923298
suffix = trimAlphaNum(suffix)
32933299
break
32943300

3295-
kb.dynamicMarkings.append((prefix if prefix else None, suffix if suffix else None))
3301+
marking = (prefix if prefix else None, suffix if suffix else None)
3302+
if marking not in kb.dynamicMarkings: # Note: avoiding duplicates (e.g. when accumulating markings across samples)
3303+
kb.dynamicMarkings.append(marking)
32963304

32973305
if len(kb.dynamicMarkings) > 0:
32983306
infoMsg = "dynamic content marked for removal (%d region%s)" % (len(kb.dynamicMarkings), 's' if len(kb.dynamicMarkings) > 1 else '')
@@ -3311,11 +3319,11 @@ def removeDynamicContent(page):
33113319
if prefix is None and suffix is None:
33123320
continue
33133321
elif prefix is None:
3314-
page = re.sub(r"(?s)^.+%s" % re.escape(suffix), suffix.replace('\\', r'\\'), page)
3322+
page = re.sub(r"(?s)^.+?%s" % re.escape(suffix), suffix.replace('\\', r'\\'), page)
33153323
elif suffix is None:
33163324
page = re.sub(r"(?s)%s.+$" % re.escape(prefix), prefix.replace('\\', r'\\'), page)
33173325
else:
3318-
page = re.sub(r"(?s)%s.+%s" % (re.escape(prefix), re.escape(suffix)), "%s%s" % (prefix.replace('\\', r'\\'), suffix.replace('\\', r'\\')), page)
3326+
page = re.sub(r"(?s)%s.+?%s" % (re.escape(prefix), re.escape(suffix)), "%s%s" % (prefix.replace('\\', r'\\'), suffix.replace('\\', r'\\')), page)
33193327

33203328
return page
33213329

@@ -4122,6 +4130,9 @@ def intersect(containerA, containerB, lowerCase=False):
41224130
def decodeStringEscape(value):
41234131
"""
41244132
Decodes escaped string values (e.g. "\\t" -> "\t")
4133+
4134+
>>> decodeStringEscape("a" + chr(92) + "tb") == "a" + chr(9) + "b"
4135+
True
41254136
"""
41264137

41274138
retVal = value
@@ -4136,6 +4147,9 @@ def decodeStringEscape(value):
41364147
def encodeStringEscape(value):
41374148
"""
41384149
Encodes escaped string values (e.g. "\t" -> "\\t")
4150+
4151+
>>> encodeStringEscape("a" + chr(9) + "b") == "a" + chr(92) + "tb"
4152+
True
41394153
"""
41404154

41414155
retVal = value
@@ -4283,7 +4297,10 @@ def safeSQLIdentificatorNaming(name, isTable=False):
42834297
'[begin]'
42844298
>>> getText(safeSQLIdentificatorNaming("foobar"))
42854299
'foobar'
4286-
>>> kb.forceDbms = popValue()
4300+
>>> kb.forcedDbms = DBMS.FIREBIRD
4301+
>>> getText(safeSQLIdentificatorNaming("foo bar"))
4302+
'"foo bar"'
4303+
>>> kb.forcedDbms = popValue()
42874304
"""
42884305

42894306
retVal = name
@@ -4303,9 +4320,9 @@ def safeSQLIdentificatorNaming(name, isTable=False):
43034320
if not conf.noEscape:
43044321
retVal = unsafeSQLIdentificatorNaming(retVal)
43054322

4306-
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.CUBRID, DBMS.SQLITE, DBMS.SPANNER): # Note: in SQLite double-quotes are treated as string if column/identifier is non-existent (e.g. SELECT "foobar" FROM users)
4323+
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.CUBRID, DBMS.SQLITE, DBMS.SPANNER, DBMS.CLICKHOUSE): # Note: in SQLite double-quotes are treated as string if column/identifier is non-existent (e.g. SELECT "foobar" FROM users)
43074324
retVal = "`%s`" % retVal
4308-
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE, DBMS.RAIMA, DBMS.VIRTUOSO, DBMS.SNOWFLAKE):
4325+
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE, DBMS.RAIMA, DBMS.VIRTUOSO, DBMS.SNOWFLAKE, DBMS.FIREBIRD, DBMS.DERBY, DBMS.MAXDB):
43094326
retVal = "\"%s\"" % retVal
43104327
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE, DBMS.MIMERSQL, DBMS.HANA):
43114328
retVal = "\"%s\"" % retVal.upper()
@@ -4342,9 +4359,9 @@ def unsafeSQLIdentificatorNaming(name):
43424359
retVal = name
43434360

43444361
if isinstance(name, six.string_types):
4345-
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.CUBRID, DBMS.SQLITE, DBMS.SPANNER):
4362+
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.CUBRID, DBMS.SQLITE, DBMS.SPANNER, DBMS.CLICKHOUSE):
43464363
retVal = name.replace("`", "")
4347-
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE, DBMS.RAIMA, DBMS.VIRTUOSO, DBMS.SNOWFLAKE):
4364+
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE, DBMS.RAIMA, DBMS.VIRTUOSO, DBMS.SNOWFLAKE, DBMS.FIREBIRD, DBMS.DERBY, DBMS.MAXDB):
43484365
retVal = name.replace("\"", "")
43494366
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE, DBMS.MIMERSQL, DBMS.HANA):
43504367
retVal = name.replace("\"", "").upper()

0 commit comments

Comments
 (0)