diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a81c8ee --- /dev/null +++ b/.gitignore @@ -0,0 +1,138 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..15c0e6c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +# To build the container +# docker build -t [container-name] . +# To run the container +# docker run --rm -it [container-name] + +FROM debian:stretch-20210721-slim + +WORKDIR /exploit-suggester + +COPY requirements.txt . +COPY windows-exploit-suggester.py . + +RUN apt update -y +RUN apt install -y python3 \ + python3-xlrd \ + apt-utils \ + python-pip \ + nano \ + vim + +RUN pip install -r requirements.txt +ENTRYPOINT ["/bin/bash"] diff --git a/README.md b/README.md index e3b5148..6b8b5df 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,28 @@ It was heavily inspired by Linux_Exploit_Suggester by Pentura. Blog Post: "Introducing Windows Exploit Suggester", https://blog.gdssecurity.com/labs/2014/7/11/introducing-windows-exploit-suggester.html +INSTALLATION +============ + +For easy docker usage scroll below. + +Dependencies: install dependencies `virtualenv`,`python3-xlrd`, `pip install xlrd==1.2.0`, + +Run the `setup.sh` +``` +$ chmod +x setup.sh +$ ./setup.sh +``` + USAGE ===== -update the database + +1. Activate the virtualenvironment +``` +$ . ./venv/bin/activate +``` + +2. Update the database ``` $ ./windows-exploit-suggester.py --update [*] initiating... @@ -37,11 +56,8 @@ $ ./windows-exploit-suggester.py --update [+] writing to file 2014-06-06-mssb.xlsx [*] done ``` -install dependencies - -(install python-xlrd, $ pip install xlrd --upgrade) -feed it "systeminfo" input, and point it to the microsoft database +3. Feed it "systeminfo" input, and point it to the microsoft database ``` $ ./windows-exploit-suggester.py --database 2014-06-06-mssb.xlsx --systeminfo win7sp1-systeminfo.txt [*] initiating... @@ -87,6 +103,47 @@ $ ./windows-exploit-suggester.py --database 2014-06-06-mssb.xlsx --ostext 'windo [M] MS09-072: Cumulative Security Update for Internet Explorer (976325) - Critical ``` +BUILD FROM DOCKER +================= + +``` +docker build -t windows-exploit-suggester . +``` + +INSTALLATION FROM DOCKERHUB +=========================== + +[Dockerhub Project](https://hub.docker.com/r/gr33nm0nk2802/windows-exploit-suggester) + +``` +docker pull gr33nm0nk2802/windows-exploit-suggester +docker tag gr33nm0nk2802/windows-exploit-suggester windows-exploit-suggester +``` + + +USAGE +====== + +1. Run the Exploit Suggester from interactive terminal + +``` +docker run --rm -it windows-exploit-suggester +``` + +2. Inside the interactive terminal save the output of `systeminfo` command into a text file using `nano` or `vim` + +3. Update the exploit database + +``` +./windows-exploit-suggester.py +``` + +3. Use the exploit database-file and the systeminfo details files with the container. + +``` +./windows-exploit-suggester.py --database [database-file].xls --systeminfo [systeminfo-file].txt +``` + LIMITATIONS =========== Currently, if the 'systeminfo' command reveals 'File 1' as the output for diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..bd208ae --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +xlrd==1.2.0 diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..7144088 --- /dev/null +++ b/setup.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# To update the repositories for python3 +sudo apt update -y +sudo apt install -y python3-xlrd virtualenv + +# Creating and installing pip3 dependencies inside venv +virtualenv venv +source venv/bin/activate +pip install -r requirements.txt + + diff --git a/windows-exploit-suggester.py b/windows-exploit-suggester.py index 108c1b6..89e3121 100755 --- a/windows-exploit-suggester.py +++ b/windows-exploit-suggester.py @@ -1,13 +1,14 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Windows Exploit Suggester -# revision 3.3, 2017-02-13 +# revision 4.0, 2021-08-10 # # author: Sam Bertram, Gotham Digital Science # contact: labs@gdssecurity.com,sbertram@gdssecurity.com,sammbertram@gmail.com # blog post: "Introducing Windows Exploit Suggester", http://blog.gdssecurity.com/ -# +# Modified by: gr33nm0nk2802 +# # DESCRIPTION # # This tool compares a targets patch levels against the Microsoft vulnerability @@ -49,7 +50,6 @@ # # install dependencies # -# (install python-xlrd, $ pip install xlrd --upgrade) # # feed it "systeminfo" input, and point it to the microsoft database # @@ -327,10 +327,10 @@ import argparse import subprocess import csv -import StringIO +from io import StringIO import os import datetime -import urllib2 +import urllib.request import io from random import randint from time import sleep @@ -387,7 +387,7 @@ def main(): try: dbfile = open(ARGS.database, 'r') - except IOError, e: + except IOError as e: ALERT("could not open the file %s" % filename, ALERT.BAD) exit(1) @@ -425,13 +425,13 @@ def main(): data = '' # loop through xls - for rownum in xrange(sh.nrows): + for rownum in range(sh.nrows): values = sh.row_values(rownum) # loop through row values, and process input for i in range(len(values)): - values[i] = unicode(values[i]).encode('utf8') + values[i] = str(values[i]) values[i] = values[i].replace('\n',' ') values[i] = values[i].replace(',','') values[i] = values[i].replace('.0','') @@ -662,7 +662,7 @@ def run(database): # get the potential bulletins try: - for row in csv.reader(StringIO.StringIO(database)): + for row in csv.reader(StringIO(database)): bulletinid=row[1] affected=row[6] @@ -676,7 +676,7 @@ def run(database): if ARGS.verbose: ALERT("%s has been added to potential list '%s'" % (bulletinid, affected)) - except csv.Error, e: + except csv.Error as e: ALERT('could not parse database file, make sure it is in the proper format', ALERT.BAD) exit(1) @@ -705,7 +705,7 @@ def run(database): ALERT(" %s hotfix triggered a removal of %skb and the %s bulletin; componentkb is %s" % (hotfix,kb,bulletinid,componentkb)) # get the linked ms, this will automatically calculate the superseded by as well - linkedms = getlinkedms([bulletinid], csv.reader(StringIO.StringIO(database))) + linkedms = getlinkedms([bulletinid], csv.reader(StringIO(database))) linkedmsstr = '' # calculate the pretty string, only care when verbose @@ -735,7 +735,7 @@ def run(database): if bulletinid in bulletinids and not "elevation of privilege" in impact.lower(): - remove = getlinkedms([bulletinid], csv.reader(StringIO.StringIO(database))) + remove = getlinkedms([bulletinid], csv.reader(StringIO(database))) if ARGS.verbose: ALERT(" removing %s (total of %s MS ids), because of its impact %s" % (bulletinid, len(remove), impact)) @@ -752,7 +752,7 @@ def run(database): if bulletinid in bulletinids and not "remote code execution" in impact.lower(): - remove = getlinkedms([bulletinid], csv.reader(StringIO.StringIO(database))) + remove = getlinkedms([bulletinid], csv.reader(StringIO(database))) if ARGS.verbose: ALERT(" removing %s (total of %s MS ids), because of its impact %s" % (bulletinid, len(remove), impact)) @@ -830,7 +830,7 @@ def run(database): if ARGS.sub: # linked ms, the children of this msid - linked = set(getlinkedms([msid], csv.reader(StringIO.StringIO(database)))) + linked = set(getlinkedms([msid], csv.reader(StringIO(database)))) linked = linked.intersection(msids) # loop through the linked msids, and only display those that qualify and @@ -844,7 +844,7 @@ def run(database): ALERT("|_%s: %s (%s) - %s" % (lmsid, vulns[lmsid][0], vulns[lmsid][1], vulns[lmsid][2]), lalert) # only allow duplicate events to be displayed when command-line args passed - if not ARGS.duplicates: alerted.add(lmsid) + if not ARGS.duplicates: alerted.add(lmsid) # end run() @@ -871,7 +871,7 @@ def trace(database): ALERT("searching for bulletin id %s" % bulletinid) # get linked msids - lmsids = getlinkedms([bulletinid], csv.reader(StringIO.StringIO(database))) + lmsids = getlinkedms([bulletinid], csv.reader(StringIO(database))) msids = [] @@ -895,7 +895,7 @@ def trace(database): exit(1) # get linked msids, loop through the row - for row in csv.reader(StringIO.StringIO(database)): + for row in csv.reader(StringIO(database)): msid = row[1] affected = row[6] @@ -920,7 +920,7 @@ def patches(database): ALERT("searching all kb's for bulletin id %s" % bulletinid) # get linked msids, loop through the row - for row in csv.reader(StringIO.StringIO(database)): + for row in csv.reader(StringIO(database)): bulletinkb=row[2] componentkb=row[7] @@ -1530,7 +1530,7 @@ def update(): csvFile = '%s.%s' % (filenames, 'csv') # url request opener with user-agent - opener = urllib2.build_opener() + opener = urllib.request.build_opener() opener.addheaders = [('User-agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36')] # grab the new data from ms and scrape the site @@ -1564,7 +1564,7 @@ def update(): try: #sleep(randint(1,3)) response = opener.open(bulletinUrl) - except urllib2.URLError, e: + except urllib.request.URLError as e: ALERT("error getting ms sb url %s" % bulletinUrl, ALERT.BAD) exit(1) @@ -1581,7 +1581,7 @@ class ALERT(object): def __init__(self, message, level=0, ansi=True): # default to ansi alerting, if it's detected as windows platform then disable - if platform.system() is "Windows": ansi = False + if platform.system() == "Windows": ansi = False good = '[+]' bad = '[-]' @@ -1591,20 +1591,20 @@ def __init__(self, message, level=0, ansi=True): exploit = '[E]' if ansi == True: - if level == ALERT.GOOD: print("%s%s%s" % ('\033[1;32m',good,"\033[0;0m")), - elif level == ALERT.BAD: print("%s%s%s" % ('\033[1;31m',bad,"\033[0;0m")), - elif level == ALERT.MSF: print("%s%s%s" % ('\033[1;32m',msf,"\033[0;0m")), - elif level == ALERT.EXP: print("%s%s%s" % ('\033[1;32m',exploit,"\033[0;0m")), - else: print("%s%s%s" % ('\033[1;34m',normal,"\033[0;0m")), + if level == ALERT.GOOD: print("%s%s%s" % ('\033[1;32m',good,"\033[0;0m"), end=''), + elif level == ALERT.BAD: print("%s%s%s" % ('\033[1;31m',bad,"\033[0;0m"), end=''), + elif level == ALERT.MSF: print("%s%s%s" % ('\033[1;32m',msf,"\033[0;0m"), end=''), + elif level == ALERT.EXP: print("%s%s%s" % ('\033[1;32m',exploit,"\033[0;0m"), end=''), + else: print("%s%s%s" % ('\033[1;34m',normal,"\033[0;0m"), end=''), else: - if level == ALERT.GOOD: print('%s' % good), - elif level == ALERT.BAD: print('%s' % bad), - elif level == ALERT.MSF: print('%s' % msf), - elif level == ALERT.EXP: print('%s' % exploit), - else: print('%s' % normal), + if level == ALERT.GOOD: print('%s' % good, end=''), + elif level == ALERT.BAD: print('%s' % bad, end=''), + elif level == ALERT.MSF: print('%s' % msf, end=''), + elif level == ALERT.EXP: print('%s' % exploit, end=''), + else: print('%s' % normal, end=''), - print message + print (message) @staticmethod @property