#!/usr/bin/python3 -O
# freewvs - a free web vulnerability scanner
#
# https://freewvs.schokokeks.org/
#
# Written by schokokeks.org Hosting, https://schokokeks.org
#
# Contributions by
# Hanno Boeck, https://hboeck.de/
# Fabian Fingerle, https://fabian-fingerle.de/
# Bernd Wurst, https://bwurst.org/
#
# To the extent possible under law, the author(s) have dedicated all copyright
# and related and neighboring rights to this software to the public domain
# worldwide. This software is distributed without any warranty.
#
# You should have received a copy of the CC0 Public Domain Dedication along
# with this software. If not, see
# https://creativecommons.org/publicdomain/zero/1.0/
# Nevertheless, in case you use a significant part of this code, we ask (but
# not require, see the license) that you keep the authors' names in place and
# return your changes to the public. We would be especially happy if you tell
# us what you're going to do with this code.
import os
import glob
import re
import argparse
import sys
import json
from xml.sax.saxutils import escape
def versioncompare(safe_version, find_version):
if safe_version == "":
return True
safe_version_tup = [int(x) for x in safe_version.split(".")]
find_version_tup = [int(x) for x in find_version.split(".")]
return find_version_tup < safe_version_tup
def vulnprint(appname, version, safeversion, vuln, vfilename, subdir,
xml):
appdir = '/'.join(os.path.abspath(vfilename).split('/')[:-1 - subdir])
if not xml:
print("%(appname)s %(version)s (%(safeversion)s) %(vuln)s "
"%(appdir)s" % vars())
else:
state = 'vulnerable'
if safeversion == 'ok':
state = 'ok'
print(' ' % state)
print(' %s' % escape(appname))
print(' %s' % escape(version))
print(' %s' % escape(appdir))
if state == 'vulnerable':
print(' %s' % escape(safeversion))
print(' %s' % escape(vuln))
print(' ')
# Command-line options
parser = argparse.ArgumentParser()
parser.add_argument("dirs", nargs="*",
help="Directories to scan")
parser.add_argument("-a", "--all", action="store_true",
help="Show all webapps found, not just vulnerable")
parser.add_argument("-x", "--xml", action="store_true",
help="Output results as XML")
parser.add_argument("-3", "--thirdparty", action="store_true",
help="Scan for third-party components like jquery")
opts = parser.parse_args()
jdir = False
for p in [os.path.dirname(sys.argv[0]) + '/freewvsdb', '/var/lib/freewvs']:
if os.path.isdir(p):
jdir = p
if not jdir:
print("Can't find freewvs json db")
sys.exit(1)
jconfig = []
for cfile in glob.glob(jdir + '/*.json'):
with open(cfile) as json_file:
data = json.load(json_file)
jconfig += data
scanfiles = set()
for app in jconfig:
for det in app['detection']:
scanfiles.add(det['file'])
if opts.xml:
print('')
print('')
# start the search
for fdir in opts.dirs:
for root, NULL, files in os.walk(fdir):
for filename in scanfiles.intersection(files):
for item in jconfig:
if not opts.thirdparty and 'thirdparty' in item:
continue
for det in item['detection']:
if filename == det['file']:
mfile = os.path.join(root, filename)
try:
file = open(mfile, errors='replace')
except IOError:
continue
filestr = file.read()
file.close()
if (('extra_match' in det
and det['extra_match'] not in filestr)
or ('extra_nomatch' in det
and det['extra_nomatch'] in filestr)):
continue
if ('path_match' in det
and (not root.endswith(det['path_match']))):
continue
findversion = re.search(re.escape(det['variable'])
+ r"[^0-9\n\r]*[.]*"
"([0-9.]*[0-9])[^0-9.]",
filestr)
if not findversion:
continue
findversion = findversion.group(1)
# Very ugly phpbb workaround
if 'add_minor' in det:
findversion = findversion.split('.')
findversion[-1] = str(int(findversion[-1])
+ int(det['add_minor']))
findversion = '.'.join(findversion)
if ((not versioncompare(item['safe'], findversion))
or ('old_safe' in item
and findversion in
item['old_safe'].split(','))):
if opts.all:
vulnprint(item['name'], findversion, "ok", "",
mfile, det['subdir'], opts.xml)
continue
safev = item['safe']
if 'old_safe' in item:
for ver in item['old_safe'].split(','):
if versioncompare(ver, findversion):
safev = ver
vulnprint(item['name'], findversion, safev,
item['vuln'], mfile, det['subdir'], opts.xml)
if opts.xml:
print('')