From b2cd735a07a359436857fc34152cfe8649a77fd7 Mon Sep 17 00:00:00 2001 From: Cooper Quintin Date: Fri, 13 Dec 2024 15:11:23 -0800 Subject: [PATCH] proof of concept pcap reader for nas heuristic --- tools/nasparse.py | 15 ++++++++++----- tools/pcap_check.py | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 5 deletions(-) create mode 100755 tools/pcap_check.py diff --git a/tools/nasparse.py b/tools/nasparse.py index f1652ea..ee581e7 100755 --- a/tools/nasparse.py +++ b/tools/nasparse.py @@ -9,8 +9,13 @@ from enum import Enum import pycrate_mobile.TS24301_EMM +EPS_IMSI_ATTACH = 2 + def parse_nas_message(buffer, uplink=None): - bin = binascii.unhexlify(buffer) + if isinstance(buffer, str): #handle string argument or raw bytes + bin = binascii.unhexlify(buffer) + else: + bin = buffer if uplink: parsed = NASLTE.parse_NASLTE_MO(bin) elif uplink == None: #We don't know if its an up or downlink @@ -33,7 +38,7 @@ def heur_ue_imsi_sent(msg): except pycrate_core.elt.EltErr: return (False, None) - if msg['EPSAttachType']['V'].to_int() == 2: + if msg['EPSAttachType']['V'].to_int() == EPS_IMSI_ATTACH: #EPSAttachType Value is 'Combined EPS/IMSI Attach (2)' return (True, output) return (False, None) @@ -46,7 +51,7 @@ if __name__ == "__main__": buffer = sys.argv[1] msg = parse_nas_message(buffer) pprint.pprint(msg) - res = heur_ue_imsi_sent(msg) - if(res[0]): - print(res[1]) + (triggered, message)= heur_ue_imsi_sent(msg) + if(triggered): + print(message) exit(1) \ No newline at end of file diff --git a/tools/pcap_check.py b/tools/pcap_check.py new file mode 100755 index 0000000..e3b9df7 --- /dev/null +++ b/tools/pcap_check.py @@ -0,0 +1,39 @@ +#!/usr/bin/python3 +import nasparse +from scapy.utils import RawPcapNgReader +import sys + +TYPE_LTE_NAS = 0x12 +UDP_LEN = 28 + +def process_pcap(pcap_path): + print('Opening {}...'.format(pcap_path)) + + count = 0 + for (pkt_data, pkt_metadata,) in RawPcapNgReader(pcap_path): + count += 1 + gsmtap_len = pkt_data[UDP_LEN+1] * 4 # gsmtap header length is stored in the 2nd byte of GSMTAP as a number of 32 bit words + header_end = gsmtap_len + UDP_LEN #length of UDP/IP header plus GSMTAP header + gsmtap_end_idx = (len(pkt_data) - header_end) * -1 + + gsmtap_hdr = pkt_data[UDP_LEN:gsmtap_end_idx] + + if gsmtap_hdr[2] != TYPE_LTE_NAS: + continue + + # uplink status is the 7th bit of the 5th byte of the GSMTAP header. + # Uplink (Mobile originated) = 0 Downlink (mobile terminated) = 1 + uplink = (gsmtap_hdr[4] & 0b01000000) >> 6 + buffer = pkt_data[header_end:] + msg = nasparse.parse_nas_message(buffer, uplink) + (triggered, message)= nasparse.heur_ue_imsi_sent(msg) + if triggered: + print(f"Frame {count} triggered heuristic: {message}") + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("usage: pcap_check.py [path/to/pcap/file]") + exit(1) + + pcap_path = sys.argv[1] + process_pcap(pcap_path) \ No newline at end of file