Browse code

change license to 0BSD due to controversy around CC0, all contributors agreed

Hanno Böck authored on 17/08/2022 20:07:02
Showing 1 changed files
... ...
@@ -10,18 +10,7 @@
10 10
 # Hanno Boeck, https://hboeck.de/
11 11
 # Fabian Fingerle, https://fabian-fingerle.de/
12 12
 # Bernd Wurst, https://bwurst.org/
13
-#
14
-# To the extent possible under law, the author(s) have dedicated all copyright
15
-# and related and neighboring rights to this software to the public domain
16
-# worldwide. This software is distributed without any warranty.
17
-#
18
-# You should have received a copy of the CC0 Public Domain Dedication along
19
-# with this software. If not, see
20
-# https://creativecommons.org/publicdomain/zero/1.0/
21
-# Nevertheless, in case you use a significant part of this code, we ask (but
22
-# not require, see the license) that you keep the authors' names in place and
23
-# return your changes to the public. We would be especially happy if you tell
24
-# us what you're going to do with this code.
13
+
25 14
 
26 15
 import os
27 16
 import glob
Browse code

use black codingstyle

Hanno Böck authored on 15/07/2022 12:43:59
Showing 1 changed files
... ...
@@ -58,40 +58,48 @@ def checkoldsafe(old_safe, find_version):
58 58
     return False
59 59
 
60 60
 
61
-def vulnprint(appname, version, safeversion, vuln, vfilename, subdir,
62
-              xml):
63
-    appdir = '/'.join(os.path.abspath(vfilename).split('/')[:-1 - subdir])
61
+def vulnprint(appname, version, safeversion, vuln, vfilename, subdir, xml):
62
+    appdir = "/".join(os.path.abspath(vfilename).split("/")[: -1 - subdir])
64 63
     if not xml:
65 64
         print(f"{appname} {version} ({safeversion}) {vuln} {appdir}")
66 65
     else:
67
-        state = 'vulnerable'
68
-        if safeversion == 'ok':
69
-            state = 'ok'
66
+        state = "vulnerable"
67
+        if safeversion == "ok":
68
+            state = "ok"
70 69
         print(f'  <app state="{state}">')
71
-        print(f'    <appname>{escape(appname)}</appname>')
72
-        print(f'    <version>{escape(version)}</version>')
73
-        print(f'    <directory>{escape(appdir)}</directory>')
74
-        if state == 'vulnerable':
75
-            print(f'    <safeversion>{escape(safeversion)}</safeversion>')
76
-            print(f'    <vulninfo>{escape(vuln)}</vulninfo>')
77
-        print('  </app>')
70
+        print(f"    <appname>{escape(appname)}</appname>")
71
+        print(f"    <version>{escape(version)}</version>")
72
+        print(f"    <directory>{escape(appdir)}</directory>")
73
+        if state == "vulnerable":
74
+            print(f"    <safeversion>{escape(safeversion)}</safeversion>")
75
+            print(f"    <vulninfo>{escape(vuln)}</vulninfo>")
76
+        print("  </app>")
78 77
 
79 78
 
80 79
 # Command-line options
81 80
 parser = argparse.ArgumentParser()
82
-parser.add_argument("dirs", nargs="*",
83
-                    help="Directories to scan")
84
-parser.add_argument("-a", "--all", action="store_true",
85
-                    help="Show all webapps found, not just vulnerable")
86
-parser.add_argument("-x", "--xml", action="store_true",
87
-                    help="Output results as XML")
88
-parser.add_argument("-3", "--thirdparty", action="store_true",
89
-                    help="Scan for third-party components like jquery")
81
+parser.add_argument("dirs", nargs="*", help="Directories to scan")
82
+parser.add_argument(
83
+    "-a",
84
+    "--all",
85
+    action="store_true",
86
+    help="Show all webapps found, not just vulnerable",
87
+)
88
+parser.add_argument("-x", "--xml", action="store_true", help="Output results as XML")
89
+parser.add_argument(
90
+    "-3",
91
+    "--thirdparty",
92
+    action="store_true",
93
+    help="Scan for third-party components like jquery",
94
+)
90 95
 opts = parser.parse_args()
91 96
 
92 97
 jdir = False
93
-for p in [os.path.dirname(sys.argv[0]) + '/freewvsdb', '/var/lib/freewvs',
94
-          str(pathlib.Path.home()) + "/.cache/freewvs/"]:
98
+for p in [
99
+    os.path.dirname(sys.argv[0]) + "/freewvsdb",
100
+    "/var/lib/freewvs",
101
+    str(pathlib.Path.home()) + "/.cache/freewvs/",
102
+]:
95 103
     if os.path.isdir(p):
96 104
         jdir = p
97 105
         break
... ...
@@ -100,20 +108,20 @@ if not jdir:
100 108
     sys.exit(1)
101 109
 
102 110
 jconfig = []
103
-for cfile in glob.glob(jdir + '/*.json'):
111
+for cfile in glob.glob(jdir + "/*.json"):
104 112
     with open(cfile, encoding="ascii") as json_file:
105 113
         data = json.load(json_file)
106 114
         jconfig += data
107 115
 
108 116
 scanfiles = set()
109 117
 for app in jconfig:
