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