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:37:43 +00:00
cryptopatterns = re . compile ( " (?i)(?P<c>crypto|cryptographic|cryptography|encipherement|encryption|ciphers|cipherAES|DES|3DES|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 )