]> git.zerfleddert.de Git - proxmark3-svn/blame - client/scripts/mfkeys.lua
CHG: renamed struct sector -> sector_t
[proxmark3-svn] / client / scripts / mfkeys.lua
CommitLineData
16b04cb2 1--[[
2 This is an example of Lua-scripting within proxmark3. This is a lua-side
3 implementation of hf mf chk
4
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
7 the license.
8
9 Copyright (C) 2013 m h swende <martin at swende.se>
05ed5c49 10--]]
16b04cb2 11-- Loads the commands-library
12local cmds = require('commands')
13-- Load the default keys
14local keys = require('mf_default_keys')
a2d82b46 15-- Ability to read what card is there
16local reader = require('read14a')
62254ea5 17local getopt = require('getopt')
a2d82b46 18
62254ea5 19local OR = bit32.bor
20local LSHIFT = bit32.lshift
05ed5c49 21
62254ea5 22example =[[
23 script run mfkeys
24]]
25author = "Iceman"
26usage = "script run mfkeys"
27desc = ("This script implements Mifare check keys. It utilises a large list of default keys (currently %d keys).\
28If you want to add more, just put them inside /lualibs/mf_default_keys.lua\n"):format(#keys) ..
29[[
30
31Arguments:
32 -h : this help
57778a46 33 -p : print keys
62254ea5 34]]
16b04cb2 35
36local TIMEOUT = 10000 -- 10 seconds
62254ea5 37---
38-- Usage help
39function help()
40 print(desc)
41 print("Example usage")
42 print(example)
43end
05ed5c49 44
45--[[This may be moved to a separate library at some point]]
46local utils =
47{
48 ---
49 -- Asks the user for Yes or No
50 confirm = function(message, ...)
51 local answer
52 message = message .. " [y]/[n] ?"
53 repeat
54 io.write(message)
55 io.flush()
56 answer=io.read()
57 if answer == 'Y' or answer == "y" then
58 return true
59 elseif answer == 'N' or answer == 'n' then
60 return false
61 end
62 until false
63 end,
64 ---
65 -- Asks the user for input
66 input = function (message , default)
67 local answer
68 if default ~= nil then
69 message = message .. " (default: ".. default.. " )"
70 end
71 message = message .." \n > "
72 io.write(message)
73 io.flush()
74 answer=io.read()
75 if answer == '' then answer = default end
76
77 return answer
78 end,
79}
80
16b04cb2 81
82local function checkCommand(command)
83
84 --print("Sending this command : " .. tostring(command))
85 local usbcommand = command:getBytes()
86 core.SendCommand(usbcommand)
87 local result = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT)
88 if result then
89 local count,cmd,arg0 = bin.unpack('LL',result)
90 if(arg0==1) then
91 local count,arg1,arg2,data = bin.unpack('LLH511',result,count)
92 key = data:sub(1,12)
93 return key
94 else
95 --print("Key not found...")
96 return nil
97 end
98 else
99 print("Timeout while waiting for response. Increase TIMEOUT in keycheck.lua to wait longer")
100 return nil, "Timeout while waiting for device to respond"
101 end
102end
103
16b04cb2 104function checkBlock(blockNo, keys, keyType)
105 -- The command data is only 512 bytes, each key is 6 bytes, meaning that we can send max 85 keys in one go.
106 -- If there's more, we need to split it up
107 local start, remaining= 1, #keys
108 local packets = {}
109 while remaining > 0 do
110 local n,data = remaining, nil
111 if remaining > 85 then n = 85 end
112 local data = table.concat(keys,"",start,n)
16b04cb2 113 print(("Testing block %d, keytype %d, with %d keys"):format(blockNo, keyType, n))
114 local command = Command:new{cmd = cmds.CMD_MIFARE_CHKKEYS,
62254ea5 115 arg1 = OR(blockNo, LSHIFT(keyType,8) ),
116 arg2 = 0,
16b04cb2 117 arg3 = n,
118 data = data}
119 local status = checkCommand(command)
120 if status then return status, blockNo end
121 start = start+n+1
122 remaining = remaining - n
123 end
124 return nil
125end
126
127-- A function to display the results
62254ea5 128-- TODO: iceman 2016, still screws up output when a key is not found.
16b04cb2 129local function displayresults(results)
130 local sector, blockNo, keyA, keyB,_
131
62254ea5 132 print("|---|----------------|---|----------------|---|")
133 print("|sec|key A |res|key B |res|")
134 print("|---|----------------|---|----------------|---|")
16b04cb2 135
136 for sector,_ in pairs(results) do
137 blockNo, keyA, keyB = unpack(_)
62254ea5 138 print(("|%03d| %s | 1 | %s | 1 |"):format(sector, keyA, keyB ))
16b04cb2 139 end
62254ea5 140 print("|---|----------------|---|----------------|---|")
16b04cb2 141
142end
143-- A little helper to place an item first in the list
144local function placeFirst(akey, list)
145 akey = akey:lower()
146 if list[1] == akey then
147 -- Already at pole position
148 return list
149 end
150 local result = {akey}
151 --print(("Putting '%s' first"):format(akey))
152 for i,v in ipairs(list) do
153 if v ~= akey then
154 result[#result+1] = v
155 end
156 end
157 return result
158end
05ed5c49 159local function dumptofile(results)
160 local sector, blockNo, keyA, keyB,_
16b04cb2 161
05ed5c49 162 if utils.confirm("Do you wish to save the keys to dumpfile?") then
163 local destination = utils.input("Select a filename to store to", "dumpkeys.bin")
164 local file = io.open(destination, "w")
165 if file == nil then
166 print("Could not write to file ", destination)
167 return
168 end
169
170 local key_a = ""
171 local key_b = ""
172
173 for sector,_ in pairs(results) do
174 blockNo, keyA, keyB = unpack(_)
175 key_a = key_a .. bin.pack("H",keyA);
176 key_b = key_b .. bin.pack("H",keyB);
177 end
178 file:write(key_a)
179 file:write(key_b)
180 file:close()
181 end
182end
57778a46 183local function printkeys()
184 for i=0,#keys do
185 print(i,keys[i])
186
187 end
188 print ('Number of keys: '..#keys)
189end
05ed5c49 190
05ed5c49 191local function main( args)
16b04cb2 192
62254ea5 193 -- Arguments for the script
57778a46 194 for o, a in getopt.getopt(args, 'hp') do
62254ea5 195 if o == "h" then return help() end
57778a46 196 if o == "p" then return printkeys() end
62254ea5 197 end
198
a2d82b46 199 result, err = reader.read1443a()
200 if not result then
201 print(err)
202 return
203 end
a2d82b46 204
62254ea5 205 print(("Found a %s tag"):format(result.name))
a2d82b46 206
16b04cb2 207 core.clearCommandBuffer()
208 local blockNo
209 local keyType = 0 -- A=0, B=1
05ed5c49 210 local numSectors = 16
211
212 if 0x18 == result.sak then --NXP MIFARE Classic 4k | Plus 4k
213 -- IFARE Classic 4K offers 4096 bytes split into forty sectors,
214 -- of which 32 are same size as in the 1K with eight more that are quadruple size sectors.
215 numSectors = 40
216 elseif 0x08 == result.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k
217 -- 1K offers 1024 bytes of data storage, split into 16 sector
218 numSectors = 16
219 elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k
220 -- MIFARE Classic mini offers 320 bytes split into five sectors.
221 numSectors = 5
222 elseif 0x10 == result.sak then-- "NXP MIFARE Plus 2k"
223 numSectors = 32
224 else
225 print("I don't know how many sectors there are on this type of card, defaulting to 16")
226 end
227
228 result = {}
229 for sector=1,numSectors,1 do
16b04cb2 230
231 --[[
05ed5c49 232 The mifare Classic 1k card has 16 sectors of 4 data blocks each.
233 The first 32 sectors of a mifare Classic 4k card consists of 4 data blocks and the remaining
16b04cb2 234 8 sectors consist of 16 data blocks.
235 --]]
236 local blockNo = sector * 4 -1
237
238 if sector > 32 then
239 blockNo = 32*4+ (sector-32)*16 -1
240 end
241
242 local keyA = checkBlock(blockNo, keys, 0)
243 if keyA then keys = placeFirst(keyA, keys) end
244 keyA = keyA or ""
245
246 local keyB = checkBlock(blockNo, keys, 1)
247 if keyB then keys = placeFirst(keyB, keys) end
248 keyB = keyB or ""
249
250 result[sector] = {blockNo, keyA, keyB }
251
252 -- Check if user aborted
253 if core.ukbhit() then
254 print("Aborted by user")
255 break
256 end
257 end
258 displayresults(result)
05ed5c49 259 dumptofile(result)
16b04cb2 260end
261
05ed5c49 262main( args)
16b04cb2 263
Impressum, Datenschutz