2 This is an example of Lua-scripting within proxmark3. This is a lua-side
3 implementation of hf mf chk
5 This code is licensed to you under the terms of the GNU GPL, version 2 or,
6 at your option, any later version. See the LICENSE.txt file for the text of
9 Copyright (C) 2013 m h swende <martin at swende.se>
11 -- Loads the commands-library
12 local cmds
= require('commands')
13 -- Load the default keys
14 local keys
= require('mf_default_keys')
15 -- Ability to read what card is there
16 local reader
= require('read14a')
17 -- Asks the user for input
18 local utils
= require('utils')
21 local desc
= ("This script implements check keys. \
22 It utilises a large list of default keys (currently %d keys).\
23 If you want to add more, just put them inside mf_default_keys.lua. "):format(#keys
)
25 local TIMEOUT
= 10000 -- 10 seconds
28 local function checkCommand(command
)
30 --print("Sending this command : " .. tostring(command))
31 local usbcommand
= command
:getBytes()
32 core
.SendCommand(usbcommand
)
33 local result
= core
.WaitForResponseTimeout(cmds
.CMD_ACK
,TIMEOUT
)
35 local count
,cmd
,arg0
= bin
.unpack('LL',result
)
37 local count
,arg1
,arg2
,data
= bin
.unpack('LLH511',result
,count
)
41 --print("Key not found...")
45 print("Timeout while waiting for response. Increase TIMEOUT in keycheck.lua to wait longer")
46 return nil, "Timeout while waiting for device to respond"
51 function checkBlock(blockNo
, keys
, keyType
)
52 -- The command data is only 512 bytes, each key is 6 bytes, meaning that we can send max 85 keys in one go.
53 -- If there's more, we need to split it up
54 local start
, remaining
= 1, #keys
55 local arg1
= bit32
.bor(bit32
.lshift(keyType
, 8), blockNo
)
57 while remaining
> 0 do
58 local n
,data
= remaining
, nil
59 if remaining
> 85 then n
= 85 end
60 local data
= table.concat(keys
, "", start
, start
+ n
- 1)
62 --print("data len", #data)
63 print(("Testing block %d, keytype %d, with %d keys"):format(blockNo
, keyType
, n
))
64 local command
= Command
:new
{cmd
= cmds
.CMD_MIFARE_CHKKEYS
,
69 local status
= checkCommand(command
)
70 if status
then return status
, blockNo
end
72 remaining
= remaining
- n
77 -- A function to display the results
78 local function displayresults(results
)
79 local sector
, blockNo
, keyA
, keyB
,_
81 print("________________________________________")
82 print("|Sector|Block| A | B |")
83 print("|--------------------------------------|")
85 for sector
,_
in pairs(results
) do
86 blockNo
, keyA
, keyB
= unpack(_
)
88 print(("| %3d | %3d |%12s|%12s|"):format(sector
, blockNo
, keyA
, keyB
))
90 print("|--------------------------------------|")
94 -- A little helper to place an item first in the list
95 local function placeFirst(akey
, list
)
97 if list
[1] == akey
then
98 -- Already at pole position
101 local result
= {akey
}
102 --print(("Putting '%s' first"):format(akey))
103 for i
,v
in ipairs(list
) do
105 result
[#result
+1] = v
111 local function dumptofile(results
)
112 local sector
, blockNo
, keyA
, keyB
,_
114 if utils
.confirm("Do you wish to save the keys to dumpfile?") then
115 local destination
= utils
.input("Select a filename to store to", "dumpkeys.bin")
116 local file
= io
.open(destination
, "w")
118 print("Could not write to file ", destination
)
125 for sector
,_
in pairs(results
) do
126 blockNo
, keyA
, keyB
= unpack(_
)
127 key_a
= key_a
.. bin
.pack("H",keyA
);
128 key_b
= key_b
.. bin
.pack("H",keyB
);
137 local function main(args
)
141 result
, err
= reader
.read14443a(false, true)
146 print(("Found a %s tag"):format(result
.name
))
149 core
.clearCommandBuffer()
151 local keyType
= 0 -- A=0, B=1
152 local numSectors
= 16
154 if 0x18 == result
.sak
then -- NXP MIFARE Classic 4k | Plus 4k
155 -- IFARE Classic 4K offers 4096 bytes split into forty sectors,
156 -- of which 32 are same size as in the 1K with eight more that are quadruple size sectors.
158 elseif 0x08 == result
.sak
then -- NXP MIFARE CLASSIC 1k | Plus 2k
159 -- 1K offers 1024 bytes of data storage, split into 16 sector
161 elseif 0x09 == result
.sak
then -- NXP MIFARE Mini 0.3k
162 -- MIFARE Classic mini offers 320 bytes split into five sectors.
164 elseif 0x10 == result
.sak
then -- NXP MIFARE Plus 2k
167 print("I don't know how many sectors there are on this type of card, defaulting to 16")
171 for sector
=1,numSectors
,1 do
174 The mifare Classic 1k card has 16 sectors of 4 data blocks each.
175 The first 32 sectors of a mifare Classic 4k card consists of 4 data blocks and the remaining
176 8 sectors consist of 16 data blocks.
178 local blockNo
= sector
* 4 - 1
181 blockNo
= 32*4 + (sector
-32)*16 - 1
184 local keyA
= checkBlock(blockNo
, keys
, 0)
185 if keyA
then keys
= placeFirst(keyA
, keys
) end
188 local keyB
= checkBlock(blockNo
, keys
, 1)
189 if keyB
then keys
= placeFirst(keyB
, keys
) end
192 result
[sector
] = {blockNo
, keyA
, keyB
}
194 -- Check if user aborted
195 if core
.ukbhit() then
196 print("Aborted by user")
200 displayresults(result
)