Advertisement
Guest User

wafw00f old source code

a guest
Apr 25th, 2019
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 25.99 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # wafw00f - Web Application Firewall Detection Tool
  3. # by Sandro Gauci - enablesecurity.com (c) 2009
  4. # and Wendel G. Henrique - Trustwave 2009
  5.  
  6. __license__ = """
  7. Copyright (c) 2009, {Sandro Gauci|Wendel G. Henrique}
  8. All rights reserved.
  9.  
  10. Redistribution and use in source and binary forms, with or without modification,
  11. are permitted provided that the following conditions are met:
  12.  
  13. * Redistributions of source code must retain the above copyright notice,
  14. this list of conditions and the following disclaimer.
  15. * Redistributions in binary form must reproduce the above copyright notice,
  16. this list of conditions and the following disclaimer in the documentation
  17. and/or other materials provided with the distribution.
  18. * Neither the name of EnableSecurity or Trustwave nor the names of its contributors
  19. may be used to endorse or promote products derived from this software
  20. without specific prior written permission.
  21.  
  22. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  23. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  24. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  25. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  26. INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  28. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  29. LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  30. OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  31. OF THE POSSIBILITY OF SUCH DAMAGE.
  32. """
  33. import os
  34. import httplib
  35. from urllib import quote, unquote
  36. import urllib2
  37. from optparse import OptionParser
  38. import logging
  39. import socket
  40. import sys
  41.  
  42. currentDir = os.getcwd()
  43. scriptDir = os.path.dirname(sys.argv[0]) or '.'
  44. os.chdir( scriptDir )
  45.  
  46. from evillib import *
  47.  
  48. __version__ = '0.9.0'
  49.  
  50. lackofart = """
  51. ^ ^
  52. _ __ _ ____ _ __ _ _ ____
  53. ///7/ /.' \ / __////7/ /,' \ ,' \ / __/
  54. | V V // o // _/ | V V // 0 // 0 // _/
  55. |_n_,'/_n_//_/ |_n_,' \_,' \_,'/_/
  56. <
  57. ...'
  58.  
  59. WAFW00F - Web Application Firewall Detection Tool
  60.  
  61. By Sandro Gauci && Wendel G. Henrique
  62. """
  63.  
  64.  
  65. class WafW00F(waftoolsengine):
  66. """
  67. WAF detection tool
  68. """
  69.  
  70. xssstring = '<script>alert(1)</script>'
  71. dirtravstring = '../../../../etc/passwd'
  72. cleanhtmlstring = '<invalid>hello'
  73.  
  74. def __init__(self,target='www.microsoft.com',port=80,ssl=False,
  75. debuglevel=0,path='/',followredirect=True):
  76. """
  77. target: the hostname or ip of the target server
  78. port: defaults to 80
  79. ssl: defaults to false
  80. """
  81. waftoolsengine.__init__(self,target,port,ssl,debuglevel,path,followredirect)
  82. self.log = logging.getLogger('wafw00f')
  83. self.knowledge = dict(generic=dict(found=False,reason=''),wafname=list())
  84.  
  85. def normalrequest(self,usecache=True,cacheresponse=True,headers=None):
  86. return self.request(usecache=usecache,cacheresponse=cacheresponse,headers=headers)
  87.  
  88. def normalnonexistentfile(self,usecache=True,cacheresponse=True):
  89. import random
  90. path = self.path + str(random.randrange(1000,9999)) + '.html'
  91. return self.request(path=path,usecache=usecache,cacheresponse=cacheresponse)
  92.  
  93. def unknownmethod(self,usecache=True,cacheresponse=True):
  94. return self.request(method='OHYEA',usecache=usecache,cacheresponse=cacheresponse)
  95.  
  96. def directorytraversal(self,usecache=True,cacheresponse=True):
  97. return self.request(path=self.path+self.dirtravstring,usecache=usecache,cacheresponse=cacheresponse)
  98.  
  99. def cleanhtmlencoded(self,usecache=True,cacheresponse=True):
  100. string = self.path + quote(self.cleanhtmlstring) + '.html'
  101. return self.request(path=string,usecache=usecache,cacheresponse=cacheresponse)
  102.  
  103. def cleanhtml(self,usecache=True,cacheresponse=True):
  104. string = self.path + self.cleanhtmlstring + '.html'
  105. return self.request(path=string,usecache=usecache,cacheresponse=cacheresponse)
  106.  
  107. def xssstandard(self,usecache=True,cacheresponse=True):
  108. xssstringa = self.path + self.xssstring + '.html'
  109. return self.request(path=xssstringa,usecache=usecache,cacheresponse=cacheresponse)
  110.  
  111. def xssstandardencoded(self,usecache=True,cacheresponse=True):
  112. xssstringa = self.path + quote(self.xssstring) + '.html'
  113. return self.request(path=xssstringa,usecache=usecache,cacheresponse=cacheresponse)
  114.  
  115. def cmddotexe(self,usecache=True,cacheresponse=True):
  116. # thanks j0e
  117. string = self.path + 'cmd.exe'
  118. return self.request(path=string,usecache=usecache,cacheresponse=cacheresponse)
  119.  
  120. attacks = [cmddotexe,directorytraversal,xssstandard,xssstandardencoded]
  121.  
  122. def genericdetect(self,usecache=True,cacheresponse=True):
  123. reason = ''
  124. reasons = ['Blocking is being done at connection/packet level.',
  125. 'The server header is different when an attack is detected.',
  126. 'The server returned a different response code when a string trigged the blacklist.',
  127. 'It closed the connection for a normal request.',
  128. 'The connection header was scrambled.'
  129. ]
  130. # test if response for a path containing html tags with known evil strings
  131. # gives a different response from another containing invalid html tags
  132. r = self.cleanhtml()
  133. if r is None:
  134. self.knowledge['generic']['reason'] = reasons[0]
  135. self.knowledge['generic']['found'] = True
  136. return True
  137. cleanresponse,_tmp =r
  138. r = self.xssstandard()
  139. if r is None:
  140. self.knowledge['generic']['reason'] = reasons[0]
  141. self.knowledge['generic']['found'] = True
  142. return True
  143. xssresponse,_tmp = r
  144. if xssresponse.status != cleanresponse.status:
  145. self.log.info('Server returned a different response when a script tag was tried')
  146. reason = reasons[2]
  147. reason += '\r\n'
  148. reason += 'Normal response code is "%s",' % cleanresponse.status
  149. reason += ' while the response code to an attack is "%s"' % xssresponse.status
  150. self.knowledge['generic']['reason'] = reason
  151. self.knowledge['generic']['found'] = True
  152. return True
  153. r = self.cleanhtmlencoded()
  154. cleanresponse,_tmp = r
  155. r = self.xssstandardencoded()
  156. if r is None:
  157. self.knowledge['generic']['reason'] = reasons[0]
  158. self.knowledge['generic']['found'] = True
  159. return True
  160. xssresponse,_tmp = r
  161. if xssresponse.status != cleanresponse.status:
  162. self.log.info('Server returned a different response when a script tag was tried')
  163. reason = reasons[2]
  164. reason += '\r\n'
  165. reason += 'Normal response code is "%s",' % cleanresponse.status
  166. reason += ' while the response code to an attack is "%s"' % xssresponse.status
  167. self.knowledge['generic']['reason'] = reason
  168. self.knowledge['generic']['found'] = True
  169. return True
  170. response, responsebody = self.normalrequest()
  171. normalserver = response.getheader('Server')
  172. for attack in self.attacks:
  173. r = attack(self)
  174. if r is None:
  175. self.knowledge['generic']['reason'] = reasons[0]
  176. self.knowledge['generic']['found'] = True
  177. return True
  178. response, responsebody = r
  179. attackresponse_server = response.getheader('Server')
  180. if attackresponse_server:
  181. if attackresponse_server != normalserver:
  182. self.log.info('Server header changed, WAF possibly detected')
  183. self.log.debug('attack response: %s' % attackresponse_server)
  184. self.log.debug('normal response: %s' % normalserver)
  185. reason = reasons[1]
  186. reason += '\r\nThe server header for a normal response is "%s",' % normalserver
  187. reason += ' while the server header a response to an attack is "%s.",' % attackresponse_server
  188. self.knowledge['generic']['reason'] = reason
  189. self.knowledge['generic']['found'] = True
  190. return True
  191. for attack in self.wafdetectionsprio:
  192. if self.wafdetections[attack](self) is None:
  193. self.knowledge['generic']['reason'] = reasons[0]
  194. self.knowledge['generic']['found'] = True
  195. return True
  196. for attack in self.attacks:
  197. r = attack(self)
  198. if r is None:
  199. self.knowledge['generic']['reason'] = reasons[0]
  200. self.knowledge['generic']['found'] = True
  201. return True
  202. response, responsebody = r
  203. for h,v in response.getheaders():
  204. if scrambledheader(h):
  205. self.knowledge['generic']['reason'] = reasons[4]
  206. self.knowledge['generic']['found'] = True
  207. return True
  208. return False
  209.  
  210.  
  211. def matchheader(self,headermatch,attack=False,ignorecase=True):
  212. import re
  213. detected = False
  214. header,match = headermatch
  215. if attack:
  216. requests = self.attacks
  217. else:
  218. requests = [self.normalrequest]
  219. for request in requests:
  220. r = request(self)
  221. if r is None:
  222. return
  223. response,responsebody = r
  224. headerval = response.getheader(header)
  225. if headerval:
  226. # set-cookie can have multiple headers, python gives it to us
  227. # concatinated with a comma
  228. if header == 'set-cookie':
  229. headervals = headerval.split(', ')
  230. else:
  231. headervals = [headerval]
  232. for headerval in headervals:
  233. if ignorecase:
  234. if re.match(match,headerval,re.IGNORECASE):
  235. detected = True
  236. break
  237. else:
  238. if re.match(match,headerval):
  239. detected = True
  240. break
  241. if detected:
  242. break
  243. return detected
  244.  
  245. def isbigip(self):
  246. return self.matchheader(('X-Cnection','^close$'), attack=True)
  247.  
  248. def iswebknight(self):
  249. detected = False
  250. for attack in self.attacks:
  251. r = attack(self)
  252. if r is None:
  253. return
  254. response, responsebody = r
  255. if response.status == 999:
  256. detected = True
  257. break
  258. return detected
  259.  
  260. def ismodsecurity(self):
  261. detected = False
  262. for attack in self.attacks:
  263. r = attack(self)
  264. if r is None:
  265. return
  266. response, responsebody = r
  267. if response.status == 501:
  268. detected = True
  269. break
  270. return detected
  271.  
  272. def issecureiis(self):
  273. # credit goes to W3AF
  274. detected = False
  275. headers = dict()
  276. headers['Transfer-Encoding'] = 'z' * 1025
  277. r = self.normalrequest(headers=headers)
  278. if r is None:
  279. return
  280. response,responsebody = r
  281. if response.status == 404:
  282. detected = True
  283. return detected
  284.  
  285. def matchcookie(self,match):
  286. """
  287. a convenience function which calls matchheader
  288. """
  289. return self.matchheader(('set-cookie',match))
  290.  
  291. def isairlock(self):
  292. # credit goes to W3AF
  293. return self.matchcookie('^AL[_-]?(SESS|LB)=')
  294.  
  295. def isbarracuda(self):
  296. # credit goes to W3AF
  297. return self.matchcookie('^barra_counter_session=')
  298.  
  299. def isdenyall(self):
  300. # credit goes to W3AF
  301. if self.matchcookie('^sessioncookie='):
  302. return True
  303. # credit goes to Sebastien Gioria
  304. # Tested against a Rweb 3.8
  305. # and modified by sandro gauci and someone else
  306. for attack in self.attacks:
  307. r = attack(self)
  308. if r is None:
  309. return
  310. response, responsebody = r
  311. if response.status == 200:
  312. if response.reason == 'Condition Intercepted':
  313. return True
  314. return False
  315.  
  316. def isbeeware(self):
  317. # disabled cause it was giving way too many false positives
  318. # credit goes to Sebastien Gioria
  319. detected = False
  320. r = self.xssstandard()
  321. if r is None:
  322. return
  323. response, responsebody = r
  324. if (response.status != 200) or (response.reason == 'Forbidden'):
  325. r = self.directorytraversal()
  326. if r is None:
  327. return
  328. response, responsebody = r
  329. if response.status == 403:
  330. if response.reason == "Forbidden":
  331. detected = True
  332. return detected
  333.  
  334. def isf5asm(self):
  335. # credit goes to W3AF
  336. return self.matchcookie('^TS[a-zA-Z0-9]{3,6}=')
  337.  
  338. def isf5trafficshield(self):
  339. for hv in [['cookie','^ASINFO='],['server','F5-TrafficShield']]:
  340. r = self.matchheader(hv)
  341. if r is None:
  342. return
  343. elif r:
  344. return r
  345. return False
  346.  
  347. def isteros(self):
  348. # credit goes to W3AF
  349. return self.matchcookie('^st8id=')
  350.  
  351. def isnetcontinuum(self):
  352. # credit goes to W3AF
  353. return self.matchcookie('^NCI__SessionId=')
  354.  
  355. def isbinarysec(self):
  356. # credit goes to W3AF
  357. return self.matchheader(('server','BinarySec'))
  358.  
  359. def ishyperguard(self):
  360. # credit goes to W3AF
  361. return self.matchcookie('^WODSESSION=')
  362.  
  363. def isprofense(self):
  364. """
  365. Checks for server headers containing "profense"
  366. """
  367. return self.matchheader(('server','profense'))
  368.  
  369. def isnetscaler(self):
  370. """
  371. First checks if a cookie associated with Netscaler is present,
  372. if not it will try to find if a "Cneonction" or "nnCoection" is returned
  373. for any of the attacks sent
  374. """
  375. # NSC_ and citrix_ns_id come from David S. Langlands <dsl 'at' surfstar.com>
  376. if self.matchcookie('^(ns_af=|citrix_ns_id|NSC_)'):
  377. return True
  378. if self.matchheader(('Cneonction','close'),attack=True):
  379. return True
  380. if self.matchheader(('nnCoection','close'),attack=True):
  381. return True
  382. return False
  383.  
  384. def isurlscan(self):
  385. detected = False
  386. testheaders = dict()
  387. testheaders['Translate'] = 'z'*10
  388. testheaders['If'] = 'z'*10
  389. testheaders['Lock-Token'] = 'z'*10
  390. testheaders['Transfer-Encoding'] = 'z'*10
  391. r = self.normalrequest()
  392. if r is None:
  393. return
  394. response,_tmp = r
  395. r = self.normalrequest(headers=testheaders)
  396. if r is None:
  397. return
  398. response2,_tmp = r
  399. if response.status != response2.status:
  400. if response2.status == 404:
  401. detected = True
  402. return detected
  403.  
  404. def iswebscurity(self):
  405. detected = False
  406. r = self.normalrequest()
  407. if r is None:
  408. return
  409. response,responsebody=r
  410. if response.status == 403:
  411. return detected
  412. newpath = self.path + '?nx=@@'
  413. r = self.request(path=newpath)
  414. if r is None:
  415. return
  416. response,responsebody = r
  417. if response.status == 403:
  418. detected = True
  419. return detected
  420.  
  421. def isdotdefender(self):
  422. # thanks to j0e
  423. return self.matchheader(['X-dotDefender-denied', '^1$'],attack=True)
  424.  
  425.  
  426. def isimperva(self):
  427. # thanks to Mathieu Dessus <mathieu.dessus(a)verizonbusiness.com> for this
  428. # might lead to false positives so please report back to sandro@enablesecurity.com
  429. for attack in self.attacks:
  430. r = attack(self)
  431. if r is None:
  432. return
  433. response, responsebody = r
  434. if response.version == 10:
  435. return True
  436. return False
  437.  
  438. def ismodsecuritypositive(self):
  439. import random
  440. detected = False
  441. self.normalrequest(usecache=False,cacheresponse=False)
  442. randomfn = self.path + str(random.randrange(1000,9999)) + '.html'
  443. r = self.request(path=randomfn)
  444. if r is None:
  445. return
  446. response,responsebody = r
  447. if response.status != 302:
  448. return False
  449. randomfnnull = randomfn+'%00'
  450. r = self.request(path=randomfnnull)
  451. if r is None:
  452. return
  453. response,responsebody = r
  454. if response.status == 404:
  455. detected = True
  456. return detected
  457.  
  458. wafdetections = dict()
  459. # easy ones
  460. wafdetections['Profense'] = isprofense
  461. wafdetections['ModSecurity'] = ismodsecurity
  462. wafdetections['NetContinuum'] = isnetcontinuum
  463. wafdetections['HyperGuard'] = ishyperguard
  464. wafdetections['Barracuda'] = isbarracuda
  465. wafdetections['Airlock'] = isairlock
  466. wafdetections['BinarySec'] = isbinarysec
  467. wafdetections['F5 Trafficshield'] = isf5trafficshield
  468. wafdetections['F5 ASM'] = isf5asm
  469. wafdetections['Teros'] = isteros
  470. wafdetections['DenyALL'] = isdenyall
  471. wafdetections['BIG-IP'] = isbigip
  472. wafdetections['Citrix NetScaler'] = isnetscaler
  473. # lil bit more complex
  474. wafdetections['webApp.secure'] = iswebscurity
  475. wafdetections['WebKnight'] = iswebknight
  476. wafdetections['URLScan'] = isurlscan
  477. wafdetections['SecureIIS'] = issecureiis
  478. wafdetections['dotDefender'] = isdotdefender
  479. #wafdetections['BeeWare'] = isbeeware
  480. # wafdetections['ModSecurity (positive model)'] = ismodsecuritypositive removed for now
  481. wafdetections['Imperva'] = isimperva
  482. wafdetectionsprio = ['Profense','NetContinuum',
  483. 'Barracuda','HyperGuard','BinarySec','Teros',
  484. 'F5 Trafficshield','F5 ASM','Airlock','Citrix NetScaler',
  485. 'ModSecurity', 'DenyALL',
  486. 'dotDefender','webApp.secure', # removed for now 'ModSecurity (positive model)',
  487. 'BIG-IP','URLScan','WebKnight',
  488. 'SecureIIS','Imperva']
  489.  
  490. def identwaf(self,findall=False):
  491. detected = list()
  492. for wafvendor in self.wafdetectionsprio:
  493. self.log.info('Checking for %s' % wafvendor)
  494. if self.wafdetections[wafvendor](self):
  495. detected.append(wafvendor)
  496. if not findall:
  497. break
  498. self.knowledge['wafname'] = detected
  499. return detected
  500.  
  501. def calclogginglevel(verbosity):
  502. default = 40 # errors are printed out
  503. level = default - (verbosity*10)
  504. if level < 0:
  505. level = 0
  506. return level
  507.  
  508. class wafwoof_api:
  509. def __init__(self):
  510. self.cache = dict()
  511.  
  512. def vendordetect(self,url,findall=False):
  513. if self.cache.has_key(url):
  514. wafw00f = self.cache[url]
  515. else:
  516. r = oururlparse(url)
  517. if r is None:
  518. return ['']
  519. (hostname,port,path,query,ssl) = r
  520. wafw00f = WafW00F(target=hostname,port=80,path=path,ssl=ssl)
  521. self.cache[url] = wafw00f
  522. return wafw00f.identwaf(findall=findall)
  523.  
  524. def genericdetect(self,url):
  525. if self.cache.has_key(url):
  526. wafw00f = self.cache[url]
  527. else:
  528. r = oururlparse(url)
  529. if r is None:
  530. return {}
  531. (hostname,port,path,query,ssl) = r
  532. wafw00f = WafW00F(target=hostname,port=80,path=path,ssl=ssl)
  533. self.cache[url] = wafw00f
  534. wafw00f.genericdetect()
  535. return wafw00f.knowledge['generic']
  536.  
  537. def alltests(self,url,findall=False):
  538. if self.cache.has_key(url):
  539. wafw00f = self.cache[url]
  540. else:
  541. r = oururlparse(url)
  542. if r is None:
  543. return {}
  544. (hostname,port,path,query,ssl) = r
  545. wafw00f = WafW00F(target=hostname,port=80,path=path,ssl=ssl)
  546. self.cache[url] = wafw00f
  547. wafw00f.identwaf(findall=findall)
  548. if (len(wafw00f.knowledge['wafname']) == 0) or (findall):
  549. wafw00f.genericdetect()
  550. return wafw00f.knowledge
  551.  
  552.  
  553.  
  554.  
  555. def xmlrpc_interface(bindaddr=('localhost',8001)):
  556. from SimpleXMLRPCServer import SimpleXMLRPCServer
  557. from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler
  558.  
  559. class RequestHandler(SimpleXMLRPCRequestHandler):
  560. rpc_paths = ('/RPC2',)
  561.  
  562.  
  563. server = SimpleXMLRPCServer(bindaddr,
  564. requestHandler=RequestHandler)
  565. server.register_introspection_functions()
  566. server.register_instance(wafwoof_api())
  567. try:
  568. server.serve_forever()
  569. except KeyboardInterrupt:
  570. print "bye!"
  571. return
  572.  
  573.  
  574.  
  575.  
  576. def main():
  577. print lackofart
  578. parser = OptionParser(usage="""%prog url1 [url2 [url3 ... ]]\r\nexample: %prog http://www.victim.org/""")
  579. parser.add_option('-v','--verbose',action='count', dest='verbose', default=0,
  580. help="enable verbosity - multiple -v options increase verbosity")
  581. parser.add_option('-a','--findall',action='store_true', dest='findall', default=False,
  582. help="Find all WAFs, do not stop testing on the first one")
  583. parser.add_option('-r','--disableredirect',action='store_false',dest='followredirect',
  584. default=True, help='Do not follow redirections given by 3xx responses')
  585. parser.add_option('-t','--test',dest='test',
  586. help='Test for one specific WAF')
  587. parser.add_option('-l','--list',dest='list', action='store_true',
  588. default=False,help='List all WAFs that we are able to detect')
  589. parser.add_option('--xmlrpc',dest='xmlrpc', action='store_true',
  590. default=False,help='Switch on the XML-RPC interface instead of CUI')
  591. parser.add_option('--xmlrpcport',dest='xmlrpcport', type='int',
  592. default=8001,help='Specify an alternative port to listen on, default 8001')
  593. parser.add_option('--version','-V',dest='version', action='store_true',
  594. default=False,help='Print out the version')
  595. options,args = parser.parse_args()
  596. logging.basicConfig(level=calclogginglevel(options.verbose+1))
  597. log = logging.getLogger()
  598. if options.list:
  599. print "Can test for these WAFs:\r\n"
  600. attacker = WafW00F(None)
  601. print '\r\n'.join(attacker.wafdetectionsprio)
  602. return
  603. if options.version:
  604. print 'WAFW00F version %s' % __version__
  605. return
  606. elif options.xmlrpc:
  607. print "Starting XML-RPC interface"
  608. xmlrpc_interface(bindaddr=('localhost',options.xmlrpcport))
  609. return
  610. if len(args) == 0:
  611. parser.error("we need a target site")
  612. targets = args
  613. for target in targets:
  614. print "Checking %s" % target
  615. pret = oururlparse(target)
  616. if pret is None:
  617. log.critical('The url %s is not well formed' % target)
  618. sys.exit(1)
  619. (hostname,port,path,query,ssl) = pret
  620. log.info('starting wafw00f on %s' % target)
  621. attacker = WafW00F(hostname,port=port,ssl=ssl,
  622. debuglevel=options.verbose,path=path,
  623. followredirect=options.followredirect)
  624. if attacker.normalrequest() is None:
  625. log.error('Site %s appears to be down' % target)
  626. sys.exit(1)
  627. if options.test:
  628. if attacker.wafdetections.has_key(options.test):
  629. waf = attacker.wafdetections[options.test](attacker)
  630. if waf:
  631. print "The site %s is behind a %s" % (target, options.test)
  632. else:
  633. print "WAF %s was not detected on %s" % (options.test,target)
  634. else:
  635. print "WAF %s was not found in our list\r\nUse the --list option to see what is available" % options.test
  636. return
  637. waf = attacker.identwaf(options.findall)
  638. log.info('Ident WAF: %s' % waf)
  639. if len(waf) > 0:
  640. print 'The site %s is behind a %s' % (target, ' and/or '.join( waf))
  641. if (options.findall) or len(waf) == 0:
  642. print 'Generic Detection results:'
  643. if attacker.genericdetect():
  644. log.info('Generic Detection: %s' % attacker.knowledge['generic']['reason'])
  645. print 'The site %s seems to be behind a WAF ' % target
  646. print 'Reason: %s' % attacker.knowledge['generic']['reason']
  647. else:
  648. print 'No WAF detected by the generic detection'
  649. print 'Number of requests: %s' % attacker.requestnumber
  650.  
  651.  
  652. if __name__ == '__main__':
  653. if sys.hexversion < 0x2040000:
  654. sys.stderr.write('Your version of python is way too old .. please update to 2.4 or later\r\n')
  655. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement