From 23e6aa40b765f93e71a03fa67c3e36e423718d38 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Thu, 28 Nov 2024 17:33:43 +0100 Subject: [PATCH 01/12] hf/lf tune: fix segfault when called from script --- CHANGELOG.md | 3 ++- client/src/ui.c | 16 ++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52e139959..df8ab5448 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,8 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] -- Add option to set and get maximum read/write block number using `hf_mf_ultimatecard` script (@piotrva) +- Fixed `hf/lf tune` segfault when called from script (@doegox) +- Added option to set and get maximum read/write block number using `hf_mf_ultimatecard` script (@piotrva) - Added JEDEC information for SPI flash W25Q64JV (@ANTodorov) - Added special iclass legacy config cards in `hf iclass configcard` (@antiklesys) - Added simulation function to `hf iclass legrec` (@antiklesys) diff --git a/client/src/ui.c b/client/src/ui.c index 09730d8d3..68cc71a43 100644 --- a/client/src/ui.c +++ b/client/src/ui.c @@ -696,14 +696,18 @@ void print_progress(uint64_t count, uint64_t max, barMode_t style) { max = (count > max) ? count : max; #if defined(HAVE_READLINE) static int prev_cols = 0; - int rows; - rl_reset_screen_size(); // refresh Readline idea of the actual screen width - rl_get_screen_size(&rows, &cols); + int tmp_cols; + rl_get_screen_size(NULL, &tmp_cols); + // if cols==0: impossible to get screen size, e.g. when scripted + if (tmp_cols != 0) { + // don't call it if cols==0, it would segfault + rl_reset_screen_size(); // refresh Readline idea of the actual screen width + rl_get_screen_size(NULL, &cols); - if (cols < 36) - return; + if (cols < 36) + return; + } - (void) rows; if (prev_cols > cols) { PrintAndLogEx(NORMAL, _CLEAR_ _TOP_ ""); } From e4a3a244ce3c557d1b1e09174c0ca25f709efe3e Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Sat, 30 Nov 2024 07:53:52 +0800 Subject: [PATCH 02/12] Added unhash instructions after legbrute Added unhash instructions after legbrute --- client/src/cmdhficlass.c | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index a7e215e1e..b701aeb19 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -4152,6 +4152,7 @@ static int CmdHFiClassLegRecLookUp(const char *Cmd) { } if (check_values) { PrintAndLogEx(SUCCESS, _GREEN_("CONFIRMED VALID RAW key ") _RED_("%s"), sprint_hex(div_key, 8)); + PrintAndLogEx(INFO, "You can now run -> "_YELLOW_("hf iclass unhash -k %s")" <-to find the pre-images.", sprint_hex(div_key, 8)); verified = true; } else { PrintAndLogEx(INFO, _YELLOW_("Raw Key Invalid")); From ca15bbd01972e36b267543f0cc5897a657c3fe12 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Thu, 28 Nov 2024 16:59:05 +0100 Subject: [PATCH 03/12] Rework theremin script --- client/pyscripts/theremin.py | 216 +++++++++++++++++++++++++---------- 1 file changed, 156 insertions(+), 60 deletions(-) diff --git a/client/pyscripts/theremin.py b/client/pyscripts/theremin.py index 790fc6bf8..8cb41737a 100755 --- a/client/pyscripts/theremin.py +++ b/client/pyscripts/theremin.py @@ -1,81 +1,177 @@ #!/usr/bin/python3 -### Parameters +import os +import subprocess +import signal +import numpy as np +from pyaudio import PyAudio, paFloat32, paContinue + # Sound output parameters volume = 1.0 -sample_buf_size = 44 -sampling_freq = 44100 #Hz +sampling_freq = 44100 # Hz # Frequency generator parameters -min_freq = 200 #Hz -max_freq = 2000 #Hz +min_freq = 100 # Hz +max_freq = 6000 # Hz # Proxmark3 parameters -pm3_client="/usr/local/bin/proxmark3" -pm3_reader_dev_file="/dev/ttyACM0" -pm3_tune_cmd="hf tune" +pm3_client = "pm3" +pm3_tune_cmd = "hf tune --value" + +frequency = 440 +buffer = [] -### Modules -import numpy -import pyaudio -from select import select -from subprocess import Popen, DEVNULL, PIPE +def find_zero_crossing_index(array): + for i in range(1, len(array)): + if array[i-1] < 0 and array[i] >= 0: + return i + return None # Return None if no zero-crossing is found -### Main program -p = pyaudio.PyAudio() +def generate_sine_wave(frequency, sample_rate, duration, frame_count): + """Generate a sine wave at a given frequency.""" + t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False) + wave = np.sin(2 * np.pi * frequency * t) + return wave[:frame_count] -# For paFloat32 sample values must be in range [-1.0, 1.0] -stream = p.open(format=pyaudio.paFloat32, - channels=1, - rate=sampling_freq, - output=True) -# Initial voltage to frequency values -min_v = 100.0 -max_v = 0.0 -v = 0 -out_freq = min_freq +# PyAudio Callback function +def pyaudio_callback(in_data, frame_count, time_info, status): + # if in_data is None: + # return (in_data, pyaudio.paContinue) + global frequency + global buffer + wave = generate_sine_wave(frequency, sampling_freq, 0.01, frame_count*2) + i = find_zero_crossing_index(buffer) + if i is None: + buffer = wave + else: + buffer = np.concatenate((buffer[:i], wave)) + data = (buffer[:frame_count] * volume).astype(np.float32).tobytes() + buffer = buffer[frame_count:] + return (data, paContinue) +# pyaudio.paComplete -# Spawn the Proxmark3 client -pm3_proc = Popen([pm3_client, pm3_reader_dev_file, "-c", pm3_tune_cmd], bufsize=0, env={}, stdin=DEVNULL, stdout=PIPE, stderr=DEVNULL) -mv_recbuf = "" -# Read voltages from the Proxmark3, generate the sine wave, output to soundcard -sample_buf = [0.0 for x in range(0, sample_buf_size)] -i = 0 -sinev = 0 -while True: +def silent_pyaudio(): + """ + Lifted and adapted from https://stackoverflow.com/questions/67765911/ + PyAudio is noisy af every time you initialise it, which makes reading the + log output rather difficult. The output appears to be being made by the + C internals, so we can't even redirect the logs with Python's logging + facility. Therefore the nuclear option was selected: swallow all stderr + and stdout for the duration of PyAudio's use. + """ - # Read Proxmark3 client's stdout and extract voltage values - if(select([pm3_proc.stdout], [], [], 0)[0]): + # Open a pair of null files + null_fds = [os.open(os.devnull, os.O_RDWR) for x in range(2)] + # Save the actual stdout (1) and stderr (2) file descriptors. + save_fds = [os.dup(1), os.dup(2)] + # Assign the null pointers to stdout and stderr. + os.dup2(null_fds[0], 1) + os.dup2(null_fds[1], 2) + pyaudio = PyAudio() + os.dup2(save_fds[0], 1) + os.dup2(save_fds[1], 2) + # Close all file descriptors + for fd in null_fds + save_fds: + os.close(fd) + return pyaudio - b = pm3_proc.stdout.read(256).decode("ascii") - if "Done" in b: - break; - for c in b: - if c in "0123456789 mV": - mv_recbuf += c - else: - mv_recbuf = "" - if mv_recbuf[-3:] == " mV": - v = int(mv_recbuf[:-3]) / 1000 - if v < min_v: - min_v = v - 0.001 - if v > max_v: - max_v = v + +def run_pm3_cmd(callback): + # Start the process + process = subprocess.Popen( + [pm3_client, '-c', pm3_tune_cmd], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + bufsize=1, # Line buffered + shell=False + ) + + # Read the output line by line as it comes + try: + with process.stdout as pipe: + for line in pipe: + # Process each line + l = line.strip() # Strip to remove any extraneous newline characters + callback(l) + except Exception as e: + print(f"An error occurred: {e}") + finally: + # Ensure the subprocess is properly terminated + process.terminate() + process.wait() + + +def linear_to_exponential_freq(v, min_v, max_v, min_freq, max_freq): + # First, map v to a range between 0 and 1 + if max_v != min_v: + normalized_v = (v - min_v) / (max_v - min_v) + else: + normalized_v = 0.5 + normalized_v = 1 - normalized_v + + # Calculate the ratio of the max frequency to the min frequency + freq_ratio = max_freq / min_freq + + # Calculate the exponential frequency using the mapped v + freq = min_freq * (freq_ratio ** normalized_v) + return freq + + +class foo(): + def __init__(self): + self.p = silent_pyaudio() + # For paFloat32 sample values must be in range [-1.0, 1.0] + self.stream = self.p.open(format=paFloat32, + channels=1, + rate=sampling_freq, + output=True, + stream_callback=pyaudio_callback) + + # Initial voltage to frequency values + self.min_v = 50000.0 + self.max_v = 0.0 + + # Setting the signal handler for SIGINT (Ctrl+C) + signal.signal(signal.SIGINT, self.signal_handler) + + # Start the stream + self.stream.start_stream() + + def __exit__(self): + self.stream.stop_stream() + self.stream.close() + self.p.terminate() + + def signal_handler(self, sig, frame): + print("\nYou pressed Ctrl+C! Press Enter") + self.__exit__() + + def callback(self, line): + if 'mV' not in line: + return + v = int(line.split(' ')[1]) + if v == 0: + return + self.min_v = min(self.min_v, v) + self.max_v = max(self.max_v, v) # Recalculate the audio frequency to generate - out_freq = (max_freq - min_freq) * (max_v - v) / (max_v - min_v) \ - + min_freq + global frequency + frequency = linear_to_exponential_freq(v, self.min_v, self.max_v, min_freq, max_freq) - # Generate the samples and write them to the soundcard - sinevs = out_freq / sampling_freq * numpy.pi * 2 - sample_buf[i] = sinev - sinev += sinevs - sinev = sinev if sinev < numpy.pi * 2 else sinev - numpy.pi * 2 - i = (i + 1) % sample_buf_size - if not i: - stream.write((numpy.sin(sample_buf) * volume). - astype(numpy.float32).tobytes()) +# frequency = max_freq - ((max_freq - min_freq) * (v - self.min_v) / (self.max_v - self.min_v) + min_freq) + #frequency = (frequency + new_frequency)/2 + + +def main(): + f = foo() + run_pm3_cmd(f.callback) + + +if __name__ == "__main__": + main() From d8d090612d00248c61fc3bd6b4f4185dcdc6269b Mon Sep 17 00:00:00 2001 From: Lucifer Voeltner Date: Sat, 30 Nov 2024 17:57:48 +0700 Subject: [PATCH 04/12] 'hf mfu incr' to increment counters of UL-EV1 family; Also fix reading of NTAG counters in 'hf mfu info' --- client/src/cmdhfmfu.c | 132 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 123 insertions(+), 9 deletions(-) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 658e028e5..68869a6fb 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -1540,21 +1540,13 @@ static int ulev1_print_version(uint8_t *data) { } static int ntag_print_counter(void) { - // NTAG has one counter/tearing. At address 0x02. + // NTAG has one counter. At address 0x02. With no tearing. PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Counter")); - uint8_t tear[1] = {0}; uint8_t counter[3] = {0, 0, 0}; uint16_t len; - len = ulev1_readTearing(0x02, tear, sizeof(tear)); - (void)len; len = ulev1_readCounter(0x02, counter, sizeof(counter)); - (void)len; PrintAndLogEx(INFO, " [02]: %s", sprint_hex(counter, 3)); - PrintAndLogEx(SUCCESS, " - %02X tearing ( %s )" - , tear[0] - , (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("fail") - ); return len; } @@ -5833,6 +5825,127 @@ out: return PM3_SUCCESS; } +static int CmdHF14AMfUIncr(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfu incr", + "Increment a MIFARE Ultralight Ev1 counter\n" + "Will read but not increment counter if NTAG is detected", + "hf mfu incr -c 0 -v 1337\n" + "hf mfu incr -c 2 -v 0 -p FFFFFFFF"); + void *argtable[] = { + arg_param_begin, + arg_int1("c", "cnt", "", "Counter index from 0"), + arg_int1("v", "val", "", "Value to increment by (0-16777215)"), + arg_str0("p", "pwd", "", "PWD to authenticate with"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + uint8_t counter = arg_get_int_def(ctx, 1, 3); + uint32_t value = arg_get_u32_def(ctx, 2, 16777216); + + int pwd_len; + uint8_t pwd[4] = { 0x00 }; + CLIGetHexWithReturn(ctx, 3, pwd, &pwd_len); + bool has_key = false; + if (pwd_len) { + has_key = true; + if (pwd_len != 4) { + PrintAndLogEx(WARNING, "incorrect PWD length"); + return PM3_EINVARG; + } + } + + CLIParserFree(ctx); + + if (counter > 2) { + PrintAndLogEx(WARNING, "Counter index must be in range 0-2"); + return PM3_EINVARG; + } + if (value > 16777215) { + PrintAndLogEx(WARNING, "Value to increment must be in range 0-16777215"); + return PM3_EINVARG; + } + + uint8_t increment_cmd[6] = { MIFARE_ULEV1_INCR_CNT, counter, 0x00, 0x00, 0x00, 0x00 }; + + for (uint8_t i = 0; i < 3; i++) { + increment_cmd[i + 2] = (value >> (8 * i)) & 0xff; + } + + iso14a_card_select_t card; + if (ul_select(&card) == false) { + PrintAndLogEx(FAILED, "failed to select card, exiting..."); + return PM3_ESOFT; + } + + uint64_t tagtype = GetHF14AMfU_Type(); + uint64_t tags_with_counter_ul = MFU_TT_UL_EV1_48 | MFU_TT_UL_EV1_128 | MFU_TT_UL_EV1; + uint64_t tags_with_counter_ntag = MFU_TT_NTAG_213 | MFU_TT_NTAG_213_F | MFU_TT_NTAG_213_C | MFU_TT_NTAG_213_TT | MFU_TT_NTAG_215 | MFU_TT_NTAG_216; + if ((tagtype & (tags_with_counter_ul | tags_with_counter_ntag)) == 0) { + PrintAndLogEx(WARNING, "tag type does not have counters"); + DropField(); + return PM3_ESOFT; + } + + bool is_ntag = (tagtype & tags_with_counter_ntag) != 0; + if (is_ntag && (counter != 2)) { + PrintAndLogEx(WARNING, "NTAG only has one counter at index 2"); + DropField(); + return PM3_EINVARG; + } + + uint8_t pack[4] = { 0, 0, 0, 0 }; + if (has_key) { + if (ulev1_requestAuthentication(pwd, pack, sizeof(pack)) == PM3_EWRONGANSWER) { + PrintAndLogEx(FAILED, "authentication failed UL-EV1/NTAG"); + DropField(); + return PM3_ESOFT; + } + } + + uint8_t current_counter[3] = { 0, 0, 0 }; + int len = ulev1_readCounter(counter, current_counter, sizeof(current_counter)); + if (len != sizeof(current_counter)) { + PrintAndLogEx(FAILED, "failed to read old counter"); + if (is_ntag) { + PrintAndLogEx(HINT, "NTAG detected, try reading with PWD"); + } + DropField(); + return PM3_ESOFT; + } + + uint32_t current_counter_num = current_counter[0] | (current_counter[1] << 8) | (current_counter[2] << 16); + PrintAndLogEx(INFO, "Current counter... " _GREEN_("%8d") " - " _GREEN_("%s"), current_counter_num, sprint_hex(current_counter, 3)); + + if ((tagtype & tags_with_counter_ntag) != 0) { + PrintAndLogEx(WARNING, "NTAG detected, unable to manually increment counter"); + DropField(); + return PM3_ESOFT; + } + + uint8_t resp[1] = { 0x00 }; + if (ul_send_cmd_raw(increment_cmd, sizeof(increment_cmd), resp, sizeof(resp)) < 0) { + PrintAndLogEx(FAILED, "failed to increment counter"); + DropField(); + return PM3_ESOFT; + } + + uint8_t new_counter[3] = { 0, 0, 0 }; + int new_len = ulev1_readCounter(counter, new_counter, sizeof(new_counter)); + if (new_len != sizeof(current_counter)) { + PrintAndLogEx(FAILED, "failed to read new counter"); + DropField(); + return PM3_ESOFT; + } + + uint32_t new_counter_num = new_counter[0] | (new_counter[1] << 8) | (new_counter[2] << 16); + PrintAndLogEx(INFO, "New counter....... " _GREEN_("%8d") " - " _GREEN_("%s"), new_counter_num, sprint_hex(new_counter, 3)); + + DropField(); + return PM3_SUCCESS; +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"list", CmdHF14AMfuList, AlwaysAvailable, "List MIFARE Ultralight / NTAG history"}, @@ -5845,6 +5958,7 @@ static command_t CommandTable[] = { {"cauth", CmdHF14AMfUCAuth, IfPm3Iso14443a, "Ultralight-C - Authentication"}, {"setpwd", CmdHF14AMfUCSetPwd, IfPm3Iso14443a, "Ultralight-C - Set 3DES key"}, {"dump", CmdHF14AMfUDump, IfPm3Iso14443a, "Dump MIFARE Ultralight family tag to binary file"}, + {"incr", CmdHF14AMfUIncr, IfPm3Iso14443a, "Increments Ev1/NTAG counter"}, {"info", CmdHF14AMfUInfo, IfPm3Iso14443a, "Tag information"}, {"ndefread", CmdHF14MfuNDEFRead, IfPm3Iso14443a, "Prints NDEF records from card"}, {"rdbl", CmdHF14AMfURdBl, IfPm3Iso14443a, "Read block"}, From 4adf6633004ac6efdbd42715e1d7131605d028cc Mon Sep 17 00:00:00 2001 From: Lucifer Voeltner Date: Sun, 1 Dec 2024 16:27:35 +0700 Subject: [PATCH 05/12] Fix Gen 3 APDU block 0 SAK not being written correctly --- armsrc/mifarecmd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 659c5eec0..2eed2ca5c 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -3482,7 +3482,8 @@ void MifareGen3Blk(uint8_t block_len, uint8_t *block) { retval = PM3_ESOFT; goto OUT; } - cmd[ofs++] = card_info->sak; + cmd[ofs] = block_len < card_info->uidlen ? card_info->sak : cmd[ofs]; + ofs++; cmd[ofs++] = card_info->atqa[0]; cmd[ofs++] = card_info->atqa[1]; AddCrc14A(cmd, sizeof(block_cmd) + MIFARE_BLOCK_SIZE); From ef74de37218776cbab4d7a4fa682c605feac3713 Mon Sep 17 00:00:00 2001 From: Xavier <90627943+kitsunehunter@users.noreply.github.com> Date: Sun, 1 Dec 2024 20:17:05 -0500 Subject: [PATCH 06/12] add static laundry card keys these cards are stored value and manipulating the data is useful Signed-off-by: Xavier <90627943+kitsunehunter@users.noreply.github.com> --- client/dictionaries/mfc_default_keys.dic | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/client/dictionaries/mfc_default_keys.dic b/client/dictionaries/mfc_default_keys.dic index 76b5198b6..646099bad 100644 --- a/client/dictionaries/mfc_default_keys.dic +++ b/client/dictionaries/mfc_default_keys.dic @@ -2760,3 +2760,9 @@ D37C8F1793F7 56cf3acd90ca 542089792be2 5420aeada758 +#Coinamatic laundry +0734BFB93DAB +85A438F72A8A +#CSC Laundry +212223242555 +717273747555 From 4e40d3d6a732216bbff90de577357a2f9955e3dd Mon Sep 17 00:00:00 2001 From: Xavier <90627943+kitsunehunter@users.noreply.github.com> Date: Sun, 1 Dec 2024 20:27:08 -0500 Subject: [PATCH 07/12] Update mfc_default_keys.dic Signed-off-by: Xavier <90627943+kitsunehunter@users.noreply.github.com> --- client/dictionaries/mfc_default_keys.dic | 3 --- 1 file changed, 3 deletions(-) diff --git a/client/dictionaries/mfc_default_keys.dic b/client/dictionaries/mfc_default_keys.dic index 646099bad..f3a339c93 100644 --- a/client/dictionaries/mfc_default_keys.dic +++ b/client/dictionaries/mfc_default_keys.dic @@ -2760,9 +2760,6 @@ D37C8F1793F7 56cf3acd90ca 542089792be2 5420aeada758 -#Coinamatic laundry -0734BFB93DAB -85A438F72A8A #CSC Laundry 212223242555 717273747555 From 7fbcb1c30f869c903ade1a2dcd70ec2ae7e3e499 Mon Sep 17 00:00:00 2001 From: nya0 Date: Mon, 2 Dec 2024 16:15:13 +0300 Subject: [PATCH 08/12] added "lf hitag hts dump" command --- client/src/cmdlfhitaghts.c | 91 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/client/src/cmdlfhitaghts.c b/client/src/cmdlfhitaghts.c index d1af178dd..933427ec8 100644 --- a/client/src/cmdlfhitaghts.c +++ b/client/src/cmdlfhitaghts.c @@ -444,6 +444,96 @@ static int CmdLFHitagSRead(const char *Cmd) { return PM3_SUCCESS; } +static int CmdLFHitagSDump(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf hitag hts dump", + "Read all Hitag S memory and save to file\n" + " Crypto mode: \n" + " - key format ISK high + ISK low\n" + " - default key 4F4E4D494B52 (ONMIKR)\n\n" + " 8268/8310 password mode: \n" + " - default password BBDD3399\n", + "lf hitag hts dump --82xx -k BBDD3399 -> pwd mode\n" + "lf hitag hts dump --crypto -> use def crypto\n" + "lf hitag hts dump -k 4F4E4D494B52 -> crypto mode\n" + "lf hitag hts dump --nrar 0102030411223344\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("8", "82xx", "8268/8310 mode"), + arg_str0(NULL, "nrar", "", "nonce / answer writer, 8 hex bytes"), + arg_lit0(NULL, "crypto", "crypto mode"), + arg_str0("k", "key", "", "pwd or key, 4 or 6 hex bytes"), + arg_int0("m", "mode", "", "response protocol mode. 0 (Standard 00110), 1 (Advanced 11000), 2 (Advanced 11001), 3 (Fast Advanced 11010) (def: 3)"), + arg_str0("f", "file", "", "specify file name"), + arg_lit0(NULL, "ns", "no save to file"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + lf_hitag_data_t packet; + memset(&packet, 0, sizeof(packet)); + + if (process_hitags_common_args(ctx, &packet) < 0) { + CLIParserFree(ctx); + return PM3_EINVARG; + } + + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + + bool nosave = arg_get_lit(ctx, 7); + CLIParserFree(ctx); + + // read all pages + packet.page = 0; + packet.page_count = 0; + + clearCommandBuffer(); + SendCommandNG(CMD_LF_HITAGS_READ, (uint8_t *) &packet, sizeof(packet)); + + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_LF_HITAGS_READ, &resp, 5000) == false) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + if (resp.status != PM3_SUCCESS) { + print_error(resp.reason); + return PM3_ESOFT; + } + + lf_hts_read_response_t *card = (lf_hts_read_response_t *)resp.data.asBytes; + + const int hts_mem_sizes[] = {1, 8, 64, 64}; + int mem_size = hts_mem_sizes[card->config_page.s.MEMT] * HITAGS_PAGE_SIZE; + + hitags_config_t config = card->config_page.s; + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); + hitags_config_print(config); + + if (nosave) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "Called with no save option"); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; + } + + if (fnlen < 1) { + char *fptr = filename; + fptr += snprintf(filename, sizeof(filename), "lf-hitags-"); + FillFileNameByUID(fptr, card->pages[HITAGS_UID_PADR], "-dump", HITAGS_PAGE_SIZE); + } + + pm3_save_dump(filename, (uint8_t *)card->pages, mem_size, jsfHitag); + + return PM3_SUCCESS; +} + static int CmdLFHitagSWrite(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf hitag hts wrbl", @@ -615,6 +705,7 @@ static command_t CommandTable[] = { {"-----------", CmdHelp, IfPm3Hitag, "----------------------- " _CYAN_("General") " ------------------------"}, {"reader", CmdLFHitagSReader, IfPm3Hitag, "Act like a Hitag S reader"}, {"rdbl", CmdLFHitagSRead, IfPm3Hitag, "Read Hitag S page"}, + {"dump", CmdLFHitagSDump, IfPm3Hitag, "Dump Hitag S pages to a file"}, {"wrbl", CmdLFHitagSWrite, IfPm3Hitag, "Write Hitag S page"}, {"-----------", CmdHelp, IfPm3Hitag, "----------------------- " _CYAN_("Simulation") " -----------------------"}, {"sim", CmdLFHitagSSim, IfPm3Hitag, "Simulate Hitag S transponder"}, From cbc7d61781173ea6d79dae796cb8197dea3b6e29 Mon Sep 17 00:00:00 2001 From: Lucifer Voeltner Date: Tue, 3 Dec 2024 10:13:09 +0700 Subject: [PATCH 09/12] modify 'hf mf gen3blk' help to comply with the sak change --- client/src/cmdhfmf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 2bfd6a020..877bbdefb 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -7202,7 +7202,7 @@ static int CmdHf14AGen3Block(const char *Cmd) { " - You can specify part of manufacturer block as\n" " 4/7-bytes for UID change only\n" "\n" - "NOTE: BCC, SAK, ATQA will be calculated automatically" + "NOTE: BCC and ATQA will be calculated automatically" , "hf mf gen3blk --> print current data\n" "hf mf gen3blk -d 01020304 --> set 4 byte uid\n" From e416080ae8e44a8328910962374cad7d4349044f Mon Sep 17 00:00:00 2001 From: Lucifer Voeltner Date: Tue, 3 Dec 2024 10:23:41 +0700 Subject: [PATCH 10/12] make the help message even clearer, and fix a bug featuring me being unable to count --- armsrc/mifarecmd.c | 2 +- client/src/cmdhfmf.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 2eed2ca5c..9820d19a2 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -3482,7 +3482,7 @@ void MifareGen3Blk(uint8_t block_len, uint8_t *block) { retval = PM3_ESOFT; goto OUT; } - cmd[ofs] = block_len < card_info->uidlen ? card_info->sak : cmd[ofs]; + cmd[ofs] = block_len <= card_info->uidlen ? card_info->sak : cmd[ofs]; ofs++; cmd[ofs++] = card_info->atqa[0]; cmd[ofs++] = card_info->atqa[1]; diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 877bbdefb..e61a6a7e9 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -7202,7 +7202,8 @@ static int CmdHf14AGen3Block(const char *Cmd) { " - You can specify part of manufacturer block as\n" " 4/7-bytes for UID change only\n" "\n" - "NOTE: BCC and ATQA will be calculated automatically" + "NOTE: BCC and ATQA will be calculated automatically\n" + "SAK will be automatically set to default values if not specified" , "hf mf gen3blk --> print current data\n" "hf mf gen3blk -d 01020304 --> set 4 byte uid\n" From 2950d7870317eb4924fb329b98ad2db7ee2c02ff Mon Sep 17 00:00:00 2001 From: ry4000 <154689120+ry4000@users.noreply.github.com> Date: Tue, 3 Dec 2024 22:51:29 +1100 Subject: [PATCH 11/12] R&Y: Updated DEN MyRide AID in aid_desfire.json - Updated Vendor to its legal name (Masabi Ltd) - Added a standardised description to identify the AID as being issued by Masabi Ltd for its Justride platform. Thank you. -R&Y. Signed-off-by: ry4000 <154689120+ry4000@users.noreply.github.com> --- client/resources/aid_desfire.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/resources/aid_desfire.json b/client/resources/aid_desfire.json index 53cb47992..8ecd18a6e 100644 --- a/client/resources/aid_desfire.json +++ b/client/resources/aid_desfire.json @@ -1065,10 +1065,10 @@ }, { "AID": "DD00DD", - "Vendor": "Regional Transporation District (RTD) via masabi justride", + "Vendor": "Regional Transporation District (RTD) via Masabi Ltd", "Country": "US", "Name": "MyRide Card (DEN)", - "Description": "DEN MyRide Card", + "Description": "DEN MyRide Card; Masabi Justride Tap and Ride DESFire Smartcard", "Type": "transport" }, { From 537a9f0171ed9fdafd52d1ba7a98fcf098da836b Mon Sep 17 00:00:00 2001 From: libin-ka <46210417+libin-ka@users.noreply.github.com> Date: Tue, 3 Dec 2024 21:04:50 +0800 Subject: [PATCH 12/12] Add files via upload Add Proxmark3 Ultimate FPGA xc2s50-5-tq144.ucf files Signed-off-by: libin-ka <46210417+libin-ka@users.noreply.github.com> --- fpga/xc2s50-5-tq144.ucf | 45 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 fpga/xc2s50-5-tq144.ucf diff --git a/fpga/xc2s50-5-tq144.ucf b/fpga/xc2s50-5-tq144.ucf new file mode 100644 index 000000000..0964e1acf --- /dev/null +++ b/fpga/xc2s50-5-tq144.ucf @@ -0,0 +1,45 @@ +# See the schematic for the pin assignment. + +NET "adc_d<0>" LOC = "P54" ; +NET "adc_d<1>" LOC = "P57" ; +NET "adc_d<2>" LOC = "P59" ; +NET "adc_d<3>" LOC = "P60" ; +NET "adc_d<4>" LOC = "P62" ; +NET "adc_d<5>" LOC = "P63" ; +NET "adc_d<6>" LOC = "P65" ; +NET "adc_d<7>" LOC = "P67" ; +#NET "cross_hi" LOC = "P88" ; +#NET "miso" LOC = "P40" ; +NET "adc_clk" LOC = "P75" ; +NET "adc_noe" LOC = "P74" ; +NET "ck_1356meg" LOC = "P15" ; +NET "ck_1356megb" LOC = "P12" ; +NET "cross_lo" LOC = "P19" ; +NET "dbg" LOC = "P112" ; +NET "mosi" LOC = "P80" ; +NET "ncs" LOC = "P79" ; +NET "pck0" LOC = "P91" ; +NET "pwr_hi" LOC = "P31" ; +NET "pwr_lo" LOC = "P30" ; +NET "pwr_oe1" LOC = "P28" ; +NET "pwr_oe2" LOC = "P27" ; +NET "pwr_oe3" LOC = "P26" ; +NET "pwr_oe4" LOC = "P21" ; +NET "spck" LOC = "P88" ; +NET "ssp_clk" LOC = "P43" ; +NET "ssp_din" LOC = "P99" ; +NET "ssp_dout" LOC = "P94" ; +NET "ssp_frame" LOC = "P100" ; + +# definition of Clock nets: +NET "ck_1356meg" TNM_NET = "clk_net_1356" ; +NET "ck_1356megb" TNM_NET = "clk_net_1356b"; +NET "pck0" TNM_NET = "clk_net_pck0" ; +NET "spck" TNM_NET = "clk_net_spck" ; + +# Timing specs of clock nets: +TIMEGRP "clk_net_1356_all" = "clk_net_1356" "clk_net_1356b" ; +TIMESPEC "TS_1356MHz" = PERIOD "clk_net_1356_all" 74 ns HIGH 37 ns ; +TIMESPEC "TS_24MHz" = PERIOD "clk_net_pck0" 42 ns HIGH 21 ns ; +TIMESPEC "TS_4MHz" = PERIOD "clk_net_spck" 250 ns HIGH 125 ns ; +