Skip to content

Commit 2c95b65

Browse files
committed
Implementation for #2552 (sorry @mg98)
1 parent e47c1aa commit 2c95b65

File tree

7 files changed

+61
-42
lines changed

7 files changed

+61
-42
lines changed

lib/controller/controller.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ def start():
505505
infoMsg = "skipping %s parameter '%s'" % (paramType, parameter)
506506
logger.info(infoMsg)
507507

508-
elif parameter == conf.csrfToken:
508+
elif re.search(conf.csrfToken, parameter, re.I):
509509
testSqlInj = False
510510

511511
infoMsg = "skipping anti-CSRF token parameter '%s'" % parameter

lib/core/common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ def paramToDict(place, parameters=None):
600600

601601
if condition:
602602
testableParameters[parameter] = "=".join(parts[1:])
603-
if not conf.multipleTargets and not (conf.csrfToken and parameter == conf.csrfToken):
603+
if not conf.multipleTargets and not (conf.csrfToken and re.search(conf.csrfToken, parameter, re.I)):
604604
_ = urldecode(testableParameters[parameter], convall=True)
605605
if (_.endswith("'") and _.count("'") == 1 or re.search(r'\A9{3,}', _) or re.search(r'\A-\d+\Z', _) or re.search(DUMMY_USER_INJECTION, _)) and not parameter.upper().startswith(GOOGLE_ANALYTICS_COOKIE_PREFIX):
606606
warnMsg = "it appears that you have provided tainted parameter values "

lib/core/option.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1560,6 +1560,23 @@ def _cleanupOptions():
15601560
except re.error:
15611561
conf.testFilter = re.escape(conf.testFilter)
15621562

1563+
if conf.csrfToken:
1564+
original = conf.csrfToken
1565+
try:
1566+
re.compile(conf.csrfToken)
1567+
1568+
if re.escape(conf.csrfToken) != conf.csrfToken:
1569+
message = "provided value for option '--csrf-token' is a regular expression? [Y/n] "
1570+
if not readInput(message, default='Y', boolean=True):
1571+
conf.csrfToken = re.escape(conf.csrfToken)
1572+
except re.error:
1573+
conf.csrfToken = re.escape(conf.csrfToken)
1574+
finally:
1575+
class _(unicode):
1576+
pass
1577+
conf.csrfToken = _(conf.csrfToken)
1578+
conf.csrfToken._original = original
1579+
15631580
if conf.testSkip:
15641581
conf.testSkip = conf.testSkip.strip('*+')
15651582
conf.testSkip = re.sub(r"([^.])([*+])", r"\g<1>.\g<2>", conf.testSkip)

lib/core/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from lib.core.enums import OS
2020

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

lib/core/target.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,8 +393,8 @@ def process(match, repl):
393393
raise SqlmapGenericException(errMsg)
394394

395395
if conf.csrfToken:
396-
if not any(conf.csrfToken in _ for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))) and not re.search(r"\b%s\b" % re.escape(conf.csrfToken), conf.data or "") and conf.csrfToken not in set(_[0].lower() for _ in conf.httpHeaders) and conf.csrfToken not in conf.paramDict.get(PLACE.COOKIE, {}):
397-
errMsg = "anti-CSRF token parameter '%s' not " % conf.csrfToken
396+
if not any(re.search(conf.csrfToken, ' '.join(_), re.I) for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))) and not re.search(r"\b%s\b" % re.escape(conf.csrfToken), conf.data or "") and conf.csrfToken not in set(_[0].lower() for _ in conf.httpHeaders) and conf.csrfToken not in conf.paramDict.get(PLACE.COOKIE, {}):
397+
errMsg = "anti-CSRF token parameter '%s' not " % conf.csrfToken._original
398398
errMsg += "found in provided GET, POST, Cookie or header values"
399399
raise SqlmapGenericException(errMsg)
400400
else:

lib/request/connect.py

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class WebSocketException(Exception):
6464
from lib.core.data import conf
6565
from lib.core.data import kb
6666
from lib.core.data import logger
67+
from lib.core.datatype import AttribDict
6768
from lib.core.decorators import stackedmethod
6869
from lib.core.dicts import POST_HINT_CONTENT_TYPES
6970
from lib.core.enums import ADJUST_TIME_DELAY
@@ -960,75 +961,76 @@ def queryPage(value=None, place=None, content=False, getRatioValue=False, silent
960961
if conf.csrfToken:
961962
def _adjustParameter(paramString, parameter, newValue):
962963
retVal = paramString
963-
match = re.search(r"%s=[^&]*" % re.escape(parameter), paramString)
964+
match = re.search(r"%s=[^&]*" % re.escape(parameter), paramString, re.I)
964965
if match:
965-
retVal = re.sub(re.escape(match.group(0)), ("%s=%s" % (parameter, newValue)).replace('\\', r'\\'), paramString)
966+
retVal = re.sub(re.escape(match.group(0)), ("%s=%s" % (parameter, newValue)).replace('\\', r'\\'), paramString, flags=re.I)
966967
else:
967-
match = re.search(r"(%s[\"']:[\"'])([^\"']+)" % re.escape(parameter), paramString)
968+
match = re.search(r"(%s[\"']:[\"'])([^\"']+)" % re.escape(parameter), paramString, re.I)
968969
if match:
969-
retVal = re.sub(re.escape(match.group(0)), "%s%s" % (match.group(1), newValue), paramString)
970+
retVal = re.sub(re.escape(match.group(0)), "%s%s" % (match.group(1), newValue), paramString, flags=re.I)
970971
return retVal
971972

973+
token = AttribDict()
972974
page, headers, code = Connect.getPage(url=conf.csrfUrl or conf.url, data=conf.data if conf.csrfUrl == conf.url else None, method=conf.method if conf.csrfUrl == conf.url else None, cookie=conf.parameters.get(PLACE.COOKIE), direct=True, silent=True, ua=conf.parameters.get(PLACE.USER_AGENT), referer=conf.parameters.get(PLACE.REFERER), host=conf.parameters.get(PLACE.HOST))
973-
token = extractRegexResult(r"(?i)<input[^>]+\bname=[\"']?%s\b[^>]*\bvalue=[\"']?(?P<result>[^>'\"]*)" % re.escape(conf.csrfToken), page or "")
975+
match = re.search(r"(?i)<input[^>]+\bname=[\"']?(?P<name>%s)\b[^>]*\bvalue=[\"']?(?P<value>[^>'\"]*)" % conf.csrfToken, page or "", re.I)
974976

975-
if not token:
976-
token = extractRegexResult(r"(?i)<input[^>]+\bvalue=[\"']?(?P<result>[^>'\"]*)[\"']?[^>]*\bname=[\"']?%s\b" % re.escape(conf.csrfToken), page or "")
977+
if not match:
978+
match = re.search(r"(?i)<input[^>]+\bvalue=[\"']?(?P<value>[^>'\"]*)[\"']?[^>]*\bname=[\"']?(?P<name>%s)\b" % conf.csrfToken, page or "", re.I)
977979

978-
if not token:
979-
match = re.search(r"%s[\"']:[\"']([^\"']+)" % re.escape(conf.csrfToken), page or "")
980-
token = match.group(1) if match else None
980+
if not match:
981+
match = re.search(r"(?P<name>%s)[\"']:[\"'](?P<value>[^\"']+)" % conf.csrfToken, page or "", re.I)
981982

982-
if not token:
983-
token = extractRegexResult(r"\b%s\s*[:=]\s*(?P<result>\w+)" % re.escape(conf.csrfToken), str(headers))
983+
if not match:
984+
match = re.search(r"\b(?P<name>%s)\s*[:=]\s*(?P<value>\w+)" % conf.csrfToken, str(headers), re.I)
984985

985-
if not token:
986-
token = extractRegexResult(r"\b%s\s*=\s*['\"]?(?P<result>[^;'\"]+)" % re.escape(conf.csrfToken), page or "")
986+
if not match:
987+
match = re.search(r"\b(?P<name>%s)\s*=\s*['\"]?(?P<value>[^;'\"]+)" % conf.csrfToken, page or "", re.I)
987988

988-
if token:
989-
match = re.search(r"String\.fromCharCode\(([\d+, ]+)\)", token)
989+
if match:
990+
token.name, token.value = match.group("name"), match.group("value")
990991

991-
if match:
992-
token = "".join(chr(int(_)) for _ in match.group(1).replace(' ', "").split(','))
992+
match = re.search(r"String\.fromCharCode\(([\d+, ]+)\)", token.value)
993+
if match:
994+
token.value = "".join(chr(int(_)) for _ in match.group(1).replace(' ', "").split(','))
993995

994996
if not token:
995997
if conf.csrfUrl != conf.url and code == httplib.OK:
996998
if headers and "text/plain" in headers.get(HTTP_HEADER.CONTENT_TYPE, ""):
997999
token = page
9981000

999-
if not token and conf.cj and any(_.name == conf.csrfToken for _ in conf.cj):
1001+
if not token and conf.cj and any(re.search(conf.csrfToken, _.name, re.I) for _ in conf.cj):
10001002
for _ in conf.cj:
1001-
if _.name == conf.csrfToken:
1002-
token = _.value
1003-
if not any(conf.csrfToken in _ for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))):
1003+
if re.search(conf.csrfToken, _.name, re.I):
1004+
token.name, token.value = _.name, _.value
1005+
if not any(re.search(conf.csrfToken, ' '.join(_), re.I) for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))):
10041006
if post:
1005-
post = "%s%s%s=%s" % (post, conf.paramDel or DEFAULT_GET_POST_DELIMITER, conf.csrfToken, token)
1007+
post = "%s%s%s=%s" % (post, conf.paramDel or DEFAULT_GET_POST_DELIMITER, token.name, token.value)
10061008
elif get:
1007-
get = "%s%s%s=%s" % (get, conf.paramDel or DEFAULT_GET_POST_DELIMITER, conf.csrfToken, token)
1009+
get = "%s%s%s=%s" % (get, conf.paramDel or DEFAULT_GET_POST_DELIMITER, token.name, token.value)
10081010
else:
1009-
get = "%s=%s" % (conf.csrfToken, token)
1011+
get = "%s=%s" % (token.name, token.value)
10101012
break
10111013