110
-    for det in app['detection']:
111
-        scanfiles.add(det['file'])
118
+    for det in app["detection"]:
119
+        scanfiles.add(det["file"])
112 120
 
113 121
 
114 122
 if opts.xml:
115 123
     print('<?xml version="1.0" ?>')
116
-    print('<freewvs>')
124
+    print("<freewvs>")
117 125
 
118 126
 # start the search
119 127
 
... ...
@@ -125,61 +133,78 @@ for fdir in opts.dirs:
125 133
             del dirs[:]
126 134
         for filename in scanfiles.intersection(files):
127 135
             for item in jconfig:
128
-                if not opts.thirdparty and 'thirdparty' in item:
136
+                if not opts.thirdparty and "thirdparty" in item:
129 137
                     continue
130
-                for det in item['detection']:
131
-                    if filename == det['file']:
138
+                for det in item["detection"]:
139
+                    if filename == det["file"]:
132 140
                         mfile = os.path.join(root, filename)
133 141
                         try:
134
-                            file = open(mfile, encoding='ascii',
135
-                                        errors='replace')
142
+                            file = open(mfile, encoding="ascii", errors="replace")
136 143
                         except OSError:
137 144
                             continue
138 145
                         filestr = file.read(200000)
139 146
                         file.close()
140 147
 
141
-                        if (('extra_match' in det
142
-                             and det['extra_match'] not in filestr)
143
-                                or ('extra_nomatch' in det
144
-                                    and det['extra_nomatch'] in filestr)):
148
+                        if (
149
+                            "extra_match" in det and det["extra_match"] not in filestr
150
+                        ) or (
151
+                            "extra_nomatch" in det and det["extra_nomatch"] in filestr
152
+                        ):
145 153
                             continue
146 154
 
147
-                        if ('path_match' in det
148
-                                and (not root.endswith(det['path_match']))):
155
+                        if "path_match" in det and (
156
+                            not root.endswith(det["path_match"])
157
+                        ):
149 158
                             continue
150 159
 
151
-                        findversion = re.search(re.escape(det['variable'])
152
-                                                + r"[^0-9\n\r]*[.]*"
153
-                                                "([0-9.]*[0-9])[^0-9.]",
154
-                                                filestr)
160
+                        findversion = re.search(
161
+                            re.escape(det["variable"]) + r"[^0-9\n\r]*[.]*"
162
+                            "([0-9.]*[0-9])[^0-9.]",
163
+                            filestr,
164
+                        )
155 165
                         if not findversion:
156 166
                             continue
157 167
                         findversion = findversion.group(1)
158 168
 
159 169
                         # Very ugly phpbb workaround
160
-                        if 'add_minor' in det:
161
-                            findversion = findversion.split('.')
162
-                            findversion[-1] = str(int(findversion[-1])
163
-                                                  + int(det['add_minor']))
164
-                            findversion = '.'.join(findversion)
165
-
166
-                        if (not versioncompare(item['safe'], findversion)
167
-                                or ('old_safe' in item
168
-                                    and checkoldsafe(item['old_safe'],
169
-                                                     findversion))):
170
+                        if "add_minor" in det:
171
+                            findversion = findversion.split(".")
172
+                            findversion[-1] = str(
173
+                                int(findversion[-1]) + int(det["add_minor"])
174
+                            )
175
+                            findversion = ".".join(findversion)
176
+
177
+                        if not versioncompare(item["safe"], findversion) or (
178
+                            "old_safe" in item
179
+                            and checkoldsafe(item["old_safe"], findversion)
180
+                        ):
170 181
                             if opts.all:
171
-                                vulnprint(item['name'], findversion, "ok", "",
172
-                                          mfile, det['subdir'], opts.xml)
182
+                                vulnprint(
183
+                                    item["name"],
184
+                                    findversion,
185
+                                    "ok",
186
+                                    "",
187
+                                    mfile,
188
+                                    det["subdir"],
189
+                                    opts.xml,
190
+                                )
173 191
                             continue
174 192
 
175
-                        safev = item['safe']
176
-                        if 'old_safe' in item:
177
-                            for ver in item['old_safe'].split(','):
193
+                        safev = item["safe"]
194
+                        if "old_safe" in item:
195
+                            for ver in item["old_safe"].split(","):
178 196
                                 if versioncompare(ver, findversion):
179 197
                                     safev = ver
180 198
 
181
-                        vulnprint(item['name'], findversion, safev,
182
-                                  item['vuln'], mfile, det['subdir'], opts.xml)
199
+                        vulnprint(
200
+                            item["name"],
201
+                            findversion,
202
+                            safev,
203
+                            item["vuln"],
204
+                            mfile,
205
+                            det["subdir"],
206
+                            opts.xml,
207
+                        )
183 208
 
184 209
 if opts.xml:
185
-    print('</freewvs>')
210
+    print("</freewvs>")
Browse code

accept old_safe versions with higher minor version

Hanno Böck authored on 15/07/2022 12:39:50
Showing 1 changed files
... ...
@@ -41,6 +41,23 @@ def versioncompare(safe_version, find_version):
41 41
     return find_version_tup < safe_version_tup
42 42
 
43 43
 
44
+def checkoldsafe(old_safe, find_version):
45
+    find_version_tup = [int(x) for x in find_version.split(".")]
46
+    for oldver in old_safe.split(","):
47
+        oldver_tup = [int(x) for x in oldver.split(".")]
48
+
49
+        if find_version_tup == oldver_tup:
50
+            return True
51
+        # handle special case where minor version is larger
52
+        if (
53
+            len(find_version_tup) >= 2
54
+            and find_version_tup[:-1] == oldver_tup[:-1]
55
+            and find_version_tup[-1] > oldver_tup[-1]
56
+        ):
57
+            return True
58
+    return False
59
+
60
+
44 61
 def vulnprint(appname, version, safeversion, vuln, vfilename, subdir,
45 62
               xml):
46 63
     appdir = '/'.join(os.path.abspath(vfilename).split('/')[:-1 - subdir])
... ...
@@ -148,8 +165,8 @@ for fdir in opts.dirs:
148 165
 
149 166
                         if (not versioncompare(item['safe'], findversion)
150 167
                                 or ('old_safe' in item
151
-                                    and findversion in
152
-                                    item['old_safe'].split(','))):
168
+                                    and checkoldsafe(item['old_safe'],
169
+                                                     findversion))):
153 170
                             if opts.all:
154 171
                                 vulnprint(item['name'], findversion, "ok", "",
155 172
                                           mfile, det['subdir'], opts.xml)
Browse code

use more f-strings

Hanno Böck authored on 29/01/2022 17:55:36
Showing 1 changed files
... ...
@@ -45,19 +45,18 @@ def vulnprint(appname, version, safeversion, vuln, vfilename, subdir,
45 45
               xml):
46 46
     appdir = '/'.join(os.path.abspath(vfilename).split('/')[:-1 - subdir])
47 47
     if not xml:
48
-        print("%(appname)s %(version)s (%(safeversion)s) %(vuln)s "
49
-              "%(appdir)s" % vars())
48
+        print(f"{appname} {version} ({safeversion}) {vuln} {appdir}")
50 49
     else:
51 50
         state = 'vulnerable'
52 51
         if safeversion == 'ok':
53 52
             state = 'ok'
54
-        print('  <app state="%s">' % state)
55
-        print('    <appname>%s</appname>' % escape(appname))
56
-        print('    <version>%s</version>' % escape(version))
57
-        print('    <directory>%s</directory>' % escape(appdir))
53
+        print(f'  <app state="{state}">')
54
+        print(f'    <appname>{escape(appname)}</appname>')
55
+        print(f'    <version>{escape(version)}</version>')
56
+        print(f'    <directory>{escape(appdir)}</directory>')
58 57
         if state == 'vulnerable':
59
-            print('    <safeversion>%s</safeversion>' % escape(safeversion))
60
-            print('    <vulninfo>%s</vulninfo>' % escape(vuln))
58
+            print(f'    <safeversion>{escape(safeversion)}</safeversion>')
59
+            print(f'    <vulninfo>{escape(vuln)}</vulninfo>')
61 60
         print('  </app>')
62 61
 
63 62
 
Browse code

fix new pylint warnings

Hanno Böck authored on 05/09/2021 09:46:29
Showing 1 changed files
... ...
@@ -85,7 +85,7 @@ if not jdir:
85 85
 
86 86
 jconfig = []
87 87
 for cfile in glob.glob(jdir + '/*.json'):
88
-    with open(cfile) as json_file:
88
+    with open(cfile, encoding="ascii") as json_file:
89 89
         data = json.load(json_file)
90 90
         jconfig += data
91 91
 
... ...
@@ -115,7 +115,8 @@ for fdir in opts.dirs:
115 115
                     if filename == det['file']:
116 116
                         mfile = os.path.join(root, filename)
117 117
                         try:
118
-                            file = open(mfile, errors='replace')
118
+                            file = open(mfile, encoding='ascii',
119
+                                        errors='replace')
119 120
                         except OSError:
120 121
                             continue
121 122
                         filestr = file.read(200000)
... ...
@@ -146,7 +147,7 @@ for fdir in opts.dirs:
146 147
                                                   + int(det['add_minor']))
147 148
                             findversion = '.'.join(findversion)
148 149
 
149
-                        if ((not versioncompare(item['safe'], findversion))
150
+                        if (not versioncompare(item['safe'], findversion)
150 151
                                 or ('old_safe' in item
151 152
                                     and findversion in
152 153
                                     item['old_safe'].split(','))):
Browse code

remove obsolete warning about old freewvs dirs

Hanno Böck authored on 19/06/2020 20:12:11
Showing 1 changed files
... ...
@@ -73,13 +73,6 @@ parser.add_argument("-3", "--thirdparty", action="store_true",
73 73
                     help="Scan for third-party components like jquery")
74 74
 opts = parser.parse_args()
75 75
 
76
-# Warn people with old-style freewvsdb dirs,
77
-# should be removed in a few months
78
-for d in ["/usr/share/freewvs", "/usr/local/share/freewvs"]:
79
-    if os.path.isdir(d):
80
-        print("WARNING: Obsolete freewvs data in %s, removal recommended" % d,
81
-              file=sys.stderr)
82
-
83 76
 jdir = False
84 77
 for p in [os.path.dirname(sys.argv[0]) + '/freewvsdb', '/var/lib/freewvs',
85 78
           str(pathlib.Path.home()) + "/.cache/freewvs/"]:
Browse code

limit data we read from file to avoid DoS via large files

Hanno Böck authored on 10/06/2020 10:15:22
Showing 1 changed files
... ...
@@ -125,7 +125,7 @@ for fdir in opts.dirs:
125 125
                             file = open(mfile, errors='replace')
126 126
                         except OSError:
127 127
                             continue
128
-                        filestr = file.read()
128
+                        filestr = file.read(200000)
129 129
                         file.close()
130 130
 
131 131
                         if (('extra_match' in det
Browse code

replace deprecated IOError with OSError, see https://www.python.org/dev/peps/pep-3151/#step-1-coalesce-exception-types

Hanno Böck authored on 09/06/2020 19:46:07
Showing 1 changed files
... ...
@@ -123,7 +123,7 @@ for fdir in opts.dirs:
123 123
                         mfile = os.path.join(root, filename)
124 124
                         try:
125 125
                             file = open(mfile, errors='replace')
126
-                        except IOError:
126
+                        except OSError:
127 127
                             continue
128 128
                         filestr = file.read()
129 129
                         file.close()
Browse code

protect against deep recursion of directories

Hanno Böck authored on 09/06/2020 19:12:59
Showing 1 changed files
... ...
@@ -109,7 +109,11 @@ if opts.xml:
109 109
 # start the search
110 110
 
111 111
 for fdir in opts.dirs:
112
-    for root, _, files in os.walk(fdir):
112
+    for root, dirs, files in os.walk(fdir):
113
+        # this protects us against nested directories causing
114
+        # an exception
115
+        if root.count(os.sep) > 500:
116
+            del dirs[:]
113 117
         for filename in scanfiles.intersection(files):
114 118
             for item in jconfig:
115 119
                 if not opts.thirdparty and 'thirdparty' in item:
Browse code

use _ for unused variable to make vulture happy

Hanno Böck authored on 21/03/2020 19:23:12
Showing 1 changed files
... ...
@@ -109,7 +109,7 @@ if opts.xml:
109 109
 # start the search
110 110
 
111 111
 for fdir in opts.dirs:
112
-    for root, NULL, files in os.walk(fdir):
112
+    for root, _, files in os.walk(fdir):
113 113
         for filename in scanfiles.intersection(files):
114 114
             for item in jconfig:
115 115
                 if not opts.thirdparty and 'thirdparty' in item:
Browse code

noqa for dlint, the escape function should be safe without using defusedxml

Hanno Böck authored on 21/03/2020 13:37:15
Showing 1 changed files
... ...
@@ -30,7 +30,7 @@ import argparse
30 30
 import sys
31 31
 import json
32 32
 import pathlib
33
-from xml.sax.saxutils import escape
33
+from xml.sax.saxutils import escape  # noqa: DUO107
34 34
 
35 35
 
36 36
 def versioncompare(safe_version, find_version):
Browse code

add ~/.cache/freewvs/ dir option and enforce order of freewvsdb dirs

Hanno Böck authored on 23/12/2019 12:39:03
Showing 1 changed files
... ...
@@ -29,6 +29,7 @@ import re
29 29
 import argparse
30 30
 import sys
31 31
 import json
32
+import pathlib
32 33
 from xml.sax.saxutils import escape
33 34
 
34 35
 
... ...
@@ -80,9 +81,11 @@ for d in ["/usr/share/freewvs", "/usr/local/share/freewvs"]:
80 81
               file=sys.stderr)
81 82
 
82 83
 jdir = False
83
-for p in [os.path.dirname(sys.argv[0]) + '/freewvsdb', '/var/lib/freewvs']:
84
+for p in [os.path.dirname(sys.argv[0]) + '/freewvsdb', '/var/lib/freewvs',
85
+          str(pathlib.Path.home()) + "/.cache/freewvs/"]:
84 86
     if os.path.isdir(p):
85 87
         jdir = p
88
+        break
86 89
 if not jdir:
87 90
     print("Can't find freewvs json db")
88 91
     sys.exit(1)
Browse code

warn people who have old-style freewvsdb-dirs around

Hanno Böck authored on 21/12/2019 18:01:40
Showing 1 changed files
... ...
@@ -72,6 +72,13 @@ parser.add_argument("-3", "--thirdparty", action="store_true",
72 72
                     help="Scan for third-party components like jquery")
73 73
 opts = parser.parse_args()
74 74
 
75
+# Warn people with old-style freewvsdb dirs,
76
+# should be removed in a few months
77
+for d in ["/usr/share/freewvs", "/usr/local/share/freewvs"]:
78
+    if os.path.isdir(d):
79
+        print("WARNING: Obsolete freewvs data in %s, removal recommended" % d,
80
+              file=sys.stderr)
81
+
75 82
 jdir = False
76 83
 for p in [os.path.dirname(sys.argv[0]) + '/freewvsdb', '/var/lib/freewvs']:
77 84
     if os.path.isdir(p):
Browse code

update URL and remove version number from script

Hanno Böck authored on 17/12/2019 15:10:18
Showing 1 changed files
... ...
@@ -1,8 +1,8 @@
1 1
 #!/usr/bin/python3 -O
2 2
 
3
-# freewvs 0.1 - the free web vulnerability scanner
3
+# freewvs - a free web vulnerability scanner
4 4
 #
5
-# https://source.schokokeks.org/freewvs/
5
+# https://freewvs.schokokeks.org/
6 6
 #
7 7
 # Written by schokokeks.org Hosting, https://schokokeks.org
8 8
 #
Browse code

make pylint happier

Hanno Böck authored on 13/12/2019 12:50:42
Showing 1 changed files
... ...
@@ -109,17 +109,19 @@ for fdir in opts.dirs:
109 109
                         mfile = os.path.join(root, filename)
110 110
                         try:
111 111
                             file = open(mfile, errors='replace')
112
-                        except Exception:
112
+                        except IOError:
113 113
                             continue
114 114
                         filestr = file.read()
115 115
                         file.close()
116 116
 
117 117
                         if (('extra_match' in det
118
-                           and det['extra_match'] not in filestr)
119
-                           or ('extra_nomatch' in det
120
-                           and det['extra_nomatch'] in filestr)
121
-                           or ('path_match' in det
122
-                           and not root.endswith(det['path_match']))):
118
+                             and det['extra_match'] not in filestr)
119
+                                or ('extra_nomatch' in det
120
+                                    and det['extra_nomatch'] in filestr)):
121
+                            continue
122
+
123
+                        if ('path_match' in det
124
+                                and (not root.endswith(det['path_match']))):
123 125
                             continue
124 126
 
125 127
                         findversion = re.search(re.escape(det['variable'])
... ...
@@ -137,9 +139,10 @@ for fdir in opts.dirs:
137 139
                                                   + int(det['add_minor']))
138 140
                             findversion = '.'.join(findversion)
139 141
 
140
-                        if (not versioncompare(item['safe'], findversion)
141
-                           or ('old_safe' in item
142
-                           and findversion in item['old_safe'].split(','))):
142
+                        if ((not versioncompare(item['safe'], findversion))
143
+                                or ('old_safe' in item
144
+                                    and findversion in
145
+                                    item['old_safe'].split(','))):
143 146
                             if opts.all:
144 147
                                 vulnprint(item['name'], findversion, "ok", "",
145 148
                                           mfile, det['subdir'], opts.xml)
Browse code

fix add_minor

Hanno Böck authored on 13/12/2019 10:50:50
Showing 1 changed files
... ...
@@ -134,7 +134,7 @@ for fdir in opts.dirs:
134 134
                         if 'add_minor' in det:
135 135
                             findversion = findversion.split('.')
136 136
                             findversion[-1] = str(int(findversion[-1])
137
-                                                  + int(item['add_minor']))
137
+                                                  + int(det['add_minor']))
138 138
                             findversion = '.'.join(findversion)
139 139
 
140 140
                         if (not versioncompare(item['safe'], findversion)
Browse code

switch to json-based freewvsdb

Hanno Böck authored on 11/12/2019 18:39:17
Showing 1 changed files
... ...
@@ -23,13 +23,12 @@
23 23
 # return your changes to the public. We would be especially happy if you tell
24 24
 # us what you're going to do with this code.
25 25
 
26
-import configparser
27
-
28 26
 import os
29 27
 import glob
30 28
 import re
31 29
 import argparse
32 30
 import sys
31
+import json
33 32
 from xml.sax.saxutils import escape
34 33
 
35 34
 
... ...
@@ -73,60 +72,25 @@ parser.add_argument("-3", "--thirdparty", action="store_true",
73 72
                     help="Scan for third-party components like jquery")
74 73
 opts = parser.parse_args()
75 74
 
76
-# Parse vulnerability database
77
-config = configparser.ConfigParser()
78
-try:
79
-    config.read(glob.glob('/usr/share/freewvs/*.freewvs'))
80
-    config.read(glob.glob('/usr/local/share/freewvs/*.freewvs'))
81
-    config.read(glob.glob(os.path.dirname(sys.argv[0])
82
-                          + '/freewvsdb/*.freewvs'))
83
-except configparser.MissingSectionHeaderError as err:
84
-    print("Error parsing config files: %s" % err)
85
-
86
-vdb = []
75
+jdir = False
76
+for p in [os.path.dirname(sys.argv[0]) + '/freewvsdb', '/var/lib/freewvs']:
77
+    if os.path.isdir(p):
78
+        jdir = p
79
+if not jdir:
80
+    print("Can't find freewvs json db")
81
+    sys.exit(1)
82
+
83
+jconfig = []
84
+for cfile in glob.glob(jdir + '/*.json'):
85
+    with open(cfile) as json_file:
86
+        data = json.load(json_file)
87
+        jconfig += data
88
+
87 89
 scanfiles = set()
88
-for sect in config.sections():
89
-    item = {}
90
-
91
-    if (config.getboolean(sect, 'thirdparty', fallback=False)
92
-       and not opts.thirdparty):
93
-        continue
94
-
95
-    # base options
96
-    item['name'] = sect
97
-    item['safe'] = config.get(sect, 'safe')
98
-    item['file'] = config.get(sect, 'file')
99
-    item['vuln'] = config.get(sect, 'vuln')
100
-    item['subdir'] = int(config.get(sect, 'subdir'))
101
-    scanfiles.add(item['file'])
102
-
103
-    # match magic
104
-    item['variable'] = re.compile(re.escape(config.get(sect, 'variable'))
105
-                                  + r"[^0-9\n\r]*[.]*([0-9.]*[0-9])[^0-9.]")
106
-
107
-    # optional options
108
-    if config.has_option(sect, 'extra_match'):
109
-        item['extra_match'] = config.get(sect, 'extra_match')
110
-    else:
111
-        item['extra_match'] = False
112
-    if config.has_option(sect, 'extra_nomatch'):
113
-        item['extra_nomatch'] = config.get(sect, 'extra_nomatch')
114
-    else:
115
-        item['extra_nomatch'] = False
116
-    if config.has_option(sect, 'path_match'):
117
-        item['path_match'] = config.get(sect, 'path_match')
118
-    else:
119
-        item['path_match'] = False
120
-    if config.has_option(sect, 'add_minor'):
121
-        item['add_minor'] = config.get(sect, 'add_minor')
122
-    else:
123
-        item['add_minor'] = False
124
-    if config.has_option(sect, 'old_safe'):
125
-        item['old_safe'] = config.get(sect, 'old_safe').split(",")
126
-    else:
127
-        item['old_safe'] = []
90
+for app in jconfig:
91
+    for det in app['detection']:
92
+        scanfiles.add(det['file'])
128 93
 
129
-    vdb.append(item)
130 94
 
131 95
 if opts.xml:
132 96
     print('<?xml version="1.0" ?>')
... ...
@@ -137,50 +101,58 @@ if opts.xml:
137 101
 for fdir in opts.dirs:
138 102
     for root, NULL, files in os.walk(fdir):
139 103
         for filename in scanfiles.intersection(files):
140
-            for item in vdb:
141
-                if filename == item['file']:
142
-                    mfile = os.path.join(root, filename)
143
-                    try:
144
-                        file = open(mfile, errors='replace')
145
-                    except Exception:
146
-                        continue
147
-                    filestr = file.read()
148
-                    file.close()
149
-
150
-                    if ((item['extra_match']
151
-                       and item['extra_match'] not in filestr)
152
-                       or (item['extra_nomatch']
153
-                       and item['extra_nomatch'] in filestr)
154
-                       or (item['path_match']
155
-                       and not root.endswith(item['path_match']))):
156
-                        continue
157
-
158
-                    findversion = item['variable'].search(filestr)
159
-                    if not findversion:
160
-                        continue
161
-                    findversion = findversion.group(1)
162
-
163
-                    # Very ugly phpbb workaround
164
-                    if item['add_minor']:
165
-                        findversion = findversion.split('.')
166
-                        findversion[-1] = str(int(findversion[-1])
167
-                                              + int(item['add_minor']))
168
-                        findversion = '.'.join(findversion)
169
-
170
-                    if (not versioncompare(item['safe'], findversion)
171
-                       or findversion in item['old_safe']):
172
-                        if opts.all:
173
-                            vulnprint(item['name'], findversion, "ok", "",
174
-                                      mfile, item['subdir'], opts.xml)
175
-                        continue
176
-
177
-                    safev = item['safe']
178
-                    for ver in item['old_safe']:
179
-                        if versioncompare(ver, findversion):
180
-                            safev = ver
181
-
182
-                    vulnprint(item['name'], findversion, safev, item['vuln'],
183
-                              mfile, item['subdir'], opts.xml)
104
+            for item in jconfig:
105
+                if not opts.thirdparty and 'thirdparty' in item:
106
+                    continue
107
+                for det in item['detection']:
108
+                    if filename == det['file']:
109
+                        mfile = os.path.join(root, filename)
110
+                        try:
111
+                            file = open(mfile, errors='replace')
112
+                        except Exception:
113
+                            continue
114
+                        filestr = file.read()
115
+                        file.close()
116
+
117
+                        if (('extra_match' in det
118
+                           and det['extra_match'] not in filestr)
119
+                           or ('extra_nomatch' in det
120
+                           and det['extra_nomatch'] in filestr)
121
+                           or ('path_match' in det
122
+                           and not root.endswith(det['path_match']))):
123
+                            continue
124
+
125
+                        findversion = re.search(re.escape(det['variable'])
126
+                                                + r"[^0-9\n\r]*[.]*"
127
+                                                "([0-9.]*[0-9])[^0-9.]",
128
+                                                filestr)
129
+                        if not findversion:
130
+                            continue
131
+                        findversion = findversion.group(1)
132
+
133
+                        # Very ugly phpbb workaround
134
+                        if 'add_minor' in det:
135
+                            findversion = findversion.split('.')
136
+                            findversion[-1] = str(int(findversion[-1])
137
+                                                  + int(item['add_minor']))
138
+                            findversion = '.'.join(findversion)
139
+
140
+                        if (not versioncompare(item['safe'], findversion)
141
+                           or ('old_safe' in item
142
+                           and findversion in item['old_safe'].split(','))):
143
+                            if opts.all:
144
+                                vulnprint(item['name'], findversion, "ok", "",
145
+                                          mfile, det['subdir'], opts.xml)
146
+                            continue
147
+
148
+                        safev = item['safe']
149
+                        if 'old_safe' in item:
150
+                            for ver in item['old_safe'].split(','):
151
+                                if versioncompare(ver, findversion):
152
+                                    safev = ver
153
+
154
+                        vulnprint(item['name'], findversion, safev,
155
+                                  item['vuln'], mfile, det['subdir'], opts.xml)
184 156
 
185 157
 if opts.xml:
186 158
     print('</freewvs>')
Browse code

fix detection with no safe version

Hanno Böck authored on 10/12/2019 14:24:57
Showing 1 changed files
... ...
@@ -34,6 +34,8 @@ from xml.sax.saxutils import escape
34 34
 
35 35
 
36 36
 def versioncompare(safe_version, find_version):
37
+    if safe_version == "":
38
+        return True
37 39
     safe_version_tup = [int(x) for x in safe_version.split(".")]
38 40
     find_version_tup = [int(x) for x in find_version.split(".")]
39 41
     return find_version_tup < safe_version_tup
Browse code

performance improvement by keeping list of all scanned for files

Hanno Böck authored on 08/12/2019 18:43:47
Showing 1 changed files
... ...
@@ -82,6 +82,7 @@ except configparser.MissingSectionHeaderError as err:
82 82
     print("Error parsing config files: %s" % err)
83 83
 
84 84
 vdb = []
85
+scanfiles = set()
85 86
 for sect in config.sections():
86 87
     item = {}
87 88
 
... ...
@@ -95,6 +96,7 @@ for sect in config.sections():
95 96
     item['file'] = config.get(sect, 'file')
96 97
     item['vuln'] = config.get(sect, 'vuln')
97 98
     item['subdir'] = int(config.get(sect, 'subdir'))
99
+    scanfiles.add(item['file'])
98 100
 
99 101
     # match magic
100 102
     item['variable'] = re.compile(re.escape(config.get(sect, 'variable'))
... ...
@@ -132,7 +134,7 @@ if opts.xml:
132 134
 
133 135
 for fdir in opts.dirs:
134 136
     for root, NULL, files in os.walk(fdir):
135
-        for filename in files:
137
+        for filename in scanfiles.intersection(files):
136 138
             for item in vdb:
137 139
                 if filename == item['file']:
138 140
                     mfile = os.path.join(root, filename)
Browse code

simplify versioncompare logic

Hanno Böck authored on 08/12/2019 18:29:27
Showing 1 changed files
... ...
@@ -34,14 +34,9 @@ from xml.sax.saxutils import escape
34 34
 
35 35
 
36 36
 def versioncompare(safe_version, find_version):
37
-    if safe_version == [""]:
38
-        return True
39
-    for i in range(min(len(find_version), len(safe_version))):
40
-        if int(find_version[i]) < int(safe_version[i]):
41
-            return True
42
-        if int(find_version[i]) > int(safe_version[i]):
43
-            return False
44
-    return len(find_version) < len(safe_version)
37
+    safe_version_tup = [int(x) for x in safe_version.split(".")]
38
+    find_version_tup = [int(x) for x in find_version.split(".")]
39
+    return find_version_tup < safe_version_tup
45 40
 
46 41
 
47 42
 def vulnprint(appname, version, safeversion, vuln, vfilename, subdir,
... ...
@@ -168,27 +163,20 @@ for fdir in opts.dirs:
168 163
                                               + int(item['add_minor']))
169 164
                         findversion = '.'.join(findversion)
170 165
 
171
-                    if not (versioncompare(item['safe'].split('.'),
172
-                            findversion.split('.'))) or \
173
-                            item['old_safe'].count(findversion) > 0:
166
+                    if (not versioncompare(item['safe'], findversion)
167
+                       or findversion in item['old_safe']):
174 168
                         if opts.all:
175
-                            vulnprint(item['name'], findversion,
176
-                                      "ok", "", mfile, item['subdir'],
177
-                                      opts.xml)
178
-                    else:
179
-                        safev = "9999"
180
-                        for ver in item['old_safe']:
181
-                            if(versioncompare(ver.split('.'),
182
-                               findversion.split('.'))
183
-                               and not versioncompare(ver.split('.'),
184
-                               safev.split('.'))):
185
-                                safev = ver
186
-                        if safev == "9999":
187
-                            safev = item['safe']
188
-
189
-                        vulnprint(item['name'], findversion,
190
-                                  safev, item['vuln'],
191
-                                  mfile, item['subdir'], opts.xml)
169
+                            vulnprint(item['name'], findversion, "ok", "",
170
+                                      mfile, item['subdir'], opts.xml)
171
+                        continue
172
+
173
+                    safev = item['safe']
174
+                    for ver in item['old_safe']:
175
+                        if versioncompare(ver, findversion):
176
+                            safev = ver
177
+
178
+                    vulnprint(item['name'], findversion, safev, item['vuln'],
179
+                              mfile, item['subdir'], opts.xml)
192 180
 
193 181
 if opts.xml:
194 182
     print('</freewvs>')
Browse code

argparse instead of deprecated optparse

Hanno Böck authored on 08/12/2019 17:54:06
Showing 1 changed files
... ...
@@ -28,7 +28,7 @@ import configparser
28 28
 import os
29 29
 import glob
30 30
 import re
31
-import optparse
31
+import argparse
32 32
 import sys
33 33
 from xml.sax.saxutils import escape
34 34
 
... ...
@@ -45,12 +45,12 @@ def versioncompare(safe_version, find_version):
45 45
 
46 46
 
47 47
 def vulnprint(appname, version, safeversion, vuln, vfilename, subdir,
48
-              style=None):
48
+              xml):
49 49
     appdir = '/'.join(os.path.abspath(vfilename).split('/')[:-1 - subdir])
50
-    if not style:
50
+    if not xml:
51 51
         print("%(appname)s %(version)s (%(safeversion)s) %(vuln)s "
52 52
               "%(appdir)s" % vars())
53
-    elif style == 'xml':
53
+    else:
54 54
         state = 'vulnerable'
55 55
         if safeversion == 'ok':
56 56
             state = 'ok'
... ...
@@ -65,15 +65,16 @@ def vulnprint(appname, version, safeversion, vuln, vfilename, subdir,
65 65
 
66 66
 
67 67
 # Command-line options
68
-parser = optparse.OptionParser(usage="usage: %prog [options] <path>"
69
-                               "[<path2> ...]")
70
-parser.add_option("-a", "--all", action="store_true", dest="ALL",
71
-                  help="Show all webapps found, not just vulnerable")
72
-parser.add_option("-x", "--xml", action="store_const", dest="OUTPUT",
73
-                  const="xml", help="Output results as XML")
74
-parser.add_option("-3", "--thirdparty", action="store_true", dest="THIRDPARTY",
75
-                  help="Scan for third-party components like jquery")
76
-opts, args = parser.parse_args()
68
+parser = argparse.ArgumentParser()
69
+parser.add_argument("dirs", nargs="*",
70
+                    help="Directories to scan")
71
+parser.add_argument("-a", "--all", action="store_true",
72
+                    help="Show all webapps found, not just vulnerable")
73
+parser.add_argument("-x", "--xml", action="store_true",
74
+                    help="Output results as XML")
75
+parser.add_argument("-3", "--thirdparty", action="store_true",
76
+                    help="Scan for third-party components like jquery")
77
+opts = parser.parse_args()
77 78
 
78 79
 # Parse vulnerability database
79 80
 config = configparser.ConfigParser()
... ...
@@ -90,7 +91,7 @@ for sect in config.sections():
90 91
     item = {}
91 92
 
92 93
     if (config.getboolean(sect, 'thirdparty', fallback=False)
93
-       and not opts.THIRDPARTY):
94
+       and not opts.thirdparty):
94 95
         continue
95 96
 
96 97
     # base options
... ...
@@ -128,13 +129,13 @@ for sect in config.sections():
128 129
 
129 130
     vdb.append(item)
130 131
 
131
-if opts.OUTPUT == 'xml':
132
+if opts.xml:
132 133
     print('<?xml version="1.0" ?>')
133 134
     print('<freewvs>')
134 135
 
135 136
 # start the search
136 137
 
137
-for fdir in args:
138
+for fdir in opts.dirs:
138 139
     for root, NULL, files in os.walk(fdir):
139 140
         for filename in files:
140 141
             for item in vdb:
... ...
@@ -170,10 +171,10 @@ for fdir in args:
170 171
                     if not (versioncompare(item['safe'].split('.'),
171 172
                             findversion.split('.'))) or \
172 173
                             item['old_safe'].count(findversion) > 0:
173
-                        if opts.ALL:
174
+                        if opts.all:
174 175
                             vulnprint(item['name'], findversion,
175 176
                                       "ok", "", mfile, item['subdir'],
176
-                                      opts.OUTPUT)
177
+                                      opts.xml)
177 178
                     else:
178 179
                         safev = "9999"
179 180
                         for ver in item['old_safe']:
... ...
@@ -187,7 +188,7 @@ for fdir in args:
187 188
 
188 189
                         vulnprint(item['name'], findversion,
189 190
                                   safev, item['vuln'],
190
-                                  mfile, item['subdir'], opts.OUTPUT)
191
+                                  mfile, item['subdir'], opts.xml)
191 192
 
192
-if opts.OUTPUT == 'xml':
193
+if opts.xml:
193 194
     print('</freewvs>')
Browse code

simplify radically by removing fancy output, gettext and debug output

Hanno Böck authored on 08/12/2019 17:44:09
Showing 1 changed files
... ...
@@ -27,16 +27,11 @@ import configparser
27 27
 
28 28
 import os
29 29
 import glob
30
-import pprint
31 30
 import re
32 31
 import optparse
33 32
 import sys
34
-import gettext
35 33
 from xml.sax.saxutils import escape
36 34
 
37
-gettext.textdomain('freewvs')
38
-_ = gettext.gettext
39
-
40 35
 
41 36
 def versioncompare(safe_version, find_version):
42 37
     if safe_version == [""]:
... ...
@@ -55,23 +50,6 @@ def vulnprint(appname, version, safeversion, vuln, vfilename, subdir,
55 50
     if not style:
56 51