mirror of
				https://github.com/optim-enterprises-bv/nDPId.git
				synced 2025-11-03 19:57:50 +00:00 
			
		
		
		
	Added JA3 blacklist downloader/checker from abuse.ch
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
This commit is contained in:
		@@ -1,7 +1,9 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
import io
 | 
			
		||||
import json
 | 
			
		||||
import os
 | 
			
		||||
import pandas
 | 
			
		||||
import requests
 | 
			
		||||
import sys
 | 
			
		||||
import time
 | 
			
		||||
@@ -21,6 +23,38 @@ ja3_fps = dict()
 | 
			
		||||
# 1 hour = 3600 sec/hour = (60 minutes/hour) * (60 seconds/minute)
 | 
			
		||||
JA3_FP_MAX_AGE = 60 * 60
 | 
			
		||||
 | 
			
		||||
global ja3_bl
 | 
			
		||||
ja3_bl = None
 | 
			
		||||
 | 
			
		||||
global ja3_bl_printed
 | 
			
		||||
ja3_bl_printed = dict()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def downloadJA3Blacklist():
 | 
			
		||||
    response = requests.get(
 | 
			
		||||
        'https://sslbl.abuse.ch/blacklist/ja3_fingerprints.csv'
 | 
			
		||||
    )
 | 
			
		||||
    if response.status_code == 200:
 | 
			
		||||
        global ja3_bl
 | 
			
		||||
        ja3_bl = pandas.read_csv(io.StringIO(response.text), header=9)
 | 
			
		||||
        return True
 | 
			
		||||
    return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def getBlacklisted(ja3_hash):
 | 
			
		||||
    global ja3_bl
 | 
			
		||||
    return ja3_bl[(ja3_bl['# ja3_md5'] == ja3_hash)]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def checkBlacklisted(ja3_hash):
 | 
			
		||||
    if ja3_bl is None:
 | 
			
		||||
        return
 | 
			
		||||
    csv_entry = getBlacklisted(ja3_hash)
 | 
			
		||||
    if not csv_entry.empty and ja3_hash not in ja3_bl_printed:
 | 
			
		||||
        print('Found CSV JA3 blacklist entry:')
 | 
			
		||||
        print(csv_entry)
 | 
			
		||||
        ja3_bl_printed[ja3_hash] = True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class JA3ER(object):
 | 
			
		||||
    def __init__(self, json_dict):
 | 
			
		||||
@@ -35,6 +69,7 @@ class JA3ER(object):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def isJA3InfoTooOld(ja3_hash):
 | 
			
		||||
    global ja3_fps
 | 
			
		||||
    if ja3_hash in ja3_fps:
 | 
			
		||||
        if ja3_fps[ja3_hash].isTooOld() is True:
 | 
			
		||||
            print('Fingerprint {} too old, re-newing..'.format(ja3_hash))
 | 
			
		||||
@@ -46,6 +81,7 @@ def isJA3InfoTooOld(ja3_hash):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def getInfoFromJA3ER(ja3_hash):
 | 
			
		||||
    global ja3_fps
 | 
			
		||||
    response = requests.get('https://ja3er.com/search/' + ja3_hash)
 | 
			
		||||
    if response.status_code == 200:
 | 
			
		||||
        ja3_fps[ja3_hash] = JA3ER(json.loads(response.text, strict=True))
 | 
			
		||||
@@ -81,6 +117,8 @@ def onJsonLineRecvd(json_dict, current_flow, global_user_data):
 | 
			
		||||
        if isJA3InfoTooOld(json_dict['tls']['ja3']) is True:
 | 
			
		||||
            getInfoFromJA3ER(json_dict['tls']['ja3s'])
 | 
			
		||||
 | 
			
		||||
        checkBlacklisted(json_dict['tls']['ja3'])
 | 
			
		||||
 | 
			
		||||
    return True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -96,6 +134,13 @@ if __name__ == '__main__':
 | 
			
		||||
                             str(address[1])
 | 
			
		||||
                             if type(address) is tuple else address))
 | 
			
		||||
 | 
			
		||||
    if downloadJA3Blacklist() is False:
 | 
			
		||||
        print('Could not download JA3 blacklist.')
 | 
			
		||||
    nsock = nDPIsrvdSocket()
 | 
			
		||||
    nsock.connect(address)
 | 
			
		||||
    nsock.loop(onJsonLineRecvd, None)
 | 
			
		||||
    try:
 | 
			
		||||
        nsock.loop(onJsonLineRecvd, None)
 | 
			
		||||
    except nDPIsrvd.SocketConnectionBroken as err:
 | 
			
		||||
        sys.stderr.write('\n{}\n'.format(err))
 | 
			
		||||
    except KeyboardInterrupt:
 | 
			
		||||
        print()
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user