This part turned out to be a bit messy. Many pm3-commands does not do much on the host-side, basically just create a data structure with instructions for the device and sends it off. The hf mf mifare
is a bit more complicated, since it involves some crapto1-state-calculation wizardry.
This is what it looks like on the C-side, cmdhfmf.c:
I decided to redo that in Lua, but without the goto-stuff.
While implementing this, I noticed that as of r786, the nonce2key utility validates key candidates using hf mf chk
, thus removing the necessity for the caller to do that (thus, currently done twice in hf mf mifare
).
Another thing worth mentioning here is the use of the bin
library. In Lua, you basically treat binary data as strings. Lua strings can contain binary data, so when reading and writing low-level data, some help is often needed.
For example, creating the binary string 0xDEADBEEF can be done in these two ways:
The latter is a bit more simple. The bin
-package comes from Luiz Henrique de Figueiredo, and documentationwise you can look at Nmap for the luadoc (the pm3-wiki is not yet updated with Luadoc).
In the example above, I use “LL” as format string, which means that I want to unpack two “unsigned long (8-byte unsigned integer)”:
The first return value, count
is the position at which unpacking stopped, whereas cmd,isOK
gets set by the two return values generated by the format string - two 8-byte unsigned integers.
This little thing is a closure, a function which ‘encloses’ the data
and is nice to have sometimes.
As I noted above, there were six functions from the pm3 c-code that were exposed to the Lua layer.
core.console('hf mf nested 1 0 a FFFFFFFFFFFF')
As you can see above, I call the function core.nonce2key(uid,nt, nr, pl,ks)
. So, naturally, I had to expose that aswell. Let’s see how that was done.
OBS: You don’t have to know this just in order to develop scripts, but it is good to be aware that you dont have to re-implement existing functionality all the time - it is not very difficult to just hook into an existing function already implemented in C.
So, first of all, I opened scripting.c
here and added an entry to the already existing api:
Then I defined the function itself:
This one is actually more complex than they usually are, but that’s just because of some data conversion and validation. The main things here are that you obtain the parameters from lua via luaL_checklstring
or similar methods, and push returnvalues onto the Lua stack using lua_pushinteger
, lua_pushlstring
and similar methods. And, last but not least, return the number of return values that you have (the number of pushes you’ve made to the stack).
Committed as r807.
Ok, that was a tangent. Continuing. Does it work?
proxmark3> script run mifare_autopwn
--- Executing: ./scripts/mifare_autopwn.lua, args''
Card found, commencing crack 92C0456B
uid(92c0456b) nt(73294ab7) par(a3fbfb537343eb7b) ks(070608090e060a02)
|diff|{nr} |ks3|ks3^5|parity |
+----+--------+---+-----+---------------+
| 00 |00000000| 7 | 2 |1,1,0,0,0,1,0,1|
| 20 |00000020| 6 | 3 |1,1,0,1,1,1,1,1|
| 40 |00000040| 8 | d |1,1,0,1,1,1,1,1|
| 60 |00000060| 9 | c |1,1,0,0,1,0,1,0|
| 80 |00000080| e | b |1,1,0,0,1,1,1,0|
| a0 |000000a0| 6 | 3 |1,1,0,0,0,0,1,0|
| c0 |000000c0| a | f |1,1,0,1,0,1,1,1|
| e0 |000000e0| 2 | 7 |1,1,0,1,1,1,1,0|
key_count:1
Key FFFFFFFFFFFF
-----Finished
Fine and dandy so far. The next part should be simpler.
So, at this point, we have one valid key (A) to block 0. Now we need to take that key and use it in the nested attack to obtain the rest. Now, we can use the console API thingy:
This will create the dumpfile dumpfile.bin
. Done.
The next stage is to dump the contents. To do that, all we have to do is call hf mf dump
:
In addition, let’s create the html-dump and a dump for the emulator while we’re at it:
And, in the end, here’s the (abbreviated) output when running the script:
proxmark3> script run mifare_autopwn
--- Executing: ./scripts/mifare_autopwn.lua, args''
Card found, commencing crack 92C0456B
uid(92c0456b) nt(21439479) par(7be3631bb33b9b23) ks(01050303070b0404) nr(00000000)
|diff|{nr} |ks3|ks3^5|parity |
+----+--------+---+-----+---------------+
| 00 |00000000| 1 | 4 |1,1,0,1,1,1,1,0|
| 20 |00000020| 5 | 0 |1,1,0,0,0,1,1,1|
| 40 |00000040| 3 | 6 |1,1,0,0,0,1,1,0|
| 60 |00000060| 3 | 6 |1,1,0,1,1,0,0,0|
| 80 |00000080| 7 | 2 |1,1,0,0,1,1,0,1|
| a0 |000000a0| b | e |1,1,0,1,1,1,0,0|
| c0 |000000c0| 4 | 1 |1,1,0,1,1,0,0,1|
| e0 |000000e0| 4 | 1 |1,1,0,0,0,1,0,0|
key_count:1
Key FFFFFFFFFFFF
--block no:00 key type:00 key:ff ff ff ff ff ff etrans:0
Block shift=0
Testing known keys. Sector count=16
nested...
Time in nested: 10.000 (inf sec per key)
-----------------------------------------------
Iterations count: 0
|---|----------------|---|----------------|---|
|sec|key A |res|key B |res|
|---|----------------|---|----------------|---|
|000| ffffffffffff | 1 | ffffffffffff | 1 |
|001| ffffffffffff | 1 | ffffffffffff | 1 |
|002| ffffffffffff | 1 | ffffffffffff | 1 |
|003| ffffffffffff | 1 | ffffffffffff | 1 |
|004| ffffffffffff | 1 | ffffffffffff | 1 |
|005| ffffffffffff | 1 | ffffffffffff | 1 |
|006| ffffffffffff | 1 | ffffffffffff | 1 |
|007| ffffffffffff | 1 | ffffffffffff | 1 |
|008| ffffffffffff | 1 | ffffffffffff | 1 |
|009| ffffffffffff | 1 | ffffffffffff | 1 |
|010| ffffffffffff | 1 | ffffffffffff | 1 |
|011| ffffffffffff | 1 | ffffffffffff | 1 |
|012| ffffffffffff | 1 | ffffffffffff | 1 |
|013| ffffffffffff | 1 | ffffffffffff | 1 |
|014| ffffffffffff | 1 | ffffffffffff | 1 |
|015| ffffffffffff | 1 | ffffffffffff | 1 |
|---|----------------|---|----------------|---|
Printing keys to bynary file dumpkeys.bin...
|-----------------------------------------|
|------ Reading sector access bits...-----|
|-----------------------------------------|
#db# READ BLOCK FINISHED
#db# READ BLOCK FINISHED
#db# READ BLOCK FINISHED
#db# READ BLOCK FINISHED
#db# READ BLOCK FINISHED
#db# READ BLOCK FINISHED
#db# READ BLOCK FINISHED
#db# READ BLOCK FINISHED
#db# READ BLOCK FINISHED
#db# READ BLOCK FINISHED
#db# READ BLOCK FINISHED
#db# READ BLOCK FINISHED
#db# READ BLOCK FINISHED
#db# READ BLOCK FINISHED
#db# READ BLOCK FINISHED
#db# READ BLOCK FINISHED
|-----------------------------------------|
|----- Dumping all blocks to file... -----|
|-----------------------------------------|
#db# READ BLOCK FINISHED
Dumped card data into 'dumpdata.bin'
#db# READ BLOCK FINISHED
[... removed for brevity ...]
#db# READ BLOCK FINISHED
Dumped card data into 'dumpdata.bin'
Wrote a HTML dump to the file 92C0456B.html
Wrote an emulator-dump to the file 92C0456B.eml
ERROR: Aborted by user
The script stops when a key is pressed, thus the “ERROR: Aborted by user” - message.
And with that, we’re pretty much finished, having automated the entire hack. A few improvements could be done, for example, instead of doing hf mf mifare
we could begin by checking default keys. And perhaps also modifying that functionality to stop after one successfull key/sector, since we probably want to do nested afterwards anyway, in order to be sure we get all keys.
Committed as r809
2013-10-08