X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/a2d82b467aa9c512fd7b3992662666bf42e87518..905c55de2bbe642412b47ed4e92344096c817fac:/client/scripts/mfkeys.lua diff --git a/client/scripts/mfkeys.lua b/client/scripts/mfkeys.lua index f40b2be2..937c9172 100644 --- a/client/scripts/mfkeys.lua +++ b/client/scripts/mfkeys.lua @@ -7,19 +7,77 @@ the license. Copyright (C) 2013 m h swende -]] +--]] -- Loads the commands-library local cmds = require('commands') -- Load the default keys local keys = require('mf_default_keys') -- Ability to read what card is there local reader = require('read14a') +local getopt = require('getopt') + +local OR = bit32.bor +local LSHIFT = bit32.lshift + +example =[[ + script run mfkeys +]] +author = "Iceman" +usage = "script run mfkeys" +desc = ("This script implements Mifare check keys. It utilises a large list of default keys (currently %d keys).\ +If you want to add more, just put them inside /lualibs/mf_default_keys.lua\n"):format(#keys) .. +[[ -local desc = -("This script implements check keys. It utilises a large list of default keys (currently %d keys).\ -If you want to add more, just put them inside mf_default_keys.lua. "):format(#keys) +Arguments: + -h : this help + -p : print keys +]] local TIMEOUT = 10000 -- 10 seconds +--- +-- Usage help +function help() + print(desc) + print("Example usage") + print(example) +end + +--[[This may be moved to a separate library at some point]] +local utils = +{ + --- + -- Asks the user for Yes or No + confirm = function(message, ...) + local answer + message = message .. " [y]/[n] ?" + repeat + io.write(message) + io.flush() + answer=io.read() + if answer == 'Y' or answer == "y" then + return true + elseif answer == 'N' or answer == 'n' then + return false + end + until false + end, + --- + -- Asks the user for input + input = function (message , default) + local answer + if default ~= nil then + message = message .. " (default: ".. default.. " )" + end + message = message .." \n > " + io.write(message) + io.flush() + answer=io.read() + if answer == '' then answer = default end + + return answer + end, +} + local function checkCommand(command) @@ -43,7 +101,6 @@ local function checkCommand(command) end end - function checkBlock(blockNo, keys, keyType) -- The command data is only 512 bytes, each key is 6 bytes, meaning that we can send max 85 keys in one go. -- If there's more, we need to split it up @@ -53,12 +110,10 @@ function checkBlock(blockNo, keys, keyType) local n,data = remaining, nil if remaining > 85 then n = 85 end local data = table.concat(keys,"",start,n) - --print("data",data) - --print("data len", #data) print(("Testing block %d, keytype %d, with %d keys"):format(blockNo, keyType, n)) local command = Command:new{cmd = cmds.CMD_MIFARE_CHKKEYS, - arg1 = blockNo, - arg2 = keyType, + arg1 = OR(blockNo, LSHIFT(keyType,8) ), + arg2 = 0, arg3 = n, data = data} local status = checkCommand(command) @@ -70,19 +125,19 @@ function checkBlock(blockNo, keys, keyType) end -- A function to display the results +-- TODO: iceman 2016, still screws up output when a key is not found. local function displayresults(results) local sector, blockNo, keyA, keyB,_ - print("________________________________________") - print("|Sector|Block| A | B |") - print("|--------------------------------------|") + print("|---|----------------|---|----------------|---|") + print("|sec|key A |res|key B |res|") + print("|---|----------------|---|----------------|---|") for sector,_ in pairs(results) do blockNo, keyA, keyB = unpack(_) - - print(("| %3d | %3d |%s|%s|"):format(sector, blockNo, keyA, keyB )) + print(("|%03d| %s | 1 | %s | 1 |"):format(sector, keyA, keyB )) end - print("|--------------------------------------|") + print("|---|----------------|---|----------------|---|") end -- A little helper to place an item first in the list @@ -101,28 +156,81 @@ local function placeFirst(akey, list) end return result end +local function dumptofile(results) + local sector, blockNo, keyA, keyB,_ + + if utils.confirm("Do you wish to save the keys to dumpfile?") then + local destination = utils.input("Select a filename to store to", "dumpkeys.bin") + local file = io.open(destination, "w") + if file == nil then + print("Could not write to file ", destination) + return + end -local function main() + local key_a = "" + local key_b = "" + + for sector,_ in pairs(results) do + blockNo, keyA, keyB = unpack(_) + key_a = key_a .. bin.pack("H",keyA); + key_b = key_b .. bin.pack("H",keyB); + end + file:write(key_a) + file:write(key_b) + file:close() + end +end +local function printkeys() + for i=0,#keys do + print(i,keys[i]) + + end + print ('Number of keys: '..#keys) +end - print(desc); +local function main( args) + -- Arguments for the script + for o, a in getopt.getopt(args, 'hp') do + if o == "h" then return help() end + if o == "p" then return printkeys() end + end + result, err = reader.read1443a() if not result then print(err) return end - print(("Found a %s tag"):format(result.name)) + print(("Found a %s tag"):format(result.name)) core.clearCommandBuffer() local blockNo local keyType = 0 -- A=0, B=1 - local result = {} - for sector=1,40,1 do + local numSectors = 16 + + if 0x18 == result.sak then --NXP MIFARE Classic 4k | Plus 4k + -- IFARE Classic 4K offers 4096 bytes split into forty sectors, + -- of which 32 are same size as in the 1K with eight more that are quadruple size sectors. + numSectors = 40 + elseif 0x08 == result.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k + -- 1K offers 1024 bytes of data storage, split into 16 sector + numSectors = 16 + elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k + -- MIFARE Classic mini offers 320 bytes split into five sectors. + numSectors = 5 + elseif 0x10 == result.sak then-- "NXP MIFARE Plus 2k" + numSectors = 32 + else + print("I don't know how many sectors there are on this type of card, defaulting to 16") + end + + result = {} + for sector=1,numSectors,1 do --[[ - The mifare Classic 1k card has 16 sectors of 4 data blocks each. The - first 32 sectors of a mifare Classic 4k card consists of 4 data blocks and the remaining + The mifare Classic 1k card has 16 sectors of 4 data blocks each. + The first 32 sectors of a mifare Classic 4k card consists of 4 data blocks and the remaining 8 sectors consist of 16 data blocks. --]] local blockNo = sector * 4 -1 @@ -148,7 +256,8 @@ local function main() end end displayresults(result) + dumptofile(result) end -main() +main( args)