Commit a16baab6 authored by Alexandre Dulaunoy's avatar Alexandre Dulaunoy
Browse files

Merge pull request #92 from chervaliery/master

Add MS-Bulletin
parents d5d23bcc ecd35b96
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ vFeed: http://www.toolswatch.org/vfeed/vfeed.db.tgz
vFeedStatus: http://www.toolswatch.org/update.dat
Vendor: https://nvd.nist.gov/download/vendorstatements.xml
CAPEC: http://capec.mitre.org/data/xml/capec_v2.6.xml
MSBULLETIN: http://download.microsoft.com/download/6/7/3/673E4349-1CA5-40B9-8879-095C72D5B49D/BulletinSearch.xls
Ref: https://cve.mitre.org/data/refs/refmap/allrefmaps.zip
[Webserver]
Host: 127.0.0.1
+5 −0
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ class Configuration():
               'd2sec': "http://www.d2sec.com/exploits/elliot.xml",
               'vendor': "https://nvd.nist.gov/download/vendorstatements.xml",
               'capec': "http://capec.mitre.org/data/xml/capec_v2.6.xml",
               'msbulletin': "http://download.microsoft.com/download/6/7/3/673E4349-1CA5-40B9-8879-095C72D5B49D/BulletinSearch.xls",
               'ref': "https://cve.mitre.org/data/refs/refmap/allrefmaps.zip",
               'logging': True,           'logfile': "../log/cve-search.log",
               'maxLogSize': '100MB',     'backlog': 5,
@@ -206,6 +207,10 @@ class Configuration():
    @classmethod
    def getCAPECDict(cls):
        return cls.readSetting("Sources", "CAPEC", cls.default['capec'])

    @classmethod
    def getMSBULLETINDict(cls):
        return cls.readSetting("Sources", "MSBULLETIN", cls.default['msbulletin'])
    # Logging

    @classmethod
+1 −0
Original line number Diff line number Diff line
@@ -7,5 +7,6 @@ flask-login
flask-pymongo
tornado
passlib
xlrd
https://github.com/marianoguerra/feedformatter/archive/master.zip
six>=1.9.0

sbin/db_mgmt_ms.py

0 → 100644
+99 −0
Original line number Diff line number Diff line
#!/usr/bin/env python3
# coding=utf-8

import os
import sys
import xlrd, datetime
import shutil
runPath = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(runPath, ".."))

from lib.Config import Configuration

bulletinurl = "https://technet.microsoft.com/library/security/"

def minimalist_xldate_as_datetime(xldate, datemode):
    # datemode: 0 for 1900-based, 1 for 1904-based
    return (
        datetime.datetime(1899, 12, 30)
        + datetime.timedelta(days=xldate + 1462 * datemode)
        )

# dictionary
msbulletinurl = Configuration.getMSBULLETINDict()

# connect to db
db = Configuration.getMongoConnection()
msbulletin = db.ms
info = db.info

try:
    f = Configuration.getFile(msbulletinurl)
except:
    sys.exit("Cannot open url %s. Bad URL or not connected to the internet?"%(msbulletinurl))

# check modification date
i = info.find_one({'db': 'ms'})
if i is not None:
    if f.headers['last-modified'] == i['last-modified']:
        print("Not modified")
        sys.exit(0)

if not os.path.exists('./tmp'):
    os.mkdir('./tmp')
with open('./tmp/BulletinSearch.xls', 'wb') as fp:
    shutil.copyfileobj(f, fp)
     
# parse xlsx and store in database
wb = xlrd.open_workbook('./tmp/BulletinSearch.xls')
sh = wb.sheet_by_name('Bulletin Search')
header = [s.replace('\n', ' ') for s in sh.row_values(0)]
bulletin = {}
software = {}
prev_id = ""

for rownum in range(sh.nrows-1):    
    row =  sh.row_values(rownum + 1)
    if row[1] == prev_id:
        software = {}
        software['product'] = row[6]
        software['KB'] = str(row[7]).strip('.0')
        software['component'] = row[8]
        software['impact'] = row[9]
        software['severity'] = row[10]        
        software['replace_id'] = row[11][:8]
        software['replace_bk'] = row[11][9:-1]
        software['reeboot'] = row[12]
        bulletin['software'].append(software)
    else:
        if bulletin :
            msbulletin.update({'id': bulletin['id']}, {'$set': bulletin}, upsert=True)
        bulletin = {}
        software = {}
        bulletin['Published'] = minimalist_xldate_as_datetime(row[0], 0).isoformat()
        bulletin['id'] = row[1]
        bulletin['KB'] = str(row[2]).strip('.0')
        bulletin['severity'] = row[3]
        bulletin['impact'] = row[4]
        bulletin['title'] = row[5]
        software['product'] = row[6]
        software['KB'] = str(row[7]).strip('.0')
        software['component'] = row[8]
        software['impact'] = row[9]
        software['severity'] = row[10]
        software['replace_id'] = row[11][:8]
        software['replace_bk'] = row[11][9:-1]
        software['reeboot'] = row[12]
        bulletin['CVE'] = row[13].split(',')
        bulletin['software'] = [software]
        bulletin['url'] = bulletinurl + row[1].lower()
        
        prev_id = row[1]

#update database info after successful program-run
info.update({'db': 'ms'}, {"$set": {'last-modified': f.headers['last-modified']}}, upsert=True)
shutil.rmtree('./tmp')



+3 −1
Original line number Diff line number Diff line
@@ -40,7 +40,9 @@ sources = [{'name': "cves",
           {'name': 'redis-cache-cpe',
            'updater': "python3 " + os.path.join(runPath, "db_cpe_browser.py")},
           {'name': 'd2sec',
            'updater': "python3 " + os.path.join(runPath, "db_mgmt_d2sec.py")}]
            'updater': "python3 " + os.path.join(runPath, "db_mgmt_d2sec.py")},
           {'name': 'ms',
            'updater': "python3 " + os.path.join(runPath, "db_mgmt_ms.py")}]
posts = [{'name': "ensureindex",
          'updater': "python3 " + os.path.join(runPath, "db_mgmt_create_index.py")}]