proxmark3/client/luascripts/mfc_gen3_writer.lua

391 lines
10 KiB
Lua
Raw Normal View History

2020-03-17 18:37:38 +08:00
local utils = require('utils')
local getopt = require('getopt')
2020-04-21 01:29:32 +08:00
local cmds = require('commands')
2020-03-17 18:37:38 +08:00
local read14a = require('read14a')
2020-04-21 01:29:32 +08:00
--
---
-------------------------------
-- Notes
-------------------------------
---
--
2020-03-21 19:34:58 +08:00
--[[
2020-03-21 17:04:03 +08:00
---Suggestions of improvement:
--- Add support another types of dumps: BIN, JSON
--- Maybe it will be not only as `mfc_gen3_writer`, like a universal dump manager.
--- Add undependence from the operation system. At the moment code not working in Linux.
--- Add more chinesse backdoors RAW commands for UID changing (find RAW for the 4 byte familiar chinese card, from native it soft: http://bit.ly/39VIDsU)
--- Hide system messages when you writing a dumps, replace it to some of like [#####----------] 40%
-- iceman notes:
-- doesn't take consideration filepaths for dump files.
-- doesn't allow A keys for authenticating when writing
-- doesn't verify that card is magic gen3.
2020-03-21 19:34:58 +08:00
-- doesn't take several versions of same dump ( -1, -2, -3 ) styles.
2020-03-21 17:04:03 +08:00
--]]
2020-04-21 01:29:32 +08:00
--
---
-------------------------------
-- Script hat
-------------------------------
---
--
copyright = ''
author = 'Winds'
version = 'v1.0.0'
desc = [[
2020-03-21 17:04:03 +08:00
The script gives you a easy way to write your *.eml dumps onto normal MFC and magic Gen3 cards.
Works with both 4 and 7 bytes NXP MIFARE Classic 1K cards.
The script also has the possibility to change UID and permanent lock uid on magic Gen3 cards.
2020-04-22 05:24:01 +08:00
2020-03-21 17:04:03 +08:00
It supports the following functionality.
2020-03-21 17:04:03 +08:00
1. Write it to the same of current card UID.
2. Write it to magic Gen3 card.
3. Change uid to match dump on magic Gen3 card.
4. Permanent lock UID on magic Gen3 card.
5. Erase all data at the card and set the FF FF FF FF FF FF keys, and Access Conditions to 78778800.
2020-04-22 05:24:01 +08:00
2020-03-21 17:04:03 +08:00
Script works in a wizard styled way.
]]
example = [[
2020-03-21 17:04:03 +08:00
1. script run mfc_gen3_writer
]]
usage = [[
2020-03-21 17:04:03 +08:00
Select your *.eml dump from list to write to the card.
]]
2020-04-21 01:29:32 +08:00
--
---
2020-03-21 19:34:58 +08:00
-------------------------------
2020-04-21 01:29:32 +08:00
-- Global variables
2020-03-21 19:34:58 +08:00
-------------------------------
---
2020-04-21 01:29:32 +08:00
--
local DEBUG = false -- the debug flag
local files = {} -- Array for eml files
local b_keys = {} -- Array for B keys
local eml = {} -- Array for data in block 32
local num_dumps = 0 -- num of found eml dump files
local tab = string.rep('-', 64)
local empty = string.rep('0', 32) -- Writing blocks
local default_key = 'FFFFFFFFFFFF' -- Writing blocks
local default_key_type = '01' --KeyA: 00, KeyB: 01
local default_key_blk = 'FFFFFFFFFFFF78778800FFFFFFFFFFFF' -- Writing blocks
local piswords_uid_lock = 'hf 14a raw -s -c -t 2000 90fd111100'
local piswords_uid_change = 'hf 14a raw -s -c -t 2000 90f0cccc10'
local cmd_wrbl = 'hf mf wrbl %d B %s %s' -- Writing blocks
--
---
-------------------------------
2020-03-21 19:34:58 +08:00
-- A debug printout-function
2020-04-21 01:29:32 +08:00
-------------------------------
---
--
2020-03-21 19:34:58 +08:00
local function dbg(args)
if not DEBUG then return end
if type(args) == 'table' then
local i = 1
while args[i] do
dbg(args[i])
i = i+1
end
else
print('###', args)
end
end
2020-04-21 01:29:32 +08:00
--
2020-03-21 19:34:58 +08:00
---
2020-04-21 01:29:32 +08:00
-------------------------------
2020-03-21 19:34:58 +08:00
-- This is only meant to be used when errors occur
2020-04-21 01:29:32 +08:00
-------------------------------
---
--
2020-03-21 19:34:58 +08:00
local function oops(err)
print('ERROR:', err)
core.clearCommandBuffer()
return nil, err
end
2020-04-21 01:29:32 +08:00
--
---
2020-04-21 01:29:32 +08:00
-------------------------------
-- Usage help
2020-04-21 01:29:32 +08:00
-------------------------------
---
--
local function help()
print(copyright)
print(author)
print(version)
print(desc)
2020-03-21 19:34:58 +08:00
print('Example usage')
print(example)
print(usage)
end
2020-04-21 01:29:32 +08:00
--
2020-03-21 17:04:03 +08:00
---
2020-04-21 01:29:32 +08:00
-------------------------------
2020-03-21 17:04:03 +08:00
-- GetUID
2020-04-21 01:29:32 +08:00
-------------------------------
---
--
2020-03-21 17:04:03 +08:00
local function GetUID()
return read14a.read(true, true).uid
2020-03-17 18:37:38 +08:00
end
2020-04-16 15:01:14 +08:00
--
2020-03-21 17:04:03 +08:00
local function dropfield()
2020-03-17 18:37:38 +08:00
read14a.disconnect()
core.clearCommandBuffer()
end
2020-04-21 01:29:32 +08:00
--
2020-03-21 17:04:03 +08:00
---
2020-04-21 01:29:32 +08:00
-------------------------------
2020-03-21 17:04:03 +08:00
-- Wait for tag (MFC)
2020-04-21 01:29:32 +08:00
-------------------------------
---
--
local function wait()
read14a.waitFor14443a()
2020-03-17 18:37:38 +08:00
end
2020-04-21 01:29:32 +08:00
--
---
-------------------------------
2020-04-22 23:59:02 +08:00
-- Return key code 00/01 to string
-------------------------------
---
--
local function KeyAB()
if default_key_type == '00' then
return 'KeyA'
else
return 'KeyB'
end
end
--
---
-------------------------------
-- Check response from Proxmark
2020-04-21 01:29:32 +08:00
-------------------------------
---
--
local function getblockdata(response)
if response.Status == 0 then
return true
else
return false
end
end
--
2020-04-22 23:59:02 +08:00
---
-------------------------------
-- Check 0xFFFFFFFFFFFF key for tag (MFC)
-------------------------------
---
--
2020-04-21 01:29:32 +08:00
local function checkkey()
local status = 0
for i = 1, #eml do
2020-04-22 23:59:02 +08:00
cmd = Command:newNG{cmd = cmds.CMD_HF_MIFARE_READBL, data = ('%02x%02x%s'):format((i-1), default_key_type, default_key)}
2020-04-21 01:29:32 +08:00
if (getblockdata(cmd:sendNG(false)) == true) then
status = status + 1
2020-04-22 23:59:02 +08:00
print(('%s %02s %s %s %s'):format(' ', (i-1), KeyAB(), default_key, 'OK'))
2020-04-21 01:29:32 +08:00
else
break
end
end
if status == #eml then
return true
end
end
--
---
-------------------------------
-- Check Pissword backdor
-------------------------------
---
--
local function checkmagic()
--Have no RAW ISO14443A command in appmain.c
cmd = Command:newNG{cmd = cmds.CMD_HF_ISO14443A_READER, data = piswords_uid_change .. GetUID()} -- sample check to pull the same UID to card and check response
if (getblockdata(cmd:sendNG(false)) == true) then
print('Magic')
else
print('Not magic')
end
end
--
---
-------------------------------
-- Main function
-------------------------------
2020-03-21 17:04:03 +08:00
---
--
local function main(args)
2020-04-21 01:29:32 +08:00
--
---
-------------------------------
-- Arguments for script
-------------------------------
---
--
2020-03-21 19:37:40 +08:00
for o, a in getopt.getopt(args, 'hd') do
if o == 'h' then return help() end
2020-03-21 19:37:40 +08:00
if o == 'd' then DEBUG = true end
end
2020-03-21 17:04:03 +08:00
--
wait()
print(tab)
2020-04-21 01:29:32 +08:00
--
---
-------------------------------
-- Detect 7/4 byte card
-------------------------------
---
--
2020-04-16 15:01:14 +08:00
if string.len(GetUID()) == 14 then
2020-04-21 01:29:32 +08:00
eml_file_uid_start = 18 -- For windows with '---------- ' prefix
eml_file_uid_end = 31
eml_file_lengt = 40
else
eml_file_uid_start = 18 -- For windows with '---------- ' prefix
eml_file_uid_end = 25
eml_file_lengt = 34
2020-04-16 15:01:14 +08:00
end
2020-03-21 19:34:58 +08:00
dropfield()
2020-04-21 01:29:32 +08:00
--
---
-------------------------------
-- List all EML files in /client
-------------------------------
---
--
local dumpEML = 'find "." "*dump.eml"' -- Fixed for windows
2020-04-16 15:01:14 +08:00
local p = assert(io.popen(dumpEML))
2020-03-21 19:34:58 +08:00
for _ in p:lines() do
-- The length of eml file
2020-04-21 01:29:32 +08:00
if string.len(_) == eml_file_lengt then
2020-03-21 19:34:58 +08:00
num_dumps = num_dumps + 1
2020-04-21 01:29:32 +08:00
-- cut UID from eml file
files[num_dumps] = string.sub(_, eml_file_uid_start, eml_file_uid_end) -- cut numeretic UID
2020-03-21 19:34:58 +08:00
print(' '..num_dumps..' | '..files[num_dumps])
2020-03-17 18:37:38 +08:00
end
2020-04-16 15:01:14 +08:00
end
2020-04-21 01:29:32 +08:00
--
2020-03-21 19:40:16 +08:00
p.close()
2020-04-21 01:29:32 +08:00
--
2020-03-21 19:34:58 +08:00
if num_dumps == 0 then return oops("Didn't find any dump files") end
2020-04-21 01:29:32 +08:00
--
2020-03-17 18:37:38 +08:00
print(tab)
2020-03-21 17:04:03 +08:00
print(' Your card has UID '..GetUID())
print('')
print(' Select which dump to write (1 until '..num_dumps..')')
print(tab)
2020-03-21 17:04:03 +08:00
io.write(' --> ')
2020-04-21 01:29:32 +08:00
--
local uid_no = tonumber(io.read())
print(tab)
2020-04-21 01:29:32 +08:00
print(' You have been selected card dump No ' .. uid_no .. ', with UID: ' .. files[uid_no] .. '. Your card UID: ' .. GetUID())
--
--
---
-------------------------------
-- Load eml file
-------------------------------
---
--
local dumpfile = assert(io.open('./hf-mf-' .. files[uid_no] .. '-dump.eml', 'r'))
2020-03-21 19:40:16 +08:00
for _ in dumpfile:lines() do table.insert(eml, _); end
dumpfile.close()
2020-04-21 01:29:32 +08:00
--
---
-------------------------------
2020-04-22 05:24:01 +08:00
-- Extract B key from EML file
2020-04-21 01:29:32 +08:00
-------------------------------
---
2020-04-22 05:24:01 +08:00
--
2020-03-21 17:04:03 +08:00
local b = 0
for i = 1, #eml do
if (i % 4 == 0) then
repeat
b = b + 1
2020-03-21 17:04:03 +08:00
-- Cut key from block
2020-04-16 15:01:14 +08:00
b_keys[b] = string.sub(eml[i], (#eml[i] - 11), #eml[i])
until b % 4 == 0
end
2020-04-16 15:01:14 +08:00
end
2020-03-21 17:04:03 +08:00
print(tab)
2020-03-21 19:34:58 +08:00
dbg(b_keys)
dbg(eml)
2020-04-21 01:29:32 +08:00
--
---
-------------------------------
-- Change UID on certain version of magic Gen3 card.
-------------------------------
---
--
2020-03-21 17:04:03 +08:00
if (utils.confirm(' Change UID ?') == true) then
wait()
2020-04-21 01:29:32 +08:00
core.console(piswords_uid_change .. tostring(eml[1]))
print(tab)
2020-03-21 17:04:03 +08:00
print(' The new card UID : ' .. GetUID())
2020-04-22 05:24:01 +08:00
end
2020-04-16 15:01:14 +08:00
print(tab)
2020-04-21 01:29:32 +08:00
--checkmagic()
--
---
-------------------------------
-- Lock UID
-------------------------------
---
--
2020-03-21 17:04:03 +08:00
if (utils.confirm(' Permanent lock UID ? (card can never change uid again) ') == true) then
wait()
2020-04-21 01:29:32 +08:00
core.console(piswords_uid_lock)
2020-04-16 15:01:14 +08:00
end
2020-04-21 01:29:32 +08:00
--
2020-03-21 17:04:03 +08:00
print(tab)
2020-04-22 23:59:02 +08:00
print(' Going to check the all ' .. KeyAB() .. ' by ' .. default_key)
print(tab)
2020-04-21 01:29:32 +08:00
--
if checkkey() == true then
2020-04-22 23:59:02 +08:00
print(tab)
2020-04-21 01:29:32 +08:00
if (utils.confirm(' Card is Empty. Write selected dump to card ?') == true) then
for i = 1, #eml do
core.console(string.format(cmd_wrbl, (i-1), default_key, eml[i]))
end
2020-03-17 18:37:38 +08:00
end
else
print(tab)
2020-04-21 01:29:32 +08:00
if (utils.confirm(' Delete ALL data and write all keys to 0x' .. default_key .. ' ?') == true) then
wait()
for i = 1, #eml do
if (i % 4 == 0) then
2020-03-21 19:37:40 +08:00
core.console(string.format(cmd_wrbl, (i-1), b_keys[i], default_key_blk))
else
2020-03-21 19:37:40 +08:00
core.console(string.format(cmd_wrbl, (i-1), b_keys[i], empty))
end
end
else
2020-03-21 17:04:03 +08:00
print(tab)
2020-04-21 01:29:32 +08:00
if (utils.confirm(' Write selected dump to card ?') == true) then
print(tab)
wait()
for i = 1, #eml do
core.console(string.format(cmd_wrbl, (i-1), b_keys[i], eml[i]))
end
end
2020-03-17 18:37:38 +08:00
end
end
2020-03-21 17:04:03 +08:00
dropfield()
print(tab)
2020-04-21 01:29:32 +08:00
print('You are welcome')
2020-03-17 18:37:38 +08:00
end
2020-04-21 01:29:32 +08:00
--
---
-------------------------------
-- Start Main function
-------------------------------
---
--
2020-03-21 17:04:03 +08:00
main(args)