apt-sec.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931
  1. #!/usr/bin/python3
  2. ## Based on the perl code of Trustminer by CASED
  3. ## Nikos
  4. import sys
  5. import os
  6. from pymongo import MongoClient
  7. #mongodb assumes database at default path
  8. import logging, sys
  9. import configparser
  10. import json
  11. import csv
  12. import urllib.request
  13. import datetime
  14. import debian_advisory as da
  15. import cveparse as cv
  16. import matplotlib.pyplot as plt
  17. import numpy as np
  18. from dateutil import parser
  19. import plotly.plotly as py
  20. import plotly.graph_objs as go
  21. import lstm_reg as lstm
  22. import metadata as meta
  23. import deps
  24. import psycopg2
  25. logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
  26. ## Increase the recursion limit by much to allow bs to parse large files
  27. ## This is not good practise
  28. sys.setrecursionlimit(6000)
  29. #load config file as library
  30. config = configparser.ConfigParser()
  31. config.read('config_test')
  32. if config.sections == []:
  33. print('configuration file not found\n')
  34. sys.exit(1)
  35. #global variables
  36. secperday = 60*60*24
  37. now = datetime.datetime.now()
  38. verbosity = 1
  39. ###############################################################################
  40. ## logging
  41. # 1 fatal errors
  42. # 2 errors
  43. # 3 note
  44. # 4 trace
  45. # 5 debug
  46. def msg(lvl,msg):
  47. if lvl <= int(config['LOG']['loglevel']):
  48. print(msg)
  49. def debug(msg):
  50. msg(5, msg)
  51. # Need to see if this is necessary
  52. ## load state, different from DBs in that we always need it
  53. def load_state():
  54. cache = config['DIR']['cache_dir'] + 'state'
  55. err = 0
  56. state = dict()
  57. try:
  58. with open(cache) as json_data:
  59. state = json.load(json_data)
  60. except FileNotFoundError:
  61. # Load default state - start from the beginning
  62. state['cache_dir'] = cache
  63. state['next_adv'] = 0
  64. state['next_fsa'] = 0
  65. state['Packages'] = ''
  66. state['Sources'] = ''
  67. state['Sha1Sums'] = ''
  68. err += 1
  69. return (state, err)
  70. ###############################################################################
  71. ## save state, different from DBs in that we always need it
  72. def save_state(state):
  73. cache = config['DIR']['cache_dir'] + 'state'
  74. try:
  75. with open(cache, 'w') as fp:
  76. json.dump(state, fp)
  77. except IOError:
  78. print('write cache state failed!! Fatal error')
  79. sys.exit(1)
  80. ###############################################################################
  81. ## load sha lists :TODO later
  82. def load_sha1lists():
  83. cache = config['DIR']['cache_dir'] + 'state'
  84. ###############################################################################
  85. ## save sha lists :TODO later
  86. def save_sha1lists():
  87. pass
  88. ###############################################################################
  89. ## load from files
  90. def load_DBs():
  91. dsatable = dict()
  92. src2dsa = dict()
  93. dsa2cve = dict()
  94. cvetable = dict()
  95. src2month = dict()
  96. src2sloccount = dict()
  97. src2pop = dict()
  98. src2deps = dict()
  99. cache = config['DIR']['cache_dir']
  100. cache_dsatable = cache + 'dsatable'
  101. try:
  102. with open(cache_dsatable) as fp:
  103. dsatable = json.load(fp)
  104. except (IOError, ValueError):
  105. print('read cache dsatable failed!! Maybe first run of the system?')
  106. cache_src2dsa = cache + 'src2dsa'
  107. try:
  108. with open(cache_src2dsa) as fp:
  109. src2dsa = json.load(fp)
  110. except (IOError, ValueError):
  111. print('read cache src2dsa failed!! Maybe first run of the system?')
  112. cache_dsa2cve = cache + 'dsa2cve'
  113. try:
  114. with open(cache_dsa2cve) as fp:
  115. dsa2cve = json.load(fp)
  116. except (IOError, ValueError):
  117. print('read cache dsa2cve failed!! Maybe first run of the system?')
  118. cache_cvetable = cache + 'cvetable'
  119. try:
  120. with open(cache_cvetable) as fp:
  121. cvetable = json.load(fp)
  122. except (IOError, ValueError):
  123. print('read cache cvetable failed!! Maybe first run of the system?')
  124. cache_src2deps = cache + 'src2deps'
  125. try:
  126. with open(cache_src2deps) as fp:
  127. src2deps = json.load(fp)
  128. except (IOError, ValueError):
  129. print('read cache src2deps failed!! Maybe first run of the system?')
  130. cache_src2month = cache + 'src2month'
  131. try:
  132. with open(cache_src2month) as fp:
  133. src2month = json.load(fp)
  134. except (IOError, ValueError):
  135. print('read cache src2month failed!! Maybe first run of the system?')
  136. cache_src2sloccount = cache + 'src2sloccount'
  137. try:
  138. with open(cache_src2sloccount) as fp:
  139. src2sloccount = json.load(fp)
  140. except (IOError, ValueError):
  141. print('read cache src2sloccount failed!! Maybe first run of the system?')
  142. cache_src2pop = cache + 'src2pop'
  143. try:
  144. with open(cache_src2pop) as fp:
  145. src2pop = json.load(fp)
  146. except (IOError, ValueError):
  147. print('read cache src2pop failed!! Maybe first run of the system?')
  148. return(dsatable, src2dsa, dsa2cve, cvetable, src2month, src2sloccount, src2pop, src2deps)
  149. ###############################################################################
  150. ## help for save_DBs
  151. def myconverter(o):
  152. if isinstance(o, datetime.datetime) or isinstance(o, datetime.timedelta):
  153. return str(o)
  154. if isinstance(o, np.float):
  155. return o.astype(int)
  156. ###############################################################################
  157. ## save to files
  158. def save_DBs(dsatable, src2dsa, dsa2cve, cvetable, src2month, src2sloccount, src2pop, src2deps):
  159. cache = config['DIR']['cache_dir']
  160. cache_dsatable = cache + 'dsatable'
  161. try:
  162. with open(cache_dsatable, 'w') as fp:
  163. json.dump(dsatable, fp, default = myconverter)
  164. except IOError:
  165. print('write cache dsatable failed!! Fatal error')
  166. sys.exit(1)
  167. cache_src2dsa = cache + 'src2dsa'
  168. try:
  169. with open(cache_src2dsa, 'w') as fp:
  170. json.dump(src2dsa, fp)
  171. except IOError:
  172. print('write cache src2dsa failed!! Fatal error')
  173. sys.exit(1)
  174. cache_dsa2cve = cache + 'dsa2cve'
  175. try:
  176. with open(cache_dsa2cve, 'w') as fp:
  177. json.dump(dsa2cve, fp)
  178. except IOError:
  179. print('write cache dsa2cve failed!! Fatal error')
  180. sys.exit(1)
  181. cache_cvetable = cache + 'cvetable'
  182. try:
  183. with open(cache_cvetable, 'w') as fp:
  184. json.dump(cvetable, fp, default = myconverter)
  185. except IOError:
  186. print('write cache cvetable failed!! Fatal error')
  187. sys.exit(1)
  188. cache_src2sloccount = cache + 'src2sloccount'
  189. try:
  190. with open(cache_src2sloccount, 'w') as fp:
  191. json.dump(src2sloccount, fp, default = myconverter)
  192. except IOError:
  193. print('write cache src2sloccount failed!! Fatal error')
  194. sys.exit(1)
  195. cache_src2pop = cache + 'src2pop'
  196. try:
  197. with open(cache_src2pop, 'w') as fp:
  198. json.dump(src2pop, fp, default = myconverter)
  199. except IOError:
  200. print('write cache src2pop failed!! Fatal error')
  201. sys.exit(1)
  202. cache_src2deps = cache + 'src2deps'
  203. try:
  204. with open(cache_src2deps, 'w') as fp:
  205. json.dump(src2deps, fp, default = myconverter)
  206. except IOError:
  207. print('write cache src2deps failed!! Fatal error')
  208. sys.exit(1)
  209. cache_src2month = cache + 'src2month'
  210. int_list = dict()
  211. for element in src2month:
  212. for i in range(len(src2month[element])):
  213. if element in int_list:
  214. int_list[element].append(int(src2month[element][i]))
  215. else:
  216. int_list[element] = []
  217. int_list[element].append(int(src2month[element][i]))
  218. try:
  219. with open(cache_src2month, 'w') as fp:
  220. json.dump(int_list, fp, default = myconverter)
  221. except IOError:
  222. print('write cache src2month failed!! Fatal error')
  223. sys.exit(1)
  224. ###############################################################################
  225. ## Fetch current Packages, Sources and sha1sums files
  226. ## These are needed to find CVE stats by sha1sums/pkg-names
  227. ## Only Sha1Sums is custom generated, others are from Debian.
  228. ## FIXME: Server might do on-the-fly gzip (but should not for bzip2)
  229. ## Return: 1 on success, to signal that new parsing is needed.
  230. def fetchMeta(filename):
  231. urlbase = config['URL']['pkg_base_url']
  232. mydir = config['DIR']['cache_dir']
  233. bzFile = filename + '.bz2'
  234. url = urlbase + bzFile
  235. logging.info('Checking meta file from ' + url + '\n')
  236. # Download file
  237. urllib.request.urlretrieve(url, mydir + bzfile)
  238. # TODO catch exceptions like file not found
  239. # TODO check if file has changed, if it is new unpack
  240. ###############################################################################
  241. # Sources and Packages are not completely consistent, esp for debian-multimedia
  242. # He we store manual mappings for these..
  243. def addOrphanPkgs(pkg2src):
  244. pkg2src['liblame-dev'] = "lame";
  245. pkg2src['lame-extras'] = "lame";
  246. pkg2src['moonlight'] = "moon";
  247. pkg2src['libmoon0'] = "moon";
  248. pkg2src['xmms-mp4'] = "xmms2";
  249. pkg2src['xmms-mp4'] = "xmms2";
  250. pkg2src['lazarus-src-0.9.30'] = "lazarus";
  251. pkg2src['lazarus-ide-0.9.30'] = "lazarus";
  252. pkg2src['lcl-qt4-0.9.30'] = "lazarus";
  253. pkg2src['lazarus-ide-qt4-0.9.30'] = "lazarus";
  254. pkg2src['lcl-gtk2-0.9.30'] = "lazarus";
  255. pkg2src['lazarus-ide-gtk2-0.9.30'] = "lazarus";
  256. pkg2src['lcl-units-0.9.30'] = "lazarus";
  257. pkg2src['lazarus-0.9.30'] = "lazarus";
  258. pkg2src['lazarus-doc-0.9.30'] = "lazarus";
  259. pkg2src['lcl-0.9.30'] = "lazarus";
  260. pkg2src['lcl-utils-0.9.30'] = "lazarus";
  261. pkg2src['lcl-nogui-0.9.30'] = "lazarus";
  262. pkg2src['libx264-65'] = "x264";
  263. pkg2src['libx264-114'] = "x264";
  264. pkg2src['libx264-60'] = "x264";
  265. # pkg2src['libmlt3']
  266. # pkg2src['libgmerlin-avdec0']
  267. # pkg2src['libxul-dev']
  268. # pkg2src['libmyth-0.23.1-0']
  269. # pkg2src['libmpeg3hv']
  270. # pkg2src['libquicktimehv']
  271. # pkg2src['libxul0d']
  272. # pkg2src['acroread-fonts-kor']
  273. ###############################################################################
  274. ## Parse dpkg Packages file, create map deb-name->pkg-name
  275. def parsePackages(pkgfile):
  276. mydir = cache = config['DIR']['cache_dir']
  277. deb2pkg = dict()
  278. pkg2virt = dict()
  279. virt2pkg = ()
  280. logging.info('Parsing Packages file...\n')
  281. pkgfile = mydir + pkgfile
  282. #TODO open and parse pkg file
  283. ###############################################################################
  284. ## Parse dpkg Sources file, create map pkg-name->src-name
  285. def parseSources(srcfile):
  286. mydir = cache = config['DIR']['cache_dir']
  287. checklinecont = 0
  288. pkg2src = dict()
  289. logging.info('Parsing Sources file...\n')
  290. srcfile = mydir + srcfile
  291. #TODO open and parse sources file
  292. ###############################################################################
  293. def getSHA1(myhash, collection):
  294. return collection.find({"hash": myhash})
  295. ###############################################################################
  296. def addSHA1(myhash, deb, src):
  297. dic = getSHA1(myhash)
  298. thash = dic["hash"]
  299. tdeb = dic["deb"]
  300. tsrc = dic["src"]
  301. #TODO insert SHA to database
  302. ###############################################################################
  303. ## Parse Sha1Sums file. Format: "sha1sum::deb-name::unix-file-path"
  304. ## Create 2 maps: sha1sum->file, file->deb-name
  305. def parseSha1Sums(sha1file):
  306. pass
  307. ###############################################################################
  308. ## Parse local dpkg status, return list of debs
  309. def parseStatus(stsfile):
  310. pass
  311. ###############################################################################
  312. ## Parse Advisory (only Debian supported atm
  313. def parseAdvisory(adv):
  314. if state['vendor'] == 'debian':
  315. return da.parseDSAhtml(adv)
  316. else:
  317. print('Unsupported distribution. We only support Debian at the moment')
  318. system.exit(1)
  319. ###############################################################################
  320. ## Manually fix problems with Advisory entries
  321. def fixAdvisoryQuirks(arg, state, dsastats):
  322. if state['vendor'] == 'debian':
  323. return da.fixDSAquirks(arg, dsastats)
  324. else:
  325. print('Unsupported distribution. We only support Debian at the moment')
  326. system.exit(1)
  327. ###############################################################################
  328. ## Extract CVE ids from new advisories and print URL for mirror script
  329. def printCVEs(myid,adv, state):
  330. logging.info('Looking for CVEs in advisory...\n')
  331. dsastats = parseAdvisory(adv)
  332. if dsastats == []:
  333. return
  334. ## fix DSAs that don't contain correct CVE refs
  335. dsastats = fixAdvisoryQuirks(myid, state, dsastats);
  336. #TODO Fix this part
  337. ##for cve_id in dsastats
  338. ###############################################################################
  339. ## Update internal vuln. DB with new Advisory info
  340. ## Creates CVEtable for MTBF computation:
  341. ## ( cve-id => (date, delay, score1, score2, score3))
  342. def updateCVETables(myid, dsatable, state, src2dsa, dsa2cve, cvetable, client):
  343. logging.info('Updating vulnerability database with advisory ' + state['vendor'] + str(myid) + ' \n')
  344. adv = dsatable[myid]
  345. dsastats = parseAdvisory(adv)
  346. if dsastats == []:
  347. return
  348. dsastats = fixAdvisoryQuirks(myid, state, dsastats)
  349. for srcpkg in dsastats[0]:
  350. if srcpkg in src2dsa:
  351. src2dsa[srcpkg].append(myid)
  352. else:
  353. src2dsa[srcpkg] = []
  354. src2dsa[srcpkg].append(myid)
  355. dsa2cve[str(myid)] = dsastats[2]
  356. for cve_id in dsastats[2]:
  357. # No fetch CVE We use mongodb and cve-search
  358. cve = cv.fetchCVE(cve_id, client)
  359. cvestats = cv.parseCVE(cve_id, cve)
  360. # print(cvestats)
  361. # print(dsastats)
  362. finaldate = cvestats[0]
  363. if cvestats[0] > dsastats[1] or cvestats[0] == 0:
  364. finaldate = dsastats[1]
  365. cvedata = (finaldate, dsastats[1]-finaldate, cvestats[1], cvestats[2], cvestats[3])
  366. ## print(cvedata)
  367. cvetable[cve_id] = cvedata
  368. return cvetable
  369. ###############################################################################
  370. ## Check for updates on Package information
  371. def aptsec_update(state, config, dsatable, client, src2dsa, dsa2cve, src2month, cvetable, pkg_with_cvss):
  372. args = sys.argv
  373. # if not('--offline' in args):
  374. # fetchMeta('Packages')
  375. # fetchMeta('Sources')
  376. # fetchMeta('Sha1Sums')
  377. now = datetime.datetime.now()
  378. if not('--cves' in args):
  379. parsePackages('Packages')
  380. parseSources('Sources')
  381. # if not('--nosha1' in args):
  382. # parseSha1sums('Sha1Sums')
  383. if state['vendor'] == 'debian':
  384. newAdv = da.checkDSAs(state, config)
  385. else:
  386. print('Unsupported distribution. We only support Debian at the moment')
  387. system.exit(1)
  388. for myid in newAdv:
  389. if myid in dsatable:
  390. logging.info(state['vendor'] + ' advisory ' + myid + ' already known.\n')
  391. elif '--cves' in args:
  392. ## scan for CVE urls only?
  393. printCVEs(myid, newAdv[myid])
  394. else:
  395. ## store advisory and parse it
  396. dsatable[myid] = newAdv[myid]
  397. updateCVETables(myid, dsatable, state, src2dsa, dsa2cve, cvetable, client)
  398. # recompute all pkg statistics
  399. for srcpkg in src2dsa:
  400. processCVEs(srcpkg, now, src2dsa, dsa2cve, src2month, cvetable, pkg_with_cvss, config)
  401. return 0
  402. ###############################################################################
  403. ## find list of src pkgs from bin pkgs based on pkg2src
  404. def resolvePkg2Src(pkglist, pkg2src):
  405. srclist = []
  406. for pkg in pkglist:
  407. if pkg in pkg2src:
  408. srcpkg = pkg2src[pkg]
  409. srclist.append(srcpkg)
  410. else:
  411. logging.info('Could not find source package for: ' + pkg + ' .\n')
  412. return srclist
  413. ###############################################################################
  414. ## compute and store MTBF, MTBR and Scores of each src pkg
  415. ## output: %src2mtbf:
  416. ## (srcpkg=> ())
  417. def processCVEs(pkg, now, src2dsa, dsa2cve, src2month, cvetable, pkg_with_cvss, config):
  418. stats = [now, 0, 0, 0, 0, 0, 0]
  419. mylambda = config['TRUST']['lambda']
  420. cvestats = dict()
  421. logging.info('Processing package: ' + pkg + '.\n')
  422. ## keep track of the number of low-medium-high severity vulnerabilities
  423. ## TODO see how cvss affects vulnerability prediction - if some packages show patterns
  424. temp_cvss = 0.0
  425. with_cvss = dict()
  426. ## cvestats = (date: number)
  427. for dsa_id in src2dsa[pkg]:
  428. for cve_id in dsa2cve[str(dsa_id)]:
  429. tt = cvetable[cve_id][0]
  430. if tt in cvestats:
  431. cvestats[tt] += 1
  432. else:
  433. cvestats[tt] = 1
  434. stats[1] += 1
  435. ## with_cvss = (date: number low, number med, number high)
  436. for dsa_id in src2dsa[pkg]:
  437. for cve_id in dsa2cve[str(dsa_id)]:
  438. tt = cvetable[cve_id][0]
  439. temp_cvss = float(cvetable[cve_id][2])
  440. if tt in with_cvss:
  441. if (temp_cvss<4.0):
  442. with_cvss[tt][0] += 1
  443. elif (temp_cvss<7.0):
  444. with_cvss[tt][1] += 1
  445. else:
  446. with_cvss[tt][2] += 1
  447. else:
  448. with_cvss[tt] = [0, 0, 0]
  449. if (temp_cvss<4.0):
  450. with_cvss[tt][0] += 1
  451. elif (temp_cvss<7.0):
  452. with_cvss[tt][1] += 1
  453. else:
  454. with_cvss[tt][2] += 1
  455. # Ignore pkgs with less than one incident, should not happen..
  456. if stats[1] < 1:
  457. return
  458. prev_date = 0
  459. weight = 0
  460. dates = sorted(cvestats, key = cvestats.get)
  461. stats[0] = dates[0]
  462. count = sum(cvestats.values())
  463. print(pkg + ' ' + str(count))
  464. # pkg_with_cvss[pkg] = with_cvss
  465. format_data(pkg, with_cvss, pkg_with_cvss, True)
  466. format_data(pkg, cvestats, src2month, False)
  467. ###############################################################################
  468. ## format vulnerability data into monthly intervals, suitable for tensorflow
  469. def format_data(pkg, cvestats, src2month, cvss):
  470. x = []
  471. y = []
  472. monthyear = []
  473. year = []
  474. temp_items=list(cvestats.items())
  475. items = []
  476. for data_dict in temp_items:
  477. if isinstance(data_dict[0], str):
  478. tmpx = (parser.parse(data_dict[0]))
  479. else:
  480. tmpx = data_dict[0]
  481. x.append(tmpx)
  482. try:
  483. tmpy = int(data_dict[1])
  484. except TypeError:
  485. tmpy = data_dict[1]
  486. y.append(tmpy)
  487. items.append((tmpx, tmpy))
  488. items.sort(key=lambda tup: tup[0])
  489. for i in range(2000, 2018):
  490. temp = []
  491. for j in range(12):
  492. if cvss:
  493. temp.append([0, 0, 0])
  494. else:
  495. temp.append(0)
  496. monthyear.append(temp)
  497. for i in range(len(x)):
  498. if cvss:
  499. tmp0 = y[i][0]
  500. tmp1 = y[i][1]
  501. tmp2 = y[i][2]
  502. monthyear[x[i].year-2000][x[i].month-1][0] += tmp0
  503. monthyear[x[i].year-2000][x[i].month-1][1] += tmp1
  504. monthyear[x[i].year-2000][x[i].month-1][2] += tmp2
  505. else:
  506. monthyear[x[i].year-2000][x[i].month-1] += y[i]
  507. months_list = [item for sublist in monthyear for item in sublist]
  508. if not cvss:
  509. temp_months = np.zeros(len(months_list))
  510. i = 0
  511. for element in months_list:
  512. temp_months[i] = np.float32(element)
  513. i += 1
  514. src2month[pkg] = temp_months
  515. else:
  516. src2month[pkg] = months_list
  517. return
  518. ###############################################################################
  519. ## plot vulnerability time distribution for a single package
  520. def pkg_plot(pkg, cvestats):
  521. colors = list("rgbcmyk")
  522. items = list(cvestats.items())
  523. #print(items)
  524. items.sort(key=lambda tup: tup[0])
  525. x = []
  526. y = []
  527. for data_dict in items:
  528. x.append(parser.parse(data_dict[0]))
  529. y.append(data_dict[1])
  530. monthyear = []
  531. year = []
  532. # initialize list
  533. for i in range(2000,2017):
  534. temp = []
  535. for j in range(12):
  536. temp.append(0)
  537. monthyear.append(temp)
  538. for i in range(len(x)):
  539. # print(str(x[i].year) + str(x[i].month))
  540. monthyear[x[i].year-2000][x[i].month-1] += y[i]
  541. newx = []
  542. yearsx = []
  543. year = []
  544. monthlabel = []
  545. month = []
  546. m1 = 0
  547. m2 = 0
  548. k = 0
  549. label_months = []
  550. months_list = [item for sublist in monthyear for item in sublist]
  551. for i in range(len(months_list)):
  552. label_months.append(i)
  553. plt.bar(label_months, months_list)
  554. for i in range(len(monthyear)):
  555. year.append(0)
  556. cc = 0
  557. for j in range(len(monthyear[i])):
  558. cc += monthyear[i][j]
  559. if j == 5:
  560. m1 = cc
  561. month.append(m1)
  562. if j == 11:
  563. month.append(cc - m1)
  564. k += 1
  565. year[i] = cc
  566. for i in range(len(year)):
  567. yearsx.append(i + 2000)
  568. k = 2000
  569. datapoints = []
  570. for i in range(len(month)):
  571. datapoints.append(i+1)
  572. if i%2 == 0:
  573. monthlabel.append(str(k) + '-1')
  574. else:
  575. monthlabel.append('-2')
  576. k += 1
  577. # plt.xticks(datapoints, monthlabel)
  578. # print(year)
  579. # plt.plot.hist(yearsx,year)
  580. # plt.bar(yearsx, year, 1, color='blue')
  581. # plt.bar(datapoints, month, 1, color='blue')
  582. # ts.predict(month)
  583. plt.legend([pkg], loc='upper left')
  584. plt.show()
  585. return 0
  586. ###############################################################################
  587. ## populate src2sloccount dictionary with number of source lines of code in
  588. ## format (total, [ansic, cpp, asm, java, python, perl, sh])
  589. def getslocs(src2dsa, src2sloccount):
  590. try:
  591. conn = psycopg2.connect("dbname = 'debsources' user = 'postgres' host = 'localhost' password = 'nik'")
  592. except:
  593. print('I am unable to connect to the database')
  594. cur = conn.cursor()
  595. for pkg in src2dsa:
  596. if pkg not in src2sloccount:
  597. print(pkg)
  598. src2sloccount[pkg] = meta.getsloccount(cur, pkg)
  599. return
  600. ###############################################################################
  601. ## get popularity contest data in format src_pkg -> (installed, vote, old, recent)
  602. def getpop(src2dsa, src2pop):
  603. with open('Debian_pop.csv', newline = '') as csvfile:
  604. reader = csv.reader(csvfile, delimiter = ',', quotechar = '|')
  605. for row in reader:
  606. try:
  607. if row[1] in src2dsa and not (row[1] in src2pop):
  608. src2pop[row[1]] = row[2:6]
  609. except IndexError:
  610. print(row)
  611. continue
  612. return
  613. ###############################################################################
  614. ## get dependencies of a given source
  615. def getdeps(src2dsa, src2deps):
  616. for srcpkg in src2dsa:
  617. deps.getdeps(srcpkg, src2deps)
  618. ###############################################################################
  619. ## print some meta-info on internal data
  620. def aptsec_about(dsatable, cvetable, pkg2src, src2dsa):
  621. num_dsa = len(dsatable)
  622. num_cve = len(cvetable)
  623. num_pkg = len(pkg2src)
  624. num_src = len(src2dsa)
  625. print('\nThe current database records %d binary packages and %d DSAs.\n', num_pkg, num_src)
  626. print('%d CVEs are associated with %d source packages.\n', num_cve, num_src)
  627. return
  628. ###############################################################################
  629. ## use scores to suggest alternative packages
  630. def aptsec_alternatives(pkg):
  631. pass
  632. ###############################################################################
  633. ## print overview for pkg high scores
  634. def aptsec_hitlist():
  635. pass
  636. ###############################################################################
  637. ## evaluation helper
  638. ## compute stats until date given in $2, then compute stats
  639. ## for the next year to check accuracy of the prediction.
  640. ## @cvestats = (date base-score impact-score exploit-score)
  641. def simulate_stats(pkg, year):
  642. pass
  643. ###############################################################################
  644. ##TODO Printing functions
  645. ###############################################################################
  646. ## show info on a single src pkg, resolv to src if needed
  647. def aptsec_show(pkg, state, pkg2src, src2dsa, src2mtbf, cvetable):
  648. if state['vendor'] == 'debian':
  649. ADV = 'DSA-'
  650. else:
  651. print('Unsupported distribution. We only support Debian at the moment')
  652. system.exit(1)
  653. if (not(pkg in src2dsa)) and (pkg in pkg2src):
  654. print('\nResolving ' + pkg + ' to ' + pkg2src[pkg] + '\n')
  655. pkg = pkg2src[pkg]
  656. print('\nThe following binary packages are created from ' + pkg + ' :\n\n')
  657. lines = 0
  658. for i in pkg2src:
  659. if pkg2src[i] == pkg:
  660. print(i + '\n')
  661. lines += 1
  662. if lines < 1:
  663. print('-\n')
  664. if not (pkg in src2dsa and pkg in src2mtbf):
  665. print('\nNo vulnerabilities recorded for source package ' + pkg + '.\n')
  666. return
  667. print('\nAdvisories on package ' + pkg + ':\n\n')
  668. for dsa_id in sorted(src2dsa[pkg], key = src2dsa[pkg].get):
  669. print(ADV + dsa_id + '\n')
  670. for cve_id in dsa2cve[dsa_id]:
  671. (sec, minut, hrs, day, mon, yr) = gmtime(cvetable[cve_id][0])
  672. print('%s: Base Score: %04.1f, %02d.%02d.%04d\n', cve_id, cvetable[cve_id][2], day, mon+1, yr+1900)
  673. stats = src2mtbf[pkg]
  674. (sec, minut, hrs, day, mon, yr) = gmtime(stats[0])
  675. print('Now we print various iformation \n')
  676. ###############################################################################
  677. ## print help text
  678. def aptsec_help():
  679. print('See manual for correct usage\n')
  680. ###############################################################################
  681. ## Print system status report from component(files) measurements (sha1sums)
  682. ## Expected input format is Linux IMA. We assume input was validated.
  683. ##
  684. ## Note: aptsec_status(), considers *reportedly installed* packages, while this
  685. ## one looks at *actually loaded* software that influenced the CPU since bootup.
  686. def aptsec_attest(sha1file):
  687. pass
  688. ## Main Program starts here!!
  689. try:
  690. action = sys.argv[1]
  691. except IndexError:
  692. # print('No argument given')
  693. # aptsec_help()
  694. # sys.exit(0)
  695. action = ''
  696. client = MongoClient()
  697. dsatable = dict()
  698. cve_db = client.cvedb
  699. src2dsa = dict()
  700. dsa2cve = dict()
  701. cvetable = dict()
  702. src2month = dict()
  703. src2deps = dict()
  704. pkg_with_cvss = dict()
  705. src2sloccount = dict()
  706. src2pop = dict()
  707. (state, err) = load_state()
  708. state['vendor'] = 'debian'
  709. #detect_distribution()
  710. #d = state['cache_dir']
  711. #if not os.path.exists(d):
  712. # os.makedirs(d)
  713. if action == 'update':
  714. (dsatable, src2dsa, dsa2cve, cvetable, src2month, src2sloccount, src2pop, src2deps) = load_DBs()
  715. # loadsha1lists()
  716. aptsec_update(state,config, dsatable, client, src2dsa, dsa2cve, src2month, cvetable, pkg_with_cvss)
  717. # save_sha1lists()
  718. # getslocs(src2dsa, src2sloccount)
  719. # getpop(src2dsa, src2pop)
  720. # getdeps(src2dsa, src2deps)
  721. save_DBs(dsatable, src2dsa, dsa2cve, cvetable, src2month, src2sloccount, src2pop, src2deps)
  722. save_state(state)
  723. lstm.predict(src2month)
  724. # print(pkg_with_cvss['linux'])
  725. low = []
  726. med = []
  727. high = []
  728. for item in pkg_with_cvss['firefox']:
  729. low.append(item[0])
  730. med.append(item[1])
  731. high.append(item[2])
  732. # plt.plot(low, color = 'green')
  733. # plt.plot(med, color = 'orange')
  734. # plt.plot(high, color = 'red')
  735. # plt.show()
  736. elif action == 'status':
  737. load_DBs or exit(1)
  738. #handle errors more gracefully
  739. aptsec_status(sys.argv[2])
  740. elif action == 'show':
  741. load_DBs or exit(1)
  742. #handle errors more gracefully
  743. aptsec_show(sys.argv[2])
  744. else:
  745. aptsec_help()
  746. #print(state)
  747. save_state(state)
  748. #cve_db = client.cvedb
  749. #collection = db.cves
  750. #testcvss = collection.find_one({"cvss": 9.3})
  751. #print(testcvssi