diff --git a/CHANGELOG.md b/CHANGELOG.md index 21bbcedb4..0e167b386 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,9 @@ 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] -- Added system code name annotation to 'hf felica info' and 'hf felica rqsyscode' +- Fixed `hf mf wrbl` and `hf mfp wrbl` the ACL RO checks on 16-block sectors correct (@team-orangeBlue) +- Changed `hf mfp wrbl` command to check for Sector Trailer errors that could potentially lock sectors out (@team-orangeBlue) +- Changed `hf felica info` and `hf felica rqsyscode` system code name annotation (@team-orangeBlue) - Added `lf relay` command where it relays between two pm3 devices over internet. Thanks to Moerno for the code! (@iceman1001) - Changed `hf mf acl` command to have more recognized generic configurations (@team-orangeBlue) - Added `hf mfp acl` command (@team-orangeBlue) @@ -14,10 +16,10 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `hf mfdes createdelegateapp` command (@kormax) - Optimized `hf iclass legbrute` throughput: replaced recursive `suc()`/`output()` cipher functions with iterative loops, added 256-entry LUT for the `select()` function eliminating redundant bit arithmetic and halving key lookups per state step, switched successor state to in-place pointer update removing per-call struct copies, added `doMAC_brute()` with byte-wise LSB-first processing and direct output bit packing eliminating all bitstream struct overhead and output reversal calls per key candidate, and replaced per-iteration 64-bit modulo progress check with a countdown counter (@antiklesys) - Improved `hf iclass legbrute` fixed multithreaded key-range partitioning so threads cover non-overlapping slices of the 40-bit keyspace, added ETA display, keyboard abort with resume hint, `_Atomic` correctness for shared state, `pthread_create` error handling, and thread count capped at available CPUs (@antiklesys) -- Added wildcard support to `hf secc sim` payloads (@antiklesys) +- Changed `hf secc sim` it nows supports wildcard to payloads (@antiklesys) - Added `hf secc` to build a base for simulating basic function of iclass SE config cards (@antiklesys) -- Improved SIO parsing for `hf iclass view` based on Iceman's "Dismantling the SEOS Protocol" talk (@antiklesys) -- Added live fc/cn update to `hf iclass tagsim` refreshing the csn with each update (@antiklesys) +- Changed `hf iclass view` , improved SIO parsing for based on @Iceman1001's "Dismantling the SEOS Protocol" talk (@antiklesys) +- Changed `hf iclass tagsim` added live fc/cn update to refreshing the csn with each update (@antiklesys) - Added `--live` option to `hf iclass lookup` command to perform a live recovery of the reader's key by simulating a tag and running the lookup command against both standard and elite dictionaries (@antiklesys) - Added `hf iclass tagsim` command to quickly simulate an iclass card based on facility code and card number(@antiklesys) - Added `-f` parameter to `hf iclass sam` command to use the sam to parse a card dump (@antiklesys) diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index c01ad0550..e3aeec83e 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -869,10 +869,16 @@ static int mf_analyse_st_block(uint8_t blockno, uint8_t *block, bool force) { } bool ro_detected = false; - uint8_t bar = mfNumBlocksPerSector(mfSectorNum(blockno)); + //uint8_t bar = mfNumBlocksPerSector(mfSectorNum(blockno)); + uint8_t bar = 4; for (uint8_t foo = 0; foo < bar; foo++) { if (mfReadOnlyAccessConditions(foo, &block[6])) { - PrintAndLogEx(WARNING, "Strict ReadOnly Access Conditions on block " _YELLOW_("%u") " detected", blockno - bar + 1 + foo); + // WARNING: Sectors 33+ assume ACLs apply to groups of 4 blocks, not 1 block. + // The code as-is is bugged and actually wastes iterations. If you have 16 blocks, it'll run all 16 but only error out like it's a 4-block sector. + if (blockno<128) + PrintAndLogEx(WARNING, "Strict ReadOnly Access Conditions on block " _YELLOW_("%u") " detected", blockno - bar + 1 + foo); + else + PrintAndLogEx(WARNING, "Strict ReadOnly Access Conditions on blocks " _YELLOW_("%u-%u") " detected", blockno - bar*4 + 1 + foo*5, blockno - bar*4 + 1 + foo*5 + 4); ro_detected = true; } } diff --git a/client/src/cmdhfmfp.c b/client/src/cmdhfmfp.c index cc47acba3..47718c363 100644 --- a/client/src/cmdhfmfp.c +++ b/client/src/cmdhfmfp.c @@ -809,7 +809,7 @@ static int CmdHFMFPAcl(const char *Cmd) { " ACCESS = access bytes inside sector trailer block\n" " Increment, decrement, transfer, restore is for value blocks", "hf mf acl\n" - "hf mf acl -d FF0780\n"); + "hf mf acl -d 0FFF0780\n"); void *argtable[] = { arg_param_begin, @@ -1180,6 +1180,49 @@ static int CmdHFMFPRdsc(const char *Cmd) { return PM3_SUCCESS; } +static int mfp_analyse_st_block(uint8_t blockno, uint8_t *block, bool force) { + + if (mfIsSectorTrailer(blockno) == false) { + return PM3_SUCCESS; + } + + PrintAndLogEx(INFO, "Sector trailer (ST) write detected"); + + // ensure access right isn't messed up. + if (mfValidateAccessConditions(block + 6) == false || ((block[5] >> 4) != ((~block[5]) & 0xF))) { + PrintAndLogEx(WARNING, "Invalid Access Conditions detected, replacing with default values"); + memcpy(block + 5, "\x0F\xFF\x07\x80\x69", 5); + } + + bool ro_detected = false; + //uint8_t bar = mfNumBlocksPerSector(mfSectorNum(blockno)); + uint8_t bar = 4; + for (uint8_t foo = 0; foo < bar; foo++) { + if (mfReadOnlyAccessConditions(foo, &block[6])) { + // WARNING: Sectors 33+ assume ACLs apply to groups of 4 blocks, not 1 block. + // The code as-is is bugged and actually wastes iterations. If you have 16 blocks, it'll run all 16 but only error out like it's a 4-block sector. + if (blockno<128) + PrintAndLogEx(WARNING, "Strict ReadOnly Access Conditions on block " _YELLOW_("%u") " detected", blockno - bar + 1 + foo); + else + PrintAndLogEx(WARNING, "Strict ReadOnly Access Conditions on blocks " _YELLOW_("%u-%u") " detected", blockno - bar*4 + 1 + foo*5, blockno - bar*4 + 1 + foo*5 + 4); + ro_detected = true; + } + } + if (ro_detected) { + if (force) { + PrintAndLogEx(WARNING, " --force override, continuing..."); + } else { + PrintAndLogEx(INFO, "Exiting, please run `" _YELLOW_("hf mf acl -d %s") "` to understand", sprint_hex_inrow(&block[6], 3)); + PrintAndLogEx(INFO, "Use `" _YELLOW_("--force") "` to override and write this data"); + return PM3_EINVARG; + } + } else { + PrintAndLogEx(SUCCESS, "ST checks ( " _GREEN_("ok") " )"); + } + + return PM3_SUCCESS; +} + static int CmdHFMFPWrbl(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfp wrbl", @@ -1197,6 +1240,7 @@ static int CmdHFMFPWrbl(const char *Cmd) { arg_lit0(NULL, "nmr", "Do not expect MAC in response"), arg_str1("d", "data", "", "Data, 16 hex bytes"), arg_str0("k", "key", "", "Key, 16 hex bytes"), + arg_lit0(NULL, "force", "Override warnings"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -1214,6 +1258,8 @@ static int CmdHFMFPWrbl(const char *Cmd) { uint8_t key[250] = {0}; int keylen = 0; CLIGetHexWithReturn(ctx, 7, key, &keylen); + bool force = arg_get_lit(ctx, 8); + CLIParserFree(ctx); uint8_t keyn[2] = {0}; @@ -1239,6 +1285,16 @@ static int CmdHFMFPWrbl(const char *Cmd) { PrintAndLogEx(ERR, " must be 16 bytes. Got %d", datainlen); return PM3_EINVARG; } + // Necessary checks before doing any actual computing + tag interaction + // Block 0 detection + if (blockNum == 0) { + PrintAndLogEx(FAILED, "Cannot write block 0 on Mifare Plus"); + return PM3_EINVARG; + } + // ACL validity check + if (mfp_analyse_st_block(blockNum, datain, force) != PM3_SUCCESS) { + return PM3_EINVARG; + } uint8_t sectorNum = mfSectorNum(blockNum & 0xff); uint16_t uKeyNum = 0x4000 + sectorNum * 2 + (keyB ? 1 : 0);