Skip to content

Commit 1404133

Browse files
committed
Add --prove, opt-in --auto-tamper WAF bypass, and blindbinary/infoschema2innodb tampers
1 parent a0cbfba commit 1404133

16 files changed

Lines changed: 992 additions & 15 deletions

File tree

data/txt/sha256sums.txt

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,10 @@ ca86d61d3349ed2d94a6b164d4648cff9701199b5e32378c3f40fca0f517b128 extra/shutils/
160160
df768bcb9838dc6c46dab9b4a877056cb4742bd6cfaaf438c4a3712c5cc0d264 extra/shutils/recloak.sh
161161
1972990a67caf2d0231eacf60e211acf545d9d0beeb3c145a49ba33d5d491b3f extra/shutils/strip.sh
162162
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 extra/vulnserver/__init__.py
163-
072a2c19162cc4e76476cf474134f18a5ec45cce9a4e4d216dad8e7a71ece048 extra/vulnserver/vulnserver.py
164-
b8411d1035bb49b073476404e61e1be7f4c61e205057730e2f7880beadcd5f60 lib/controller/action.py
165-
6da812281a69c8b7a5181c2f76374dc695e4727b2936042651bacbeda4e6bcc9 lib/controller/checks.py
166-
969737ac9cd3fa7bac8b582a85016bd348ba2087daa3644a570a9127e686363b lib/controller/controller.py
163+
63657c00a046ca0fb28fd069407ab6305bd7b95c42f26a96ed083fd05b152252 extra/vulnserver/vulnserver.py
164+
3abecaec1a9c59645a4821463a2d761235f7a4f763a491f188a41a083bbddd98 lib/controller/action.py
165+
6574ed70c7fe0ac305dbc85ed7102f648b6a3f42fe2fe6b89172d69717327149 lib/controller/checks.py
166+
dcd4adcd7a2447a624ca7927541941d25767a4581af2d762c3197dc93790f4df lib/controller/controller.py
167167
d69e84f1648cdb907f5d2dd454f03874a4613752b07867510145d51d84b3c56f lib/controller/handler.py
168168
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/controller/__init__.py
169169
b36b085ff1b5797e375c1e2ca3b12c7ab4204f48acd1a1efb075cff8302d9750 lib/core/agent.py
@@ -177,30 +177,30 @@ c03dc585f89642cfd81b087ac2723e3e1bb3bfa8c60e6f5fe58ef3b0113ebfe6 lib/core/data.
177177
147823c37596bd6a56d677697781f34b8d1d1671d5a2518fbc9468d623c6d07d lib/core/defaults.py
178178
2f44a1bfe6f18aafe64147b99e69aa93cf438c0e7befe59f4e2aee9065c8b7b6 lib/core/dicts.py
179179
2592b0fd38c272c0b0d49878f4449437eb8ba8ff7536bb39b2ac9a2511010f7c lib/core/dump.py
180-
6b9932d9c789a0e2ac28a493fb7914f49100a1c91de989bcdb20df9d40648522 lib/core/enums.py
180+
e4f92e09737ff0dda7ec30e0db1912570e252853b3af9b8f2b9f68ad33cf09fe lib/core/enums.py
181181
5387168e5dfedd94ae22af7bb255f27d6baaca50b24179c6b98f4f325f5cc7b4 lib/core/exception.py
182182
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/core/__init__.py
183183
914a13ee21fd610a6153a37cbe50830fcbd1324c7ebc1e7fc206d5e598b0f7ad lib/core/log.py
184-
3ec59b5eb336d9808d28496f1cbbad716b4a0e276b5399023142826e460e3fd2 lib/core/optiondict.py
185-
b61676f0aa44798aaf9be72ff37550e2b78ed6ad3c71fbcad54f8c8bf7b34096 lib/core/option.py
184+
06651cff25422dcb84c159f80faf8dc377d82ddd451b5910f12c4c6a3ebe1e94 lib/core/optiondict.py
185+
e3a3729a24306b7ecace614fe27a8123c0becb0c5283ca519e5bcf376af2c711 lib/core/option.py
186186
ccc4a717e887652b1fcce073d9409d9c59a3b28548c703a9e453d15845f90cd7 lib/core/patch.py
187187
49c0fa7e3814dfda610d665ee02b12df299b28bc0b6773815b4395514ddf8dec lib/core/profiling.py
188188
03db48f02c3d07a047ddb8fe33a757b6238867352d8ddda2a83e4fec09a98d04 lib/core/readlineng.py
189189
48797d6c34dd9bb8a53f7f3794c85f4288d82a9a1d6be7fcf317d388cb20d4b3 lib/core/replication.py
190190
0b8c38a01bb01f843d94a6c5f2075ee47520d0c4aa799cecea9c3e2c5a4a23a6 lib/core/revision.py
191191
888daba83fd4a34e9503fe21f01fef4cc730e5cde871b1d40e15d4cbc847d56c lib/core/session.py
192-
222177a7a8e4c16ec4eae9f9542794ebf46a34b29390e967fe9fc26189261372 lib/core/settings.py
192+
f01361d999b0cf89b8418265c4a4962924fcc03a6b87e15b39c0836788725e85 lib/core/settings.py
193193
cd5a66deee8963ba8e7e9af3dd36eb5e8127d4d68698811c29e789655f507f82 lib/core/shell.py
194194
bcb5d8090d5e3e0ef2a586ba09ba80eef0c6d51feb0f611ed25299fbb254f725 lib/core/subprocessng.py
195195
70ea3768f1b3062b22d20644df41c86238157ec80dd43da40545c620714273c6 lib/core/target.py
196-
40b703993441fcd10ab06545b7dbe4a4762ab1ff517592a7e104a52785e62586 lib/core/testing.py
196+
c39dae0602b356d42f55df369c05614bbfb00c2abf2f0419fefe2ae781aa3098 lib/core/testing.py
197197
e3e653364d08d04d7492aa40a2bd29c6a28f4d78fecdd6c10f21f6cb28b98b4c lib/core/threads.py
198198
b9aacb840310173202f79c2ba125b0243003ee6b44c92eca50424f2bdfc83c02 lib/core/unescaper.py
199199
53e396902cb2546eaa09e77073fcba8be8827ee9ce055cfc899e81b0e6ad4d6d lib/core/update.py
200200
2400e465fa4d13e4c32795910878c71ff212e4361b46428d57ce43983f5e997c lib/core/wordlist.py
201201
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/__init__.py
202202
54bfd31ebded3ffa5848df1c644f196eb704116517c7a3d860b5d081e984d821 lib/parse/banner.py
203-
053079fe796dfce09cf94ac6f094043f2dfa393b5631387fadb4f735cf1ac6a4 lib/parse/cmdline.py
203+
14b2fcfa2d6c3a155e3b85f093929c6129893ad191d1988a717daa1ffbb422e7 lib/parse/cmdline.py
204204
02d82e4069bd98c52755417f8b8e306d79945672656ac24f1a45e7a6eff4b158 lib/parse/configfile.py
205205
c5b258be7485089fac9d9cd179960e774fbd85e62836dc67cce76cc028bb6aeb lib/parse/handler.py
206206
5c9a9caee948843d5537745640cc7b98d70a0412cc0949f59d4ebe8b2907c06c lib/parse/headers.py
@@ -254,6 +254,7 @@ a94958be0ec3e9d28d8171813a6a90655a9ad7e6aa33c661e8d8ebbfcf208dbb lib/utils/deps
254254
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/utils/__init__.py
255255
e7d31de0e268c129ee11c590eb618f73a85e1022c08b8ed1f77753043c949214 lib/utils/pivotdumptable.py
256256
c1dfc3bed0fed9b181f612d1d747955dd2b506dbe99bc9fd481495602371473a lib/utils/progress.py
257+
0aeb890fb6b0783f25df7c1ba7c9d0098325b4f7a677ff0151e411be24760f04 lib/utils/prove.py
257258
2cd84db16edef8c9948e197a51d870cf1c338f4a89037b4d422de990f4a45237 lib/utils/purge.py
258259
f635872093a12cd63a72d77adf88e8f8cd4084a5cc64384f12966cd75a499bdf lib/utils/safe2bin.py
259260
de4be7e291db0962cd59f9c04b3f7259f846e315df1fd9b323954f89fae0b2db lib/utils/search.py
@@ -262,6 +263,7 @@ de4be7e291db0962cd59f9c04b3f7259f846e315df1fd9b323954f89fae0b2db lib/utils/sear
262263
f0e5525a92fe971defc8f74c27942ff9138b1e8251f2e0d9a8bd59285b656084 lib/utils/timeout.py
263264
f821dc39a75ea48dccfa758788de15d38b9ca6a780a98f59935fb6610f75508c lib/utils/tui.py
264265
e430db49aa768ff2cdba76932e30871c366054599c44d91580dde459ab9b6fef lib/utils/versioncheck.py
266+
b3c5109394f6c3cdd73a524a737b36cca7ecc56619f2a5f801eb1e7f1bfdb78b lib/utils/wafbypass.py
265267
1b439fc59fd202c21c74978ed9f36d1c309533226c77907eae159461525f9fef lib/utils/xrange.py
266268
b1bbb62f5b272a6247d442d5e4f644a5bca7138e70776539ec84a5a90433fd13 LICENSE
267269
6b1828a80ae3472f1adb53a540dee0835eccac14f8cfc4bf73962c4e49a49557 plugins/dbms/access/connector.py
@@ -501,6 +503,7 @@ cf26bc8006519bd25ce06d347f72770cd75b61575cf65e5812274e8ab9392eb4 tamper/apostro
501503
11ad15d66c43f32f5d0a39052e5f623a4752ad4fb275d642f2e4cd841ff82b41 tamper/base64encode.py
502504
1b55b7c59c623411c8cf328fff9e7de96a2dfc48ef4e5455325bfd41aebbbc13 tamper/between.py
503505
6e72b92662185a56847cca235106bc354bd6a10e3e89a135b9ea8fa09cd8eb34 tamper/binary.py
506+
3fb1a7f8a37d8a49fb88fa880e163ff75a2b224c4a7799abe29bec1a367d5273 tamper/blindbinary.py
504507
f833cfbb53e6849ed1b3b554ec1c973f85e6d41ebd62f94f8e0dcf0ba5da2f49 tamper/bluecoat.py
505508
69c7eb987dec666da227ee1024c31b89ad324a3f7cab287ada6dade7f51c8a36 tamper/chardoubleencode.py
506509
c7892bff56b2b85dfdf9f24c783c569edac57a3fd5a254cf4554987a374206c9 tamper/charencode.py
@@ -524,6 +527,7 @@ d05dafb86e82807e75bb8f54dcd6afbb4a08ba3b83b35562fee7f7022a75dbd7 tamper/if2case
524527
55092820a856f583cf1b661001b60216886d172cb7d0008920bf4ab3df88aff0 tamper/ifnull2casewhenisnull.py
525528
eeda2b2fd54a4aa5fcf5630f8bfae43e0a38a840ae908e2f6b0878959067413c tamper/ifnull2ifisnull.py
526529
94fe273bee7df27c9b4f1ee043779d06e4553169d9aec30c301d469275883dd1 tamper/informationschemacomment.py
530+
ff07320cb134520c3be99407b5c1e67528f944c6a12838ab583716622e877a95 tamper/infoschema2innodb.py
527531
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 tamper/__init__.py
528532
017c91ba64c669382aa88ce627f925b00101a81c1a37a23dba09bfa2bfaf42ae tamper/least.py
529533
d762543ef6d90fd6ce8b897fdfb864e0461d2941922d331d97a334aefdbbe291 tamper/lowercase.py
@@ -606,6 +610,7 @@ b3e13febe9e0ff6f97334f2868655bfdbaa18755e464a6dc4c6d424f513bad02 tests/test_tar
606610
4b646f513c6da1e33200184ed6eabe0aa345eb2e2a19598dc123e191168591bf tests/test_urls.py
607611
23ffd75b5aec33066e6d6aad01ab2c9c1b12ee20c1a0990f8f1be81f1ad16161 tests/_testutils.py
608612
2364db35025a53ea4e5a0a80c034997642785f7e6d1566d0d0f1db959fe3c82e tests/test_utils.py
613+
93ef9944effc62d4f744c57bd643137c90fd92205c6a6cbe891e0e99efb80a7f tests/test_wafbypass.py
609614
81bb6d7449f224fa337734ae361c1a340bf9a51768a854d6a1a6e718ed1263ca tests/test_wordlist.py
610615
55eaefc664bd8598329d535370612351ec8443c52465f0a37172ea46a97c458a thirdparty/ansistrm/ansistrm.py
611616
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 thirdparty/ansistrm/__init__.py

