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

Fudan FM11R08* full-card recovery script; with Bambu tag support #2613

Merged
merged 3 commits into from
Nov 7, 2024

Conversation

csBlueChip
Copy link
Contributor

Beyond the original recovery script (used by this script) this script performs a number of tasks to aid us teaching NFC at our local defcon meet.
qv. https://eprint.iacr.org/2024/1275.pdf [Philippe Teuwen]

  • Full breakdown of Block 0 (esp. Fudan specific details)
  • Verify UID/BCC
  • SAK decode
  • Optionally perform online Fudan validation check
  • [[key recovery]]
  • Dump all 64+8 blocks
  • ...with all 32+2 keys
  • Decode ACL [clearer output]
  • [[MAD decode]]
  • Bambu tag decode
  • Create full 64+8 block dump (incl keys) ...for the CTF flag

Copy link

github-actions bot commented Nov 4, 2024

You are welcome to add an entry to the CHANGELOG.md as well

@iceman1001
Copy link
Collaborator

Nice one,
We prefer to use GPL3.0 or later as a license in this project, so if you wouldn't mind?

@csBlueChip
Copy link
Contributor Author

csBlueChip commented Nov 5, 2024 via email

@iceman1001
Copy link
Collaborator

it will make our lives much easier if its a "GPL3 or later" license. If you wanna make a "free license" its also ok, but when we start mixing its just harder. When we use third party libs, we try finding GPL3 versions, MIT or free. but of code that is all in here its GPL3 or later.

Your script can have your copyright with the license GPL3 or later. If you post your script somewhere else, it can be any license you like. However in here its locked down to GPL3.

If this all made sense, please have understanding that trying to uphold open source licenses is a nightmare if mixed.

Copy link
Contributor

@doegox doegox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see inline comments

else:
lprint("")

# We need to flush all the output we just collected <shrug>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use p.console(...., capture=False) and you don't have to flush grabbed_output

We decided the flag would be: The MD5 of the card data,
but this had to include all 8 documented Dark blocks AND all 32+2=34 Keys.
Not rocket surgery if you know what you're doing, but non-trivial for someone
who is still struggling to spell `autoporn` <-- yes, this happened!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

funny but keep your comments formal and short. thanks

@@ -0,0 +1,942 @@
#!/usr/bin/env python3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find the script name confusing.
fm11rf08s_recovery provides also a full dump and a key dump, like autopwn
so call this one "demo" or "verbose" but not "full"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you dump the card using recovery and then dump the card using full and then do an ls you will see that the (so called) "full" file is 128 bytes longer because (as discussed in the verbose intro) it includes "all 8 documented Dark blocks"

proxmark@linux:~$ ls hf-mf-5CB49CA6-dump*.bin -l
-rw-r--r-- 1 prox prox    1152    Nov  4 00:26 hf-mf-5CB49CA6-dump18.bin
-rw-r--r-- 1 prox prox    1024    Oct 30 18:59 hf-mf-5CB49CA6-dump.bin

As for the name ...It was called bc.py until the last minute, and I just thought "the full 18 blocks" is what I was going after, and grabbed the word "full" ...If you think that name is misleading, then yes, let's pick something better.

Copy link
Contributor

@doegox doegox Nov 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ha! Initially I didn't make the link when you say "dark".
You use the term "dark" both for the backdoor key (see getDarkKey) and for the advanced verification method blocks.
In MFC, dark refers to darkside (and now the variant darknested which replaces darkside+nested)
and personally I would avoid reusing the same term in other contexts.

  • dark key => backdoor key
  • dark blocks => advanced verification method blocks (or some shorter avblocks for example)

If the extra blocks are useful to get, better to change the existing commands than adding an entire new script.
Right now I refrained to do so because the existing commands cannot handle dumps of unexpected sizes, so your dump cannot be used by e.g. hf mf restore. We already have the problem with the keys file at the moment.
This is planned to handle properly these oversized dumps and keyfiles, but it takes time.
So we can merge your code but don't be surprised if tomorrow it becomes redundant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I say, the script as it stands solved a very specific problem. And, as with the "library functions" comments, if this script become a part of the (metaphoric) Borg Collective, that's no bad thing.

