Research, development and trades concerning the powerful Proxmark3 device.
Remember; sharing is caring. Bring something back to the community.
"Learn the tools of the trade the hard way." +Fravia
You are not logged in.
Time changes and with it the technology
Proxmark3 @ discord
Users of this forum, please be aware that information stored on this site is not private.
Pages: 1
Hi to all you pm3 devs out there,
Just got my pm3 recently, so I'm still figuring things out a bit. This post is actually about mifare classic client code (cmdhfmf.c in particular). However, it concerns both posix and win versions, so I could not choose either one in the software development department of these forums. It is however specific to mifare classic, so I thought I'd post it here. Moderators relocate as you see fit, I don't really know what I'm doing.
I was trying to clone a mifare classic card and restore its contents to a blank tag. The blank tag is a normal one (not a chinese magic card), so block 0 / UID would not be cloned (the system I'm pen-testing does not seem to require it, so I'm OK with that for now). Dumping the source tag was successful. Next thing I tried was to restore dumpdata.bin to a blank tag, like so:
proxmark3> hf mf restore
This did not work as expected, I only got AUTH ERRORs on all blocks (not just on block 0, as would be expected). And yes, I updated bootrom, fpga ('fullimage') and osimage to the latest versions successfully before trying this. When digging into this restore command, I noticed it should only work with blank tags because it *should* use 'ffffffffffff' for key A. My target tag satisfied this requirement, so it should have worked.
Dug into the code of the latest revision from github, and noticed the following in cmdhfmf.c, in function CmdHF14AMfRestore(), on line 437:
uint8_t key[6] = {0xFF};
According to my understanding, most compilers would fill out this array like so:
uint8_t key[6] = {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00};
I don't think this is what we need here. So I explicitly changed it to:
uint8_t key[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
When I recompiled and tried to restore, it all worked out as expected.
As far as I can tell from Makefile.common:
CROSS ?= arm-none-eabi-
CC = $(CROSS)gcc
the compiler(-driver) used is the bare-metal 'arm-none-eabi-gcc'. I don't know if there are any differences between a packaged version (I used the pre-packaged compiler on my ARM lubuntu Odroid XU3 Lite) and the devKitARM compiler (also tried that one on Windows), but in both cases I had errors before the proposed changes, and the restore command worked as expected after the changes.
I did not want to make changes immediately and commit them haphazardly (I also don't have a github account), so I'd like your thoughts on this, maybe a more seasoned pm3 dev could include it during an upcoming commit if they think I'm not actually misunderstandig the way the commands should work (I'm new to pm3!).
Also, for my own pleasure, I worked out a function with this signature: int CmdHF14AMfRewrite(const char *Cmd) and bound it to a command called 'rewrite' in the command table. With it, I was able to successfully restore a dumpfile to an already used card (or at least, to those sectors that have their access bits still unfused). Suggested usage:
"hf mf rewrite <access keys file> [card memory]"
This function opens a user specified binary access key file (same format as dumpkeys.bin) and uses those keys to access all sectors for rewriting to their respective blocks. It then writes new keys to them from dumpkeys.bin and data from dumpdata.bin (behavior similar to the restore command).
My approach to this: for every sector, I determine the sector access rights of the card-to-be-rewritten by sending a CMD_MIFARE_READBL using key A for that sector (according to the MF1S503x datasheet par. 8.7.2, table 6, access bits can always be read using key A, right?). From the datasheet I figured out that for data blocks you can write using Key A when C1C2C3 = 0x00 and using key B when bits are 0x03, 0x04 or 0x06. For sector trailers using Key A the bits could be 0x00 or 0x01 and using key B they could be 0x03, 0x04 or 0x05. Because the sets don't overlap, I figured I'd take the union of the sets for each key. So if access rights are 0x00 or 0x01, I use Key A. When they are 0x03, 0x04, 0x05 or 0x06 I use key B. Now it doesn't matter whether it is a data block or a sector trailer. At this point I have a key that I can potentially write with (safe for fused access bit combinations), so I can proceed the same way as in the restore function.
I used this function successfully for the following workflow discipline:
- dump EMPTY target tag to dumpkeys.bin and dumpdata.bin
- archive these two files for later use
- dump source tag to new dumpkeys.bin and dumpdata.bin
- open dumpdata.bin of source tag with hex editor and change access bits of all sectors to default (FF 07 80 69). Or at least check if access bits of all sectors are r/w. This will ensure that the cloned tag can be fully rewritten later on.
- archive the two source tag dump files for later use
- restore slightly altered source tag dump to empty target tag and use tag for pen test (the system I tested this with had no problems with a different UID and with me changing the access bits, YMMV)
- when pen test phase is over and point is made, copy dumpkeys.bin *of the source tag* to the client folder and rename it to accesskeys.bin. Then proceed to copy dumpkeys.bin / dumpdata.bin *of the empty target tag* to the client folder
- execute a rewrite: proxmark3> hf mf rewrite accesskeys.bin
- the cloned tag's sectors will now be accessed using the keys in accesskeys.bin and will be overwritten by the keys and data from dumpkeys.bin / dumpdata.bin, effectively restoring the card to its original state
This way, the card can be re-used for other projects.
I kinda got lost in the documentation, so there is a chance this workflow could be done far easier and faster. If so, break it to me gently please, I am here to learn. If not, a function like this might be worth adding to the code base. I am not an expert programmer, so although I will obviously share my code, I will not commit it myself without it being reviewed and mended for robustness by a more seasoned / expert pm3 developer.
Hope to hear from you guys!
Offline
The change { 0xFF } is most likely mine. Holiman told me that you can get an array to initalise with the same value when I asked him about his notation {0x00} however, I'm afraid it is like you figured out that you need explict write all bytes when initialising the array. Sad because its a nice way of doing it if it had worked. So still, my bad. Sorry.
Offline
My mistake, maybe I have done it somewhere also... I'll grep it later...
Offline
Thanks for responding guys, and no worries of course, glad I could spot one for ya. Really lovely to see some active development here.
Offline
when it comes to your process with backing up tags and ensure the accessbits are correct, I usually use a magic tag when it comes to Mifare classic stuff. Just "w" wipe it, and start over.
Offline
Fix comitted: https://github.com/Proxmark/proxmark3/c … 2450285929
Offline
@holiman nice work fixing this, thank you.
@iceman although I was aware of the existence of these magic cards, I did not know that you could rewrite all sectors even when their access bits are fused shut. Am I right to infer this from your post? It truly would make them 'magic' cards and would indeed make that option a lot faster and easier. Which is another way of saying that I need a couple of these bad boys to experiment with . Thanks for sharing...
Offline
My experience is that with Generation1 magic tags, is that you can wipe it and reset a tag quit easily, even sector trailers. Very hand tags I must say. When you use the "wipe" option, it fills the whole tag (every block) with zeros. Even the Block0.. that got me confused in the beginning. Always remember to use the "wipe" option with "hf mf csetuid"... or the tag becomes "dead" but you can just write a new block0 if you have done this.
But be careful with the Generation2 magic tags, they allow you to write to Block 0, but I'm not sure if you can easily wipe or if you can "save" the tag if you wrote a faulty sector trailer.
Offline
Pages: 1