extra/vulnserver/vulnserver.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
DEBUG = False
2525

2626
if PY3:
27+
from http.client import FORBIDDEN
2728
from http.client import INTERNAL_SERVER_ERROR
2829
from http.client import NOT_FOUND
2930
from http.client import OK
@@ -35,6 +36,7 @@
3536
else:
3637
from BaseHTTPServer import BaseHTTPRequestHandler
3738
from BaseHTTPServer import HTTPServer
39+
from httplib import FORBIDDEN
3840
from httplib import INTERNAL_SERVER_ERROR
3941
from httplib import NOT_FOUND
4042
from httplib import OK
@@ -157,6 +159,53 @@ def finish_request(self, *args, **kwargs):
157159
if DEBUG:
158160
traceback.print_exc()
159161

162+
# Primitive (CRS-style) WAF/IPS emulator used to exercise the automatic WAF/IPS bypass. The request
163+
# surface is normalized like a real WAF (lowercase, comments->space, whitespace compressed) BEFORE
164+
# a cumulative anomaly score is summed; when the score reaches the per-level threshold the request
165+
# is blocked (403 + marker). The rules are shaped so that camouflage tampers (case/whitespace/
166+
# comments) are normalized away and a *structural* substitution (e.g. 'between'/'equaltolike',
167+
# which removes the scored '=' operator) is the genuine bypass - matching real-world behavior.
168+
#
169+
# The emulator also models the OTHER real-world dimension: a scanner-fingerprint rule (mirroring
170+
# CRS 913100) adds a constant score for a recognizable scanner User-Agent that *stacks* with the
171+
# payload score. Its weight is below every threshold, so the scanner UA alone never blocks (benign
172+
# browsing passes), but it tips an otherwise-permitted payload over the threshold - so neutralizing
173+
# the request fingerprint (a non-scanner User-Agent) is itself a genuine bypass, with no SQL tamper.
174+
WAF_NUMERIC_COMPARISON = r"\d+\s*=\s*\d+" # numeric self-comparison (boolean payloads); the structural lever 'between'/'equaltolike' removes it
175+
WAF_RULES = (
176+
(r"\bunion\b.{0,40}\bselect\b", 6),
177+
(r"\binformation_schema\b", 5),
178+
(r"\b(sleep|benchmark|extractvalue|updatexml|xp_cmdshell|waitfor)\b", 5),
179+
(r"\b(select|insert|update|delete|drop)\b", 3),
180+
(WAF_NUMERIC_COMPARISON, 4),
181+
(r"<script", 6),
182+
)
183+
WAF_THRESHOLD = {1: 6, 2: 4, 3: 2, 4: 8, 5: 5} # security_level -> cumulative score that triggers a block
184+
WAF_SCANNER_UA = r"(?i)\b(?:sqlmap|nikto|nessus|acunetix|nmap|masscan|w3af|havij|wpscan|dirbuster|arachni)\b"
185+
WAF_SCANNER_UA_WEIGHT = 3 # CRS 913100-style: constant score for a scanner User-Agent, stacked with the payload score
186+
187+
# Levels 4-5 model a libinjection-class WAF (e.g. OWASP CRS rule 942100): ANY boolean-comparison
188+
# fingerprint scores a flat amount REGARDLESS of operator, so '=','LIKE','BETWEEN','IN' are all
189+
# caught equally - structural tampers (between/equaltolike) do NOT help. There, neutralizing the
190+
# scanner fingerprint is the only payload-preserving bypass (level 4); when even that is not enough
191+
# the search must bail honestly (level 5). This mirrors the hardest real-world case.
192+
WAF_LIBINJECTION_LEVELS = (4, 5)
193+
WAF_LIBINJECTION_WEIGHT = 5
194+
WAF_LIBINJECTION = r"(?i)\b(?:and|or)\b.{0,40}(?:=|>|<|\blike\b|\bbetween\b|\bin\b|\brlike\b|\bregexp\b)"
195+
196+
def waf_score(value, ua=None, level=0):
197+
value = (value or "").lower()
198+
value = re.sub(r"/\*.*?\*/", " ", value) # t:replaceComments (note: -> single space, not empty)
199+
value = re.sub(r"(?:--|#)[^\n]*", " ", value) # t:removeComments (line comments)
200+
value = re.sub(r"\s+", " ", value) # t:compressWhitespace
201+
libinjection = level in WAF_LIBINJECTION_LEVELS
202+
retVal = sum(weight for (pattern, weight) in WAF_RULES if not (libinjection and pattern == WAF_NUMERIC_COMPARISON) and re.search(pattern, value))
203+
if libinjection and re.search(WAF_LIBINJECTION, value): # operator-agnostic comparison score (tampers cannot remove it)
204+
retVal += WAF_LIBINJECTION_WEIGHT
205+
if ua and re.search(WAF_SCANNER_UA, ua): # scanner-fingerprint score, stacked with the payload score
206+
retVal += WAF_SCANNER_UA_WEIGHT
207+
return retVal
208+
160209
class ReqHandler(BaseHTTPRequestHandler):
161210
def do_REQUEST(self):
162211
path, query = self.path.split('?', 1) if '?' in self.path else (self.path, "")
@@ -198,6 +247,22 @@ def do_REQUEST(self):
198247