Re. the word "dark": We needed a word so we could discuss it. Your paper used the phrase "dark keys" and extended nested to "dark nested" ...So we took inspiration, and called the additional blocks (which we discovered from the same paper) "dark blocks" ...Again, if it's confusing - this is exactly the right moment to change it :)

checkVer()
parseCli()

print(f"{prompt} Fudan FM11RF08[S] full card recovery")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same remark as for the script name

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again I just wanted a way to highlight that this script retrieves the 8 Dark blocks, I am happy to accept a better/clearer message that conveys that.

# >> "uid"
# >> "uids"
#==============================================================================
def decodeBlock0():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be interesting to isolate this function in a separate file to be imported, so other ppl can use it in their scripts s well, or call the script with a provided block0

Copy link
Contributor Author

@csBlueChip csBlueChip Nov 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If/when this script gets pulled, I would be flattered if functions were yanked to a library. If/when that happens it would probably be wise to pick a more "API" style name for the function. I dunno, maybe hf_mf_block0_decode(binaryData[16]) ...but I'm sure you guys probably have a naming convention - so "whatever fits" is good by me

Same goes for the following 4 similar comments :)

[=] 0 | 5C B4 9C A6 D2 08 04 00 04 59 92 25 BF 5F 70 90 | \........Y.%._p.
'''
#==============================================================================
def readBlocks():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redundant with the dump file already provided by recovery()
or call it verifyDump as you have the verifyKeys...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considerations:
~ This function reads the 8 Dark blocks in addition to the 64 "normal" blocks (which were read by recovery())
~ verifyKeys takes the known keys and verifies that they are still valid. ...because we would like to avoid waiting "<30mins" if possible
~ readBlocks deliberately re-reads the card each time it is run, so as to detect edits to the card ...it only takes a few seconds ...I have to read it all to verify nothing has changed, at which point, well, I've just read it all ...There may well be credit to writing a verifyBlocks() function to detect changes - but that would need to call readblock() and loadOldFile()
~ The feature bloat had already crept in when I started detecting and decoding various tags - I just had to draw the line somewhere (for now)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you need to read the card, using "hf mf ecfill -c 4 -k ..." is wayyy faster.
Then, yes, for now, you've to dump manually the 8 avblocks because as said above, it is not yet supported in ecfill or any other mfc emulation command. (I think even letting a "hf mf ecfill --4k -c 4 -k..." dumping and failing over unexisting sectors is still faster)

3 | 00 00 00 00 00 00 87 87 87 69 00 00 00 00 00 00 | .........i......
'''
#==============================================================================
def patchKeys(keyok):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note that dump from recovery is already patched

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reasons discussed above, I do not load the existing dump.bin so this action is 'required'

#+=============================================================================
# Let's try to detect a Bambu card by the date strings...
#==============================================================================
def detectBambu():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be interesting to isolate this function in a separate file to be imported, so other ppl can use it in their scripts s well, or call the script with a provided block0

Copy link
Contributor Author

@csBlueChip csBlueChip Nov 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

qv. #2613 (comment)

this needs data other than block 0

3 | 00 00 00 00 00 00 87 87 87 69 00 00 00 00 00 00 | .........i......
'''
#+=============================================================================
def dumpBambu():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be interesting to isolate this function in a separate file to be imported, so other ppl can use it in their scripts s well, or call the script with a provided block0

Copy link
Contributor Author

@csBlueChip csBlueChip Nov 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

qv. #2613 (comment)

This needs data other than block0

IF YOU PLAN TO CHANGE ACCESS BITS, RTFM, THERE IS MUCH TO CONSIDER !
'''
#==============================================================================
def dumpAcl():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be interesting to isolate this function in a separate file to be imported, so other ppl can use it in their scripts s well, or call the script with a provided block0.
Note that we already have hf mf acl

Copy link
Contributor Author

@csBlueChip csBlueChip Nov 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

qv. #2613 (comment)

this function requires data other than block 0

I was originally going to call hf mf acl (as I say, this script is initially to support a defcon workshop) and parse the output (if I had to), but in the end I found the output difficult to decipher, and tricky to parse - ultimately, some bit twiddling just seemed easier.

@csBlueChip
Copy link
Contributor Author

it will make our lives much easier if its a "GPL3 or later" license. If you wanna make a "free license" its also ok, but when we start mixing its just harder. When we use third party libs, we try finding GPL3 versions, MIT or free. but of code that is all in here its GPL3 or later.

Your script can have your copyright with the license GPL3 or later. If you post your script somewhere else, it can be any license you like. However in here its locked down to GPL3.

If this all made sense, please have understanding that trying to uphold open source licenses is a nightmare if mixed.

Thank you for taking time to explain your position. I really hadn't considered the potential nightmare of maintaining multiple licences in one repository. I totally understand.

In case you're wondering: I have both personal and professional reasons to dislike what GPL3 has done to hinder development of/with cross-platform support, and the damage it has done to the security landscape; and I just want to make sure anything I personally release can be used by anybody for any reason and in any way they so desire ...yourself (and this fantastic project) included :)

How about this?:
~ remove the print("Licence....") line from the code
~ add this comment to the top of the script
"To minimise administrative overheads on the Proxmark code, this copy of the script is released under the GPLv3 licence. If you require/desire a less restrictive licence, this script may instead be obtained from [a link on my github page] under the MIT licence"
...Does that work for you? :)

@doegox
Copy link
Contributor

doegox commented Nov 6, 2024

Thank you for taking time to explain your position. I really hadn't considered the potential nightmare of maintaining multiple licences in one repository. I totally understand.

Just to say, I second Iceman comment on the license with this example: I discussed many parts of this script as better being moved into some common MFC helper functions Python module. Now if each helper function had to retain its original license, it becomes a nightmare to constitute such module mixing licenses.

In case you're wondering: I have both personal and professional reasons to dislike what GPL3 has done to hinder development of/with cross-platform support, and the damage it has done to the security landscape; and I just want to make sure anything I personally release can be used by anybody for any reason and in any way they so desire ...yourself (and this fantastic project) included :)

Fair enough. On our side, we tend to dislike the several manufacturers who stole the proxmark3 code to make their closed-source variants...

How about this?: ~ remove the print("Licence....") line from the code ~ add this comment to the top of the script "To minimise administrative overheads on the Proxmark code, this copy of the script is released under the GPLv3 licence. If you require/desire a less restrictive licence, this script may instead be obtained from [a link on my github page] under the MIT licence" ...Does that work for you? :)

IMHO the first sentence is useless.
"The original version of this script is also kept at your disposal under the MIT license at the following link..."

"Original version" is important because once merged, over time, this code will evolve in the repo.
E.g. we can merge it now and tomorrow I'll do the code refactoring into Python module(s).

@iceman1001
Copy link
Collaborator

iceman1001 commented Nov 6, 2024

Here is what I suggest you put on top of your script file.
And remove the line in Main().

#
# Copyright @csBlueChip
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   See LICENSE.txt for the text of the license.
#
#  The original version of this script is also kept at your disposal under the MIT license at the following link   <enter link>
#   or reach out to author for alternative licenses. 

and since we use git, we don't need a "internal" change log.

When @doegox is happy, we merge

@doegox
Copy link
Contributor

doegox commented Nov 6, 2024

We can merge, then I'll make the discussed changes (module etc)

@doegox
Copy link
Contributor

doegox commented Nov 6, 2024

but yeah change the licensing terms before merge, else it looks like maintainers are rewriting your terms...

@csBlueChip
Copy link
Contributor Author

but yeah change the licensing terms before merge, else it looks like maintainers are rewriting your terms...

it is done

@iceman1001 iceman1001 merged commit cf7431c into RfidResearchGroup:master Nov 7, 2024
1 check passed
@iceman1001
Copy link
Collaborator

Excellent!
I like the idea for your ctf challenge

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants