Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect read of Mifare Ultralight tag with password locked pages #3945

Open
mishamyte opened this issue Oct 14, 2024 · 8 comments
Open

Incorrect read of Mifare Ultralight tag with password locked pages #3945

mishamyte opened this issue Oct 14, 2024 · 8 comments
Labels
NFC NFC-related Triage Issues under initial investigation

Comments

@mishamyte
Copy link

mishamyte commented Oct 14, 2024

Describe the bug.

I'm doing research with PWD locked MFUL tags (for devs: Vizit RF3.1).

Those tags have locked pages after 0x22:

[usb] pm3 --> hf mfu info -k ...
...
[=] --- Tag Configuration
[=]   cfg0 [37/0x25]: 00000022
[=]                     - strong modulation mode disabled
[=]                     - page 34 and above need authentication
...

From the datasheet:
cfg_pages

AUTH0 defines the page address from which the password verification
is required. Valid address range for byte AUTH0 is 00h to FFh.
If AUTH0 is set to a page address which is higher than the last user
configuration page, the password protection is effectively disabled.

For such kind of tags, if they are being read without pwd, FZ reads 36 pages instead of 34, but last two pages in that case are filled with the data of blocks 0 & 1 + sets like there are 36 pages unlocked (which is wrong):

...
Pages total: 41
Pages read: 36
Page 0: 04 C9 D0 95
Page 1: 42 7A 17 90
...
Page 34: 04 C9 D0 95
Page 35: 42 7A 17 90
...
Page 37: 00 00 00 24
...

Other devices like Proxmark3, TMD-5S, SMKey works correctly and read 34 pages, as it should be by AUTH0


Attached files:
Proxmark3.log (tag info + dumps with and without password)
Locked.nfc
Unlocked.nfc


Many thanks!

Reproduction

  1. Enter NFC app
  2. Read MFUL21 tag with password and locked pages, starting from 0x22
  3. Inspect the dump

Target

v.1.0.1

Logs

No response

Anything else?

No response

@doomwastaken doomwastaken added NFC NFC-related Triage Issues under initial investigation labels Oct 14, 2024
@mishamyte
Copy link
Author

mishamyte commented Oct 15, 2024

The reason for that issue is next.
When you read with READBLOCK(N) command, you get 16 bytes answer (4 block from 4 bytes):
N, N+1, N+2, N+3

In case if you read (for example) latest unlocked block and following will be blocked, you will get 1st available blocks.

So in our case: 33 0 1 2.

Because FZ iterates by 4 const uint8_t read_cnt = instance->data->type == MfUltralightTypeMfulC ? 1 : 4; actual NACK will be received when you will try to read next 4 blocks. But data from the previous (actually blocks 0, 1...) will be treated as valid and pages will be marked as read.

Personally, based on that, I would propose remove that optimization (potential) and read by one (also that's implementation approach in mentioned in 1st post devices).

@RebornedBrain
Copy link
Contributor

Hi, this behaviour is normal and happens because of the roll-over mechanism described in datasheet:
image
Despite the fact that this datasheet is about NTAGs, this feature is implemeted mostly in all mfu cards.

It works as follows, everytime tag gets READ command from reader it also gets block number which is the first one. But card always returns 4 blocks beginning from that block number and then it depends on reader how many blocks it will take from tag response. And here is the answer why Flipper reads more rather than other readers, because it consumes all 4 pages after one request, that is done in order to minimize the amount of requests.

In your case you locked page 0x22, which is 34 in decimal. Flipper starts reading from page 0 with step of 4. Then after 8 iterations it will be on page 32, (4 pages per request * 8 iterations = 32 page). Then Flipper sends request with block 32 to your card, which must return 4 blocks as a response (32, 33, 34 and 35). But because of your AUTH settings (page 34) card cannot give you pages 34 and 35, so it fills them with blocks 0 and 1 which are always openned. From Flipper's point of view it gets a valid result and stores those 34 and 35 as a valid pages. Then on the next iteration it will request page 36 which will result in a NACK from card, then Flipper stops.

For example try to send command hf mfu rdbl -b 32 on proxmark, you will get such result:
image
But if you then send command hf 14a list to see request trace, you will see that in fact proxmark also got 4 pages and last 2 pages are filled with data from page 0 and 1
image

Solution

Flipper supports unlock with pswd for such case. When you read card for the first time then press 'Unlock' button in menu, then choose 'Enter Password Manually'. It will lead you to the window where you need to paste your password:
image
When done, press 'Save', then confirm that you want to read your card using this password:
image

After that apply your tag to Flipper again, it will read your card correctly:
image
And data on those pages will be also correct.

@mishamyte
Copy link
Author

mishamyte commented Oct 16, 2024

Thank you @RebornedBrain,

I think we have the same vision on mechanisms (referring to my previous message).

The issue is the optimization for UL when FL reads by 4. And it doesn't know are the blocks actual or cycled from the beginning.

That's why false information appeared (see initial post's attachments).

I still think the solution would be to read block by block (from answer get first 4 bytes), until we will get NACK.

That mechanism is implemented in a bunch of professional tools (like PM3, TMD-5S, SMKey) and leads to correct data read.

So, unfortunately, I can't agree with you about the correctness of that behaviour (putting into read result data from the cycled blocks). But it's 💯 understandable that optimization was done to use the whole response of the READ BLOCK command.
Unfortunately, the final result, which will be flushed to the dump, is wrong

@mishamyte
Copy link
Author

So just to summarize, because I'm feeling like I confused you a bit with info:

  1. Work of rollover mechanism is understandable and why 16b is returned while executing READBLOCK(*) command.
  2. But because we work here with 16 bytes and fill buffer with value of 4 blocks every iteration, we are getting NACK later then it actually is
  3. Because of that data, which is returned from rollover mechanism is written into blocks, to which it doesn't belong
  4. Because of that, in case of working with locked tags, we are getting wrong dumps
  5. It will not be the point for unlocked tags (caz PWD AUTH will occur), but we can't forbid users to save intermediate result (partial dump)
  6. For that case dump should be correct

Thanks for understanding and sorry if my formulations are chaotic

@RebornedBrain
Copy link
Contributor

Hi, I agree that we can fix this. And your solution is right. Actually this solution was already been tested by me few months ago, when Ultralight C auth was implemented, but I decided not to do that. Well now seems that it's time to fix that, but we need to test it on our side. I saw you've already done such PR, so could you please open it here also. Then qa will test it and once they confirm everything is ok, we can merge.
Best regards!

P.s. Actually there is an idea to keep both read features, so users can choose how they want to read 4 pages at once or one by one, but this requires a little bit more tweaks on the app side, therefore it can be posponded for now.

@mishamyte
Copy link
Author

Hi, I agree that we can fix this. And your solution is right. Actually this solution was already been tested by me few months ago, when Ultralight C auth was implemented, but I decided not to do that. Well now seems that it's time to fix that, but we need to test it on our side. I saw you've already done such PR, so could you please open it here also. Then qa will test it and once they confirm everything is ok, we can merge. Best regards!

P.s. Actually there is an idea to keep both read features, so users can choose how they want to read 4 pages at once or one by one, but this requires a little bit more tweaks on the app side, therefore it can be posponded for now.

Yeah, that makes sense. Actually it could be done in read by 4 feature, when you get a first NACK, you just rewind to check if actual NACK was from the previous quartet. But so far as it's now needed, I would just create a PR there for a validation too.

Thanks for the answer!

@RebornedBrain
Copy link
Contributor

RebornedBrain commented Oct 17, 2024

Yeah, that makes sense. Actually it could be done in read by 4 feature, when you get a first NACK, you just rewind to check if actual NACK was from the previous quartet. But so far as it's now needed, I would just create a PR there for a validation too.

We thought about that also and came to the conclusion that such approach increases complexity and we discarded that also, so nevermind on that 😄

@mishamyte
Copy link
Author

We thought about that also and came to the conclusion that such approach increases complexity and we discarded that also, so nevermind on that 😄

Yeah, agree about complexity, also don't like that idea. So good you discarded it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NFC NFC-related Triage Issues under initial investigation
Projects
None yet
Development

No branches or pull requests

3 participants