pcap_to_request_fingerprint.py 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. #!/usr/bin/env python3
  2. # requires: TShark (Wireshark) >= v3.0.0
  3. import sys
  4. import subprocess
  5. import json
  6. class RequestFingerprint:
  7. def __init__(self):
  8. self.record_tls_version = ""
  9. self.tls_version = ""
  10. self.ciphersuites = []
  11. self.compression_methods = []
  12. self.signature_algorithms = []
  13. self.extensions = []
  14. self.supported_groups = []
  15. self.ec_point_formats = []
  16. self.headers = []
  17. self.quirks = []
  18. def __str__(self):
  19. if len(self.compression_methods) > 1:
  20. self.quirks.append("compr")
  21. return "{version}:{ciphersuites}:{extensions}:{supported_groups}:{ec_point_formats}:{headers}:{quirks}".format(
  22. version="{:x}".format(int(self.tls_version,16)),
  23. ciphersuites=",".join("{:x}".format(int(x)) for x in self.ciphersuites),
  24. extensions=",".join("{:x}".format(int(x)) for x in self.extensions),
  25. supported_groups=",".join("{:x}".format(int(x,16)) for x in self.supported_groups),
  26. ec_point_formats=",".join("{:x}".format(int(x)) for x in self.ec_point_formats),
  27. #signature_algorithms=",".join("{:x}".format(int(x,16)) for x in self.signature_algorithms), # not currently used in fingerprint
  28. headers=",".join(self.headers), quirks=",".join(self.quirks))
  29. def parse(self, filename):
  30. tshark = subprocess.run(["tshark", "-r", filename, "-Y", "tls.handshake.type == 1", "-T", "json",
  31. "-e", "tls.record.version",
  32. "-e", "tls.handshake.version",
  33. "-e", "tls.handshake.ciphersuite",
  34. "-e", "tls.handshake.comp_method",
  35. "-e", "tls.handshake.extension.type",
  36. "-e", "tls.handshake.extensions_supported_group",
  37. "-e", "tls.handshake.extensions_ec_point_format",
  38. "-e", "tls.handshake.sig_hash_alg"], capture_output=True, encoding='utf-8')
  39. if tshark.returncode != 0:
  40. print(tshark.stderr)
  41. exit()
  42. json_str = tshark.stdout
  43. pkts = json.loads(json_str)
  44. # use the last TLS Client Hello in the pcap
  45. record = pkts[-1]["_source"]["layers"]
  46. self.record_tls_version = record["tls.record.version"][0]
  47. self.tls_version = record["tls.handshake.version"][0]
  48. self.ciphersuites = record["tls.handshake.ciphersuite"]
  49. self.compression_methods = record["tls.handshake.comp_method"]
  50. self.extensions = record["tls.handshake.extension.type"]
  51. if '10' in self.extensions:
  52. self.supported_groups = record["tls.handshake.extensions_supported_group"]
  53. if '11' in self.extensions:
  54. self.ec_point_formats = record["tls.handshake.extensions_ec_point_format"]
  55. if '13' in self.extensions:
  56. self.signature_algorithms = record["tls.handshake.sig_hash_alg"]
  57. if __name__ == "__main__":
  58. import argparse
  59. parser = argparse.ArgumentParser()
  60. parser.add_argument("filename", type=str, help="pcap containing TLS client hello")
  61. args = parser.parse_args()
  62. req_fp = RequestFingerprint()
  63. # parse request fingerprint from pcap
  64. try:
  65. req_fp.parse(args.filename)
  66. except IndexError as e:
  67. print(args.filename, e, file=sys.stderr)
  68. sys.exit(1)
  69. except KeyError as e:
  70. print(args.filename, e, file=sys.stderr)
  71. sys.exit(1)
  72. print(req_fp)