def main(): parser = argparse.ArgumentParser() parser.add_argument( '--url', required=True, help='IP or FQDN for Vectra brain (http://www.example.com)') group = parser.add_mutually_exclusive_group(required=True) group.add_argument('--token', help='api token') group.add_argument('--user', help='username for basic auth') parser.add_argument('--csv', help='output to csv', action='store_true') parser.add_argument('--list_hosts', help='add host list to csv', action='store_true') parser.add_argument( '--all-hosts', action='store_true', help='return active and inactive hosts (only active hosts by default)') args = vars(parser.parse_args()) print args if args['user']: args['password'] = getPassword() vc = vectra.VectraClient(url=args['url'], user=args['user'], password=args['password']) else: vc = vectra.VectraClient(url=args['url'], token=args['token']) total_count = 0 subnets = {} for page in vc.get_all_hosts(all=args['all_hosts'], fields='name,last_source'): for host in page.json()['results']: if not host['last_source']: continue octet = re.search('(?P<subnet>(\d+\.){3})\d+', host['last_source']) network = "{subnet}0".format(subnet=octet.group('subnet')) if not subnets.get(network): subnets[network] = {'count': 0, 'hosts': []} subnets[network]['count'] += 1 subnets[network]['hosts'].append(host['name']) total_count += 1 # TODO numeric sorting if args['csv']: for key in sorted(subnets.iterkeys()): print "{key},{count},".format(key=key, count=subnets[key]['count']), if args['list_hosts']: print " ".join(subnets[key]['hosts']) else: print else: pprint.pprint(subnets, width=40) print "\n\n{:<18} {count}".format('total host count:', count=total_count)
def main(): parser = argparse.ArgumentParser() parser = commonArgs(parser) parser.add_argument('-c', '--category', choices=[ "botnet", "command", "reconnaissance", "lateral", "exfiltration" ], help='detection category') parser.add_argument('-t', '--type', dest='detection_type', help='detection type') parser.add_argument('--src', dest='src_ip', help='ip address of source host') parser.add_argument('--threat', dest='threat_gte', type=int, help='minimum threat score') parser.add_argument('--certainty', type=int, dest='certainty_gte', help='minimum certainty score') parser.add_argument('--host', dest='host_id', help='host id attributed to detection') args = vars(parser.parse_args()) if args['user']: args['password'] = getPassword() vc = vectra.VectraClient(url=args['url'], user=args['user'], password=args['password']) else: vc = vectra.VectraClient(url=args['url'], token=args['token']) resp = vc.get_detections(category=args.get('category', None), certainty_gte=args.get('certainty_gte', None), detection_type=args.get('detection_type', None), fields=args.get('fields', None), host_id=args.get('host_id', None), order=args.get('order', None), page=args.get('page', None), page_size=args.get('page_size', None), src_ip=args.get('src_ip', None), state=args.get('state', None), threat_gte=args.get('threat_gte', None)) print resp.json()
def main(): parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(dest='action') proxy_list = subparsers.add_parser('list', help='list configured proxies') proxy_list = commonArgs(proxy_list) proxy_add= subparsers.add_parser('add', help='create proxies') proxy_add = commonArgs(proxy_add) proxy_add.add_argument('host', help='host to add to proxy list') # parser_file = subparsers.add_parser('file', # help='Load data from file') # parser_file.add_argument('filename', # help='file to import data') args = vars(parser.parse_args()) if args['user']: print("This script only supports v2 of the API. Please use --token") exit() else: vc = vectra.VectraClient(url=args['url'], token=args['token']) if args['action'] == 'list': proxies = vc.get_proxies().json()['proxies'] pprint.pprint(proxies) elif args['action'] == 'add': resp = vc.add_proxy(host=args['host']) pprint.pprint(resp.json()['proxy'])
def main(): parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(dest='type') parser_hostname = subparsers.add_parser('hostname', help='Set key asset flag based on hostname') parser_hostname = commonArgs(parser_hostname) parser_hostname.add_argument('target', help='hostname or file name with list of hostnames') parser_ip = subparsers.add_parser('ip', help='Set key asset flag based on ip address') parser_ip = commonArgs(parser_ip) parser_ip.add_argument('target', help='ip address or file name with list of ip addresses') parser_id = subparsers.add_parser('id', help='Set key asset based on id') parser_id = commonArgs(parser_id) parser_id.add_argument('target', help='host id or file name with list of ids') args = vars(parser.parse_args()) vc = vectra.VectraClient(url=args['url'], token=args['token']) set_ka = True if not args['unset'] else False if args['file'] and args['type'] == 'hostname': hostfile = open(args['target'], 'r') for host in hostfile.readlines(): try: host_id = vc.get_hosts(name=host.strip()).json()['results'][0]['id'] resp = vc.set_key_asset(host_id=host_id, set=set_ka) respCode(args, resp, host.strip()) except IndexError: print host.strip() + " is not present in Vectra" elif args['file'] and args['type'] == 'ip': hostfile = open(args['target'], 'r') for host in hostfile.readlines(): try: host_id = vc.get_hosts(last_source=host.strip()).json()['results'][0]['id'] resp = vc.set_key_asset(host_id=host_id, set=set_ka) respCode(args, resp, host.strip()) except IndexError: print host.strip() + " is not present in Vectra" else: if args['type'] == 'hostname': hosts = vc.get_hosts(name=args['target']).json()['results'] for host in hosts: resp = vc.set_key_asset(host_id=host['id'], set=set_ka) respCode(args, resp, args['target']) if args['type'] == 'ip': hosts = vc.get_hosts(last_source=args['target']).json()['results'] for host in hosts: resp = vc.set_key_asset(host_id=host['id'], set=set_ka) respCode(args, resp, args['target']) if args['type'] == 'id': resp = vc.set_key_asset(host_id=args['target'], set=set_ka) respCode(args, resp, args['target'])
def retrieve_c2hosts(args, db): vc = vectra.VectraClient(url=args['url'], token=args['token']) wl = args.get('dst_wl', []) if bool(args.get('state', None)) and bool(args.get('triaged', None)): detections = vc.get_detections(detection_category='command & control', state=args['state'], is_triaged=args['triaged'], page_size=1000).json() elif args.get('triaged', None): detections = vc.get_detections(detection_category='command & control', is_triaged=args['triaged'], page_size=1000).json() else: detections = vc.get_detections(detection_category='command & control', page_size=1000).json() for detection in detections['results']: ips = [] if (detection['src_host']['threat'] >= args['c2_threat_score'] and detection['src_host']['certainty'] >= args['c2_certainty_score']): if detection['detection_type'] == 'Suspect Domain Activity': for detail in detection['grouped_details']: ips += detail['dns_response'].split( ',') if detail['dns_response'] else [] ips = list(set(ips)) elif detection[ 'detection_type'] == 'Suspicious HTTP': # or detection['detection_type'] == 'Hidden DNS Tunnel': for detail in detection['grouped_details']: ips.extend(detail['dst_ips']) #elif detection['detection_type'] == 'Multi-home Fronted Tunnel': # for detail in detection['grouped_details']: # ips.extend(detail['cdn_ips']) elif detection['detection_type'] == 'Suspicious Relay': ips = detection['summary']['origin_ips'] elif (detection['detection_type'] == 'Vectra Threat Intelligence Match' or detection['detection_type'] == 'Hidden DNS Tunnel' or detection['detection_type'] == 'Multi-home Fronted Tunnel'): pass else: ips = detection['summary']['dst_ips'] if detection['groups'] and wl: ips = remove_wl_ips(detection, wl, vc, ips) db.insert({'id': detection['id'], 'dst_ips': ips})
def retrieve_detections(args, db): vc = vectra.VectraClient(url=args['url'], token=args['token']) wl = args.get('dst_wl', []) if bool(args.get('state', None)) and bool(args.get('triaged', None)): detections = vc.get_detections(detection_type=args.get( 'detection_type', None), state=args['state'], is_triaged=args['triaged'], page_size=1000).json() elif args.get('triaged', None): detections = vc.get_detections(detection_type=args.get( 'detection_type', None), is_triaged=args['triaged'], page_size=1000).json() else: detections = vc.get_detections(detection_type=args.get( 'detection_type', None), page_size=1000).json() logging.debug( '{count} detections were returned with detection {detection}'.format( count=detections['count'], detection=args.get('detection_type', None))) for detection in detections['results']: ips = [] if detection['detection_type'] == 'Suspect Domain Activity': for detail in detection['grouped_details']: ips += detail['dns_response'].split( ',') if detail['dns_response'] else [] ips = list(set(ips)) elif detection['detection_type'] == 'Suspicious HTTP': for detail in detection['grouped_details']: ips.extend(detail['dst_ips']) elif detection['detection_type'] == 'Suspicious Relay': ips = detection['summary']['origin_ips'] else: ips = detection['summary']['dst_ips'] if detection['groups'] and wl: ips = remove_wl_ips(detection, wl, vc, ips) logging.debug(f'det_id:{detection["id"]}, dst_ips:{ips}') db.insert({'id': detection['id'], 'dst_ips': ips}) logging.debug(f'{str(ips)} added to block list')
def main(): parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(dest='action') # Host score subparser parser_score = subparsers.add_parser( 'score', help='retrieve hosts base on threat/certainty score') parser_score = commonArgs(parser_score) parser_score.add_argument( '-t', '--threat', dest='threat_gte', type=int, help='minimum threat score (default: %(default)s)', default=75) parser_score.add_argument( '-c', '--certainty', type=int, dest='certainty_gte', help='minimum certainty score (default: %(default)s)', default=75) # Host tags subparser parser_tags = subparsers.add_parser( 'tags', help='retrieve hosts base on threat/certainty score') parser_tags = commonArgs(parser_tags) parser_tags.add_argument('-g', '--tags', required=True, help='tags assigned to hosts') # Advanced query parser_adv = subparsers.add_parser( 'advance', help='retrieve hosts base on threat/certainty score') parser_adv = commonArgs(parser_adv) parser_adv.add_argument( '-c', '--certainty', type=int, dest='certainty_gte', help='minimum certainty score (default: %(default)s)') parser_adv.add_argument('-g', '--tags', help='tags assigned to hosts') parser_adv.add_argument('-i', '--ip', dest='last_source', help='ip address of host') parser_adv.add_argument('-k', '--key_asset', action='store_true', help='host marked as a key asset') parser_adv.add_argument('-m', '--mac', dest='mac_address', help='mac address of host') parser_adv.add_argument('-t', '--threat', dest='threat_gte', type=int, help='minimum threat score (default: %(default)s)') args = vars(parser.parse_args()) if args['user']: args['password'] = getPassword() vc = vectra.VectraClient(url=args['url'], user=args['user'], password=args['password']) else: vc = vectra.VectraClient(url=args['url'], token=args['token']) resp = vc.get_hosts(certainty_gte=args.get('certainty_gte', None), threat_gte=args.get('threat_gte', None), tags=args.get('tags', None), last_source=args.get('last_source', None), is_key_asset=args.get('key_asset', None), mac_address=args.get('mac_address', None)) print resp.json()
parser_file.add_argument('filename', help='file to import data') args = vars(parser.parse_args()) if args['action'] == 'file': filename = open(args['filename'], 'r') response = json.loads(filename.read()) else: if args['user']: args['password'] = getPassword() else: print('This script only supports v1 of the API. Please use --user') exit(0) vc = vectra.VectraClient(url=args['url'], user=args['user'], password=args['password']) response = vc.get_detections(state=args['state'], page_size=args['page_size'], page=args['page'], fields=args['fields'], order=args['order']).json() if args['summary'] == 'detection': srcList = [] count = [] for result in response['results']: name = result['type_vname'] srcIp = result['src_ip'] srcList.append([result['type_vname'], result['src_ip']])
def main(): parser = argparse.ArgumentParser( description= "Manage Vectra threat feeds (This script is only supported by v2 endpoint which requires token auth)" ) # Command line arguments for creating new threat feed subparsers = parser.add_subparsers(dest='action') parser_create = subparsers.add_parser('create', help='Create new threat feed') parser_create.add_argument('--feed', required=True, action='store', help='Name for threat feed') parser_create.add_argument('--token', required=True, action='store', help='Authentication token') parser_create.add_argument( '--url', required=True, action='store', help='IP or FQDN for Vectra brain (http://www.example.com)') parser_create.add_argument('--file', required=True, action='store', help='SITX file') parser_create.add_argument('--category', required=True, action='store', choices=["exfil", "lateral", "cnc"], help='Detection category (case sensitive)') parser_create.add_argument('--certainty', required=True, action='store', choices=['Low', 'Medium', 'High'], help='Detection certainty (case sensitive)') parser_create.add_argument('--type', required=True, action='store', choices=[ 'Anonymization', 'C2', 'Exfiltration', 'Malware Artifacts', 'Watchlist' ], help='Indicator type (case sensitive)') parser_create.add_argument('--duration', required=True, action='store', type=int, help='Duration') # Command line arguments for updating an existing threat feed parser_edit = subparsers.add_parser( 'update', help='Update STIX file for existing threat feed') parser_edit.add_argument('--feed', required=True, action='store', help='Name for threat feed') parser_edit.add_argument('--token', required=True, action='store', help='Authentication token') parser_edit.add_argument( '--url', required=True, action='store', help='IP or FQDN for Vectra brain (http://www.example.com)') parser_edit.add_argument('--file', required=True, action='store', help='SITX file') # Command line arguments for deleting a threat feed parser_delete = subparsers.add_parser('delete', help='Delete threat feed') parser_delete.add_argument('--feed', required=True, action='store', help='Name for threat feed') parser_delete.add_argument('--token', required=True, action='store', help='Authentication token') parser_delete.add_argument( '--url', required=True, action='store', help='IP or FQDN for Vectra brain (http://www.example.com)') # Command line argument for listing threat feeds parser_show = subparsers.add_parser('list', help='Shows list of all threat feeds') parser_show.add_argument('--token', required=True, action='store', help='Authentication token') parser_show.add_argument( '--url', required=True, action='store', help='IP or FQDN for Vectra brain (http://www.example.com)') # print(parser.parse_args()) args = vars(parser.parse_args()) vc = vectra.VectraClient(url=args['url'], token=args['token']) if args['action'] == 'create': feed_id = vc.create_feed( name=args['feed'], category=args['category'], certainty=args['certainty'], itype=args['type'], duration=args['duration']).json()['threatFeed']['id'] print 'Threat feed created\nUploading STIX file\n' vc.post_stix_file(feed_id=feed_id, stix_file=args['file']) print "success" if args['action'] == 'update': feed_id = vc.get_feed_by_name(name=args['feed']) if feed_id: vc.post_stix_file(feed_id=feed_id, stix_file=args['file']) print "success" else: print 'Could not find threat feed' if args['action'] == 'delete': feed_id = vc.get_feed_by_name(name=args['feed']) if feed_id: vc.delete_feed(feed_id=feed_id) print "success" else: print 'Could not find threat feed' if args['action'] == 'list': result = vc.get_feeds() for e in result.json()['threatFeeds']: pprint.pprint(e)
def retrieve_hosts(args, db): vc = vectra.VectraClient(url=args['url'], token=args['token']) wl = args.get('src_wl', []) if args.get('tags', None): hosts = vc.get_hosts(tags=args['tags'], state=args['state'], page_size=1000).json() logging.debug( f'{hosts["count"]} hosts returned with tags: {args["tags"]}') for host in hosts['results']: logging.debug('host_id:{}, name:{}, ip:{}'.format( host['id'], host['name'], host['last_source'])) if not in_group_wl(host, wl): db.insert({ 'id': host['id'], 'name': host['name'], 'ip': host['last_source'] }) logging.debug('host ' + host['name'] + ':' + host['last_source'] + ' added to block list') if args.get('certainty_gte', None) or args.get('threat_gte', None): hosts = vc.get_hosts(certainty_gte=args.get('certainty_gte', 50), threat_gte=args.get('threat_gte', 50), page_size=1000).json() logging.debug( '{count} hosts returned with score: certainty {certainty} threat {threat}' .format(count=hosts['count'], certainty=args.get('certainty_gte', 50), threat=args.get('threat_gte', 50))) for host in hosts['results']: logging.debug('host_id:{}, name:{}, ip:{}'.format( host['id'], host['name'], host['last_source'])) if not in_group_wl(host, wl): db.insert({ 'id': host['id'], 'name': host['name'], 'ip': host['last_source'] }) logging.debug('host ' + host['name'] + ':' + host['last_source'] + ' added to block list') if args.get('src_detection_types', None): for src_det_type in args.get('src_detection_types'): response = vc.advanced_search( stype='hosts', page_size=5000, query= f"host.detection_summaries.detection_type:\"{src_det_type}\"") for page in response: for host in page.json()['results']: logging.debug('host_id:{}, name:{}, ip:{}'.format( host['id'], host['name'], host['last_source'])) if not in_group_wl(host, wl): db.insert({ 'id': host['id'], 'name': host['name'], 'ip': host['last_source'] }) logging.debug('host ' + host['name'] + ':' + host['last_source'] + ' added to block list')
def vc_v2(request): brain = request.config.getoption('--url') token = request.config.getoption('--token') return vectra.VectraClient(url=brain, token=token)
def vc_v1(request): brain = request.config.getoption('--url') username = request.config.getoption('--user') passwd = request.config.getoption('--password') return vectra.VectraClient(url=brain, user=username, password=passwd)
import sys import ssl try: import urllib.request import urllib.parse import requests import validators import vat.vectra as vectra from jose import jwt from .config import COGNITO_BRAIN, COGNITO_TOKEN, TENANT_ID, APP_ID, APP_SECRET except Exception as error: print("\nMissing import requirements: %s\n" % str(error)) # Setup Vectra client VC = vectra.VectraClient(COGNITO_BRAIN, token=COGNITO_TOKEN) # Suppress Detect certificate warning requests.packages.urllib3.disable_warnings() ssl._create_default_https_context = ssl._create_unverified_context # Setup logging LOG = logging.getLogger(__name__) # MS ATP Related URLs ATP_URL = 'https://api.securitycenter.windows.com/api/' RESOURCE_APP_ID_URI = "https://api.securitycenter.windows.com" AUTH_URL = "https://login.windows.net/{}/oauth2/token".format(TENANT_ID) SECURITY_CENTER_URL = 'https://securitycenter.windows.com/machines/'
params = { 'url': '', 'token': '', 'smtp_server': '', 'smtp_port': '', 'username': '', 'password': '', 'fromAddr': '', 'toAddr': '' } vdb = TinyDB('vectra.json') ht = vdb.table('hosts') upd = vdb.table('updates') vc = vectra.VectraClient(url=params['url'], token=params['token']) hosts = vc.get_hosts(fields='id,name,last_source').json()['results'] def insert_host(db, host): db.insert({ 'id': host['id'], 'name': host['name'], 'ip': host['last_source'] }) def send_message(hosts): msg = MIMEMultipart() msg['From'] = params['fromAddr'] msg['To'] = params['toAddr']