#Advanced MIFARE attacks on the FZ
1 messages ¡ Page 2 of 1
I basically have no use for this tool as I am not really in NFC research, but, in following along its really neat
For sure. And yeah the MFKey app is a super fun optimization challenge, trying to get a modern attack to run quickly on the worst CPU ever. I'm going to open up a challenge on a few FZ servers after I publish this version, $500 to anyone who can make it 50% faster without sacrificing accuracy or number of nonces.
Actually after I combine it with Mfkey33/the parity research because that's 25% faster or so and I don't want to make the challenge too easy.
Current WIP code for heap memory planning on the FZ
(runs on desktop, just not sure the algo works fully yet)
Freezing isn't a great experience though, really should pop up a message or something saying what happened
It used to hard crash, I think they changed the behavior of the OOM condition
I preferred the hard crash too, at least then I didn't have to wonder if it was doing work still. I'd get an error message
Well, this would have worked but there's no API to use it:
bool memmgr_can_reserve_blocks(BlockLink_t* xStart) {
// malloc sizes in recover
const size_t block_sizes[] = {4096, 49216, 49216, 5120, 5120};
const int num_blocks = sizeof(block_sizes) / sizeof(block_sizes[0]);
for(int i = 0; i < num_blocks; i++) {
size_t required_size = block_sizes[i];
bool block_reserved = false;
BlockLink_t* pxBlock = xStart;
while(pxBlock != NULL) {
if(pxBlock->xBlockSize >= required_size) {
pxBlock->xBlockSize -= required_size;
block_reserved = true;
break;
}
pxBlock = pxBlock->pxNextFreeBlock;
}
if(!block_reserved) {
return false;
}
}
return true;
}
( #community-dev message )
welp, time to add your own lol
I'm just going to reserve heap and keeping checking the largest available block, and if the largest available block is insufficient then I need to roll back and free all of the previously allocated blocks and run it back in half speed (reserving half the memory)
Seems silly but the alternative is to open a buffered reader callback for the FURI_LOG and read the strings it prints, because that's the only way to see the free blocks. And the code alone will be more memory than the dumb solution of repeatedly checking how much is left and giving up
There should really be an API that does more than print that information to the log
All fixed. No more crashes for MFKey.
I want to track down the 1 KB memory leak before I PR it to the good-faps repo, but its superior in every way to the original Mfkey32 app now
more features (Nested key cracking), no crashes, better RAM utilization, and faster
I think the workflow that Flipper Devices is using for good-faps is broken. https://github.com/flipperdevices/flipperzero-good-faps/actions/runs/8381039016/workflow going to be blocked from merging until that's fixed
Resumed development of Nested firmware changes today
Need to think of a better way to organize this
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;
Maybe I can OR attributes of the PRNG
I'll just remove MfClassicPrngTypeStaticSector, I have the rest of the cards
Probably should mention here too, I have a $825 bounty to make MFKey faster on a different server, including smaller bounties for smaller speedups. If anyone is interested in trying to write faster code just DM me and I'll link you to the channel and rules.
The qualifying speedups are as little as 5% and as high as 20%, with the reward scaling to match it.
Just please don't send me patches without reading the rules first
@regal storm I know you are doing a bunch of stuff - is there a quick and dirty guide to compiling the KDFs out of your repo for a given firmware version
I'm trying to do it with ufbt for 0.99.1 - I don't need them urgently - just looking to have it up to date.
would be good if the GitHub actions could be run every time there's a new firmware. I don't think ufbt can build it, I think you need to build within the full flipper firmware git repo checkout
I have that too
I copied the instructions from the GitHub workflow config when I last built it go figure
Is the github workflow config something I should be able to see? If so I will go look.
Gives a pretty step by step explanation of how to do it
check out the branch, append the plugins to the NFC app's application.fam, copy the plugins in, then build
some CFWs have modified the plugin a bit, I haven't been able to review their changes but the KDF for Saflok is accurate
related, another large KDF may drop soon
oOo
Ok I'll work on it tonight - the CTF is starting
I'm no stranger to CLI and compiling things and on OFW
speaking of, looks like the saflok kdf is broken:
applications\main\nfc\plugins\supported_cards\saflok.c: In function 'saflok_verify':
applications\main\nfc\plugins\supported_cards\saflok.c:85:9: error: implicit declaration of function 'nfc_util_num2byte ' [-Werror=implicit-function-declaration]
85 | nfc_util_num2bytes(saflok_1k_keys[CHECK_SECTOR].a, COUNT_OF(key.data), key.data);
| ^~~~~~~~~~~~~~~~~~
applications\main\nfc\plugins\supported_cards\saflok.c: In function 'saflok_read':
applications\main\nfc\plugins\supported_cards\saflok.c:125:28: error: implicit declaration of function 'nfc_util_bytes2num' [-Werror=implicit-function-declaration]
125 | uint64_t num_key = nfc_util_bytes2num(key, KEY_LENGTH);
| ^~~~~~~~~~~~~~~~~~ CC applications\system\js_app\modules\js_serial.c
against latest ofw
looks like it just got renamed to bit_lib_bytes_to_num_be, so should be a simple fix
speaking of, mizip and mykey are both in the firmware repo these days, is there anything different about the version in the flipper_kdf repo or should those just get nuked these days @regal storm?
ok, so I finally tried this and I got errors in a couple of the kdfs when compiling
I tried @harsh cobalt 's version and it also throws errors in mizip and mykey plugins
I don't need any of it right now. Just trying to learn for later when I want to use it
I'm not quite sure what the difference between our version and the version in the firmware is for those ones tbh
Key A Key B Key C
UID 00000000 000000000000 000000000000 8f0bfea8f5ff
UID 00000001 100010000000 000000000000 712c1de2e297
UID 00000002 200020000000 000000000000 38891d5ded48
UID 00000003 300030000000 000000000000 d1322d882496
UID 0000000f f000f0000000 000000000000 8f1a489c9b17
UID 000000ff f00ff00f0000 000000000000 28a1509bc0ba
UID 00000fff 000fe010ff0f 000000000f00 663705b6cfe5
UID 0000ffff 0000e01fef10 00000000ff00 7522778a6fe7
UID 000fffff f000df20ef01 0000cc1e2dd2 34d61334a07e
UID 00ffffff f00f2f2fef10 0000fcfaf906 5f4c784d5075
UID 0fffffff 0f0f3f30ef01 1f0e0b08ed12 601ad5c6e170
UID ffffffff ff003f3fef10 ff00fbf803fc de218bd1a9d0
UID 0f0f0f0f 0f00cf033f0c 0f008b03f807 9b1fd3dbe00c
UID f0f0f0f0 f000f03cb004 f000f084b07c 63d7f74c79f9
UID aaaaaaaa aa002a2a4a0b aa003ac3c837 f77a7033edae
UID a0a0a0a0 a000a0282003 a000a090a05a 119b26eea062
UID c0c0c0c0 c000c030c003 c000c040c030 f7dbbb8603aa
UID 12345678 92007411c60f a20024382a40 05d62df6c5c1
UID 87654321 870865153310 0744f584590d 2be547ecd6ce
UID cafebabe ca03fe34ea00 aa267e393894 b7af9988c4aa
UID 00abcdef 9008db261d07 0000669a99ca f866639a77ee
UID 89abcdef 8900ab2f9d01 8900fbf6816a 60c8e21d0f15
UID bbbbbbbb bb007b2e9b0f bb00df22dd33 406317cb3f0a
UID cccccccc cc00cc33fc03 cc008c8ac4a1 b5406bf89bfb
UID 92460430 920e8610a400 52800e495802 f55038031502
UID 92460431 a20e9610a402 e480c8499803 922121bbc806
UID 92460432 b20ea610a400 76819249b400 1dfb6376a6e4
UID 92460433 c20eb610a406 08825c4a7402 c22882b6a929
UID 92460434 d20e4611b408 9a82264ad401 ab934e2c6b4c
UID 92460435 e20e5611b40a 2c83e04a1800 a9254dde00f3
UID 92460436 f20e6611b408 be83aa4a7803 5e0d5b616ca2
UID 92460437 020f7611a406 5084744bb003 40707e0b13b7
UID 92460438 120f0611a400 e2843e4b5000 112b748eb1b5
UID 92460439 220f1611a402 7485f84b0c01 986a439b6c6b
UID 9246043a 320f2611a400 0686424c3c02 17bdb21a4f0b
UID 4b7a0631 ab00ba0fe601 0d0262788400 b13dc264b714
UID 4b7a0632 9b00aa0fe603 c201e878f801 6531e3db8df8
UID 4b7a0642 9b07aa106602 92224880d602 306463dcf0b5
UID 4b7a0742 8b079a106700 4722d6806c01 0c9122346fe1
UID 4b7a1742 8b069a117700 971d3688c304 89d48a4543db
UID 4b7b1742 9b068b118700 e21d9e89ef14 7b8edd93dbbf
UID 4b8b1742 9b097b12c70f f22b0ea46c0a 2e69212e138a
UID 4c8b1742 6c098b13e70f a42b9ba5fe0f a2553cad33c7
UID 5c8b1742 7c088b14c70e 142f4badf213 bfa4ec5efa7b
UID 00000002 200020000000 000000000000 38891d5ded48
UID 00000004 400040000000 000000000000 0d10c11fb14d
UID 00000008 800080000000 000000000000 f6010c672a2d
UID 00000010 000100010000 000000000000 684ca35bb02d
UID 00000020 000200020000 000000000000 75eef6ee3e0e
UID 00000040 000400040000 000000000000 fd09f949aeed
UID 00000080 000800080000 000000000000 fab7156e886e
UID 00000100 100010000100 000000000100 164e9503a5c0
UID 00000200 200020000200 000000000200 b09356b0e9e4
UID 00000400 400040000400 000000000400 d8ad8e486f21
UID 00000800 800080000800 000000000800 c0a768c9af09
UID 00001000 000100011000 000000001000 e15c2b673e0c
UID 00002000 000200022000 000000002000 a3348fc95d57
UID 00004000 000400044000 000000004000 d46f8452adc6
UID 00008000 000800088000 000000008000 2296cf2366fa
UID 00010000 100011001000 000000000000 fb9021425f7e
UID 00020000 200022002000 000006000000 9eddc4954ea6
UID 00040000 400044004000 000014000000 37259f9874d0
UID 00080000 800088008000 000048000000 beaf0b0a39e0
UID 00100000 000110010001 000010010000 759d7c10791b
UID 00200000 000220020002 000020040000 b00921fba60c
UID 00400000 000440040004 000040100000 2cf0ddcb35f6
UID 00800000 000880080008 000080400000 dd572191eb39
UID 01000000 110010001000 020000000000 78d079c42053
UID 02000000 220020002000 060000000000 0a93ed1a6371
UID 04000000 440040004000 140000000000 e97f3ea5b7de
UID 08000000 880080008000 480000000000 03ff0803c1c9
UID 10000000 100100010001 100100000000 2e793ef8da9a
UID 20000000 200200020002 200400000000 91a5da854349
UID 40000000 400400040004 401000000000 b6a6591259c4
UID 80000000 800800080008 804000000000 7ae8090c541d
Find the pattern đ
Heyo, has there been any progress here for nested?
iirc its still not available on post refactor firmware, rollback to official 0.93.0 and you will be able to use it.
there is a bounty for up to 2,300 (there is price tiers) for code acceleration to cut down on the time it takes.
Thank you!
Would you happen to be able to identify what actually takes time in the attack?
the crypto exchanges between the flipper and card
the offline part is the longest part on a flipper, not the comms
But isn't the offline part done in an actual computer after?
you were just having a disucssion about that in #nfc... thanks to @regal storm's efforts the offline part for nested can run on the flipper now
although you can also collect nonces and run the offline part using the flipper mobile app which is a lot faster, but that's not what the bounty is about
Yeah, I'd prefer running it in the app or laptop, since its much faster and I already have it lying around
I haven't managed to run it yet, I'd have to go get the tag. Any idea how long it takes on the pc?
utter ballpark estimation is fine
2-30 minutes
Thats ballpark enough, ty
Just wondering if it was not 2 days
Else I could think of gpu implementation, but I don't even know if the attack is parallelizable lol
Nested is back on some CFW's. some nonces can be cracked standalone with Mfkey on the flipper. works like a charm
Got ya, for my use case standalone doesn't really matter, I always have a phone/laptop on me lol
This is just regular nested not hard nested
It's seconds on a real machine from memory
Depending on how many unique keys anyway
Unique keys? wdym?
Ah, different keys in each sector.
What is the difference?
regular nested doesnât work on cards with a hardened PRNG (pseudo random number generator [for the nonces]), hardnested does work on those cards
I'm assuming hardnested is slower?
So there are different prng algs in different cards?
All within mifare classic?
(I'm new to this, but not new to computers/crypto)
Does this require precomputing a key table?
The presentation on the attack talked about this, but I could not fully understand if it was for another attack, or the same one.
itâs not a toggleable thing, itâs a chip revision and manufacturer thing. theyâre all still mifare classic their RNG is just different. weak, hard, static &
thereâs a new breed as of 2 or so years ago âstatic encrypted noncesâ which cannot be attacked via nested, hardnested, static nested, dark side. the only key recovery for those is MFKEY which requires the reader.
Is the prng alg not part of the spec?
Mifare Classic is proprietary, there is no public 'spec', just what has been reverse engineered
Got it, thank you for all the good info
I was not expecting the flipper discord to actually be interesting xD
it has it's moments
I was sort of expecting it to be "hi sir how do I hack car fast pls" type posts, but I haven't really seen any of that
watch #general long enough...
well there is a public spec it just doesnât have a lot on it in terms of what mifare classic actually does on the low level
plenty of those still ^^, but once you get into interesting channels, the braincell count goes up exponentially :p
I mean, there is the datasheet, but it doesn't go so far as to talk about PRNG, right? I was thinking it's different than like Desfire which is clear on what cryptographic standards it uses
oh yah yah mf1s50yyx doesnât exposit about crypto1
I have one of those cards! The weird thing is after I MfKeyed the nonces I read all the sectors and had 28/32 keys. I couldn't recover 4 Key Bs from the nonces no matter what.
Is that because Key B just isn't used by the reader?
yes, if it doesnât show up in your trace itâs either not used or accessed via nested auth
got it. thanks!
Okay, what reasons are there for not being able to recover a key from an old mifare classic card?
#1134994594661146674 message
These are older than 2 years though.
2 or so years
That said, a proxmark would give you greater details about the PRNG and nonces
that essentially just rules out static nested. all other rng potentialities are still present.
also you havenât said what youâve tried with this card
Only FlipperNested
huzzah
I may have a key of interest for the flipper default db?
most likely not.
do you have another card from the same system that was active at the same time as this one?
Yep
I got 4 :D
Same key in all
if yes, get the keys off that card and diff them to your original card, if theyâre the same then you have static keys that are shared by cards within that system, those are useful.
if the keys are different then the keys are dynamic and change for each card in the system.
if you do not have a 2nd card from the same system & same period, you have no way to validate whether the keys are static or not, committing those to the repo without knowing just adds bloat.
in the system still active? and issuing cards with that same key?
Yep
Cards are active right now
There's a few hundred of these cards, publicly available sorta
then sure, go PR it into the flipper repo.
i would recommend committing those keys to the bottom of the Proxmark Repo mfc_default_keys.dict) file with a #comment regarding where they have come from.
in the commit notes specify that youâve verified theyâre static keys or iceman will just bin your commit
what is this shared key btw
iâll run a quicky see if itâs popped up anywhere on my radar
May I dm them?
did you ever use the system dictionary?
Yep
what key(s) did you get with the system dictionary?
Most sectors, besides a few
Besides 4 I believe?
I'm only on phone and flipper rn
I can check better when on PC
and the 4 you got are the same on all your cards?
My phone can't connect to the flipper :(((
Theres a bug in the app, I've reported it
Yep
shore
@dreamy pine the main issue is we don't want or need Full Nested. part of the challenge is that we are not trying to port it to the latest firmware, we're trying to fix it.
Then what do you want if not full nested?
Consider I am very new to nfc, not new to computers
By my understanding we want nested, on device?
first you'll want to get caught up on what nested attacks are doing. if we can predict nt, as in the case of weak RNGs, we're able to do a Nested attack. the RNG of the card is either weak or strong - strong is Hardnested.
Notice - I described two scenarios. Weak and hard RNG
is the RNG just whatever prng alg they use?
Or is there more to it?
ask, if there are two scenarios, why are there three attacks?
I was not aware there were three attacks! I'm listening and curious
haha
RNG is based on the hardware. The weak RNG only has 16 bits and is constantly shifted based on the start time of the card, which makes it predictable if you can time the precise moment you ask the card for a challenge
I simply forgot about static. I thought that was a different kind of attack? Did that not require mfkey stuff? I'm sorry about the newbie questions, I'm very much aware that sometimes its annoying to explain the same stuff a bunch of times because people don't get it as quickly as one does.
(a nonce, nt)
static encrypted nonce cards require you to do mfkey because there is no nested that can attack it
Okay, so its a hardware pseudo random number gen, and different cards have different hardware gens. That was a very good explanation of weak rng.
.<
Do you have a paper on all the different attacks? I only found the presentation by nememba(?)
each shift of the LFSR (linear feedback shift register) on the card happens every 9 nanoseconds
Why is it standardized at 9ns?
approximately. the card is reliable, but here's the thing
that Flipper is not programmed to reliably probe the card for the nonce
So the flipper is not programmed for those kinds of timings?
it's how Crypto1 works
Does Crypto1 require 9ns? if you somehow had a true random number gen, would it not work?
yes. so what should be exactly 2 attacks, is now 3. Instead of:
- Nested
- Hardnested
you now have - Nested
- "Full Nested"
- Hardnested
where the regular attack is Static Nested
in other words, no need to offload regular Nested key calculation, it's already running on the Flipper in 4 minutes if we collect the nonces at the right time
Ah! I see, having the correct nonces makes it easier to calculate?
Else we may be collecting wrong nonces that we will simply have to discard?
exactly
Okay, I got it
or rather, guess how far off our timing is
which is called "distance" in the previous implementation of the attack on the Flipper Zero
(I would still like to be able to export it, I can run it faster on my server likely)
I see!
Agh its so nice talking to people that know what they are talking about
So a reimplementation of the previous collection mechanism would take ages to run on the flipper directly.
And this is why you want to redo it, since its currently being done semi badly, or not ideally, or whatever adverb.
you can run it faster on your computer for now but I promise in a year we'll be having a different conversation, and your work to offload it will be immediately outdated
the next gen Zero device will be able to crack Nested nonces in seconds, it'll have a better processor with an integrated GPU
i think its more of a stopgap, to have a nested of some sort thats accessible via current fw versions
so getting it working right the first time will save everyone a lot of work
has that even been announced or designed yet
2 counterpoints:
- We are not a year in the future
- I've spent so much on the flipper I don't want to have to buy a new one aksjdlkajsd xD
Yep, this was sorta my idea
Yep, this I get
announced officially, no, only details we have are from Q&A and it's the same software. designed, yes. in fact, already made, it exists today
they have a working device
Do you think there would be no value in doing a dirty port of the previous attack, just to not have to permanently swap the firmware whenever we want to use it?
me personally, no I don't see value, because I don't want to roll back broken or incorrect code in OFW. I just want one working version
I can see why it's a pain point today
Fair enough
I do see value, but not sure I see enough for me to learn nfc + flipper stack xD
we can definitely work on the Nested code together if you're interested, I'm just juggling several things
and above all I don't want to ship out Full Nested
I mean, what is the issue now? I remember reading it was an issue of optimization?
Full nested is when we have bad distance estimations?
I feel I should have got that by now
It's when we don't talk to the card at the right time to ask it for a challenge
And that messes up the "distance"?
it's possible that there's another way though. I have deep knowledge of these attacks, it's nearly all I've researched for 2 years, and we've found multiple improvements over the papers that have been published (http://www.proxmark.org/files/Documents/13.56 MHz - MIFARE Classic/). it may be optimization that fixes it, or it could be something more creative, but I'm sure it's possible
This makes me feel a little less bad about my newbieness
what's even better is, if we code is correctly, we can expect scanning most MIFARE Classic cards to take several seconds instead of around 5-10 minutes like it does today
and even reduce the time it takes to run Mfkey32 key cracking by 50%
the main barrier to all of this is time
On old fw it took me like 40 seconds to scan a card?
I'm one dev. I've been sick for a while and before that I was burnt out, so there haven't been many good options for Nested attacks lately. I just got back to 100% several days ago and we solved a few major things
But there are probably a few variables influencing it
I only had to collect 6 nonces and I see screenshots of collecting 90 something
I see! This is cool
That's if you have default keys, and the keys are near the top of the dictionary
Ah, you mean normal scans instead of nonce collection?
Correct
Again, I'm not knowledgeable here
Dictionary attacks
yepyep
I'm talking like, 3-5 seconds for a dictionary attack against the card. And only maybe 1.5 sec of that is holding the Flipper near it
it'll work for any card that doesn't have a hardened PRNG. so most of them
dictionary of like 1300 keys?
yes
Damn
Also, I noticed something, 103 fw is way faster at the dictionary than 93.0
I assume it has to do with the refactor of the nfc stack?
NFC refactor
yep
How ultra far away are we?
Hmmm
Exporting the keys doesn't make this any easier as it seems that the hard part is reading stuff accurately, not cracking after
distance?
In terms of code completion
not far but I keep having to deal with merge conflicts on the main branch. I'm just going to delete my branch and merge many smaller changes
we're also finishing another part of this project hopefully today or tomorrow
okay finally something we can relate on
I hate merge conflicts!!!!!
Heya. Came up with no less than 5 MFKey optimizations this morning, expected total time to be reduced by 10-20%. May combine it with the other fixes. Recently I've been dedicating time to other parts of this project, and I can't wait to share them.
I do believe that 1 minute average time for Nested nonces is within reach.
Mfkey32, hard to say. Maybe a minute and a half.
woah 
Status update: I've been working on Mfkey33 today. The main issue is that the parity bit buffer from the NFC listener is empty in Detect Reader, so we can't just add them to .mfkey32.log. Most likely the parity bits are not sent over the fifo when the firmware calls st25r3916_read_fifo (my guess is they are disabled via flag, ST25R3916_REG_ISO14443A_NFC_no_rx_par_off).
Once I have them sent by the st25r3916 to the NFC listener I can add the bits to the .mfkey32.log file. I'm going to work a bit ahead tonight and use the Proxmark dump to get the two bits and make sure we can use them with a POC version of Mfkey33
I don't see why it wouldn't work but if it doesn't, we'll know and it'll save us some time
Right now my setup is just a Flipper Zero and a PM3 against each other, with the Flipper running Detect Reader and the Proxmark running hf mf rdbl.
whoa - so that would neccesitate a change in the NFC app code?
as Detect Reader is a function in that app
mfkey32_logger.c for sure, as it's part of the NFC app, but most of the changes take place in the firmware.
Anyway now that I have a setup (and since the Proxmark worked better for this than a real encoder) we should know tonight if Mfkey33 is actually possible.
otherwise we just fix up MFKey and get back to Nested
# In this trace, the Proxmark is authenticating to sector 0 with key A of 800813510101.
# The Flipper Zero is listening with Detect Reader.
# We extract the transmitted ar enc parity bit by calculating the parity of the last byte, and if it disagrees with the Proxmark parity (indicated by !), we inverse it.
# This bit is the 33rd encrypted bit of the keystream.
# Parity function:
# def calculate_parity(byte):
# count = bin(byte).count('1')
# return 1 if count % 2 == 0 else 0
# 87168 | 96480 | Rdr |8E 7C ff! bc! 8b! ab! 37! 14 | | AUTH: nr ar (enc)
# 87296 | 96608 | Rdr |f8! ED dc! C4 15 85! 6D 07! | | AUTH: nr ar (enc)
# Par bytes: 14, 07!
# Par bits: 1, 1
Sec 0 key A cuid 382d88da nt0 27ae1ba5 nr0 8e7cffbc ar0 8bab3714 par0 1 nt1 c9a7d883 nr1 f8eddcc4 ar1 15856d07 par1 1
# 87168 | 96480 | Rdr |1e! 66! 69! 7B 4e! 02! 70 23! | | AUTH: nr ar (enc)
# 87296 | 96672 | Rdr |29! 1d! 58 39 B7 42 BF 2d! | | AUTH: nr ar (enc)
# Par bytes: 23!, 2D!
# Par bits: 1, 0
Sec 0 key A cuid 382d88da nt0 22165c99 nr0 1e66697b ar0 4e027023 par0 1 nt1 4bbbe3e4 nr1 291d5839 ar1 b742bf2d par1 0
# 87296 | 96608 | Rdr |F3 5c! 05 dc! ED 16 BF 92! | | AUTH: nr ar (enc)
# 87296 | 96672 | Rdr |58! 00! 85 61! 87 D5 DA 3B | | AUTH: nr ar (enc)
# Par bytes: 92!, 3B
# Par bits: 1, 0
Sec 0 key A cuid 382d88da nt0 a31fa658 nr0 f35c05dc ar0 ed16bf92 par0 1 nt1 8a868671 nr1 58008561 ar1 87d5da3b par1 0
# 87296 | 96672 | Rdr |1A 78! D2 D1 F6 8C fc! F7 | | AUTH: nr ar (enc)
# 87168 | 96480 | Rdr |18! e4! 13! D2 ca! 36 b3! 89! | | AUTH: nr ar (enc)
# Par bytes: F7, 89!
# Par bits: 0, 1
Sec 0 key A cuid 382d88da nt0 a2ccf59a nr0 1a78d2d1 ar0 f68cfcf7 par0 0 nt1 3541f449 nr1 18e413d2 ar1 ca36b389 par1 1
# 87296 | 96608 | Rdr |62! 3C C1 A9 9a! 56 54! 0e! | | AUTH: nr ar (enc)
# 87296 | 96608 | Rdr |66 c7! 60! 43 D1 FC 2c! 9C | | AUTH: nr ar (enc)
# Par bytes: 0E!, 9C
# Par bits: 1, 1
Sec 0 key A cuid 382d88da nt0 cf6e27b2 nr0 623cc1a9 ar0 9a56540e par0 1 nt1 e633be1e nr1 66c76043 ar1 d1fc2c9c par1 1
Sec 0 key A cuid 382d88da nt0 27ae1ba5 nr0 8e7cffbc ar0 8bab3714 par0 1 nt1 c9a7d883 nr1 f8eddcc4 ar1 15856d07 par1 1
Sec 0 key A cuid 382d88da nt0 22165c99 nr0 1e66697b ar0 4e027023 par0 1 nt1 4bbbe3e4 nr1 291d5839 ar1 b742bf2d par1 0
Sec 0 key A cuid 382d88da nt0 a31fa658 nr0 f35c05dc ar0 ed16bf92 par0 1 nt1 8a868671 nr1 58008561 ar1 87d5da3b par1 0
Sec 0 key A cuid 382d88da nt0 a2ccf59a nr0 1a78d2d1 ar0 f68cfcf7 par0 0 nt1 3541f449 nr1 18e413d2 ar1 ca36b389 par1 1
Sec 0 key A cuid 382d88da nt0 cf6e27b2 nr0 623cc1a9 ar0 9a56540e par0 1 nt1 e633be1e nr1 66c76043 ar1 d1fc2c9c par1 1
now working on a Mfkey33 POC for these nonces
if anyone isn't up to speed, here's a diagram from my presentation
each box represents a bit. the red bit is keystream we're not collecting, thats par0 and par1
i'm going to try to reduce the number of states that need to be checked by 50% with the parity bit, so đ¤
have what appears to be a working 25% speedup
going to test on more nonces to be sure, but there's actually a bit more we can get out of it
what's more surprising is that this speedup seems to exist without Mfkey33, which we separately have tested and seems to also be real
We didn't get 10-20% faster, sorry all.
MFKey is now 30% faster, has no more UI bugs, and doesn't repeatedly slow down when cracking in half speed like the last version. It's already PR'd to good-faps and merged with the main repo.
and we still have another speedup.
works on latest OFW now too?
It should work well on OFW, I tested with the latest release.
nice
hopefully one day I'll get to see the full talk. I know when you gave it was at a con that didn't do/allow recording
Mfkey33 works and it is 9% faster than Mfkey32
this would bring the average time down to 3 min, worse case close to 5 min.
assuming the STM32 actually measures up to the desktop speedups which it never does lol
the 9% speedup should also work for Nested too
đ¤
Mfkey33, Nested, KDF, EMFI MIFARE attacks on the FZ
I went on a trip w/o updating the safflok plugin for the new flipper os - i didnât bring a laptop
Anyone have the file for latest you wouldnât mind dropping me here or a dm?
If not i have a tablet Iâll take a crack at building in termux
Actually Iâm already on it
wonder if someone could just PR it to the OFW repo and mention it is included in the Proxmark repo already 
call it "SL"
safunlok
either I'm incredibly unlucky or I just found a new shortcut for mfkey
im scared to find out how that constitutes a spot of bad luck
In all of my tested Mfkey33 nonces (10 of them), running filter on the even state before it xors in the odd component will equal the 33rd bit of keystream obtained from the parity
I can use that to reduce the number of even states by 50% if I didn't randomly get unlucky and that just happened to be true for all 10 of my nonces
not only would that be faster, but it would be considerably less memory
I really shouldn't speculate because I want this to be true lmao
I'm confused I thought that was the plan all along?
it was. I couldn't find a way to eliminate states with out outside of check_state originally
but apparently running filter on the even state produces the correct value
Ah
alright here it goes
Sec 0 key A cuid 2b374c2f nt0 604a22ce nr0 28b684ec ar0 8632eadf par0 1 nt1 1a578e8f nr1 6889d1a0 ar1 835b69df par1 0
Sec 0 key B cuid 2b374c2f nt0 c151500b nr0 f91c3cbc ar0 b0a04882 par0 1 nt1 8358299e nr1 c0de3560 ar1 d4cdc4b7 par1 1
Sec 1 key A cuid 2b374c2f nt0 c8db85c1 nr0 59807123 ar0 db262acf par0 0 nt1 d378f480 nr1 fd4c4693 ar1 b936ca05 par1 0
Sec 1 key B cuid 2b374c2f nt0 8b958f15 nr0 2078a197 ar0 c5327f42 par0 0 nt1 0abece48 nr1 5e1ff18a ar1 d393d91b par1 1
Sec 2 key A cuid 2b374c2f nt0 bdf41768 nr0 a2343183 ar0 6fb5a74c par0 0 nt1 d24f9c86 nr1 4a7f916e ar1 4998df5a par1 0
keys are
b1e55b1e55b1
e55b1e55b1e5
5b1e55b1e55b
1e55b1e55b1e
55b1e55b1e55
okay so the odds of this failing were 1 in 16384
and it failed on the last nonce
it worked on 14 nonces in a row and failed on the 15th
no way the proxmark reads the wrong parity right
I mean read errors are always possible, should be able to confirm if it's right or not if you have the key though
it failed 2/20 nonces now. oddly low but certainly no-go
yea gg no more optimizations from the 33rd parity bit. can't eliminate half the states early. it's 9% faster at best.
its the recombination that's killing it because we can't deduplicate values within the FZ's memory constraints
I'm working on collecting Nested nonces today, and revisiting the fast Nested dictionary attack I'm not clear on why it won't work for more than just Static Nested
if having a distance is unavoidable we just test every possible nT
(within the distance)
it takes milliseconds to test one nT value, provided we "know" the key
so the only time the fast Nested dictionary attack wouldn't work is if it is Hardnested as far as I can tell
with parity it should be possible to reduce the time to do the dictionary attack further, by 50%
Also, for Nested nonce collection I thought of a way to fairly accurately predict nT. Writing this tonight
I now have the firmware collecting Nested nonces
it's not a big achievement or anything, I've just been making some progress on this lately
most of my effort has been exploring what is and is not possible. at this point I fully understand Crypto1 and all of the attacks against it, except Hardnested
this is most likely wrong. I expect to be able to prove it's wrong
unfortunately there is a minor setback because the system i wrote the complete implementation of the new mfkey32 last year fried itself for no discernable reason
so i need to rewrite the 8/12/15 checkpoint mfkey to test out how we'd use the 33rd bit to reduce states. in theory we should just need to increment a few values by 1 and shift in the parity bit's keystream
that can wait. nested is first
I have a new rfid test setup. I've expertly rubber-banded the Flipper Zero, a MIFARE Classic card, and a Proxmark 3 together.
the Proxmark 3 is making sure that the values I'm collecting on the Flipper are correct
rubber bands are excellent fast problem solvers
yup. real RFID research⢠done here
progress update: my method of syncing nT seems to be more reliable than FlipperNested (much quicker) but there's a technical issue I'm sorting out with it
also, there was a bug in FlipperNested. it rotated through 65565 states when there are only 65535 states (2^16 - 1)
if anyone here has used mfkey32 you may be familiar with the fact that it doesn't work all the time
tonight we had a unique opportunity to dive into crypto1 to find out why. the Flipper Zero is only collecting valid nonces from these sectors 1/4th of the time, for reasons unknown
what we can do, however, is collect the parity bits of ar like we started to do for Mfkey33
that will allow us to eliminate invalid nonces, as well as allow us to mix and match valid nt/ar/nr pairs to be valid mfkey32 nonce pairs, allowing you to use previously unusable nonce pairs to recover keys
so what we'll do post-mfkey32 parity bit update is identify when this is happening using parity bits, ensure we have multiple nonce pairs per sector, drop all ar0, then recover from only ar1 by cycling through possible pairs
barring any better way, or hardware related fix
truly amazed on the creative workaround skills for the issue 
isnt the next gen flipper being tested already anyways right now? something to ensure works there without this problem in any case.
Having MCU CLK available would let you time the carrier frequency precisely
I'm not 100% sure it's related
the only way to know for sure is to hold a Proxmark up to the reader when the invalid nonces are sent
Luckily we now know exactly which readers have this behavior (VingCard)
I'm sure it's not only VingCard but being able to reproduce it is key to pinpointing the issue
Is there any interest in doing a hardware mod on the current flipper implementation to get that clk (probably out of scope for this conversation, happy to move to #hardware or #nfc to discuss more)? I know its come up a few times that it would be a nice to have. There are no free IO pins on the uC but one could sacrifice a GPIO pin, ibutton, etc., maybe there is a clean way to add a MUX too to not lose functionality, and use that to enable measure of that clock output.
I've considered it in the past but have no NFC hardware in general to do testing on, but if there is interest and someone can recommend/let me borrow hardware that is known to need that external clock to synchronize to, I'd be happy to work on a hardware mod to get that functionality on the zero, and freely mod units for other NFC devs down the line too.
Making such a mod would be very tricky (I've done it on a dev board) and the code to make use of it would be tricky too, so not sure if it's worth the effort for the 3 people willing to do the mod
The hardware mod is the easy part for me lol, the codebase for NFC (and NFC in general) is what I'm not very familiar with.
But that is a fair assessment. In any case, my offer to help put something together, and do the mod for other NFC devs who would like to have it, stands. Feel free to ping me at any point in the future.
If a new hw revision came out with it connected, doing the mod on older flippers would probably start to make more sense though, since then it's not doing heaps of work for minimal gain
after a lot of failing over the past few days, I got the modified distance function working this morning and I'll test it on the FZ today
the way the original distance function works, as described in the papers (and used in FlipperNested), is to wake up the card, auth to it, auth nested to the same sector, then calculate the distance (the number of prng successors) from the original auth to the nested auth. the prng shifts every 9.4395 us
what i'm testing is if we can reliably get a distance estimation by simply authenticating to the exploit sector via nested auth like 10 times in a row followed by an 11th nested auth to the target sector, averaging the distance across the first 10 auths, then using that distance for the 11th auth. plus parity to confirm we collected the intended nonce
i'm thinking this will work more reliably than FlipperNested, which often had trouble approximating the distance
i reaalllllly need to think about this, because there may be a way to eliminate timing and distances entirely
it's not clear to me why its necessary, since the prng really only has 65k states
we might be able to just bake it into the existing logic, by xoring the uid with every one of the 65k prng values for a specific key
like think about it. why do we need to know nt1 precisely as long as we have a pretty good approximation of what it is, and there are only a few hundred thousand candidate keys. worst case scenario it takes a bit longer. we can even eliminate possible candidates with the parity
without parity checking its around 19 billion checks, with parity checking i assume in the tens of millions. but that's for every possible distance
tbh i'm going pause Nested dev to check my assumptions with the desktop version of mfkey. because if this works, goodbye Full Nested?
that would also eliminate like 70% of the crazy logic in FlipperNested
Claude Sonnet ported MFKey (minus dictionary cracking) back to the desktop. It's cracking nonces pretty well. just going to verify its 1:1 then I'll test the Full Nested changes
good enough to test the theory I think https://github.com/noproto/FlipperMfkey/blob/master/dev/ndv.c
had to fix Mfkey32
but it runs both Nested and Mfkey32 on a desktop as far as I can tell, using something close to what MFKey does on the Flipper
Good news. I have Full Nested being cracked with the same RAM requirements as Static Nested.
Bad news. It takes one metric eternity.
Also: I can make it run 95% faster (already know how), but 95% faster than eternity is still eternity. Still thinking about shortcuts.
I think if it runs on the Flipper it would take 5 hours to test all possible states for a Full Nested nonce. Distance is one way to fix this, but I want something better.
5 hours is better than the time we had before, which was 2 months lol
Actually, this matters more than I gave it credit for. This means the fast Nested dictionary attack will work with all weak PRNGs.
I'm not clear yet on why it wouldn't solve static encrypted nonces too, as long as the PRNG is weak
I'll test it on a static encrypted tag at some point
actually I have some static encrypted traces, let's see if this works on static encrypted tags. no chance 
it works
#738046276138041415 message
also @oak granite since you were interested in this
with traces you mean traces from the reader?
The traces aren't necessary, but I used the traces to debug it
nice
If I can get more traces I can get more confident in the solution, but it already worked for the traces I have here
and the likelihood of randomly getting a key is... LOW
The solution uses only information included in standard nested nonces like the FlipperNested app collected
so like, the keystream, parity, nt, etc
on this chapter of "MIFARE Classic gets broken yet again"..
this is incredibly significant you're the first (documented) to overcome static encrypted nonces
your research can solve a burning gap in the proxmark's functionality let alone the flipper
incredible stuff man. seriously amazed by the talent you've got
unfortunately I'm not sure if the Flipper Zero can handle it, we may need to offload it to the companion app
the next generation hw should be fine though
I put our cards on the table on the RFID Discord after some more testing. Now everyone knows what the static encrypted nonce solver we have does but we need to test the proof of concept a bit more before we share that too.
these are the main observations that were made and how the key recovery is done #738046276138041415 message
I think I have everything I need to wrap up the proof of concept
but I won't say no to more traces
running one final test
#738046276138041415 message
poc solver shared with details
more good news, figured out what should work as a static encrypted nonce attack on the Flipper Zero
and on the Proxmark too. it's not as good as the first attack since it can only get neighboring keys, but that applies to pretty much every one of my static encrypted tags
good job actually on successful possible keys reduction
I've somehow failed on that, just managed to find already known valid key in the first 2 millions batch, but not intersect with other sectors with the same keys
you got your account back??
oh i thought you got compromised in a way that made you need to burn it
well, after about 2500 re-keys of a static encrypted smartcard i'm seeing a pattern in the distribution of the output
this silicon version might get cracked
it would be nice if i had a scanning electron microscope like the original ccc researchers lol
if anyone wants to donate one, dm me
i'll take your garage sale multi-million dollar microscope so i dont have to black box RE these kdfs
While I don't have one, I might be able to ask around and connect you with someone who has access to an SEM if you are serious about it.
just venting, i'm not qualified to operate one and i don't know how to remove individual layers of the IC
i have used 21 genetic algorithms, a random forest algorithm, and a neural net in tensorflow to analyze this kdf. it's not cyclic and its not obvious
lol
the generic algorithms just trended to the middle of the range, so I had to add penalties if they did that. it still got stuck at local minima
certain keys produce the same static encrypted nonce, which means its at the same offset from 0 in the LFSR
15,0000000001A5,12198
15,0000000131A0,12198
15,000000013B64,23778
15,00000002A36F,23778
15,000000000284,24726
15,00000002AC88,24726
15,000000013D58,28147
15,00000002A55B,28147
15,0000000001AC,30889
15,00000002A8A0,30889
15,00000001377C,44961
15,00000002A675,44961
15,000000000098,51939
15,00000002AA94,51939
xoring them reveals something close to a pattern
>>> hex(0x0000000001A5^0x0000000131A0)
'0x13005'
>>> hex(0x000000013B64^0x00000002A36F)
'0x3980b'
>>> hex(0x000000000284^0x00000002AC88)
'0x2ae0c'
>>> hex(0x000000013D58^0x00000002A55B)
'0x39803'
>>> hex(0x0000000001AC^0x00000002A8A0)
'0x2a90c'
>>> hex(0x00000001377C^0x00000002A675)
'0x39109'
>>> hex(0x000000000098^0x00000002AA94)
'0x2aa0c'
>>> bin(0x0000000001A5^0x0000000131A0)
'0b10011000000000101'
>>> bin(0x000000013B64^0x00000002A36F)
'0b111001100000001011'
>>> bin(0x000000000284^0x00000002AC88)
'0b101010111000001100'
>>> bin(0x000000013D58^0x00000002A55B)
'0b111001100000000011'
>>> bin(0x0000000001AC^0x00000002A8A0)
'0b101010100100001100'
>>> bin(0x00000001377C^0x00000002A675)
'0b111001000100001001'
>>> bin(0x000000000098^0x00000002AA94)
'0b101010101000001100'
the xored offsets are all divisible by 8
maybe some kind of xorshift
@oak granite for your Fudan 10-90 static encrypted nonce tags, would it be possible for you to you get a trace (trace list -t mf) of hf mf nested authenticating with a known key to a few sectors?
it should error with the unpredictable prng message, but the trace would have valuable info
10-90 are 7 byte as I remember? Will try to find one of them today
no, I don't have any keys for both of my 7 byte fudan cards, search might be longer then...
update: solving static encrypted nonces 94% faster #738046276138041415 message
i just spent four days on a proof from hardnested that yielded a 0% improvement. very cool
anyway here is my current best code for static encrypted nonces:
https://gist.github.com/noproto/e6f4905107e9a7d56a90db7324ba9bf8 v3, here's a static encrypted nonce solver that is coded fairly well. Support for threads, distance with offsets, no more making formatted nonce files, good error handling, and usage examples. plus, GPL licensed
that's 99.9999% of the possible keys eliminated, you can merge two files and get the key for your tag in an hour if its shared in two sectors
if you know where the LFSR offset is, you can get the key without it even taking that long. some static encrypted tags are easier than others, but the POC works on all of them
at least all of the ones I know of
it takes an average of 10 days using the POC to crack any static encrypted tag. i'd like to get that number down further but it can wait. we need nested running on the FZ firmware
also now this project has touched on all of the known reader-based and card-based attacks đ
there are some SAT solvers and GPU bruteforce/bitslicing that we obviously don't use or consider though. all I want to get working is every known Nested attack
It also made some new variants, this is the first time card only attacks against static encrypted nonces gave been possible
not just possible. Possible on the Flipper Zero
i'm going to implement it
the calibration solution works on at least 04-90 tags. so no additional hardware needed
Advanced MIFARE attacks on the FZ
Indeed, massive effort!
if anyone knows where I can buy some 04-90 static encrypted MFC tags I'd appreciate it so I can add support to MFKey
!pinmsg #1134994594661146674 message
message 1266915261307420722 pinned
I've got a few I can check, what's the easiest way to verify which type it is? I've only just gotten back home or I'd have checked earlier
rdbl 0
ok so these three were all from the same hotel stay and are in a wooden based card used with an Onity system:
A0 9F 2A 49 5C 08 04 00 03 38 29 D2 7F D6 EF 90
C0 F9 FA 4B 88 08 04 00 03 3B EB 60 FD E8 EF 90
90 87 6D 4B 31 08 04 00 03 AA B4 76 97 A5 19 90
these two were from another hotel using Saflok in a regular PVC (presumably) card:
36 AD BF 9C B8 08 04 00 03 BA 34 B4 6C E4 5F 90
E6 5A C4 9C E4 08 04 00 03 7A BB 2A 9D 71 1A 90
let me know if any of those are the what you're after @regal storm
03-90 
Damn
Out of curiosity have you looked into how GDM/USCUID tags act when the static encrypted nonce flag is set in the config block?
this morning I'm looking into what doegox shared
Haha yeah I've only had a quick squiz so far but interesting so far
I'm not sure how common this chip is yet, and I've modified the firmware to send the backdoor command that's mentioned in the paper
everything mentioned up to the backdoor we already have
but if this specific IC is for all encrypted tags, that would be pretty awesome
1918464 | 1928992 | Rdr |93 70 F5 DC 44 FE 93 3F 2A | ok | SELECT_UID
1930052 | 1933572 | Tag |08 B6 DD | ok |
1935616 | 1940320 | Rdr |61 0F DA 9A | ok | AUTH-B(15)
1941828 | 1946564 | Tag |C1 22 3F F7 | | AUTH: nt
1955968 | 1965280 | Rdr |c6! d6! 0d! 93 DE 54! bd! 5A | | AUTH: nr ar (enc)
1966404 | 1971140 | Tag |af! c3! b7! C2 | | AUTH: at (enc)
1935616 | 1940384 | Rdr |07! 76 AD b2! | |
| | * | key 00FFFFFFFFFF prng WEAK | |
| | * |64 0F 62 E4 | ok |
1983044 | 1987780 | Tag |89! 64 0C 5f! | |
| | * |8A D1 94 51 | !! |
ut oh..
whats 89! 64 0C 5f 
1918208 | 1928736 | Rdr |93 70 F5 4A 77 EA 22 53 B0 | ok | SELECT_UID
1929796 | 1933316 | Tag |08 B6 DD | ok |
1935360 | 1940064 | Rdr |61 0F DA 9A | ok | AUTH-B(15)
1941572 | 1946308 | Tag |6A 27 66 5B | | AUTH: nt
1955712 | 1965088 | Rdr |D5 D0 a8! f9! 69 34 cd! 14! | | AUTH: nr ar (enc)
1966148 | 1970820 | Tag |07 d3! a5! 02! | | AUTH: at (enc)
1935360 | 1940128 | Rdr |4c! 90! AF 89 | |
| | * | key 000000000BBB prng WEAK | |
| | * |64 0F 62 E4 | ok |
1982788 | 1987524 | Tag |ac! ad! 45! 6f! | |

4188928 | 4199456 | Rdr |93 70 5D 2D 95 14 F1 65 70 | ok | SELECT_UID
4200516 | 4204036 | Tag |08 B6 DD | ok |
4206080 | 4210784 | Rdr |61 0F DA 9A | ok | AUTH-B(15)
4212292 | 4217028 | Tag |78 F0 EA 45 | | AUTH: nt
4226432 | 4235808 | Rdr |C7 CC 26! 89 BC 9E D2 5a! | | AUTH: nr ar (enc)
4236868 | 4241604 | Tag |8B e9! dc! 41! | | AUTH: at (enc)
4206080 | 4210848 | Rdr |4a! 22 ba! 4F | |
| | * | key 000000000FCC prng WEAK | |
| | * |64 0F 62 E4 | ok |
4253508 | 4258244 | Tag |5b! 9a! 29! 51 | |
| | * |14 76 9A EF | !! |
non static encrypted:
| | * | key FFFFFFFFFFFF prng WEAK | |
| | * |64 0F 62 E4 | ok |
908612 | 909252 | Tag |02(4) | |
it's flipping real
well. static encrypted nonces are pwned. we'll be able to support them on the Flipper Zero - all of them. and they can be cracked as fast as static nested
that didn't take long
90357 [E][MfClassicPoller] nt_enc (plain) 8a715528
90359 [E][MfClassicPoller] dist from nt prev: 188
90377 [E][MfClassicPoller] nt_enc (plain) aeb4b5c2
90380 [E][MfClassicPoller] dist from nt prev: 188
90398 [E][MfClassicPoller] nt_enc (plain) 7e65a5bb
90400 [E][MfClassicPoller] dist from nt prev: 188
90418 [E][MfClassicPoller] nt_enc (plain) 9b548ad9
90421 [E][MfClassicPoller] dist from nt prev: 188
90439 [E][MfClassicPoller] nt_enc (plain) 607ec775
90441 [E][MfClassicPoller] dist from nt prev: 188
90460 [E][MfClassicPoller] nt_enc (plain) bfd92a62
90462 [E][MfClassicPoller] dist from nt prev: 188
90480 [E][MfClassicPoller] nt_enc (plain) 8e026842
90483 [E][MfClassicPoller] dist from nt prev: 188
90501 [E][MfClassicPoller] nt_enc (plain) a55d950b
90503 [E][MfClassicPoller] dist from nt prev: 188
how's that for stability on a Full Nested tag
the highest drift I get is around 10. easily corrected with validating the nonce matches the expected parity bits
I can discard two outliers, take the median value, then collect static nonces đ
might get more than one valid plaintext nt, which is simple to overcome as well. store both within the max observed distance. since i'm running them through a dictionary attack until they get cracked, its not really costing anything
for context, 10 is very good. it's basically Static Nested. all of my Full Nested tags will be cracked as fast as Static Nested tags now, in the MFKey app. goodbye, Full Nested!
FlipperNested halted and woke up the card repeatedly. this led to significant distances: 518, 3532, 3326, 3354, 468
the way we avoid this is by doing multiple nested auths to the same sector, then auth to the target sector. we only calculate avg distance after the collection period
and this, is why it pays to wait to find how to do it right. because we can roll up the static encrypted nonce detection into the same logic. can't wait đ
the only time you should have to crack nonces off-device is when you have a hardnested tag
in my collection of tags i want to say only 5-15% of them are hard
Make sure you quote yourself when you pull that one out of a hat and manage to run it on a flipper too đ
I mostly only see it from public transport cards as they seem to be the only folk still using genuine NXP mifare classic cards
it will, just not this one 
I looked at it and it looks legitimately impossible to run on a STM32
I'm happy with Full Nested, that could take gigabytes on a desktop and we're going to run it on a Flipper Zero. same with static nested. The code is coming along rapidly today since I have every regular Nested attack memorized right now. I might get done tonight, if not very close
trying to make the code simple and elegant. One function to collect nonces for all of Static, Static Encrypted, Full, and Hardnested
all it's doing is collecting nt_enc in different ways, with a different handler to decide how to best attack the tag
Static, Static Encrypted, and Full all get logged the same way as regular Static Nested nonces. That way we get instant compatibility with MFKey
MFKey only sees "Static Nested"
anyway three big things I'm working on now, parity collection, backdoors (magic wakeup, FUDAN), rapid dictionary attack contributing back to the ongoing dictionary attack
it's going to melt people's minds when they see how fast this is going to be for dictionary attacks, since so many tags are static at this point. like 85% of tags scan in seconds
if I even tried to do the implementation last week or before that, we would have ended up with something messier
besides the firmware side we'll need the NFC app to reflect what's happening, and I need to optimize calibration a bit so it doesn't try to calibrate every nonce
I'm trying to make the measurements collected by the Flipper Zero as precise as possible. The Flipper uses the LSE, which doesn't seem to offer the precision we need. I'm only seeing anywhere from 30 to 60 microseconds of precision, when the card shifts every 9 microseconds. There do seem to be better time sources in the MCU though
I switched to the HSE for nonce collection and I'm getting closer. I'm getting subseconds but not at the precision I need them yet. Probably an issue with the prescaler.
Still this is great progress
Tried both DWT->CYCCNT and LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_HSE_DIV32), getting very minimal correlation.
Figured out how to solve Full Nested once and for all lol
On a flipper?
yes
Nice, just hardnested left then đ
I had an idea for Hardnested, which is what I've spent most of today working on, but I can't get the Flipper to reproduce the behavior I'm getting on a Proxmark
Oh? What's different? Timing doesn't matter with hardnested cause we're not predicting nonces anymore yeah?
I wanted to play around with the RNG by keeping the card powered between failed Nested auths and successful Nested auths, something that seemingly works by keeping the field on and selecting the tag/WUPA? Like the tag doesn't HALT
anyway it's unusual behavior and I noticed it in more than just the static encrypted tags
Hmm it should be possible to keep the field on like that, is there some other code in furi or something that's turning it off unexpectedly? Check with a scope to see if the field is staying up?
I found some code that was responsible for halting the tag, commented it out and its still failing. Not sure but back to Full Nested:
Small sample, distances, my most variable tag (range: 30, ~3 possible values)
Large sample, distances, my most variable tag (range: 30, ~3 possible values)
it's not quite a bell curve, clearly there are certain distances which are more common. but that's just it, certain distances are more common - as we'd expect - from our starting nested nT
we take the mode distance, and for the nonces we collect, we'd expect the mode nonce to be the same nonce as the one found at the mode distance
I always have a mode value, so it works
as long as we have a predictable starting point, which we do in nested authentication. to confirm we found the expected value, we match it with the parity bits
so its not only parity bits, which has a 1/16 chance of returning an invalid nonce, but also the frequency we observe the nonce. we're certain its the same value
even more samples
for most of my tags, the distance is either 0 or something very low, like 10. and the mode in those is a single value. for static nested, it's a single value no matter what.
so works for every case.
anyway. good progress today. here's where we are: https://github.com/flipperdevices/flipperzero-firmware/compare/dev...noproto:flipperzero-firmware:nestednonces
message 1269475139901198397 pinned
@hidden nexus or just wait for your Flipper to do it in a few weeks. I'll drop the backdoor key the moment doegox does.
until then we're building in all of the functionality to do the attack automatically on-device
gave an update here: https://github.com/AloneLiberty/FlipperNested/issues/21#issuecomment-2267267501
I mean I'd like to understand it somewhat on the proxmark as well.
While I really appreciate all the work you and others do sometimes the waiting for the stuff soon is less soon than we all anticipate because life/not regular job/etc
fair. The reason why it was delayed was because we were solving all three attacks to run them on the Zero. Doing nothing but writing the code required now, which is honestly the easiest part
explaining the significant amount of code that's been written in the past few days
I was being generous, since I expect maybe a few days of real development time plus going back and forth with OFW developers on various requirements to merge it. I will be out for a couple days starting Monday though
the only part which is required to take a few weeks is waiting for doegox's presentation. then we'll swap 6 bytes in the code and it'll all work
(we already know those 6 bytes, it's just not public)
12 bytes if you consider the original variant, which I think just gets added to the regular MFC system dictionary
totally understand
It still needs a special auth command though like on the static enc cards, so probably not a huge amount of sense adding it there really as it still needs special handling
so whats the difference between -S and the original?
In terms of how the key is used? Nothing as far as I can tell
The original can be attacked with regular nested though of course
While the S is static encrypted
ohh gotcha
Free sector key to start off the nested attack though and free read of all data blocks
yeah the attacks that can be done without a key are interesting, but I'm not sure if they can be done on a Flipper, or worth being done on a Flipper
mfkey32 works well enough
people will always want better, but its no different from any other attack in physical security - limited by the resources of the attacker
(safe to say I can't fund infinite research hours)
hi @oak granite may I DM you? I'd like to do a few fingerprinting measurements on the 1090 for the paper. I don't expect much differences with 0390/0490 but I don't want to make up numbers đ
yes
decrypts nt_enc, shortcut I'm planning to use:
struct Crypto1State *pcs = crypto1_create(key);
if (pcs == NULL) {
fprintf(stderr, "Failed to create restored Crypto1 state\n");
return 1;
}
crypto1_word(pcs, nt_enc ^ uid, 1);
uint32_t nt_enc_plain = (nt_enc ^ lfsr_rollback_word(pcs, uid ^ nt_enc, 1));
printf("nt_enc plain: %08x\n", nt_enc_plain);
trying to make sure the calibration function and the actual nt_enc collection function run in the same amount of time
Looks like nonce collection and logging is working on my dev nestednonces. Haven't uploaded the changes yet. Takes 12 seconds to collect 64 nonces, and write them. After feeding back into the dictionary, I'm expecting 20 (or sub-20) second dictionary attacks.
with the plus of being able to crack them in MFKey immediately after trying to read your card, which adds the keys to your user dict
man the only thing that's stopping me from pushing this code is the parity
found the parity bits
they were in the rx buffer at an offset I don't really understand yet, and inverted. pmo is the proxmark observed parity, inv is the proxmark parity inverted, and data is the rx buffer dumped. I wasn't getting this with bit_buffer_get_parity for some reason, maybe the way I was using it or something. nobody else uses this function
pmo -> inv -> data
a b c d
1. 0101 -> 1010 -> 00000010 11110111 00010000 00000101 00000111
2. 0110 -> 1001 -> 11010101 00011101 00000001 00011001 00001000
3. 0000 -> 1111 -> 01110111 00001101 10011111 11001100 00001010
4. 0111 -> 1000 -> 11011111 00110001 00010100 11110010 00000010
5. 0010 -> 1101 -> 01001001 10011001 11100010 11111010 00001111
6. 0100 -> 1011 -> 11011110 11000111 11000001 11011110 00001111
okay I'm like 90% sure bit_buffer_copy_bytes_with_parity is broken in the firmware which in turn causes the parity to not be copied from the recv buffer. data is fine but parity is wrong
edit: it was. fixed
nobody noticed parity was broken because the Flipper doesn't check the parity and nobody else uses the function
yup. I'm not crazy:
148781 [E][BB] ORing 0 to buf->parity[0]
148783 [E][BB] Assigning 1 to buf->parity[0]
148786 [E][BB] Assigning 0 to buf->parity[0]
148788 [E][BB] Assigning 0 to buf->parity[0]
that's the right parity, and it's constantly overwriting itself at the zeroth index of the parity array. lol
I think the way we're going to reduce candidate nt_enc plain values is by making a faster auth nested function. No more random values, no more checking if we're in nested auth or regular, reduced function calls.
Damn, nice catch!
Can only imagine the pain tracking that down
Wasted an entire day of development
at least nobody else has to once it's merged
not sure how it ended up in OFW to begin with though? most of the code in OFW gets tested as far as I know
first made sure the HAL was setting flags to collect the bits, then made sure the bits ended up in the buffer, then looked at how the buffer got copied which is where it was broken. figured out what gornekich had meant to write so the fix ended up being a one liner
@flat copper want this separate from PR#3822 or is it okay if I roll it all up in the PR
Could even be a 3-character PR; just !( and )
valid_nonce isn't working properly. I have a modified version that's working on 70% of tests but that's 30% less than what it needs to be.
once this is fixed, the nonces should be crackable
ah damn, user error. it's working, updating it now
Fixed and now the firmware is collecting valid static Nested nonces for all tags that are not static encrypted or Hardnested đ
I was able to take a "Full Nested" card, read the tag with the firmware Nested implementation, loaded the nonces up in FlipperNestedRecovery as static Nested and it found the keys
even in its current state it should be able to do the accelerated dictionary attacks and all of the planned attacks with MFKey (with some changes), so we're getting closer
I really want to get it all finished but I have to switch back to other work for now. until then, 𼳠𼳠đĽł
right now we use parity to eliminate some states but we end up with 2-3 other possible states
I was thinking about the PRNG, we have 65535 possible states. we can leak the parity, but nothing else
that brings it down 1/8th, 87.5%. good, but we're still left with those 2-3 others within a small range of about 16 candidates
but that assumes even distribution of parity in the LFSR
and parity is not evenly distributed. I just checked. so that means we may be able to target a specific nonce, since we know how many steps there would be to reach it from the initial state, we know how many steps it makes every time we do a nested auth, and we have the last known state
here's an example, straight from actual output (I wasn't being selective at all - this is unoptimized, a random 29 successors):
par: 110
par: 001
par: 111
par: 111
par: 001
par: 110
par: 000
par: 110
par: 100
par: 011
par: 111
par: 110
par: 010
par: 101
par: 000
par: 100
par: 000
par: 111
par: 110
par: 101
par: 100
par: 011
par: 001
par: 000
par: 000
par: 111
par: 100
par: 011
par: 001
what if we targeted a nonce with parity bits 010 in that range? if our distance is only 16, and we typically see the median value, then if we see 010 from the predicted distance it's almost a certainty we have the right nonce
so what we can do is find the largest continuous range where a certain parity isn't seen, then target specifically that parity
if we see it, we have the nonce with 100% certainty
even better if we can find a range with two or three tightly coupled unique parities
bam. Full Nested solved
we can reliably get the plaintext nonce
actually Proxmark/FlipperNested has something like this (CTRL+F "we are only interested in disambiguous nonces, try again"), I'll compare both strategies to see if one is better
Clever
so yeah we can use the previous nt enc decrypted to make sure we haven't drifted off the expected value in the LFSR, that way we always end up in the expected range. this will definitely work. I've looked through the frequency of each parity in the LFSR, on average this will always work within a few attempts
i think that's every challenge solved, just a matter of writing the code. i'll continue writing it after today.
tldr: we are getting static nested, full nested, and static encrypted nested on our Flippers. they'll all crack in around 3 minutes or less, and be integrated with dictionary attacks for faster dictionary attacks plus integrated nonce collection
should be done in 2 weeks. Hardnested nonce collection will be included and I'll fork FlipperNestedRecovery for initial support until its merged with the Android app
anyway will update this project thread when Full Nested has been eliminated
okay I hate my life but the scope of this project has been expanded yet again. once I'm done with the changes I'm working on I'm going to make a MF Skeleton Key app
because I can, it's simple, and it'll work against some dumb readers
against those readers you should only need to launch the app, hold the Flipper up to the reader, and the door will open
woah...
it'll work against some dumb readers
IMHO an incredibly narrow segment of the real world. Still absolutely possible. A step just above "Only checks UID"
Even checking the UID would be better though, because then the possibilities are still 2^32
nobody will guess a UID in practice, unless it's predictable
https://discord.com/channels/740930220399525928/1134994594661146674 bringing watchdogs to you - one step at a time. 
Lol what are they doing if not UID?
key only auth
I'll bruteforce {aR} using our dictionary keys, then if it decrypts to the successor of nT then we have the right key. So I just send {aT} back and the auth is successful
Lol
as long as the reader is only using the keys to auth, it'll open
better chances with Mfkey32 too
no chance for nested auth though
also to be clear, the bruteforce isn't active (no failed auth attempts against the door)
just local on the FZ to find a matching key to the keystream data
if it really wants to read we can send it a blank sector with default access conditions too
if it really wants to read won't it be expecting something in that block/sector it's polled?
could be stupidly checking the ability to read the card, or the content of the card could be not relevant to the overall auth
the plausibility of that depresses me
either way we can just make the reader as happy as it can be, might work on some KDF systems too which depend on the diversified key being the auth
Is there precedent for this? Itâs hard to believe someone would be that silly when setting up a system, but I feel like Iâm constantly lowering my expectations and opinions of folks deploying these systems, the more I learn
There's UID only readers, which is enough precedent for me to make the app lol
hard to say how many readers could be doing crap like this if we aren't checking
successful authentication seems like a good condition to open the door on
well, unless you know literally anything about MIFARE Classic
Wonder if one could use a modified bloom filter (or some other probabilistic approach) to speed up evaluating that over a large dict. Need to refresh my memory on the nitty gritty of mfc to see if that actually makes sense
I'll add it to the MFC document under the list of methods to try in order of despair
what matters though is that it's a zero cost attack. if it doesn't work, you didn't waste any time
every other method requires investing measurable effort, even if it's not much
I can see myself holding it up to doors just to know for sure
also to feel like a hollywood hacker, that's important
"damn the attack that has a 98% fail rate didn't work. they're good"
âiâm in đ (because someone saw me by the door and let me in)â
i'm in (someone let me in and i realised im not in the right place but you have to badge out)
Full Nested is working on my nestednonces branch as Static Nested, but I don't like the time cost (adds another 30 sec).
will work on bringing that down, I already brought down calibration time. Currently reliably identifies valid Static Nested nonces for all Full Nested weak PRNG tags.
but yeah confirmed this: #1134994594661146674 message
gg full nested đ
from FlipperNested repo, for context
PRNG doesn't jump around anymore, we accurately predict it 90% of the time in my first draft implementation, RAM usage eliminated, calibration time is well under a second and working on other delays to bring it down further from 30s
btw, if PRNG issue is solved now, does it mean darkside also can be easily ported to Flipper?
Darkside can be ported, I'm just not too interested in it since most cards have encrypted NACKs disabled to the best of my knowledge
also we can't let perfect be the enemy of good enough. good enough is the accelerated dictionary attack, nested nonce collection, and static encrypted backdoor support. should work for almost everyone, with Mfkey32 already available
truthfully I see what is being completed now through the end of this month as the end of this multi-year project. anyone is welcome to continue it and add things like Darkside, magic wakeup, etc.
the end for MIFARE Classic at least. I'm ready to start over with MFUL-C
we already have our first MFUL-C KDF planned and there's an unimplemented attack against MFUL-C cards, plus our original plans for EMFI attacks using transparent mode on the ST25R3916
Where can I track the work on these? This is largely news to me (exciting!)
planning on working on it in our Signal research group. I have been sharing updates regarding MIFARE Classic here instead of our group because the transparency has worked out well for static encrypted nonce cards at least.
initial FM11RF08S backdoor detection added, works perfectly
I'll extend it out into the Nested attack tomorrow or this weekend
after reading a bit more about the backdoor, this will be trivial to write. we'll need about 7 minutes to crack each unique key in MFKey. With a few changes to how MFKey processes nonces we can do a look-ahead dictionary attack to save us from having to crack most or all of the rest of the keys. anyway there's a lot of options here, and ways we can guide the overall dictionary attack. I'll need to think about the fastest way to do all of it
just thought of an even faster Nested dictionary attack
i'll shuffle things around and give it a shot. i'm thinking close to 5 seconds for the full attack
once we have a valid key and confirmed its a weak PRNG, we'll collect nt_enc for all sectors and run decrypt_nt_enc with all of the keys in the dictionary. if the result is a valid LFSR candidate we auth to test and add it to the found keys
uint32_t decrypt_nt_enc(uint32_t cuid, uint32_t nt_enc, MfClassicKey known_key) {
uint64_t known_key_int = bit_lib_bytes_to_num_be(known_key.data, 6);
Crypto1 crypto_temp;
crypto1_init(&crypto_temp, known_key_int);
crypto1_word(&crypto_temp, nt_enc ^ cuid, 1);
uint32_t decrypted_nt_enc = (nt_enc ^ lfsr_rollback_word(&crypto_temp, nt_enc ^ cuid, 1));
return decrypted_nt_enc;
}
this is going to be a lightning fast dictionary attack if I'm not overlooking anything, and it'll work on all weak PRNGs including static encrypted tags
no need for calibration either. we only calibrate and collect nonces for the sectors we failed to recover from
also, figured out how to do the fast Nested dictionary attack on hard PRNGs too
we can do a rapid attack on every MFC tag that exists
for everyone who said we'd only get static nested, please give me your card so I can give you your weekly "not anymore" stamp
10 stamps and you get a prize
I can't wait for this all to drop!!!! Its so much more than initially expected.
truly. every time I think we have it all figured out, we get a new attack. the good news there are very minimal changes made to support the new attacks for each improvement
we're up to a thousand lines of new code in the PR which is more complex than i wanted it to be, but the features will make it worth it
I'm going to try and minimize it as much as possible to make it more likely we'll get it merged
the last thing I'd want is for us to write all of this for 5 sec dictionary attacks and the OFW devs to reject it because they want to externalize it (making the process more complicated for everyone)
the good news is, hedger seems onboard so I'm less worried about it getting rejected.

maybe i'll check with them tonight on Q&A to make sure I won't get any surprise obstacles to it being merged
I'm sure it'll be merged into the iceman flipper firmware without question though đ
I'm going to look into offering users to directly launch MFKey once the main changes are finished
(mfkey.fap exists, we have nonces, we send a signal to the active app, unlock the loader, and use loader_start to spawn). but I will not include it in 3822 due to high likihood it'll be rejected
after detect reader?
after detect reader and dictionary. like a button to launch if the app is available but I don't want to include it in the main PR because I want the main PR to be accepted
if they choose to not merge the convenience feature itll make sense (don't wan't firmware too tightly coupled with extapps) but i'm just looking for the easiest process for users
A feature like this could be a great optional addition to NFC plugins or similar; offer the option to launch in an ext fap if available
> on Q&A after-party
> "Flipper has no new attacks"
> I'm literally coding new attacks on stream

Been taking a sneak peek đŤŁ
will this help with memory availability as well - or would it still have the saved menu state from when the NFC app was first launched?
since both the NFC app and MFKey use high amounts of memory, I need to kill one to start the other. if someone tried to bring down the memory consumption of the official NFC app, we could bake in Mfkey32/Nested and get rid of MFKey entirely
the way to do this is with plugins (fal)
at the moment the entire NFC app gets loaded on start, minus the NFC plugin system which is separate from the plugin design I'm thinking of
anyway fixing the problem is not a small effort but it needs to be done. the NFC app already crashes due to insufficient memory
won't be in my PR but if someone fixes it I'll take the steps to turn MFKey into an NFC app plugin
that would be..chefs kiss. NFC -> Read. for 95%+ of MFC smartcards it would end there lol
fun side fact: Flipper Nested also initially was planned as static nested only, but then it got full nested (which took 20 months to get rid of, but at least it was working all this time đ)
yea credit where credit is due. I'm happy that everyone had an app to use that worked all of this time that I've been trying to solve the attacks
well, worked fairly well.
also I'm pretty sure if AloneLiberty was working on this for as long as I have, they would have solved it too
holy shit haha
I just gave the rapid nested dictionary attack a first attempt
it was done in 8 seconds
the card is Full Nested
doing a benchmark now, no rapid attack versus rapid attack
no rapid dict attack, latest OFW: 5 minutes 6 seconds
rapid dict attack, nested fork: 14 seconds
I'll see if I can speed it up any more by the time we do the PR but I think current maximum time is close to 20-30 seconds with an average time of 10 seconds
this is actually slower than I thought it would be. was expecting 5 sec so there may be a bottleneck
then again "this is slower than i thought it would be" is the mantra of STM32 developers
anyway, only gets better from here.
I wonder if we can get it to be fast enough to copy tags by bumping into people
hard prng nested rapid attack should be mostly coded, plus I cleaned up all of the code. including a few nice things then testing soon
some of this code is honestly really elegant. i've refactored it like 5 times
we're going to have the best MIFARE Classic mfkey/nested attacks of any device
the others have the code scattered across multiple files, duplicated code, and junk/useless code. we have a single function which guides all of the nested attacks.
that one function has general-purpose code which knows how to direct an accelerated nested dictionary attack, leaving early if we're done, checking for all card backdoors, calibrating, collecting encrypted nt values with reliable timing for any keys we don't have, and logging nonces for those keys. and the individual functions responsible for doing the work are properly asynchronous
we approach static encrypted cards, static cards, weak PRNG cards, and hard PRNG cards all with the same set of functions
just happy for the direction development is going
the code in the final PR is going to be đĽ đĽ đĽ
Did a skim of your fork; looking beautiful. Iâm not too familiar with what the former bottlenecks were â is all of the speedup owing to the fact that the dict can be evaluated âofflineâ against the nonces, rather than trying to auth on the card repeatedly with each key in the dict â ie the primary bottleneck was rate of communication?
I haven't uploaded the changes lol
You're looking at the bad code
I do have a weak Nested dict attack working, but I fully refactored the code and added hard support. Tracking down a memory corruption bug before I commit it
my refactor made it a few seconds slower but more robust
I'll try to regain that time
mf_classic_poller_handler_nested_controller runs the entire attack
we enter it when the poller calls the reuse key function for the first time, meaning we found a key to do nested attacks with
also for anyone who wants to try it out, the keys just get logged to the CLI error log. I'll properly add them to the found keys when I get the hard PRNG fast dictionary attack working
yes!
that's exactly what we're changing
its way faster for us to check whether keys can generate certain encrypted nonces rather than auth to the card and fail
we decrypt the nonce with the guessed key and make sure its valid for both the PRNG (for weak PRNG tags) and the observed parity bits
in the case of hard PRNG tags, 3 parity bits isn't to go on for validation, so we collect 8 nonces to reduce the number of candidates we auth with. the parity must be accurate for all collected encrypted nonces
ho lee shit
hard PRNG rapid nested dictionary attack is working
going to see if i can get a benchmark for it in a moment
on one hand, my code works. on the other hand, the code written by Flipper Devices doesn't
at least I think?
[+] -----+-----+--------------+---+--------------+----
[+] Sec | Blk | key A |res| key B |res
[+] -----+-----+--------------+---+--------------+----
[+] 000 | 003 | FFFFFFFFFFFF | D | FFFFFFFFFFFF | D
[+] 001 | 007 | 8A19D40CF2B5 | H | 8A19D40CF2B5 | R
[+] 002 | 011 | FFFFFFFFFFFF | D | FFFFFFFFFFFF | D
[+] 003 | 015 | FFFFFFFFFFFF | D | FFFFFFFFFFFF | D
[+] 004 | 019 | FFFFFFFFFFFF | D | FFFFFFFFFFFF | D
[+] 005 | 023 | FFFFFFFFFFFF | D | FFFFFFFFFFFF | D
[+] 006 | 027 | FFFFFFFFFFFF | D | FFFFFFFFFFFF | D
[+] 007 | 031 | FFFFFFFFFFFF | D | FFFFFFFFFFFF | D
[+] 008 | 035 | FFFFFFFFFFFF | D | FFFFFFFFFFFF | D
[+] 009 | 039 | FFFFFFFFFFFF | D | FFFFFFFFFFFF | D
[+] 010 | 043 | FFFFFFFFFFFF | D | FFFFFFFFFFFF | D
[+] 011 | 047 | FFFFFFFFFFFF | D | FFFFFFFFFFFF | D
[+] 012 | 051 | FFFFFFFFFFFF | D | FFFFFFFFFFFF | D
[+] 013 | 055 | FFFFFFFFFFFF | D | FFFFFFFFFFFF | D
[+] 014 | 059 | FFFFFFFFFFFF | D | FFFFFFFFFFFF | D
[+] 015 | 063 | 8A19D40CF2B5 | R | 8A19D40CF2B5 | R
[+] 016 | 067 | 5C8FF9990DA2 | D | D01AFEEB890A | D ( * )
[+] 017 | 071 | 75CCB59C9BED | D | 4B791BEA7BCC | D ( * )
[+] -----+-----+--------------+---+--------------+----
[=] ( * ) These sectors used for signature. Lays outside of user memory
it is an EV1 and OFW only sees 32 keys/16 sectors
@lean sundial/bettse that's wrong, right?
based on the Proxmark's output it should be seeing 36 keys and 18 sectors
Are you sure the flipper tries 16 and 17?
just a moment, screenshot coming
I thought it stopped at 16 sectors / 64 blocks for a 1k
but it is an EV1, shouldn't it read the signature sectors 17 and 18 or am I wrong? all it identifies it as is a 1K despite being EV1
not sure if there's some nuance here I'm missing
all it identifies it as is a 1K despite being EV1
I believe so
So far as I know, flipper doesn't do any extra EV1 work, and doesn't check the signature
for a system that checks signatures: good possibility (of failure)
hadn't really thought about it, but some people reporting failure with emulation and/or gen1 could totally be in that situation
okay. I'll open an issue on the issue tracker, just never noticed until now and wasn't sure if signature sectors were special in some way
You can dump it as a 4K if you want to get the signature. This also happens the same way on pm3
It should detect EV1 the same way the PM3 does
can't expect users will try and manually read it as a 4K
(despite being a possible workaround)
the user is never informed it is an EV1, so they wouldn't know to perform the workaround regardless. all you see is 1K
unless they'd try and read every tag as a 4K
good point btw, I have a decent number of EV1 tags
actually now that I think about it, if EV1 detection is absent, we can't recommend people get gen1a for certain
their gen1a may not have enough memory for the full dump, and NFC Magic wouldn't know to write it
đ welcome to why I'm so hesitant to every say things concretely about NFC
sooo many fucking edge cases
it does feel a bit overwhelming trying to find everything out there. I mistakenly thought we had EV1 support already
only MIFARE Plus EV1, and MFUL EV1
somehow fell into the cracks. no issues on GitHub
(besides the one I just opened)
if we don't look for the signature sectors, we also likely miss out on a free nested key
Okay now that the hard PRNG dictionary attack is working, we just shovel the keys into the key reuse state.
Note USCUID/GDM tags can emulate the EV1 signature sectors too
working on one last major refactor, this one should be faster than ever and finish the accelerated dictionary attack mostly
expecting this one to run in 2-3 seconds. then i'm out of optimization ideas lol
maybe I'll share a dfu/tgz file so you all can test it later today đ
ahhh so many NFC/RFID things to test lately! so much new stuff coming đ
@granite lava feel free to track the updates here. technically the firmware already does the detection you're asking about
it logs "Backdoor identified" to the error log
there are 3 major parts of the update and the first is being finished now. that's next
code is up
I haven't really tested it much but I'll post a dfu/tgz here
maybe you all can let me know what you think of the speed?
compiling now
for best results, read your card(s) on OFW and write down how long it took and how many keys it found/sectors read. then flash this and do the same thing.
feel free to compile it yourself from the branch, if you do make sure you switch to the branch https://github.com/noproto/flipperzero-firmware/tree/nestednonces
you'd need to clear the key caches for that tho
maybe, for my tests I was testing on two Flippers
tl;dr remove (or backup) /ext/nfc/.cache/
https://eprint.iacr.org/2024/1275.pdf
Interesting, this you @regal storm ? 
nah but I have a minor credit
no, this is doegox's paper, phillipe from the RfidHackers community
that's doegox, they're in this channel too đ
without doegox's research you'd still be looking at 10 days to crack the tags
with it, we can run the attack on the Zero
(which I'm REALLY happy about)
static encrypted nonce tags having a backdoor feels like a troll. it's just so funny that mifare classics new "secure-ish" variant has a gaping wound
also Samwise I could use some help testing the code if you can
#1134994594661146674 message
that's a firmware image of latest OFW plus accelerated dictionary attacks
could use some before (stock/CFW) and after times
i'll be back at home in about an hour then i've got you
OFW 0.105.0: 4 min 44 seconds (found 19/32 keys, 16 sectors read)
Fork: 10 seconds (found 19/32 keys, 16 sectors read)
are you wanting to test keys in dict time ti find within card? because i can scramble a card with each sector having 2 different keys from within the dict
that would be super useful (scrambled in the dictionary)
real works too. I'm testing a tag right now that I thought I found a bug in my code for, but no, turns out OFW is broken too
18 or more keys found, only 2 sectors read
OFW 0.105.0: 5 min 8 seconds (found 18/32 keys, 2 sectors read)
Fork: 25 seconds (found 18/32 keys, 2 sectors read)

OFW 0.105.0: 22 seconds (found 32/32 keys, 16 sectors read)
Fork: 3 seconds (found 32/32 keys, 16 sectors read)
OFW 0.105.0: 35 seconds (found 32/32 keys, 16 sectors read)
Fork: 10 seconds (found 32/32 keys, 16 sectors read)
OFW 0.105.0: 5 min 3 seconds (found 18/32 keys, 16 sectors read)
Fork: 10 seconds (found 18/32 keys, 16 sectors read)
those are all of the real tags I'll test
so the fork takes an average of 11 sec in my tests. OFW 0.105.0 takes an average of 3 min 10 sec. varying conditions on real tags. slower than I expected, STM32 moment
Curse you, only making it 2 orders of magnitude faster! Back to work! 3 OOMs by tomorrow!
Seriously though, I don't think it can be understated how massive a contribution this is
Going to change the standard experience of using the F0 overnight
Huge kudos
I'm going to sacrifice some of that free time/speedup to collecting nested nonces
it might add another 5-10 seconds but then we can dramatically simplify the guides
for certain tags you could run an entire Nested attack on the Flipper in the time the original dictionary attack took to run
25s dictionary+nonces for one unknown key, 3.5 min Nested attack to recover the unknown key, finish reading the tag in 4.5 min
test running now
holy shit
@regal storm that took 17 seconds
all random keys from all over the dict
i double checked the file after it found all the keys and it does have all the right keys
no this was just a normal gen1a mifare classic
hell yes 
i can grab a fudan and test that if thats also something that needs checking?
OFW benchmark for the same tag?
accelerated dict attack should work against all tags, including static encrypted and hard
should
we are at one minute with 6 keys found so far
yes
noprotos key finding uses nonces to match keys faster
yea hard PRNG/Hardnested
fucking hell @regal storm this is incredibly impressive my hat is all the way off for you, im at 2 minutes and we arent even halfway through the tag
I'll include this benchmark on the PR btw once you've finished it
Impressive
youve got way enough on your plate but this would do absolute wonders for the proxmark, the full dict check could be the first step of autopwn by default
5 minutes, 18keys
8 minutes 2 seconds, full check @regal storm
thats nearly 30 times faster
get smoked OFW devs. should have spent years studying Crypto1. seriously though, thanks, all random keys is a really useful benchmark to have. it hasn't failed on any tags as far as I can tell
and yeah it could be ported to the Proxmark. since the Proxmark requires a host PC/phone they aren't searching for new speedups in this category since it's already quite fast when you have a host involved. they might be interested in how we unify nonce collection and cracking across all weak PRNG tags though
still in development until the end of this month. IMO it's going to be elegant to have one implementation to collect nonces and crack nonces for static nested, regular nested, static encrypted static nested, and mfkey32.
It would still make for a faster dict attack no?
small blog: just unmotivated to develop for the Proxmark. the Flipper community and developers appreciate contributions and are very incredibly overwhelmingly positive. also it has a wider impact since there are more Flipper devices. this may be a 20x code speedup, but the last 20x code speedup I brought up on the RFID discord was met with heavy skepticism and being told i "perhaps didn't belong there". is it okay to be skeptical, absolutely. but i'm a person too. i try to contribute back, i think that was out of line, and killed my interest in Proxmark development almost entirely. if someone else wants to port my code, go for it
unrelated, thanks for writing the auth nested code auguzanellato đ
also I'm going to fork your nested test app next month for a small experiment
Idea: Flipper vs Flipper attack experiment
two bugs in nestednonces courtesy of willy:
- crash on missing user dict
- no support for 7b UIDs
I'll need to look into how 7b UIDs even work for Crypto1 but planning on fixing both soon
i mustve explained poorly đ i was just debating whether to use a magic tag or not, but the attack worked great on a 7byte tag emulated from my second flipper. i was just saying that i dont have a 7byte uid magic tag to test on, but the attack seems to work fine on 7byte
I still need to validate I'm doing everything correctly for 7b UIDs, it's something I never considered. because I store UIDs in 4 byte integers so they can be xored, it may work because Crypto1 only xors the first 4 bytes
either way, it is coincidence it works and I need to go back and test it more
for 7b you need the last 4 bytes
UID: 11 22 33 44 55 66 77
you take 44556677
holy shit, thats fast for nested and hardnested
is this version you posted supposed to work on static nonce/static encrypted nonce cards?
I mean that is crazy fast though
to be clear this is the dictionary attack we're talking about, not the nested key cracking. Nested key cracking still takes around 3 minutes
the dictionary attack was reduced to ~10 seconds for all cards. works on static, regular, hard, and static encrypted
more or less 20x faster than the current dictionary attack. then we look for the backdoor and collect nested nonces so users can crack their cards
still working on that last part though
I had it working before, but the refactored dictionary attack broke it lol
just wanted to check, the dictionary was crazy fast
we could make Nested key recovery faster in MFKey by authing to the card while its cracking to validate key candidates, then terminate early if they are valid. that's not a good idea though, because we'd be duplicating functionality of the NFC app
the benefit if we don't start integrating NFC app features is that we can easily do the reverse integration when new Flipper hardware models come out
(MFKey merged into the NFC app, taking advantage of our free memory and cracking cards as we read them with the performance improvements)
do we still have enough memory to load everything required for the nonce collection?
yeah
most of the necessary code would reside in flash memory
yw
OK so I turned Debug on in the flipper and set the log level to Debug and I can see it use the KDF now for SAFLOK
@regal storm did you say it should have an entry in there about being Fudan/backdoor possible - even if it can't do anything about it/use the backdoor?
(I like to be able to find things in logs, because it helps with troubleshooting/info gathering I inevitably try to do down the road but like in the middle of the night in a hotel room or conference)
For the nestednonces branch of the firmware, yes
ah - is that the branch the firmware file you posted earlier this week is from?
wtf. I don't have a single 7B UID MFC in my stack of 110 tags
at least I have a Gen4 UMC?
I need to know where you all are finding 7B UID tags
disney infinity are 7b mifare mini
oh sweet, I'll check my disney infinity figures. thanks for the tip
sure enough, 7B. excellent, now I have a real tag
both fixed. validated that we are handling 7B UID's correctly, and missing user dict crash is gone.
in europe (austria) here I only ever encountered 7b uid mifare
apparently there's such a thing as 10B UID MFC. I assume that's for the discriminating access control supplier that needs to deploy a septillion credentials in their installation.
the fact that they just ignore everything except the last 4 bytes introduces a vulnerability because MFC was never designed for it
Honestly I never saw a 10B UID in the real world
1K UID MFC 1K: it just dumps the entire memory of the card to any SELECT command
Its actually hard to find real 7B UID magic tags like stickers etc. on aliexpress or similar. They are usually all 4B and not useable here for pretty much everything.
yea i just ran script run hf_mf_ultimatecard -t 5 -u 00010203040506 to configure it on an ultimate magic card
yeah that works
lol the Flipper doesn't even support 10B UID
it can recognize it, but the get_cuid function will fail because it only recognizes up to 7B
uint32_t iso14443_3a_get_cuid(const Iso14443_3aData* data) {
furi_check(data);
uint32_t cuid = 0;
const uint8_t* cuid_start = data->uid;
if(data->uid_len == ISO14443_3A_UID_7_BYTES) {
cuid_start = &data->uid[3];
}
cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) | (cuid_start[3]);
return cuid;
}
ISO14443_3A_UID_10_BYTES is valid, but isn't checked in this context
I could be wrong though. I'll configure my UMC to be a 10B UID after we're all done with the fw changes and make sure it uses the last 4 bytes instead of the first 4.
Any chance/ consideration/sense in getting what is already done pushed to OFW before before tackling the 10b uid since that isn't as common?
for sure, that's what I meant by #1134994594661146674 message . sorry if that was unclear
only after the firmware changes
I think the only person I've seen claim to have a 10B UID tag is Iceman
like a real one
today the goal is to get nonce collection working again
for real. tired of fumbling around for the Flipper whenever I want to look at changes
on average it takes another 6 seconds to collect nonces from the tag
10 seconds for the dict attack, which eliminates around half the nonces you need to collect, then 6 seconds to collect on the remaining keys
on a Full Nested tag đ
I'll see if we can add backdoor or Hard nonce support today too
decided to support the backdoor tonight. It should be identifying both backdoors now, but I don't have an older card to check with
hoping NVX can confirm it works
going to relocate the backdoor detection to the beginning of the dictionary attack
that way we can actually use certain backdoors at the appropriate time (the original NXP/Fudan backdoor)
if nothing else I want it to notify the user the tag is backdoored
but it will use the original NXP/Fudan backdoor
If it's gen1 could just skip the dictionary attack entirely and just dump the card directly đ
still would need the keys though
Yeah gen1 can dump keys, the fudan backdoors can't dump keys though
So just to be clear, the old backdoor can dump keys? And the new one can't.
I've taken to not calling it the Fudan backdoor. Fudan is the most impacted, and the S cards are owned by Fudan, but the backdoor itself predates them.
In the code it's just labeled auth1 backdoor (old generation) and auth2 backdoor (new generation)
and if the older cards can just dump all of the keys with the backdoor then no need for nested I suppose
No no, the gen1 magic card magic wakeup can dump keys, the fudan backdoor keys (both the old one that's existed for ages or the new one that was introduced with static encrypted nonce cards) can't read keys
Ohh okay, I interpreted bettse's question to be about the first generation non-magic backdoor. Lol
I'll die on this hill
#1134994594661146674 message
I won't refer to it as the Fudan backdoor so we don't confuse anyone into thinking Fudan made it, or it only affects Fudan
Yeah that's fair
it doesn't actually exist fyi, it's supported by umc but you won't find any nxp references to that.
and i think same applies for 10b uids in general in 14a, it's allowed by the standard but to my knowledge no commercial tags exist with 10b uids
#738046276138041415 message
I expect to be done with PR #3822 in the next 4 days. but I doubt we'll make the cut for 0.106.0
I'm hoping we can be included in 0.107.0, which will give the maintainers time to review it. mid-September is my guess for the official firmware update
who knows though. looks like 0.106.0 isn't too close yet, so maybe we get super lucky and an early merge?
Understand Hardnested nonce collection now. Will do my best to finalize nonce collection today, giving me tomorrow to write what is left of the backdoor code and the NFC app UI changes.
then, PR moved from draft to open for review.
while Flipper Devices does the review I'll update MFKey to 3.0, dropping FlipperNested support and able to crack the nonces. The firmware and the app can drop at the same time.
Hardnested is working
do we direct our appreciation to NXP or Fudan?
my favorite part is that it happens in under a second
as doegox described, you can literally just bump up against people and get all of the data off their tags if they are at an establishment using these tags.
key recovery can happen later.
first version of the feature will be finished tonight. Going to open it for review. besides fixing a few issues, this morning I confirmed we're also not missing any of the features in FlipperNested.
Attacking a static encrypted tag. After 2 seconds, all of the sectors are read and the dictionary attack is over.
damn. I'm collecting static encrypted nonces with the backdoor static encrypted nested attack but the nonces are wrong according to my Proxmark. going to take a bit longer to run down the issue. most likely an invalid nt plain
nevermind, it was user error.
./static_encrypted -u 275ba695 -e cba8f1c5 -p 1010 -n 7e6f3532 -o 0 -d 0|grep -i 3093FE5734EB
kc: 3093fe5734eb
./static_encrypted -u 275ba695 -e cba8f1c5 -p 1010 -n 7e6f3532 -o 0 -d 0|wc -l
58065
58 thousand key candidates, possibly fewer with doegox's improvements (right now I'm just running my own POC). I think I remember him mentioning several thousand in his version
58k might take a few minutes. then if the key is reused, you get the entire tag
(to be clear, we're going to do the 2 sector attack against reused keys with MFKey. I'm going to try and pair them up during the cracking process so 58k auths aren't needed)
I'm thinking we save full dicts, then a dict of each key that was reused at least once made from searching for reused keys across all dicts
sorting would be better but would require more memory than there is available. Nothing to be done right now though. nestednonces is functional, I'm going to see if I can update the NFC app UI now.
PR 3822 opened: https://github.com/flipperdevices/flipperzero-firmware/pull/3822
it's not what I want it to be yet, but I don't want that to get in the way of it being reviewed since it is functional with a few minor issues.
for anyone who wants to try it out early. Please don't report bugs without debug logs or a backtrace.
FAQ:
"How do I crack the nonces?" Wait until I finish MFKey 3.0.
"It gets stuck on collecting nonces" Calibration issue, will be fixed. It's not stuck, just taking a long time and most likely having trouble finding a candidate range.
"It crashes after a few reads" I'm thinking this may be a memory leak? I'd appreciate the help tracking it down.
"There's no progress bar" UI issue, will be fixed. For now you can use the header to know what phase it is on, and how many recovered keys. You can interrupt it during the nonce collection if all you want to do is run the accelerated dictionary attack/backdoor read. I'd like to see an option added to turn on/off nonce collection (default: on).
"Hardnested is slow" I'll be fixing this in the next few days. It has to do with how I'm collecting the nonces, and I have several ways to speed it up. I'll try to find the fastest.
During this video, it identifies the tag is backdoored, reads all 16 data sectors first (most critical, if you want to bump up against someone), then it does a nested/accelerated dictionary attack to recover known keys, then it repeatedly calibrates the tag (to get the plain nt) and collects static nested nonces from all remaining sectors using doegox's backdoor static nested attack.
What I like about the code is that it's a state machine with very few functions. Each function has a specific purpose, but they are designed to handle multiple scenarios. We come up 1000(+?) lines shorter than FlipperNested (a port from the Proxmark), while adding two new attacks and maintaining or improving the existing features.
and before anyone talks shit about the code, you are required to review the Hardnested implementation on the Proxmark first. My spaghetti is Gordon Ramsay tier compared to that.
when I saw you had 6387 keys I thought it was an error at first
Beautiful
Thought I'd get today to improve Hardnested collection but doegox just had to find another backdoor. 
Same backdoor but different key on another chip isn't it?
yes
more accurately: another backdoor key
I had my code set up like "if its backdoored and its not backdoor 1, its the other backdoor" which now comes back to burn me
not a big deal though, I'll fix it. if we get a fourth key though I'm making a dictionary 
do an array of structs like
typedef enum {
BackdoorOrigNxp,
BackdoorFudan1,
BackdoorFudan2,
BackdoorNum,
} backdoor_name_t;
typedef struct {
uint8_t auth_command;
uint64_t key;
const char* name;
} backdoor_type_t;
static const backdoor_type_t mfc_backdoors[BackdoorNum] = {
[BackdoorOrigNxp] = {
.auth_command = 0x69,
.key = 0x694206942069,
.name = "orig nxp old fudan",
},
};
that won't apply in the case that a single tag has multiple backdoors but afaik there's none
in what instance will auth_command not be 0x64 or 0x65 for a backdoor? wouldn't we be building out functionality where it doesn't exist?
and at that point having the enum as a bitflag enum should suffice
this is what I have now:
#define MF_CLASSIC_CMD_AUTH_KEY_A (0x60U)
#define MF_CLASSIC_CMD_AUTH_KEY_B (0x61U)
#define MF_CLASSIC_CMD_BACKDOOR_AUTH_KEY_A (0x64U)
#define MF_CLASSIC_CMD_BACKDOOR_AUTH_KEY_B (0x65U)
uscuid/magic85/whatever you want to call em tags?
but yeah that's not what you're probably thinking about
those do auth to block 0 with 0x80 iirc
in that case just leave out auth_command and you're golden
I asked the NFC group here (bettse, equip) if I should support magic tags and nobody seemed to be in favor of it. NFC Magic does it already. Merging the two would be nice in my opinion (disregarding the feature creep) but we have limited RAM and the NFC app is already near the max consumption with around 10kb remaining I believe.
don't ask me how, I have no idea why
anything thats taking up 100 KB in RAM should be split out into FALs
and - if we did make the NFC app modular and loaded FALs on demand - we'd be able to crack MIFARE Classic from within the app.
that would have the usability benefit of just allowing users to hold their Flipper against the tag until its read
uhhh protocol support split to fal when
fwiw, we also have no use for .name as we don't do identification of the tags. We just find the backdoor and use it, otherwise we'd need to store our findings in the saved .nfc file. Since the success screen uses only that information, from the MfClassicData struct
so I just generically say "Backdoor read" and "Nested dictionary (backdoor)"
anything more would exceed our 128px width
I feel like we should be using the fact that the auth command for B is just the same thing as A ORed with 0x01
but yeah, there's room for improvement 100%. for this PR I only want to finish an initial implementation, I keep getting pulled between finishing it and my day job and users need it sooner rather than later
refactoring would be appreciated
I've done my best to keep the changes as small as possible & reuse official APIs
makes sense, maybe just show the used backdoor key
ended up doing something very similar
I'm having this weird issue where the tags are responding to the v1 auth backdoor
like a bunch of them. trying to track it down so I can release the new backdoor code, I have everything else written
v1 is the old backdoor
v3 is the static encrypted one
I just tested 3 cards in a row and they all registered as v1
seems unlikely
// Ordered by frequency, labeled chronologically
const MfClassicBackdoorKeyPair mf_classic_backdoor_keys[] = {
{{{0xa3, 0x96, 0xef, 0xa4, 0xe2, 0x4f}}, MfClassicBackdoorAuth3}, // Fudan (static encrypted)
{{{0xa3, 0x16, 0x67, 0xa8, 0xce, 0xc1}}, MfClassicBackdoorAuth1}, // Fudan, Infineon, NXP
{{{0x51, 0x8b, 0x33, 0x54, 0xe7, 0x60}}, MfClassicBackdoorAuth2}, // Fudan
I am not calling it the "FM11RF08S" backdoor because it may affect more than the FM11RF08S
as we've found for the v1 and v2 keys etc
if anyone is curious about the naming. it made more sense to call it v1, v2, and v3 with respect to the point in time they were created
I mean they all work the same so doesn't really matter which one it is other than for fingerprinting
I dunno, if your cards are mostly from hotels likely to be using cheap knockoff cards seems legit
