2019-11-03 14:26:43 +00:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Finding potential software vulnerabilities from git commit messages
#
# Software is free software released under the "GNU Affero General Public License v3.0"
#
# This software is part of cve-search.org
#
# Copyright (c) 2019 Alexandre Dulaunoy - a@foo.be
import re
import git
import json
import sys
import argparse
2019-12-17 07:45:28 +00:00
import typing
2019-11-03 14:26:43 +00:00
parser = argparse . ArgumentParser ( description = " Finding potential software vulnerabilities from git commit messages. " , epilog = " More info: https://github.com/cve-search/git-vuln-finder " )
parser . add_argument ( " -v " , help = " increase output verbosity " , action = " store_true " )
parser . add_argument ( " -r " , type = str , help = " git repository to analyse " )
parser . add_argument ( " -o " , type = str , help = " Output format: [json] " , default = " json " )
2019-11-03 20:04:09 +00:00
parser . add_argument ( " -s " , type = str , help = " State of the commit found " , default = " under-review " )
2019-12-17 07:45:28 +00:00
parser . add_argument ( " -p " , type = str , help = " Matching pattern to use: [vulnpatterns, cryptopatterns, cpatterns] - the pattern ' all ' is used to match all the patterns at once. " , default = " vulnpatterns " )
2019-11-03 14:26:43 +00:00
args = parser . parse_args ( )
2019-11-04 06:27:16 +00:00
vulnpatterns = re . compile ( " (?i)(denial of service | \b XXE \b |remote code execution| \b open redirect|OSVDB| \b vuln| \b CVE \b | \b XSS \b | \b ReDoS \b | \b NVD \b |malicious|x− frame− options|attack|cross site |exploit|malicious|directory traversal | \b RCE \b | \b dos \b | \b XSRF \b | \b XSS \b |clickjack|session.fixation|hijack| \b advisory| \b insecure |security | \b cross− origin \b |unauthori[z|s]ed |infinite loop) " )
2019-11-03 14:26:43 +00:00
2019-12-17 08:28:55 +00:00
cryptopatterns = re . compile ( " (?i)
( ? P < c > crypto | cryptographic | cryptography | encipherement | encryption | ciphers | cipherAES | DES | 3 DES | cipher | GPG | PGP | OpenSSL | SSH | wireguard | VPN | CBC | ECB | CTR | key | private ( [ \s - ] ? ) key | public ( [ \s - ] ? ) key | size | length | strenght | generation | randomness | entropy | prng | rng )
( ? P < q > assessment | lack of | bad | vulnerable | missing | unproper | unsuitable | breakable | broken | replace | assessment | pen ( [ \s - ] ? ) test | pentest | penetration ( [ \s - ] ? ) test | report | vulnerablity | replace | fix | issue | fixes | add | remove | check )
| . * ( \g < q > ) . * ( \g < c > ) > * " )
2019-11-15 06:39:19 +00:00
cpatterns = re . compile ( " (?i)(double[-| ]free|buffer overflow|double free|race[-| ]condition) " )
if args . p == " vulnpatterns " :
defaultpattern = vulnpatterns
elif args . p == " cryptopatterns " :
defaultpattern = cryptopatterns
elif args . p == " cpatterns " :
defaultpattern = cpatterns
2019-12-17 07:45:28 +00:00
elif args . p == " all " :
defaultpattern = [ vulnpatterns , cryptopatterns , cpatterns ]
2019-11-15 06:39:19 +00:00
else :
parser . print_usage ( )
parser . exit ( )
2019-11-03 14:26:43 +00:00
if not args . r :
parser . print_usage ( )
parser . exit ( )
else :
repo = git . Repo ( args . r )
found = 0
potential_vulnerabilities = { }
2019-11-15 06:39:19 +00:00
def find_vuln ( commit , pattern = vulnpatterns ) :
m = pattern . search ( commit . message )
2019-11-03 14:26:43 +00:00
if m :
if args . v :
print ( " Match found: {} " . format ( m . group ( 0 ) ) , file = sys . stderr )
print ( commit . message , file = sys . stderr )
print ( " --- " , file = sys . stderr )
ret = { }
ret [ ' commit ' ] = commit
ret [ ' match ' ] = m . group ( 1 )
return ret
else :
return None
2019-12-17 07:45:28 +00:00
def summary ( commit , branch , pattern ) :
rcommit = commit
2019-11-03 14:26:43 +00:00
2019-12-17 07:45:28 +00:00
if rcommit . hexsha in potential_vulnerabilities :
potential_vulnerabilities [ rcommit . hexsha ] [ ' branches ' ] . append ( branch )
else :
potential_vulnerabilities [ rcommit . hexsha ] = { }
potential_vulnerabilities [ rcommit . hexsha ] [ ' message ' ] = rcommit . message
potential_vulnerabilities [ rcommit . hexsha ] [ ' commit-id ' ] = rcommit . hexsha
potential_vulnerabilities [ rcommit . hexsha ] [ ' summary ' ] = rcommit . summary
potential_vulnerabilities [ rcommit . hexsha ] [ ' stats ' ] = rcommit . stats . total
potential_vulnerabilities [ rcommit . hexsha ] [ ' author ' ] = rcommit . author . name
potential_vulnerabilities [ rcommit . hexsha ] [ ' author-email ' ] = rcommit . author . email
potential_vulnerabilities [ rcommit . hexsha ] [ ' authored_date ' ] = rcommit . authored_date
potential_vulnerabilities [ rcommit . hexsha ] [ ' committed_date ' ] = rcommit . committed_date
potential_vulnerabilities [ rcommit . hexsha ] [ ' branches ' ] = [ ]
potential_vulnerabilities [ rcommit . hexsha ] [ ' branches ' ] . append ( branch )
potential_vulnerabilities [ rcommit . hexsha ] [ ' pattern-selected ' ] = pattern . pattern
potential_vulnerabilities [ rcommit . hexsha ] [ ' pattern-matches ' ] = ret [ ' match ' ]
potential_vulnerabilities [ rcommit . hexsha ] [ ' state ' ] = args . s
return rcommit . hexsha
2019-11-15 06:39:19 +00:00
2019-11-03 14:26:43 +00:00
repo_heads = repo . heads
repo_heads_names = [ h . name for h in repo_heads ]
print ( repo_heads_names , file = sys . stderr )
for branch in repo_heads_names :
commits = list ( repo . iter_commits ( branch ) )
2019-12-17 07:45:28 +00:00
defaultpattern
2019-11-03 14:26:43 +00:00
for commit in commits :
2019-12-17 07:45:28 +00:00
if isinstance ( defaultpattern , typing . Pattern ) :
ret = find_vuln ( commit , pattern = defaultpattern )
if ret :
#print("Vulnerability found: {}".format(ret))
#print(ret.hexsha)
rcommit = ret [ ' commit ' ]
summary ( rcommit , branch , defaultpattern )
# Deduplication of commits on different branches
2019-11-03 14:26:43 +00:00
found + = 1
2019-12-17 07:45:28 +00:00
elif isinstance ( defaultpattern , list ) :
for p in defaultpattern :
ret = find_vuln ( commit , pattern = p )
if ret :
rcommit = ret [ ' commit ' ]
summary ( rcommit , branch , p )
found + = 1
2019-11-03 14:26:43 +00:00
print ( json . dumps ( potential_vulnerabilities ) )
2019-12-17 07:45:28 +00:00
2019-11-03 14:26:43 +00:00
print ( " Total potential vulnerability found in {} commit(s) " . format ( found ) , file = sys . stderr )