199248
self.url, self.params = path, params
200249

250+
# primitive WAF/IPS emulator (opt-in via 'security_level' param; 0/absent = off)
251+
try:
252+
level = int(self.params.get("security_level", 0) or 0)
253+
except (TypeError, ValueError):
254+
level = 0
255+
256+
if level > 0:
257+
surface = "%s %s" % (unquote_plus(query), getattr(self, "data", "") or "")
258+
if waf_score(surface, ua=self.params.get("user-agent"), level=level) >= WAF_THRESHOLD.get(level, 2):
259+
self.send_response(FORBIDDEN)
260+
self.send_header("Content-type", "text/html; charset=%s" % UNICODE_ENCODING)
261+
self.send_header("Connection", "close")
262+
self.end_headers()
263+
self.wfile.write(b"<html><body>Request blocked: security policy violation (WAF)</body></html>")
264+
return
265+
201266
if self.url == "/csrf":
202267
if self.params.get("csrf_token") == _csrf_token:
203268
self.url = "/"

lib/controller/action.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88
from lib.controller.handler import setHandler
99
from lib.core.common import Backend
1010
from lib.core.common import Format
11+
from lib.core.common import hashDBWrite
1112
from lib.core.data import conf
1213
from lib.core.data import kb
1314
from lib.core.data import logger
1415
from lib.core.data import paths
1516
from lib.core.enums import CONTENT_TYPE
17+
from lib.core.enums import DBMS
18+
from lib.core.enums import HASHDB_KEYS
1619
from lib.core.exception import SqlmapNoneDataException
1720
from lib.core.exception import SqlmapUnsupportedDBMSException
1821
from lib.core.settings import SUPPORTED_DBMS
@@ -30,8 +33,41 @@ def action():
3033

