'''
phishtank.py
Copyright 2006 Andres Riancho
This file is part of w3af, w3af.sourceforge.net .
w3af is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation version 2 of the License.
w3af is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with w3af; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
'''
import core.controllers.outputManager as om
from core.controllers.basePlugin.baseDiscoveryPlugin import baseDiscoveryPlugin
from core.controllers.w3afException import w3afRunOnce
import core.data.kb.knowledgeBase as kb
import core.data.kb.vuln as vuln
from core.data.parsers.urlParser import *
import urllib
import socket
from xml.sax import make_parser
from xml.sax.handler import ContentHandler
import os.path
class phishtank(baseDiscoveryPlugin):
'''
This plugin searches the phishtank.com database to determine if your server is (or was) being used in phishing scams.
@author: Andres Riancho ( andres.riancho@gmail.com ) ; special thanks to http://www.phishtank.com/ !
'''
def __init__(self):
baseDiscoveryPlugin.__init__(self)
self._run = True
# User defines variable
self._phishtankDB = 'plugins' + os.path.sep + 'discovery' + os.path.sep + 'phishtank' + os.path.sep + 'index.xml'
self._updateDB = False
def discover(self, fuzzableRequest ):
self._fuzzableRequests = []
if not self._run:
# This will remove the plugin from the discovery plugins to be runned.
raise w3afRunOnce()
else:
# Run one time
self._run = False
if self._updateDB:
self._doUpdate()
domain = getDomain( fuzzableRequest.getURL() )
toCheckList = self._getToCheck( domain )
phishTankMatches = self._isInPhishtank( toCheckList )
for ptm in phishTankMatches:
response = self._urlOpener.GET( ptm.url )
self._fuzzableRequests.extend( self._createFuzzableRequests( response ) )
v = vuln.vuln()
v.setURL( ptm.url )
v.setId( response.id )
v.setDesc( ptm.url + ' seems to be involved in a phishing scam. Please see ' + ptm.moreInfoURL + ' for more info.' )
om.out.vulnerability( v.getDesc() )
return self._fuzzableRequests
def _getToCheck( self, domain ):
'''
@return: From the domain, get a list of fqdn, rootDomain and IP address.
'''
res = []
addrinfo = None
try:
addrinfo = socket.getaddrinfo( domain, 0)
except:
pass
else:
res.extend( [info[4][0] for info in addrinfo] )
fqdn = ''
try:
fqdn = socket.getfqdn( domain )
except:
pass
else:
res.append( fqdn )
rootDomain = ''
try:
rootDomain = getRootDomain( domain )
except:
om.out.debug( str(e) )
else:
res.append( rootDomain )
res = list( set( res ) )
return res
def _isInPhishtank( self, toCheckList ):
'''
Reads the phishtank db and tries to match the entries on that db with the toCheckList
@return: A list with the sites to match against the phishtank db
'''
class phishTankMatch:
def __init__( self, url, moreInfoURL ):
self.url = url
self.moreInfoURL = moreInfoURL
class phishtankHandler(ContentHandler):
'''
1188842007-03-03T21:01:19+00:00yes2007-03-04T01:58:05+00:00yes
'''
def __init__ (self, toCheckList):
self._toCheckList= toCheckList;
self.insideEntry = False
self.insideURL = False
self.insideDetail = False
self.matches = []
def startElement(self, name, attrs):
if name == 'entry':
self.insideEntry = True
elif name == 'url':
self.insideURL= True;
self.url = "";
elif name == 'phish_detail_url':
self.insideDetail = True;
self.phish_detail_url = "";
return
def characters (self, ch):
if self.insideURL:
self.url += ch
if self.insideDetail:
self.phish_detail_url += ch
def endElement(self, name):
if name == 'phish_detail_url':
self.insideDetail = False
if name == 'url':
self.insideURL = False
if name == 'entry':
self.insideEntry = False
#
# Now I try to match the entry with an element in the toCheckList
#
phishDomain = getDomain( self.url )
for url in self._toCheckList:
if url == phishDomain or phishDomain.endswith('.' + url ):
ptm = phishTankMatch( self.url, self.phish_detail_url )
self.matches.append( ptm )
fd = None
try:
fd = file( self._phishtankDB )
except Exception, e:
raise w3afException('Failed to open phishtank database file: ' + self._phishtankDB )
parser = make_parser()
curHandler = phishtankHandler( toCheckList )
parser.setContentHandler( curHandler )
try:
parser.parse( fd )
except Exception, e:
om.out.debug( 'XML parsing error: ' + str(e) )
raise w3afException('phishtank database file is not a valid XML file.' )
return curHandler.matches
def setOptions( self, OptionList ):
if 'dbFile' in OptionList.keys():
self._phishtankDB = OptionList['dbFile']
if 'updateDB' in OptionList.keys():
self._updateDB = OptionList['updateDB']
def getOptionsXML(self):
'''
This method returns a XML containing the Options that the plugin has.
Using this XML the framework will build a window, a menu, or some other input method to retrieve
the info from the user. The XML has to validate against the xml schema file located at :
w3af/core/output.xsd
'''
return '\
\
\
\
\
'
def _doUpdate(self):
'''
This method is called to update the database.
'''
fd = None
try:
fd = open( self._phishtankDB, 'w' )
except:
raise w3afException('Failed to open file: ' + self._phishtankDB )
om.out.information('Updating the phishtank database, this will take some minutes ( almost 7MB to download ).')
res = self._urlOpener.GET('http://data.phishtank.com/data/online-valid/')
om.out.information('Download complete, writing to the database file.')
try:
fd.write( res.getBody() )
fd.close()
except:
raise w3afException('Failed to write to file: ' + self._phishtankDB )
else:
return True
def getPluginDeps( self ):
'''
@return: A list with the names of the plugins that should be runned before the
current one.
'''
return []
def getLongDesc( self ):
'''
@return: A DETAILED description of the plugin functions and features.
'''
return '''
This plugin searches the domain being tested in the phishtank database.
If your site is in this database the chances are that you were hacked and your server is now being
used in phishing attacks.
Two configurable parameters exist:
- dbFile
- updateDB
'''