Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added trigger URL in response #182

Merged
merged 3 commits into from
Jun 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ coverage.xml
# Sphinx documentation
docs/_build/


*.csv
*.json
.idea/*

.vscode/*
4 changes: 2 additions & 2 deletions wafw00f/lib/evillib.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
import requests
import urllib3
try:
from urlparse import urlparse, urlunparse
from urlparse import urlparse
except ImportError:
from urllib.parse import urlparse, urlunparse
from urllib.parse import urlparse

# For requests < 2.16, this should be used.
# requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
Expand Down
44 changes: 24 additions & 20 deletions wafw00f/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def performCheck(self, request_method):
r = request_method()
if r is None:
raise RequestBlocked()
return r
return r, r.url

# Most common attacks used to detect WAFs
attcom = [xssAttack, sqliAttack, lfiAttack]
Expand All @@ -123,7 +123,7 @@ def genericdetect(self):
]
try:
# Testing for no user-agent response. Detects almost all WAFs out there.
resp1 = self.performCheck(self.normalRequest)
resp1, _ = self.performCheck(self.normalRequest)
if 'User-Agent' in self.headers:
self.headers.pop('User-Agent') # Deleting the user-agent key from object not dict.
resp3 = self.customRequest(headers=self.headers)
Expand All @@ -139,7 +139,7 @@ def genericdetect(self):
return True

# Testing the status code upon sending a xss attack
resp2 = self.performCheck(self.xssAttack)
resp2, xss_url = self.performCheck(self.xssAttack)
if resp1.status_code != resp2.status_code:
self.log.info('Server returned a different response when a XSS attack vector was tried.')
reason = reasons[2]
Expand All @@ -148,10 +148,10 @@ def genericdetect(self):
reason += ' while the response code to cross-site scripting attack is "%s"' % resp2.status_code
self.knowledge['generic']['reason'] = reason
self.knowledge['generic']['found'] = True
return True
return xss_url

# Testing the status code upon sending a lfi attack
resp2 = self.performCheck(self.lfiAttack)
resp2, lfi_url = self.performCheck(self.lfiAttack)
if resp1.status_code != resp2.status_code:
self.log.info('Server returned a different response when a directory traversal was attempted.')
reason = reasons[2]
Expand All @@ -160,10 +160,10 @@ def genericdetect(self):
reason += ' while the response code to a file inclusion attack is "%s"' % resp2.status_code
self.knowledge['generic']['reason'] = reason
self.knowledge['generic']['found'] = True
return True
return lfi_url

# Testing the status code upon sending a sqli attack
resp2 = self.performCheck(self.sqliAttack)
resp2, sqli_url = self.performCheck(self.sqliAttack)
if resp1.status_code != resp2.status_code:
self.log.info('Server returned a different response when a SQLi was attempted.')
reason = reasons[2]
Expand All @@ -172,7 +172,7 @@ def genericdetect(self):
reason += ' while the response code to a SQL injection attack is "%s"' % resp2.status_code
self.knowledge['generic']['reason'] = reason
self.knowledge['generic']['found'] = True
return True
return sqli_url

# Checking for the Server header after sending malicious requests
normalserver, attackresponse_server = '', ''
Expand Down Expand Up @@ -272,17 +272,17 @@ def matchContent(self, regex, attack=True):
def identwaf(self, findall=False):
detected = list()
try:
self.attackres = self.performCheck(self.centralAttack)
self.attackres, xurl = self.performCheck(self.centralAttack)
except RequestBlocked:
return detected
return detected, None
for wafvendor in self.checklist:
self.log.info('Checking for %s' % wafvendor)
if self.wafdetections[wafvendor](self):
detected.append(wafvendor)
if not findall:
break
self.knowledge['wafname'] = detected
return detected
return detected, xurl

def calclogginglevel(verbosity):
default = 40 # errors are printed out
Expand All @@ -291,18 +291,21 @@ def calclogginglevel(verbosity):
level = 0
return level

def buildResultRecord(url, waf):
def buildResultRecord(url, waf, evil_url=None):
result = {}
result['url'] = url
if waf:
result['detected'] = True
if waf == 'generic':
result['trigger_url'] = evil_url
result['firewall'] = 'Generic'
result['manufacturer'] = 'Unknown'
else:
result['trigger_url'] = evil_url
result['firewall'] = waf.split('(')[0].strip()
result['manufacturer'] = waf.split('(')[1].replace(')', '').strip()
else:
result['trigger_url'] = evil_url
result['detected'] = False
result['firewall'] = 'None'
result['manufacturer'] = 'None'
Expand Down Expand Up @@ -490,22 +493,23 @@ def main():
else:
print('[-] WAF %s was not found in our list\r\nUse the --list option to see what is available' % options.test)
return
waf = attacker.identwaf(options.findall)
waf, xurl = attacker.identwaf(options.findall)
log.info('Identified WAF: %s' % waf)
if len(waf) > 0:
for i in waf:
results.append(buildResultRecord(target, i))
results.append(buildResultRecord(target, i, xurl))
print('[+] The site %s%s%s is behind %s%s%s WAF.' % (B, target, E, C, (E+' and/or '+C).join(waf), E))
if (options.findall) or len(waf) == 0:
print('[+] Generic Detection results:')
if attacker.genericdetect():
generic_url = attacker.genericdetect()
if generic_url:
log.info('Generic Detection: %s' % attacker.knowledge['generic']['reason'])
print('[*] The site %s seems to be behind a WAF or some sort of security solution' % target)
print('[~] Reason: %s' % attacker.knowledge['generic']['reason'])
results.append(buildResultRecord(target, 'generic'))
results.append(buildResultRecord(target, 'generic', generic_url))
else:
print('[-] No WAF detected by the generic detection')
results.append(buildResultRecord(target, None))
results.append(buildResultRecord(target, None, None))
print('[~] Number of requests: %s' % attacker.requestnumber)
#print table of results
if len(results) > 0:
Expand All @@ -514,7 +518,7 @@ def main():
if options.output == '-':
enableStdOut()
if options.format == 'json':
json.dump(results, sys.stdout, indent=2)
json.dump(results, sys.stdout, indent=2, sort_keys=True)
elif options.format == 'csv':
csvwriter = csv.writer(sys.stdout, delimiter=',', quotechar='"',
quoting=csv.QUOTE_MINIMAL)
Expand All @@ -530,7 +534,7 @@ def main():
elif options.output.endswith('.json'):
log.debug("Exporting data in json format to file: %s" % (options.output))
with open(options.output, 'w') as outfile:
json.dump(results, outfile, indent=2)
json.dump(results, outfile, indent=2, sort_keys=True)
elif options.output.endswith('.csv'):
log.debug("Exporting data in csv format to file: %s" % (options.output))
with open(options.output, 'w') as outfile:
Expand All @@ -547,7 +551,7 @@ def main():
log.debug("Exporting data in text format to file: %s" % (options.output))
if options.format == 'json':
with open(options.output, 'w') as outfile:
json.dump(results, outfile, indent=2)
json.dump(results, outfile, indent=2, sort_keys=True)
elif options.format == 'csv':
with open(options.output, 'w') as outfile:
csvwriter = csv.writer(outfile, delimiter=',', quotechar='"',
Expand Down