10121014
if not token:
1013-
errMsg = "anti-CSRF token '%s' can't be found at '%s'" % (conf.csrfToken, conf.csrfUrl or conf.url)
1015+
errMsg = "anti-CSRF token '%s' can't be found at '%s'" % (conf.csrfToken._original, conf.csrfUrl or conf.url)
10141016
if not conf.csrfUrl:
10151017
errMsg += ". You can try to rerun by providing "
10161018
errMsg += "a valid value for option '--csrf-url'"
10171019
raise SqlmapTokenException(errMsg)
10181020

10191021
if token:
1020-
token = token.strip("'\"")
1022+
token.value = token.value.strip("'\"")
10211023

10221024
for place in (PLACE.GET, PLACE.POST):
10231025
if place in conf.parameters:
10241026
if place == PLACE.GET and get:
1025-
get = _adjustParameter(get, conf.csrfToken, token)
1027+
get = _adjustParameter(get, token.name, token.value)
10261028
elif place == PLACE.POST and post:
1027-
post = _adjustParameter(post, conf.csrfToken, token)
1029+
post = _adjustParameter(post, token.name, token.value)
10281030

10291031
for i in xrange(len(conf.httpHeaders)):
1030-
if conf.httpHeaders[i][0].lower() == conf.csrfToken.lower():
1031-
conf.httpHeaders[i] = (conf.httpHeaders[i][0], token)
1032+
if conf.httpHeaders[i][0].lower() == token.name.lower():
1033+
conf.httpHeaders[i] = (conf.httpHeaders[i][0], token.value)
10321034

10331035
if conf.rParam:
10341036
def _randomizeParameter(paramString, randomParameter):

txt/checksum.md5

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ b3e60ea4e18a65c48515d04aab28ff68 extra/sqlharvest/sqlharvest.py
2424
c1bccc94522d3425a372dcd57f78418e extra/wafdetectify/wafdetectify.py
2525
3459c562a6abb9b4bdcc36925f751f3e lib/controller/action.py
2626
0f0feede9750be810d2b8a7ab159b7b0 lib/controller/checks.py
27-
95cde6dc7efe2581a5936f0d4635cb3b lib/controller/controller.py
27+
93f7eabf92f3da3d96cbd8266e30414d lib/controller/controller.py
2828
988b548f6578adf9cec17afdeee8291c lib/controller/handler.py
2929
1e5532ede194ac9c083891c2f02bca93 lib/controller/__init__.py
3030
e62309b22a59e60b270e62586f169441 lib/core/agent.py
3131
c347f085bd561adfa26d3a9512e5f3b9 lib/core/bigarray.py
32-
9d040f1771efaab4fde8d09821a09f51 lib/core/common.py
32+
cf84ff84891b7f51620a457b0bff28c5 lib/core/common.py
3333
0d082da16c388b3445e656e0760fb582 lib/core/convert.py
3434
9f87391b6a3395f7f50830b391264f27 lib/core/data.py
3535
72016ea5c994a711a262fd64572a0fcd lib/core/datatype.py
@@ -42,17 +42,17 @@ cada93357a7321655927fc9625b3bfec lib/core/exception.py
4242
1e5532ede194ac9c083891c2f02bca93 lib/core/__init__.py
4343
458a194764805cd8312c14ecd4be4d1e lib/core/log.py
4444
7d6edc552e08c30f4f4d49fa93b746f1 lib/core/optiondict.py
45-
9bf3349158df05775eb41742d6402ad8 lib/core/option.py
45+
ecf9879967182e6402f3cab6840f5b75 lib/core/option.py
4646
c8c386d644d57c659d74542f5f57f632 lib/core/patch.py
4747
6783160150b4711d02c56ee2beadffdb lib/core/profiling.py
4848
6f654e1715571eff68a0f8af3d62dcf8 lib/core/readlineng.py
4949
0c3eef46bdbf87e29a3f95f90240d192 lib/core/replication.py
5050
a7db43859b61569b601b97f187dd31c5 lib/core/revision.py
5151
fcb74fcc9577523524659ec49e2e964b lib/core/session.py
52-
7535ff33c85d9b886f9e631dc0158cb9 lib/core/settings.py
52+
e0b7d1e6e148bc962df6b59d35910b92 lib/core/settings.py
5353
a971ce157d04de96ba6e710d3d38a9a8 lib/core/shell.py
5454
a7edc9250d13af36ac0108f259859c19 lib/core/subprocessng.py
55-
52642badbbca4c31a2fcdd754d67a983 lib/core/target.py
55+
d6da5998fea61068a80d9c671db1095f lib/core/target.py
5656
72d499ca8d792e90a1ebfb2ad2341a51 lib/core/testing.py
5757
cd0067d1798e45f422ce44b98baf57db lib/core/threads.py
5858
c40758411bb0bd68764d78e0bb72bd0f lib/core/unescaper.py
@@ -71,7 +71,7 @@ f6b5957bf2103c3999891e4f45180bce lib/parse/payloads.py
7171
30eed3a92a04ed2c29770e1b10d39dc0 lib/request/basicauthhandler.py
7272
2b81435f5a7519298c15c724e3194a0d lib/request/basic.py
7373
859b6ad583e0ffba154f17ee179b5b89 lib/request/comparison.py
74-
77b24c30b1a2163add76652998e74127 lib/request/connect.py
74+
9eb0cc48e7e4779e44f1641aa7d39a4d lib/request/connect.py
7575
dd4598675027fae99f2e2475b05986da lib/request/direct.py
7676
2044fce3f4ffa268fcfaaf63241b1e64 lib/request/dns.py
7777
98535d0efca5551e712fcc4b34a3f772 lib/request/httpshandler.py

0 commit comments

Comments
 (0)