diff --git a/tools/nasparse.py b/tools/nasparse.py new file mode 100755 index 0000000..f1652ea --- /dev/null +++ b/tools/nasparse.py @@ -0,0 +1,52 @@ +#!/usr/bin/python3 +import pycrate_mobile +from pycrate_mobile import NASLTE +import pycrate_core +import binascii +import sys +import pprint +from enum import Enum + +import pycrate_mobile.TS24301_EMM + +def parse_nas_message(buffer, uplink=None): + bin = binascii.unhexlify(buffer) + if uplink: + parsed = NASLTE.parse_NASLTE_MO(bin) + elif uplink == None: #We don't know if its an up or downlink + parsed = NASLTE.parse_NASLTE_MO(bin) + if parsed[0] == None: + parsed = NASLTE.parse_NASLTE_MT(bin) + else: + parsed = NASLTE.parse_NASLTE_MT(bin) + return parsed[0] + +def heur_ue_imsi_sent(msg): + output = "device transmitted IMSI to base station!" + + if type(msg) not in [pycrate_mobile.TS24301_EMM.EMMAttachRequest, pycrate_mobile.TS24301_EMM.EMMSecProtNASMessage]: + return (False, None) + + if isinstance(msg, pycrate_mobile.TS24301_EMM.EMMSecProtNASMessage): + try: + msg = msg['EMMAttachRequest'] + except pycrate_core.elt.EltErr: + return (False, None) + + if msg['EPSAttachType']['V'].to_int() == 2: + return (True, output) + return (False, None) + + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("usage: nasparse.py [hex encoded nas message]") + exit(1) + + buffer = sys.argv[1] + msg = parse_nas_message(buffer) + pprint.pprint(msg) + res = heur_ue_imsi_sent(msg) + if(res[0]): + print(res[1]) + exit(1) \ No newline at end of file diff --git a/tools/nasparse_test.py b/tools/nasparse_test.py new file mode 100644 index 0000000..c877e0b --- /dev/null +++ b/tools/nasparse_test.py @@ -0,0 +1,37 @@ +#!/usr/bin/python3 +import unittest +import nasparse + + +class TestNasparse(unittest.TestCase): + imsi_sent_msg = '07412208391185184409309005f0700000100030023ed031d127298080211001000010810600000000830600000000000d00000300ff0003130184000a000005000010005c0a009011034f18a6f15d0103c1000000000000' + sec_imsi_sent_msg = '1727db4b7c0207412208391185184409309005f0700000100030023ed031d127298080211001000010810600000000830600000000000d00000300ff0003130184000a000005000010005c0a009011034f18a6f15d0103c1' + non_nas_msg = '1312deadbeefcafe' + other_nas_msg = '074413780004023fd121' + other_nas_mt_msg = "023fd12100000000000000000000000000000000000000000000000000000000" + ciphered_nas_msg = "27ed6146bd0162a5d62d62e1ce501720dc8bd84f1167fd" + + def run_heur(self, msg): + buf = nasparse.parse_nas_message(msg) + return nasparse.heur_ue_imsi_sent(buf)[0] + + def test_imsi_sent(self): + self.assertEqual(self.run_heur(self.imsi_sent_msg), True, "imsi_sent_msg should trigger heuristic") + + def test_sec_imsi_sent(self): + self.assertEqual(self.run_heur(self.imsi_sent_msg), True, "sec_imsi_sent_msg should trigger heuristic") + + def test_non_nas_msg(self): + self.assertEqual(self.run_heur(self.non_nas_msg), False, "non_nas_msg should not trigger heuristic") + + def test_other_nas(self): + self.assertEqual(self.run_heur(self.other_nas_msg), False, "other_nas_msg should not trigger heuristic") + + def test_other_nas_mt(self): + self.assertEqual(self.run_heur(self.other_nas_mt_msg), False, "other_nas_mt_msg should not trigger heuristic") + + def test_ciphered_nas(self): + self.assertEqual(self.run_heur(self.ciphered_nas_msg), False, "ciphered_nas_msg should not trigger heuristic") + +if __name__ == '__main__': + unittest.main()