FIX: 'script run mfkeys' Script was mistakingly only checked first testkeys block with 85 keys. Since the selection in testkeys list was not taking lua way of ranges, it only sent zeros.

This commit is contained in:
iceman1001 2017-07-22 14:02:51 +02:00
parent 72f6ed45eb
commit c4c3bedb8a
2 changed files with 169 additions and 155 deletions

View file

@ -45,6 +45,7 @@ local _keys = {
'5c598c9c58b5', -- RKF SL Key B '5c598c9c58b5', -- RKF SL Key B
'e4d2770a89be', -- RKF SL Key B 'e4d2770a89be', -- RKF SL Key B
--[[ --[[
Data from: http://pastebin.com/svGjN30Q Data from: http://pastebin.com/svGjN30Q
--]] --]]

View file

@ -11,13 +11,11 @@
-- Loads the commands-library -- Loads the commands-library
local cmds = require('commands') local cmds = require('commands')
-- Load the default keys -- Load the default keys
local keys = require('mf_default_keys') local keylist = require('mf_default_keys')
-- Ability to read what card is there -- Ability to read what card is there
local reader = require('read14a') local lib14a = require('read14a')
local getopt = require('getopt') local getopt = require('getopt')
local utils = require('utils')
local OR = bit32.bor
local LSHIFT = bit32.lshift
example =[[ example =[[
script run mfkeys script run mfkeys
@ -25,7 +23,7 @@ example =[[
author = "Iceman" author = "Iceman"
usage = "script run mfkeys" usage = "script run mfkeys"
desc = ("This script implements Mifare check keys. It utilises a large list of default keys (currently %d keys).\ 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) .. If you want to add more, just put them inside /lualibs/mf_default_keys.lua\n"):format(#keylist) ..
[[ [[
Arguments: Arguments:
@ -41,104 +39,81 @@ function help()
print("Example usage") print("Example usage")
print(example) print(example)
end end
---
--[[This may be moved to a separate library at some point]] -- This is only meant to be used when errors occur
local utils = function oops(err)
{ print('ERROR: ',err)
--- return nil,err
-- Asks the user for Yes or No end
confirm = function(message, ...) --
local answer -- waits for answer from pm3 device
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) local function checkCommand(command)
core.clearCommandBuffer()
--print("Sending this command : " .. tostring(command)) local usb = command:getBytes()
local usbcommand = command:getBytes() core.SendCommand(usb)
core.SendCommand(usbcommand) local result = core.WaitForResponseTimeout(cmds.CMD_ACK, TIMEOUT)
local result = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT)
if result then if result then
local count,cmd,arg0 = bin.unpack('LL',result) local count, cmd, arg0 = bin.unpack('LL',result)
if(arg0==1) then if(arg0==1) then
local count,arg1,arg2,data = bin.unpack('LLH511',result,count) local count, arg1, arg2, data = bin.unpack('LLH511',result,count)
key = data:sub(1,12) key = data:sub(1,12)
return key return key
else else
--print("Key not found...")
return nil return nil
end end
else else
print("Timeout while waiting for response. Increase TIMEOUT in keycheck.lua to wait longer") print("Timeout while waiting for response. Increase TIMEOUT in mfkeys.lua to wait longer")
return nil, "Timeout while waiting for device to respond" return nil, "Timeout while waiting for device to respond"
end end
end end
function checkBlock(blockNo, keys, keyType) local function checkBlock(blockno, testkeys, keytype)
-- The command data is only 512 bytes, each key is 6 bytes, meaning that we can send max 85 keys in one go. -- 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 -- If there's more, we need to split it up
local start, remaining= 1, #keys local arg1 = bit32.bor(bit32.lshift(keytype, 8), blockno)
local packets = {}
local start, remaining = 1, #testkeys
local chunksize = remaining
if remaining > 85 then chunksize = 85 end
local n = chunksize
while remaining > 0 do while remaining > 0 do
local n,data = remaining, nil --print('start', start, 'chunksize', chunksize, 'testkeys kvar', remaining, 'N-index=', n)
if remaining > 85 then n = 85 end
local data = table.concat(keys,"",start,n) local d1 = table.concat(testkeys, "", start, n)
print(("Testing block %d, keytype %d, with %d keys"):format(blockNo, keyType, n))
print(("Testing block %d, keytype %d, with %d keys"):format(blockno, keytype, chunksize))
local command = Command:new{cmd = cmds.CMD_MIFARE_CHKKEYS, local command = Command:new{cmd = cmds.CMD_MIFARE_CHKKEYS,
arg1 = OR(blockNo, LSHIFT(keyType,8) ), arg1 = arg1,
arg2 = 0, arg2 = 0,
arg3 = n, arg3 = chunksize,
data = data} data = d1}
local status = checkCommand(command) local status = checkCommand(command)
if status then return status, blockNo end if status then return status, blockno end
start = start+n+1 start = start + chunksize
remaining = remaining - n remaining = remaining - chunksize
if remaining < 85 then chunksize = remaining end
n = n + chunksize
end end
return nil return nil
end end
-- A function to display the results -- A function to display the results
-- TODO: iceman 2016, still screws up output when a key is not found. -- TODO: iceman 2016, still screws up output when a key is not found.
local function displayresults(results) local function display_results(keys)
local sector, blockNo, keyA, keyB,_ local sector, keyA, keyB, succA, succB
print('')
print('|---|----------------|---|----------------|---|')
print('|sec|key A |res|key B |res|')
print('|---|----------------|---|----------------|---|')
print("|---|----------------|---|----------------|---|") for sector = 0, #keys do
print("|sec|key A |res|key B |res|") succA, succB, keyA, keyB = unpack(keys[sector])
print("|---|----------------|---|----------------|---|") print(('|%03d| %s | %s | %s | %s |'):format(sector, keyA, succA, keyB, succB))
for sector,_ in pairs(results) do
blockNo, keyA, keyB = unpack(_)
print(("|%03d| %s | 1 | %s | 1 |"):format(sector, keyA, keyB ))
end end
print("|---|----------------|---|----------------|---|") print('|---|----------------|---|----------------|---|')
end end
-- A little helper to place an item first in the list -- A little helper to place an item first in the list
local function placeFirst(akey, list) local function placeFirst(akey, list)
@ -156,24 +131,47 @@ local function placeFirst(akey, list)
end end
return result return result
end end
local function dumptofile(results) --[[
local sector, blockNo, keyA, keyB,_ 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 function get_blockno(s)
if utils.confirm("Do you wish to save the keys to dumpfile?") then local b, sector
local destination = utils.input("Select a filename to store to", "dumpkeys.bin")
local file = io.open(destination, "w") if type(s) == 'string' then
sector = tonumber(s)
else
sector = s
end
if sector < 32 then
b = sector * 4
else
b = 32 * 4 + (sector - 32) * 16
end
return ('%02x'):format(b)
end
--
-- dumps all keys to file
local function dumptofile(keys)
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, 'wb')
if file == nil then if file == nil then
print("Could not write to file ", destination) print('Could not write to file ', destination)
return return
end end
local key_a = "" local key_a = ''
local key_b = "" local key_b = ''
for sector,_ in pairs(results) do --for sector,_ in pairs(keys) do
blockNo, keyA, keyB = unpack(_) for sector = 0, #keys do
key_a = key_a .. bin.pack("H",keyA); local succA, succB, keyA, keyB = unpack(keys[sector])
key_b = key_b .. bin.pack("H",keyB); key_a = key_a .. bin.pack('H', keyA);
key_b = key_b .. bin.pack('H', keyB);
end end
file:write(key_a) file:write(key_a)
file:write(key_b) file:write(key_b)
@ -181,82 +179,97 @@ local function dumptofile(results)
end end
end end
local function printkeys() local function printkeys()
for i=0,#keys do for i=1, #keylist do
print(i,keys[i]) print(i, keylist[i])
end end
print ('Number of keys: '..#keys) print ('Number of keys: '..#keylist)
end end
local function perform_check(numsectors)
local keyType = 0 -- A=0, B=1
-- empty list of found keys
local keys = {}
for i = 0, numsectors-1 do
keys[i] = {0,0,'',''}
end
for sector = 0, #keys do
-- Check if user aborted
if core.ukbhit() then
print('Aborted by user')
break
end
local targetblock = tonumber(get_blockno(sector), 16)
local succA, succB, keyA, keyB = unpack(keys[sector])
local keyA = checkBlock(targetblock, keylist, 0)
if keyA then succA = 1; keylist = placeFirst(keyA, keylist) end
keyA = keyA or '------------'
local keyB = checkBlock(targetblock, keylist, 1)
if keyB then succB = 1; keylist = placeFirst(keyB, keylist) end
keyB = keyB or '------------'
keys[sector] = {succA, succB, keyA, keyB }
end
display_results(keys)
-- save to dumpkeys.bin
dumptofile(keys)
end
--
-- shows tag information
local function taginfo(tag)
local sectors = 16
-- Show tag info
print((' Found tag %s'):format(tag.name))
if 0x18 == tag.sak then --NXP MIFARE Classic 4k | Plus 4k
-- MIFARE 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.
sectors = 40
elseif 0x08 == tag.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k
-- 1K offers 1024 bytes of data storage, split into 16 sector
sectors = 16
elseif 0x09 == tag.sak then -- NXP MIFARE Mini 0.3k
-- MIFARE Classic mini offers 320 bytes split into five sectors.
sectors = 5
elseif 0x10 == tag.sak then-- "NXP MIFARE Plus 2k"
sectors = 32
else
print("I don't know how many sectors there are on this type of card, defaulting to 16")
end
return sectors
end
---
-- The main entry point
local function main( args) local function main( args)
local start_time = os.time()
local numSectors = 16
-- Arguments for the script -- Arguments for the script
for o, a in getopt.getopt(args, 'hp') do for o, a in getopt.getopt(args, 'hp') do
if o == "h" then return help() end if o == "h" then return help() end
if o == "p" then return printkeys() end if o == "p" then return printkeys() end
end end
result, err = reader.read1443a() -- identify tag
if not result then tag, err = lib14a.read1443a(false)
print(err) if not tag then return oops(err) end
return
end
print(("Found a %s tag"):format(result.name)) -- detect sectors and print taginfo
numsectors = taginfo(tag)
core.clearCommandBuffer() perform_check(numsectors)
local blockNo
local keyType = 0 -- A=0, B=1
local numSectors = 16
if 0x18 == result.sak then --NXP MIFARE Classic 4k | Plus 4k local end_time = os.time()
-- IFARE Classic 4K offers 4096 bytes split into forty sectors, print('mfkeys - Total execution time: '..os.difftime(end_time, start_time)..' sec')
-- 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
8 sectors consist of 16 data blocks.
--]]
local blockNo = sector * 4 -1
if sector > 32 then
blockNo = 32*4+ (sector-32)*16 -1
end
local keyA = checkBlock(blockNo, keys, 0)
if keyA then keys = placeFirst(keyA, keys) end
keyA = keyA or ""
local keyB = checkBlock(blockNo, keys, 1)
if keyB then keys = placeFirst(keyB, keys) end
keyB = keyB or ""
result[sector] = {blockNo, keyA, keyB }
-- Check if user aborted
if core.ukbhit() then
print("Aborted by user")
break
end
end
displayresults(result)
dumptofile(result)
end end
main( args) main( args)