diff --git a/scripts/flippigator/conftest.py b/scripts/flippigator/conftest.py index 1c5ca9f3986..2b6d16ed4c2 100644 --- a/scripts/flippigator/conftest.py +++ b/scripts/flippigator/conftest.py @@ -10,6 +10,7 @@ FlipperProtoException, ) from flipperzero_protobuf_py.flipperzero_protobuf.flipper_proto import FlipperProto +from flippigator.extensions.proxmark_wrapper import proxmark_wrapper from flippigator.flippigator import ( FlippigatorException, Gator, @@ -84,6 +85,13 @@ def pytest_addoption(parser): default=False, help="use this flag for skip setup cycle", ) + parser.addoption( + "--px3_path", + action="store", + default="C:\\Users\\User\\Desktop\\proxmark3\\client\\proxmark3.exe", + help="path to proxmark3 executable file", + type=str, + ) def pytest_configure(config): @@ -340,6 +348,12 @@ def nav(flipper_serial, request): return nav +@pytest.fixture(scope="session") +def px(request): + px = proxmark_wrapper(request.config.getoption("--px3_path")) + return px + + @pytest.fixture(scope="session") def nav_reader(flipper_reader_serial, request): proto = FlipperProto(serial_port=flipper_reader_serial, debug=True) diff --git a/scripts/flippigator/flippigator/extensions/CMD_READ.json b/scripts/flippigator/flippigator/extensions/CMD_READ.json new file mode 100644 index 00000000000..6f176bb557a --- /dev/null +++ b/scripts/flippigator/flippigator/extensions/CMD_READ.json @@ -0,0 +1,346 @@ +{ + "ASCII_MIRROR_UID_0": + { + "tag":"ASCII_MIRROR_UID", + "Card":"NTAG213.nfc", + "Description":"Set ascii mirror page = 36, byte = 0, mode = UID. Then read data", + "Cmds": [ + { + "cmd":"hf 14a raw -sc A229440024FF", + "result":"0A" + }, + { + "cmd": "hf 14a raw -sc 3024", + "result": "30 34 42 41 46 46 43 41 34 44 35 44 38 30 00 00 [ E9 19 ]" + }, + { + "cmd": "hf 14a raw -sc 3023", + "result": "00 00 00 00 30 34 42 41 46 46 43 41 34 44 35 44 [ 1C AC ]" + }, + { + "cmd": "hf 14a raw -sc 3025", + "result": "46 46 43 41 34 44 35 44 38 30 00 00 00 AA AA BD [ 32 A3 ]" + } + ] + }, +"ASCII_MIRROR_UID_1" :{ + "tag":"ASCII_MIRROR_UID", + "Card":"NTAG213.nfc", + "Description":"Set ascii mirror page = 36, byte = 1, mode = UID. Then read data", + "Cmds": [ + { + "cmd":"hf 14a raw -sc A229540024FF", + "result":"0A" + }, + { + "cmd": "hf 14a raw -sc 3024", + "result": "00 30 34 42 41 46 46 43 41 34 44 35 44 38 30 00 [ 45 02 ]" + }, + { + "cmd": "hf 14a raw -sc 3023", + "result": "00 00 00 00 00 30 34 42 41 46 46 43 41 34 44 35 [ B1 7C ]" + }, + { + "cmd": "hf 14a raw -sc 3025", + "result": "41 46 46 43 41 34 44 35 44 38 30 00 00 AA AA BD [ 36 2A ]" + } + ] + }, + "ASCII_MIRROR_UID_2" : { + "tag":"ASCII_MIRROR_UID", + "Card":"NTAG213.nfc", + "Description":"Set ascii mirror page = 36, byte = 2, mode = UID. Then read data", + "Cmds": [ + { + "cmd":"hf 14a raw -sc A229640024FF", + "result":"0A" + }, + { + "cmd": "hf 14a raw -sc 3024", + "result": "00 00 30 34 42 41 46 46 43 41 34 44 35 44 38 30 [ EE 77 ]" + }, + { + "cmd": "hf 14a raw -sc 3023", + "result": "00 00 00 00 00 00 30 34 42 41 46 46 43 41 34 44 [ 76 6C ]" + }, + { + "cmd": "hf 14a raw -sc 3025", + "result": "42 41 46 46 43 41 34 44 35 44 38 30 00 AA AA BD [ 4A D4 ]" + } + ] + }, + "ASCII_MIRROR_UID_3" : { + "tag":"ASCII_MIRROR_UID", + "Card":"NTAG213.nfc", + "Description":"Set ascii mirror page = 36, byte = 3, mode = UID. Then read data", + "Cmds": [ + { + "cmd":"hf 14a raw -sc A229740024FF", + "result":"0A" + }, + { + "cmd": "hf 14a raw -sc 3024", + "result": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 37 49 ]" + }, + { + "cmd": "hf 14a raw -sc 3023", + "result": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 37 49 ]" + }, + { + "cmd": "hf 14a raw -sc 3025", + "result": "00 00 00 00 00 00 00 00 00 00 00 00 00 AA AA BD [ 7B 09 ]" + } + ] + }, + "ASCII_COUNTER_0" : { + "tag":"ASCII_COUNTER", + "Card":"NTAG213.nfc", + "Description":"Disable counter -> set ascii mirror page = 38, byte = 0, mode = COUNTER -> \nread data -> Enable counter -> read data", + "Cmds": [ + { + "cmd": "hf 14a raw -sc A22A00050000", + "result": "0A" + }, + { + "cmd":"hf 14a raw -sc A229840026FF", + "result":"0A" + }, + { + "cmd": "hf 14a raw -sc 3025", + "result": "00 00 00 00 00 00 00 00 00 00 00 00 00 AA AA BD [ 7B 09 ]" + }, + { + "cmd": "hf 14a raw -sc 3026", + "result": "00 00 00 00 00 00 00 00 00 AA AA BD 84 00 26 FF [ DB E9 ]" + }, + { + "cmd": "hf 14a raw -sc 3027", + "result": "00 00 00 00 00 AA AA BD 84 00 26 FF 00 05 00 00 [ E3 5C ]" + }, + { + "cmd": "hf 14a raw -sc A22A10050000", + "result": "0A" + }, + { + "cmd": "hf 14a raw -sc 3025", + "result": "00 00 00 00 30 30 30 30 30 30 00 00 00 AA AA BD [ 54 E9 ]" + }, + { + "cmd": "hf 14a raw -sc 3025", + "result": "00 00 00 00 30 30 30 30 30 31 00 00 00 AA AA BD [ 81 76 ]" + }, + { + "cmd": "hf 14a raw -sck 3025", + "result": "00 00 00 00 30 30 30 30 30 32 00 00 00 AA AA BD [ EF DE ]" + }, + { + "cmd": "hf 14a raw -ac 3025", + "result": "00 00 00 00 30 30 30 30 30 33 00 00 00 AA AA BD [ 3A 41 ]" + }, + { + "cmd": "hf 14a raw -sc 3026", + "result": "30 30 30 30 30 33 00 00 00 AA AA BD 84 00 26 FF [ 63 23 ]" + }, + { + "cmd": "hf 14a raw -sc 3027", + "result": "30 34 00 00 00 AA AA BD 84 00 26 FF 10 05 00 00 [ 4F B2 ]" + }, + { + "cmd": "hf 14a raw -sc A22A00050000", + "result": "0A" + } + ] + }, + "ASCII_COUNTER_1" : { + "tag":"ASCII_COUNTER", + "Card":"NTAG213.nfc", + "Description":"Disable counter -> set ascii mirror page = 38, byte = 1, mode = COUNTER -> \nread data -> Enable counter -> read data", + "Cmds": [ + { + "cmd": "hf 14a raw -sc A22A00050000", + "result": "0A" + }, + { + "cmd":"hf 14a raw -sc A229940026FF", + "result":"0A" + }, + { + "cmd": "hf 14a raw -sc 3025", + "result": "00 00 00 00 00 00 00 00 00 00 00 00 00 AA AA BD [ 7B 09 ]" + }, + { + "cmd": "hf 14a raw -sc 3026", + "result": "00 00 00 00 00 00 00 00 00 AA AA BD 84 00 26 FF [ DB E9 ]" + }, + { + "cmd": "hf 14a raw -sc 3027", + "result": "00 00 00 00 00 AA AA BD 84 00 26 FF 00 05 00 00 [ E3 5C ]" + }, + { + "cmd": "hf 14a raw -sc A22A10050000", + "result": "0A" + }, + { + "cmd": "hf 14a raw -sc 3025", + "result": "00 00 00 00 30 30 30 30 35 39 00 00 00 AA AA BD [ 0C 3F ]" + }, + { + "cmd": "hf 14a raw -sc 3026", + "result": "30 30 30 30 35 41 00 00 00 AA AA BD 84 00 26 FF [ A8 56 ]" + }, + { + "cmd": "hf 14a raw -sc 3027", + "result": "35 42 00 00 00 AA AA BD 84 00 26 FF 10 05 00 00 [ 5F D8 ]" + }, + { + "cmd": "hf 14a raw -sc A22A00050000", + "result": "0A" + } + ] + }, + "ASCII_COUNTER_2" : { + "tag":"ASCII_COUNTER", + "Card":"NTAG213.nfc", + "Description":"Disable counter -> set ascii mirror page = 38, byte = 2, mode = COUNTER -> \nread data -> Enable counter -> read data", + "Cmds": [ + { + "cmd": "hf 14a raw -sc A22A00050000", + "result": "0A" + }, + { + "cmd":"hf 14a raw -sc A229A40026FF", + "result":"0A" + }, + { + "cmd": "hf 14a raw -sc 3025", + "result": "00 00 00 00 00 00 00 00 00 00 00 00 00 AA AA BD [ 7B 09 ]" + }, + { + "cmd": "hf 14a raw -sc 3026", + "result": "00 00 00 00 00 00 00 00 00 AA AA BD 84 00 26 FF [ DB E9 ]" + }, + { + "cmd": "hf 14a raw -sc 3027", + "result": "00 00 00 00 00 AA AA BD 84 00 26 FF 00 05 00 00 [ E3 5C ]" + }, + { + "cmd": "hf 14a raw -sc A22A10050000", + "result": "0A" + }, + { + "cmd": "hf 14a raw -sc 3025", + "result": "00 00 00 00 30 30 30 30 35 39 00 00 00 AA AA BD [ 0C 3F ]" + }, + { + "cmd": "hf 14a raw -sc 3026", + "result": "30 30 30 30 35 41 00 00 00 AA AA BD 84 00 26 FF [ A8 56 ]" + }, + { + "cmd": "hf 14a raw -sc 3027", + "result": "35 42 00 00 00 AA AA BD 84 00 26 FF 10 05 00 00 [ 5F D8 ]" + }, + { + "cmd": "hf 14a raw -sc A22A00050000", + "result": "0A" + } + ] + }, + "ASCII_COUNTER_3" : { + "tag":"ASCII_COUNTER", + "Card":"NTAG213.nfc", + "Description":"Disable counter -> set ascii mirror page = 38, byte = 3, mode = COUNTER -> \nread data -> Enable counter -> read data -> Result: ignore", + "Cmds": [ + { + "cmd": "hf 14a raw -sc A22A00050000", + "result": "0A" + }, + { + "cmd":"hf 14a raw -sc A229B40026FF", + "result":"0A" + }, + { + "cmd": "hf 14a raw -sc 3025", + "result": "00 00 00 00 00 00 00 00 00 00 00 00 00 AA AA BD [ 7B 09 ]" + }, + { + "cmd": "hf 14a raw -sc 3026", + "result": "00 00 00 00 00 00 00 00 00 AA AA BD B4 00 26 FF [ 29 A5 ]" + }, + { + "cmd": "hf 14a raw -sc 3027", + "result": "00 00 00 00 00 AA AA BD B4 00 26 FF 00 05 00 00 [ 6B B1 ]" + }, + { + "cmd": "hf 14a raw -sc A22A10050000", + "result": "0A" + }, + { + "cmd": "hf 14a raw -sc 3025", + "result": "00 00 00 00 00 00 00 00 00 00 00 00 00 AA AA BD [ 7B 09 ]" + }, + { + "cmd": "hf 14a raw -sc 3026", + "result": "00 00 00 00 00 00 00 00 00 AA AA BD B4 00 26 FF [ 29 A5 ]" + }, + { + "cmd": "hf 14a raw -sc 3027", + "result": "00 00 00 00 00 AA AA BD B4 00 26 FF 10 05 00 00 [ CA 72 ]" + }, + { + "cmd": "hf 14a raw -sc A22A00050000", + "result": "0A" + } + ] + }, + "ASCII_COUNTER_0_PWD" : { + "tag":"ASCII_COUNTER", + "Card":"NTAG213.nfc", + "Description":"Disable counter -> set ascii mirror page = 38, byte = 0, mode = COUNTER ->\nread data -> CNT_ENABLE = 1 PSWD_CNT = 1 -> read data", + "Cmds": [ + { + "cmd": "hf 14a raw -sc A22A00050000", + "result": "0A" + }, + { + "cmd":"hf 14a raw -sc A229840026FF", + "result":"0A" + }, + { + "cmd": "hf 14a raw -sc 3025", + "result": "00 00 00 00 00 00 00 00 00 00 00 00 00 AA AA BD [ 7B 09 ]" + }, + { + "cmd": "hf 14a raw -sc 3026", + "result": "00 00 00 00 00 00 00 00 00 AA AA BD 84 00 26 FF [ DB E9 ]" + }, + { + "cmd": "hf 14a raw -sc 3027", + "result": "00 00 00 00 00 AA AA BD 84 00 26 FF 00 05 00 00 [ E3 5C ]" + }, + { + "cmd": "hf 14a raw -sc A22A18050000", + "result": "0A" + }, + { + "cmd": "hf 14a raw -sck 1BFFFFFFFF", + "result": "00 00 00 00 30 30 30 30 35 39 00 00 00 AA AA BD [ 0C 3F ]" + }, + { + "cmd": "hf 14a raw -ack 3025", + "result": "00 00 00 00 30 30 30 30 35 39 00 00 00 AA AA BD [ 0C 3F ]" + }, + { + "cmd": "hf 14a raw -ack 3026", + "result": "30 30 30 30 35 41 00 00 00 AA AA BD 84 00 26 FF [ A8 56 ]" + }, + { + "cmd": "hf 14a raw -ack 3027", + "result": "35 42 00 00 00 AA AA BD 84 00 26 FF 10 05 00 00 [ 5F D8 ]" + }, + { + "cmd": "hf 14a raw -ac A22A00050000", + "result": "0A" + } + ] + } +} diff --git a/scripts/flippigator/flippigator/extensions/CMD_READ.nfctests b/scripts/flippigator/flippigator/extensions/CMD_READ.nfctests new file mode 100644 index 00000000000..c1f6c55960e --- /dev/null +++ b/scripts/flippigator/flippigator/extensions/CMD_READ.nfctests @@ -0,0 +1,14 @@ +#Some test cases for nfc +#this is one line comment + +''' +Multiline +comment +''' + +[Scenario=1, Card=NTAG213.nfc, Description="Describes what scenario does"] +hf 14a raw -sc 3000 -> 04 BA FF C9 CA 4D 5D 80 5A 48 00 00 E1 10 12 00 [ F5 67 ] + +[Scenario=2, Card=NTAG213.nfc, Description="Reading password protected data"] +hf 14a raw -sck 1BDEADBEAF -> 00 00 [ A0 1E ] //Authentication with pwd = DEADBEAF +hf 14a raw -sc 300A -> 04 BA FF C9 CA 4D 5D 80 5A 48 00 00 E1 10 12 00 [ F5 67 ] //Read pages 0x0A - 0x0D diff --git a/scripts/flippigator/flippigator/extensions/CMD_READ_TST.py b/scripts/flippigator/flippigator/extensions/CMD_READ_TST.py new file mode 100644 index 00000000000..30c119f6abd --- /dev/null +++ b/scripts/flippigator/flippigator/extensions/CMD_READ_TST.py @@ -0,0 +1,26 @@ +import unittest + +from command_result import command_result +from proxmark_wrapper import proxmark_wrapper + +PM3 = "C:\\Proxmark\\pm3.bat" + + +class TestCmdRead(unittest.TestCase): + def setUp(self) -> None: + self.pm = proxmark_wrapper(PM3) + + def test_Read_Page0(self): + print("Test: 1") + cmd = "hf 14a raw -sc 3000\n" + expected = "04 BA FF C9 CA 4D 5D 80 5A 48 00 00 E1 10 12 00 [ F5 67 ]" + cmds = [cmd] + result = self.pm.execute(cmds) + self.pm.shutdown() + + self.assertEqual(result[0].Command, cmd.removesuffix("\n")) + self.assertEqual(result[0].Result, expected) + + +if __name__ == "__main__": + unittest.main() diff --git a/scripts/flippigator/flippigator/extensions/command_result.py b/scripts/flippigator/flippigator/extensions/command_result.py new file mode 100644 index 00000000000..27ce6ea8555 --- /dev/null +++ b/scripts/flippigator/flippigator/extensions/command_result.py @@ -0,0 +1,62 @@ +from typing import List + + +class command_result: + @property + def Command(self): + return self.__Command + + @property + def Result(self): + return self.__Result + + def __init__(self, input): + print("input: ", input) + s = str(input).split("\n") + self.__Command = s[0] + self.__Result = s[1].removeprefix("[+] ").removesuffix(" ") + + +class proxmark_command: + @property + def Command(self): + return self.__Command + + @property + def Result(self): + return self.__Result + + @property + def Expected(self): + return self.__Expected + + def parse_result(self, result): + s = str(input).split("\n") + self.__Result = command_result(result) + + def __init__(self, cmd, expected): + self.__Command = cmd + self.__Expected = expected + + +class Scenario: + def __init__(self, json): + self.Name = self.__decode(json, "Name") + self.Card = self.__decode(json, "Card") + self.Description = self.__decode(json, "Description") + self.Cmds = [] + for jsc in json["Cmds"]: + cmd = proxmark_command(jsc["cmd"], jsc["result"]) + self.Cmds.append(cmd) + + def __decode(self, json, name): + try: + return json[name] + except KeyError: + return "" + + def get_commands(self) -> List[str]: + result = [] + for cmd in self.Cmds: + result.append(cmd.Command + "\n") + return result diff --git a/scripts/flippigator/flippigator/extensions/main.py b/scripts/flippigator/flippigator/extensions/main.py new file mode 100644 index 00000000000..84514e8ac6a --- /dev/null +++ b/scripts/flippigator/flippigator/extensions/main.py @@ -0,0 +1,105 @@ +import json +from types import SimpleNamespace +from typing import List + +from command_result import Scenario, command_result, proxmark_command +from proxmark_wrapper import proxmark_wrapper + +PM3 = "/home/vk/work/proxmark3/pm3" + + +def print_result(result: List[command_result]): + for r in result: + print(f"Command: {r.Command}\n Result: {r.Result}") + + +def raw_proxmark_test(): + pm = proxmark_wrapper(PM3) + pm.execute_single("hf 14a raw -sc 3000") + result = pm.execute( + ["hf 14a raw -sc 3000\n", "hf 14a raw -sc 3000\n", "hf 14a raw -sc 3001\n"] + ) + print_result(result) + print("-------------------------------------") + + result = pm.execute(["hf 14a raw -sc 300A\n"]) + print_result(result) + print("-------------------------------------") + + result = pm.execute(["hf 14a raw -sc 300A -k DEADBEAF\n"]) + print_result(result) + print("-------------------------------------") + + result = pm.execute(["hf 14a raw -sck 1BDEADBEAF\n", "hf 14a raw -ac 300A\n"]) + print_result(result) + print("-------------------------------------") + + pm.shutdown() + + +def read_scenarios_from_file(file) -> List[Scenario]: + return read_scenarios_from_json(file) + + +def read_scenarios_from_json(file) -> List[Scenario]: + with open(file, "r") as file: + data = json.loads(file.read()) + + scenarios_data = data["scenarios"] + + scenarios = [] + for data in scenarios_data: + scenarios.append(Scenario(data)) + return scenarios + + +def main(): + """ + with open("CMD_READ.json", "r") as file: + data = json.loads(file.read()) + + scenarios_data = data["scenarios"] + + scenarios = [] + for data in scenarios_data: + scenarios.append(Scenario(data)) + """ + raw_proxmark_test() + + +def run_scenario(scenario): + pm3 = proxmark_wrapper(PM3) + cmds = scenario.get_commands() + results = pm3.execute(cmds) + + expected_len = len(scenario.Cmds) + actual_len = len(results) + passed = 1 + passed &= check_result(actual_len, expected_len) + + i = 0 + while i < actual_len: + passed &= check_result(results[i].Command, scenario.Cmds[i].Command) + passed &= check_result(results[i].Result, scenario.Cmds[i].Expected) + i += 1 + + if passed: + print("PASSED") + else: + print("FAILED") + print( + "-----------------------------------------------------------------------------------" + ) + + +def check_result(actual, expected): + if actual != expected: + print(f"{actual} != {expected}\tFAILED") + return False + print(f"{actual} == {expected}\tPASSED") + return True + + +if __name__ == "__main__": + # raw_proxmark_test() + main() diff --git a/scripts/flippigator/flippigator/extensions/proxmark_wrapper.py b/scripts/flippigator/flippigator/extensions/proxmark_wrapper.py new file mode 100644 index 00000000000..00b79557000 --- /dev/null +++ b/scripts/flippigator/flippigator/extensions/proxmark_wrapper.py @@ -0,0 +1,64 @@ +import subprocess +import time +from typing import List + +from .command_result import command_result + + +class proxmark_wrapper: + @property + def PM3(self): + return self.__PM3 + + def __init__(self, path): + self.__PM3 = path + + def execute_cmds(self, cmds) -> List[command_result]: + with subprocess.Popen( + [self.__PM3], + text=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + encoding="cp866", + ) as process: + for cmd in cmds: + process.stdin.write(cmd) + + process.stdin.write("exit\n") + process.stdin.close() + data_out = process.stdout.read() + + result = self.__get_result(data_out) + return result + + def execute(self, cmd) -> List[command_result]: + with subprocess.Popen( + [self.__PM3, "-c", cmd], + text=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + ) as process: + data_out = process.stdout.read() + + print("data_out: ", data_out) + + result = self.__get_result(data_out) + print("result: ", result[0]) + return result + + def shutdown(self): + pass + + def __get_result(self, data): + cmd_result = self.__parse_data(data) + return cmd_result + + def __parse_data(self, output_data): + raw_result = str(output_data).split("[usb|script] pm3 --> ") + + print("raw_result: ", raw_result) + result = [] + for raw in raw_result[1:]: + print("raw: ", raw) + result.append(command_result(raw).Result) + return result diff --git a/scripts/flippigator/flippigator/extensions/scenarios_parser.py b/scripts/flippigator/flippigator/extensions/scenarios_parser.py new file mode 100644 index 00000000000..40833387c25 --- /dev/null +++ b/scripts/flippigator/flippigator/extensions/scenarios_parser.py @@ -0,0 +1,8 @@ +class nfc_scenario: + @property + def Name(self): + return self.__Name + + @property + def Result(self): + return self.__Result diff --git a/scripts/flippigator/img/ref/browser_T_Ntag_213.bmp b/scripts/flippigator/img/ref/browser_T_Ntag_213.bmp new file mode 100644 index 00000000000..be2a91bb648 Binary files /dev/null and b/scripts/flippigator/img/ref/browser_T_Ntag_213.bmp differ diff --git a/scripts/flippigator/nfc/ReadMe.md b/scripts/flippigator/nfc/ReadMe.md new file mode 100644 index 00000000000..3ea7019a835 --- /dev/null +++ b/scripts/flippigator/nfc/ReadMe.md @@ -0,0 +1,46 @@ +Internal readme for nfc team + +How to install framework +======================== +1. Install all submodules and make sure all works +2. Install python 3.11 or higher +3. Create your own venv (optional and prefered) +4. Install proxmark3 client with a make SKIPQT=1 (or alternatively use headless openCV example later) +5. Go to scripts/flippigator +6. Install requirements.txt with python3 -m pip install -r requirements.txt +(or alternatively python -m pip install -r requirements-headless.txt) + +(you might run into issues with pyreadline on windows, just message me to fix it or google errors and do some additional imports) + + +Run the framework +================= +1. Go to scripts/flippigator +2. pytest -vv --no_init --port=/dev/ttyACM0 --px3_path="/home/vk/work/proxmark3/pm3" -k TestEmulateNtag213 where: +--vv very verbose for additional debug output +--no_init do not init flipper (checks settings and enables debug, takes 30+ seconds) +--port=/dev/ttyACM0 port to flipper +--px3_path="/home/vk/work/proxmark3/pm3" path to proxmark3 client (make sure you either use noqt version or headless openCV), pm3 client finds the port automatically +-k here you can select any test name, part of it or class name +-m runs a specific mark (tag), they are added via decorator and must be specified in pytest.ini file + +Writing your own tests +====================== +1. All NFC related tests are in scripts/flippigator/nfc and are split by type (emulation, read etc) and by protocol +2. Typically, all tests that are ran with same idea or card ran inside same class +3. In test_emulate_ntag213.py you can see that class has own set of tests and can be ran with -k TestEmulateNtag213. +Additionally test has its own fixture that is ran once on launch of any test from that class, that starts the emulation. +If you wish to do this manually, just comment the fixture emulate_ntag213 +4. Currently, proxmark wrapper is in really poor testing state, preferably add additional result parsers into test class or move them to separate module, +fewer modifications we do to output, the better + +Also if you wish to crop your own images for framework recognition, then you need to do the following: +1. Run python3 testOpenCV.py /dev/ttyACM0 +2. Go to needed screen on flippper (or via arrow keys + space + backspace) +3. Press C (as for crop) +4. Select the area and press V (no clue why V, probably paste, ask Daniil) +5. File will appear in /img folder +6. Name the file, usually it is same as text and case sensitive. If you are selecting text in browser, then you need to add "browser_" +7. Copy that image to /img/ref and now you can look up your own things on screen + +(you can look examples in /ref and in code) diff --git a/scripts/flippigator/nfc/test_emulate_ntag213.py b/scripts/flippigator/nfc/test_emulate_ntag213.py new file mode 100644 index 00000000000..4d46897d378 --- /dev/null +++ b/scripts/flippigator/nfc/test_emulate_ntag213.py @@ -0,0 +1,387 @@ +import time + +import pytest +from flippigator.extensions.proxmark_wrapper import proxmark_wrapper + + +class TestEmulateNtag213: + @pytest.fixture(scope="class", autouse=True) + def emulate_ntag213(self, nav): + nav.go_to_main_screen() + if nav.open_file("NFC", "T_Ntag_213") == -1: + assert 0, "File not found" + + @pytest.mark.skip(reason="not implemented") + def test_ntag213_basic(self, px): + # nav.go_to_main_screen() + # + # if nav.open_file("NFC", "Ntag213") == -1: + # assert 0, "File not found" + # nav.get_current_state() + + # data = px.execute_single("hf 14a raw -sc 3000") + # repeat previous line with enter button in the end + # data = px.execute(["hf 14a raw -sc 3000\n"]) + # + # print(data) + # result = px.execute_single("hf 14a raw -sc 3000") + pm = proxmark_wrapper("/home/vk/work/proxmark3/pm3") + # pm.execute_single("hf 14a raw -sc 3000") + + result = pm.execute( + ["hf 14a raw -sc 3000\n", "hf 14a raw -sc 3000\n", "hf 14a raw -sc 3001\n"] + ) + print(result) + print("-------------------------------------") + + # result = px.execute(["hf 14a raw -sc 3000\n","hf 14a raw -sc 3000\n","hf 14a raw -sc 3001\n"]) + # print(result) + + assert ( + result == "04 63 5D B2 9A 5A 12 90 42 48 00 00 E1 10 6D 00 [ 65 9C ]" + ), "Incorrect data on NFC card" + # reader_nfc.go_to_place() + # reader_nfc.clear() + # + # if nav.open_file("NFC", "BN2") == -1: + # assert 0, "File not found" + # nav.get_current_state() + # + # start_time = time.time() + # while start_time + 5 > time.time(): + # if reader_nfc.update(): + # string = reader_nfc.get() + # assert string == "W58W60950399D1334", "Emulated NFC card reading failed" + # break + # + # if start_time + 5 < time.time(): + # assert 0, "Timeout of emulation" + + # nav.go_to_main_screen() + + Test_Data = [ + ("hf 14a raw -sc A229440024FF", "0A", "Error: NFC card not found"), + ( + "hf 14a raw -sc 3024", + "30 34 42 41 46 46 43 41 34 44 35 44 38 30 00 00 [ E9 19 ]", + "Error: Incorrect data on NFC card", + ), + ( + "hf 14a raw -sc 3023", + "00 00 00 00 30 34 42 41 46 46 43 41 34 44 35 44 [ 1C AC ]", + "Error: Incorrect data on NFC card", + ), + ( + "hf 14a raw -sc 3025", + "46 46 43 41 34 44 35 44 38 30 00 00 00 AA AA BD [ 32 A3 ]", + "Error: Incorrect data on NFC card", + ), + ] + + @pytest.mark.parametrize("command, expected_result, error", Test_Data) + def test_ascii_mirror_uid(self, px, command, expected_result, error): + px_result = px.execute(command) + + result = px_result[0] + + assert expected_result == result, error + + test_data_byte_1 = [ + ("hf 14a raw -sc A229440024FF", "0A", "Error: NFC card not found"), + ( + "hf 14a raw -sc 3024", + "30 34 42 41 46 46 43 41 34 44 35 44 38 30 00 00 [ E9 19 ]", + "Error: Incorrect data on NFC card", + ), + ( + "hf 14a raw -sc 3023", + "00 00 00 00 30 34 42 41 46 46 43 41 34 44 35 44 [ 1C AC ]", + "Error: Incorrect data on NFC card", + ), + ( + "hf 14a raw -sc 3025", + "46 46 43 41 34 44 35 44 38 30 00 00 00 AA AA BD [ 32 A3 ]", + "Error: Incorrect data on NFC card", + ), + ] + + @pytest.mark.parametrize("command, expected_result, error", test_data_byte_1) + def test_ascii_mirror_uid_byte_1(self, px, command, expected_result, error): + px_result = px.execute(command) + + result = px_result[0] + + assert expected_result == result, error + + test_data_byte_2 = [ + ("hf 14a raw -sc A229540024FF", "0A", "Error: NFC card not found"), + ( + "hf 14a raw -sc 3024", + "00 30 34 42 41 46 46 43 41 34 44 35 44 38 30 00 [ 45 02 ]", + "Error: Incorrect data on NFC card", + ), + ( + "hf 14a raw -sc 3023", + "00 00 00 00 00 30 34 42 41 46 46 43 41 34 44 35 [ B1 7C ]", + "Error: Incorrect data on NFC card", + ), + ( + "hf 14a raw -sc 3025", + "41 46 46 43 41 34 44 35 44 38 30 00 00 AA AA BD [ 36 2A ]", + "Error: Incorrect data on NFC card", + ), + ] + + @pytest.mark.parametrize("command, expected_result, error", test_data_byte_2) + def test_ascii_mirror_uid_byte_2(self, px, command, expected_result, error): + px_result = px.execute(command) + + result = px_result[0] + + assert expected_result == result, error + + test_data_ascii_counter_0 = [ + ("hf 14a raw -sc A22A00050000", "0A"), + ("hf 14a raw -sc A229840026FF", "0A"), + ( + "hf 14a raw -sc 3025", + "00 00 00 00 00 00 00 00 00 00 00 00 00 AA AA BD [ 7B 09 ]", + ), + ( + "hf 14a raw -sc 3026", + "00 00 00 00 00 00 00 00 00 AA AA BD 84 00 26 FF [ DB E9 ]", + ), + ( + "hf 14a raw -sc 3027", + "00 00 00 00 00 AA AA BD 84 00 26 FF 00 05 00 00 [ E3 5C ]", + ), + ("hf 14a raw -sc A22A10050000", "0A"), + ( + "hf 14a raw -sc 3025", + "00 00 00 00 30 30 30 30 30 30 00 00 00 AA AA BD [ 54 E9 ]", + ), + ( + "hf 14a raw -sc 3025", + "00 00 00 00 30 30 30 30 30 31 00 00 00 AA AA BD [ 81 76 ]", + ), + ( + "hf 14a raw -sck 3025", + "00 00 00 00 30 30 30 30 30 32 00 00 00 AA AA BD [ EF DE ]", + ), + ( + "hf 14a raw -ac 3025", + "00 00 00 00 30 30 30 30 30 33 00 00 00 AA AA BD [ 3A 41 ]", + ), + ( + "hf 14a raw -sc 3026", + "30 30 30 30 30 33 00 00 00 AA AA BD 84 00 26 FF [ 63 23 ]", + ), + ( + "hf 14a raw -sc 3027", + "30 34 00 00 00 AA AA BD 84 00 26 FF 10 05 00 00 [ 4F B2 ]", + ), + ("hf 14a raw -sc A22A00050000", "0A"), + ] + + ASCII_COUNTER_1 = [ + ("hf 14a raw -sc A22A00050000", "0A"), + ("hf 14a raw -sc A229940026FF", "0A"), + ( + "hf 14a raw -sc 3025", + "00 00 00 00 00 00 00 00 00 00 00 00 00 AA AA BD [ 7B 09 ]", + ), + ( + "hf 14a raw -sc 3026", + "00 00 00 00 00 00 00 00 00 AA AA BD 84 00 26 FF [ DB E9 ]", + ), + ( + "hf 14a raw -sc 3027", + "00 00 00 00 00 AA AA BD 84 00 26 FF 00 05 00 00 [ E3 5C ]", + ), + ("hf 14a raw -sc A22A10050000", "0A"), + ( + "hf 14a raw -sc 3025", + "00 00 00 00 30 30 30 30 35 39 00 00 00 AA AA BD [ 0C 3F ]", + ), + ( + "hf 14a raw -sc 3026", + "30 30 30 30 35 41 00 00 00 AA AA BD 84 00 26 FF [ A8 56 ]", + ), + ( + "hf 14a raw -sc 3027", + "35 42 00 00 00 AA AA BD 84 00 26 FF 10 05 00 00 [ 5F D8 ]", + ), + ("hf 14a raw -sc A22A00050000", "0A"), + ] + + test_data_ascii_counter_1 = [ + ("hf 14a raw -sc A22A00050000", "0A"), + ("hf 14a raw -sc A229840026FF", "0A"), + ( + "hf 14a raw -sc 3025", + "00 00 00 00 00 00 00 00 00 00 00 00 00 AA AA BD [ 7B 09 ]", + ), + ( + "hf 14a raw -sc 3026", + "00 00 00 00 00 00 00 00 00 AA AA BD 84 00 26 FF [ DB E9 ]", + ), + ( + "hf 14a raw -sc 3027", + "00 00 00 00 00 AA AA BD 84 00 26 FF 00 05 00 00 [ E3 5C ]", + ), + ("hf 14a raw -sc A22A10050000", "0A"), + ( + "hf 14a raw -sc 3025", + "00 00 00 00 30 30 30 30 35 39 00 00 00 AA AA BD [ 0C 3F ]", + ), + ( + "hf 14a raw -sc 3026", + "30 30 30 30 35 41 00 00 00 AA AA BD 84 00 26 FF [ A8 56 ]", + ), + ( + "hf 14a raw -sc 3027", + "35 42 00 00 00 AA AA BD 84 00 26 FF 10 05 00 00 [ 5F D8 ]", + ), + ("hf 14a raw -sc A22A00050000", "0A"), + ] + + test_data_ascii_counter_2 = [ + ("hf 14a raw -sc A22A00050000", "0A"), + ("hf 14a raw -sc A229A40026FF", "0A"), + ( + "hf 14a raw -sc 3025", + "00 00 00 00 00 00 00 00 00 00 00 00 00 AA AA BD [ 7B 09 ]", + ), + ( + "hf 14a raw -sc 3026", + "00 00 00 00 00 00 00 00 00 AA AA BD 84 00 26 FF [ DB E9 ]", + ), + ( + "hf 14a raw -sc 3027", + "00 00 00 00 00 AA AA BD 84 00 26 FF 00 05 00 00 [ E3 5C ]", + ), + ("hf 14a raw -sc A22A10050000", "0A"), + ( + "hf 14a raw -sc 3025", + "00 00 00 00 30 30 30 30 35 39 00 00 00 AA AA BD [ 0C 3F ]", + ), + ( + "hf 14a raw -sc 3026", + "30 30 30 30 35 41 00 00 00 AA AA BD 84 00 26 FF [ A8 56 ]", + ), + ( + "hf 14a raw -sc 3027", + "35 42 00 00 00 AA AA BD 84 00 26 FF 10 05 00 00 [ 5F D8 ]", + ), + ("hf 14a raw -sc A22A00050000", "0A"), + ] + + test_data_ascii_counter_3 = [ + ("hf 14a raw -sc A22A00050000", "0A"), + ("hf 14a raw -sc A229B40026FF", "0A"), + ( + "hf 14a raw -sc 3025", + "00 00 00 00 00 00 00 00 00 00 00 00 00 AA AA BD [ 7B 09 ]", + ), + ( + "hf 14a raw -sc 3026", + "00 00 00 00 00 00 00 00 00 AA AA BD B4 00 26 FF [ 29 A5 ]", + ), + ( + "hf 14a raw -sc 3027", + "00 00 00 00 00 AA AA BD B4 00 26 FF 00 05 00 00 [ 6B B1 ]", + ), + ("hf 14a raw -sc A22A10050000", "0A"), + ( + "hf 14a raw -sc 3025", + "00 00 00 00 00 00 00 00 00 00 00 00 00 AA AA BD [ 7B 09 ]", + ), + ( + "hf 14a raw -sc 3026", + "00 00 00 00 00 00 00 00 00 AA AA BD B4 00 26 FF [ 29 A5 ]", + ), + ( + "hf 14a raw -sc 3027", + "00 00 00 00 00 AA AA BD B4 00 26 FF 10 05 00 00 [ CA 72 ]", + ), + ("hf 14a raw -sc A22A00050000", "0A"), + ] + + @pytest.mark.parametrize("command, expected_result", test_data_ascii_counter_0) + def test_ascii_counter_0(self, px, command, expected_result): + px_result = px.execute(command) + + result = px_result[0] + + assert expected_result == result + + result = px_result[0] + + assert expected_result == result + + @pytest.mark.parametrize("command, expected_result", test_data_ascii_counter_1) + def test_ascii_counter_1(self, px, command, expected_result): + px_result = px.execute(command) + + result = px_result[0] + + assert expected_result == result + + @pytest.mark.parametrize("command, expected_result", test_data_ascii_counter_2) + def test_ascii_counter_2(self, px, command, expected_result): + px_result = px.execute(command) + + result = px_result[0] + + assert expected_result == result + + @pytest.mark.parametrize("command, expected_result", test_data_ascii_counter_3) + def test_ascii_counter_3(self, px, command, expected_result): + px_result = px.execute(command) + + result = px_result[0] + + assert expected_result == result + + test_data_ascii_counter_0_pwd = [ + ("hf 14a raw -sc A22A00050000", "0A"), + ("hf 14a raw -sc A229840026FF", "0A"), + ( + "hf 14a raw -sc 3025", + "00 00 00 00 00 00 00 00 00 00 00 00 00 AA AA BD [ 7B 09 ]", + ), + ( + "hf 14a raw -sc 3026", + "00 00 00 00 00 00 00 00 00 AA AA BD 84 00 26 FF [ DB E9 ]", + ), + ( + "hf 14a raw -sc 3027", + "00 00 00 00 00 AA AA BD 84 00 26 FF 00 05 00 00 [ E3 5C ]", + ), + ("hf 14a raw -sc A22A18050000", "0A"), + ( + "hf 14a raw -sck 1BFFFFFFFF", + "00 00 00 00 30 30 30 30 35 39 00 00 00 AA AA BD [ 0C 3F ]", + ), + ( + "hf 14a raw -ack 3025", + "00 00 00 00 30 30 30 30 35 39 00 00 00 AA AA BD [ 0C 3F ]", + ), + ( + "hf 14a raw -ack 3026", + "30 30 30 30 35 41 00 00 00 AA AA BD 84 00 26 FF [ A8 56 ]", + ), + ( + "hf 14a raw -ack 3027", + "35 42 00 00 00 AA AA BD 84 00 26 FF 10 05 00 00 [ 5F D8 ]", + ), + ("hf 14a raw -ac A22A00050000", "0A"), + ] + + @pytest.mark.parametrize("command, expected_result", test_data_ascii_counter_0_pwd) + def test_ascii_counter_0_pwd(self, px, command, expected_result): + px_result = px.execute(command) + + result = px_result[0] + + assert expected_result == result