1 local utils
= require('utils')
2 local getopt
= require('getopt')
3 local cmds
= require('commands')
4 local read14a
= require('read14a')
7 -------------------------------
9 -------------------------------
13 ---Suggestions of improvement:
14 --- Add support another types of dumps: BIN, JSON
15 --- Maybe it will be not only as `hf_mf_gen3_writer`, like a universal dump manager.
16 --- Hide system messages when you writing a dumps, replace it to some of like [#####----------] 40%
19 -- doesn't take consideration filepaths for dump files.
20 -- doesn't allow A keys for authenticating when writing
21 -- doesn't verify that card is magic gen3.
22 -- doesn't take several versions of same dump ( -1, -2, -3 ) styles.
26 -------------------------------
28 -------------------------------
31 copyright
= 'RRG Team'
35 This script gives you an easy way to write your *.eml dumps into normal MIFARE Classic and Magic Gen3 cards.
37 Works with both 4 and 7 bytes NXP MIFARE Classic 1K cards.
38 The script also has the possibility to change UID and permanent lock uid on magic Gen3 cards.
40 It supports the following functionality.
42 1. Write it to the same of current card UID.
43 2. Write it to magic Gen3 card.
44 3. Change uid to match dump on magic Gen3 card.
45 4. Permanent lock UID on magic Gen3 card.
46 5. Erase all data at the card and set the FF FF FF FF FF FF keys, and Access Conditions to 78778800.
48 Script works in a wizard styled way.
51 1. script run mfc_gen3_writer
54 Give script to know if you uses an Windows OS
55 Select your *.eml dump from list to write to the card.
60 -------------------------------
62 -------------------------------
65 local DEBUG
= false -- the debug flag
66 local dumpEML
-- Find all *.EML files
67 local files
= {} -- Array for eml files
68 local b_keys
= {} -- Array for B keys
69 local eml
= {} -- Array for data in block 32
70 local num_dumps
= 0 -- num of found eml dump files
71 local tab
= string.rep('-', 64)
72 local empty
= string.rep('0', 32) -- Writing blocks
73 local default_key
= 'FFFFFFFFFFFF' -- Writing blocks
74 local default_key_type
= '01' --KeyA: 00, KeyB: 01
75 local default_key_blk
= 'FFFFFFFFFFFF7C378800FFFFFFFFFFFF' -- Writing blocks
76 local piswords_uid_lock
= 'hf 14a raw -s -c -t 2000 90fd111100'
77 local piswords_uid_change
= 'hf 14a raw -s -c -t 2000 90f0cccc10'
78 local cmd_wrbl_a
= 'hf mf wrbl --blk %d -a -k %s -d %s' -- Writing blocks by A key
79 local cmd_wrbl_b
= 'hf mf wrbl --blk %d -b -k %s -d %s' -- Writing blocks by B key
82 -------------------------------
83 -- A debug printout-function
84 -------------------------------
87 local function dbg(args
)
88 if not DEBUG
then return end
89 if type(args
) == 'table' then
101 -------------------------------
102 -- This is only meant to be used when errors occur
103 -------------------------------
106 local function oops(err
)
108 core
.clearCommandBuffer()
113 -------------------------------
115 -------------------------------
118 local function help()
123 print('Example usage')
129 -------------------------------
131 -------------------------------
134 local function GetUID()
135 return read14a
.read(true, true).uid
138 local function dropfield()
140 core
.clearCommandBuffer()
144 -------------------------------
145 -- Wait for tag (MFC)
146 -------------------------------
149 local function wait()
150 read14a
.waitFor14443a()
154 -------------------------------
155 -- Return key code 00/01 to string
156 -------------------------------
159 local function KeyAB()
160 if default_key_type
== '00' then
168 -------------------------------
169 -- Check response from Proxmark
170 -------------------------------
173 local function getblockdata(response
)
174 if response
.Status
== 0 then
182 -------------------------------
183 -- Check 0xFFFFFFFFFFFF key for tag (MFC)
184 -------------------------------
187 local function checkkey()
190 cmd
= Command
:newNG
{cmd
= cmds
.CMD_HF_MIFARE_READBL
, data
= ('%02x%02x%s'):format((i
-1), default_key_type
, default_key
)}
191 if (getblockdata(cmd
:sendNG(false)) == true) then
193 print(('%s %02s %s %s %s'):format(' ', (i
-1), KeyAB(), default_key
, 'OK'))
198 if status
== #eml
then
204 -------------------------------
205 -- Check user input A or B for blank tag (MFC)
206 -------------------------------
209 local function check_user_key(user_key_type
)
210 if user_key_type
== 'A' then
212 elseif user_key_type
== 'B' then
218 -------------------------------
220 -------------------------------
223 local function main(args
)
226 -------------------------------
227 -- Arguments for script
228 -------------------------------
231 for o
, a
in getopt
.getopt(args
, 'hd') do
232 if o
== 'h' then return help() end
233 if o
== 'd' then DEBUG
= true end
240 -------------------------------
241 -- Detect 7/4 byte card
242 -------------------------------
245 if (utils
.confirm(' Are you use a Windwos OS ?') == true) then
246 dumpEML
= 'find "." "*dump.eml"'
247 if string.len(GetUID()) == 14 then
248 eml_file_uid_start
= 18
249 eml_file_uid_end
= 31
252 eml_file_uid_start
= 18
253 eml_file_uid_end
= 25
257 dumpEML
= "find '.' -iname '*dump.eml' -type f"
258 if string.len(GetUID()) == 14 then
259 eml_file_uid_start
= 9
260 eml_file_uid_end
= 22
263 eml_file_uid_start
= 9
264 eml_file_uid_end
= 16
272 -------------------------------
273 -- List all EML files in /client
274 -------------------------------
277 local p
= assert(io
.popen(dumpEML
))
278 for _
in p
:lines() do
279 -- The length of eml file
280 if string.len(_
) == eml_file_lengt
then
281 num_dumps
= num_dumps
+ 1
282 -- cut UID from eml file
283 files
[num_dumps
] = string.sub(_
, eml_file_uid_start
, eml_file_uid_end
) -- cut numeretic UID
284 print(' '..num_dumps
..' | '..files
[num_dumps
])
290 if num_dumps
== 0 then return oops("Didn't find any dump files") end
293 print(' Your card has UID '..GetUID())
295 print(' Select which dump to write (1 until '..num_dumps
..')')
299 local uid_no
= tonumber(io
.read())
301 print(' You have been selected card dump No ' .. uid_no
.. ', with UID: ' .. files
[uid_no
] .. '. Your card UID: ' .. GetUID())
305 -------------------------------
307 -------------------------------
310 local dumpfile
= assert(io
.open('hf-mf-' .. files
[uid_no
] .. '-dump.eml', 'r'))
311 for _
in dumpfile
:lines() do table.insert(eml
, _
); end
315 -------------------------------
316 -- Extract B key from EML file
317 -------------------------------
325 -- Cut key from block
326 b_keys
[b
] = string.sub(eml
[i
], (#eml
[i
] - 11), #eml
[i
])
335 -------------------------------
336 -- Change UID on certain version of magic Gen3 card.
337 -------------------------------
340 if (utils
.confirm(' Change UID ?') == true) then
342 core
.console(piswords_uid_change
.. tostring(eml
[1]))
344 print(' The new card UID : ' .. GetUID())
349 -------------------------------
351 -------------------------------
354 if (utils
.confirm(' Permanent lock UID ? (card can never change uid again) ') == true) then
356 core
.console(piswords_uid_lock
)
360 print(' Going to check the all ' .. KeyAB() .. ' by ' .. default_key
)
363 if checkkey() == true then
365 if (utils
.confirm(' Card is Empty. Write selected dump to card ?') == true) then
367 core
.console(string.format(cmd_wrbl_b
, (i
-1), default_key
, eml
[i
]))
372 if (utils
.confirm(' It this is a new blank card ? Do you wishing to change Access Conditions to using B key ' .. default_key
.. ' as main ?') == true) then
374 print(' With one key type we will use, A or B ?')
377 local user_key_type
= tostring(io
.read())
379 print(' Enter 12 HEX chars of the key for access to card. By default ' .. default_key
.. '.')
382 local user_key_input
= tostring(io
.read())
386 core
.console(string.format(check_user_key(user_key_type
), (i
-1), user_key_input
, default_key_blk
))
388 core
.console(string.format(check_user_key(user_key_type
), (i
-1), user_key_input
, empty
))
393 if (utils
.confirm(' Write selected dump to card ?') == true) then
397 core
.console(string.format(cmd_wrbl_b
, (i
-1), b_keys
[i
], eml
[i
]))
401 if (utils
.confirm(' Delete ALL data and write all keys to 0x' .. default_key
.. ' ?') == true) then
405 core
.console(string.format(cmd_wrbl_b
, (i
-1), b_keys
[i
], default_key_blk
))
407 core
.console(string.format(cmd_wrbl_b
, (i
-1), b_keys
[i
], empty
))
416 print('You are welcome')
420 -------------------------------
421 -- Start Main function
422 -------------------------------