3134
# First of all we have to identify the back-end database management
3235
# system to be able to go ahead with the injection
36+
# automatic WAF-bypass: if a WAF/IPS is present and the back-end DBMS is already indicated by the error
37+
# page or the heuristic checks, skip active fingerprinting (the WAF would just block its payloads
38+
# and flood the run with 403s) and assume that DBMS, so the user gets a usable result
39+
if kb.wafBypass and not conf.forceDbms:
40+
fallback = Backend.getErrorParsedDBMSes() or ([kb.heuristicDbms] if kb.heuristicDbms else [])
41+
fallback = next((_ for _ in fallback if _ and _.lower() in SUPPORTED_DBMS), None)
42+
if fallback:
43+
logger.warning("skipping active back-end DBMS fingerprinting behind the WAF/IPS and assuming '%s' from error/heuristic detection" % fallback)
44+
conf.forceDbms = fallback
45+
3346
setHandler()
3447

48+
if kb.wafBypass and Backend.getDbms(): # persist the assumed DBMS so a resumed run restores it instead of re-fingerprinting (and dead-ending) behind the WAF
49+
hashDBWrite(HASHDB_KEYS.DBMS, Backend.getDbms())
50+
51+
# automatic WAF-bypass: with MySQL behind the WAF, make data retrieval AND table enumeration survive a
52+
# libinjection-class WAF (e.g. OWASP CRS), verified end-to-end through ModSecurity/CRS:
53+
# * fingerprinting was skipped, so flag has_information_schema (modern MySQL >=5.0 always has it) -
54+
# otherwise enumeration wrongly assumes 'MySQL < 5.0' and bails with "no tables";
55+
# * 'blindbinary' reshapes the single-character read ORD(MID())->RIGHT(LEFT())>BINARY 0x.. (sheds the
56+
# ORD/MID function names scored by 942151/942190);
57+
# * 'infoschema2innodb' moves table enumeration off 'information_schema' (scored by 942140) onto
58+
# 'mysql.innodb_table_stats', which is not on those blocklists.
59+
# (blindbinary also reshapes PostgreSQL, but full extraction through the CRS proxy garbles there - an
60+
# open issue - so PG is not auto-applied; it stays available as manual '--tamper=blindbinary'.)
61+
if kb.wafBypass and Backend.getIdentifiedDbms() == DBMS.MYSQL:
62+
kb.data.has_information_schema = True
63+
if not conf.tamper:
64+
from lib.utils.wafbypass import loadTamper
65+
for _name in ("blindbinary", "infoschema2innodb"):
66+
function = loadTamper(_name)
67+
if function is not None and function not in (kb.tamperFunctions or []):
68+
kb.tamperFunctions = (kb.tamperFunctions or []) + [function]
69+
logger.info("using tamper scripts 'blindbinary' and 'infoschema2innodb' so data retrieval and table enumeration can pass the WAF/IPS")
70+
3571
if not Backend.getDbms() or not conf.dbmsHandler:
3672
htmlParsed = Format.getErrorParsedDBMSes()
3773

lib/controller/checks.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,10 @@ def checkWaf():
13511351
warnMsg = "previous heuristics detected that the target "
13521352
warnMsg += "is protected by some kind of WAF/IPS"
13531353
logger.critical(warnMsg)
1354+
if hashDBRetrieve(HASHDB_KEYS.CHECK_WAF_BYPASS, True): # re-apply a previously accepted automatic bypass
1355+
from lib.utils.wafbypass import neutralizeFingerprint
1356+
kb.wafBypass = True
1357+
neutralizeFingerprint()
13541358
return _
13551359

13561360
if not kb.originalPage:
@@ -1393,6 +1397,7 @@ def checkWaf():
13931397

13941398
hashDBWrite(HASHDB_KEYS.CHECK_WAF_RESULT, retVal, True)
13951399

1400+
13961401
if retVal:
13971402
if not kb.identifiedWafs:
13981403
warnMsg = "heuristics detected that the target "
@@ -1406,9 +1411,19 @@ def checkWaf():
14061411
if not choice:
14071412
raise SqlmapUserQuitException
14081413
else:
1409-
if not conf.tamper:
1410-
warnMsg = "please consider usage of tamper scripts (option '--tamper')"
1411-
singleTimeWarnMessage(warnMsg)
1414+
if not conf.tamper and not kb.tamperFunctions:
1415+
message = "do you want sqlmap to try to automatically bypass the WAF/IPS during "
1416+
message += "the run (e.g. by using a non-scanner User-Agent and tamper script(s))? [Y/n] "
1417+
kb.wafBypass = readInput(message, default='Y', boolean=True)
1418+
hashDBWrite(HASHDB_KEYS.CHECK_WAF_BYPASS, kb.wafBypass, True)
1419+
if kb.wafBypass:
1420+
# apply it up-front so the whole run (detection included) avoids the scanner
1421+
# fingerprint, instead of getting blocked first and only then retrying
1422+
from lib.utils.wafbypass import neutralizeFingerprint
1423+
neutralizeFingerprint()
1424+
logger.info("using a random (non-scanner) User-Agent and browser-like headers to bypass the WAF/IPS")
1425+
else:
1426+
singleTimeWarnMessage("please consider manual usage of tamper scripts (option '--tamper')")
14121427

14131428
return retVal
14141429

0 commit comments

Comments
 (0)