local cmds = require('commands') local getopt = require('getopt') local lib14a = require('read14a') local utils = require('utils') local ansicolors = require('ansicolors') -- global local DEBUG = false -- the debug flag local bxor = bit32.bxor local _ntagpassword = nil local _key = '00000000' -- default UMC key local err_lock = 'use -k or change cfg0 block' local _print = 0 copyright = '' author = 'Nathan Glaser' version = 'v1.0.4' date = 'Created - Jan 2022' desc = 'This script enables easy programming of an Ultimate Mifare Magic card' example = [[ -- read magic tag configuration ]]..ansicolors.yellow..[[script run hf_mf_ultimatecard -c ]]..ansicolors.reset..[[ -- set uid ]]..ansicolors.yellow..[[script run hf_mf_ultimatecard -u 04112233445566 ]]..ansicolors.reset..[[ -- set NTAG pwd / pack ]]..ansicolors.yellow..[[script run hf_mf_ultimatecard -p 11223344 -a 8080 ]]..ansicolors.reset..[[ -- set version to NTAG213 ]]..ansicolors.yellow..[[script run hf_mf_ultimatecard -v 0004040201000f03 ]]..ansicolors.reset..[[ -- set ATQA/SAK to [00 44] [08] ]]..ansicolors.yellow..[[script run hf_mf_ultimatecard -q 004408 ]]..ansicolors.reset..[[ -- wipe tag with a NTAG213 or Mifare 1k S50 4 byte ]]..ansicolors.yellow..[[script run hf_mf_ultimatecard -w 1]]..ansicolors.reset..[[ -- use a non default UMC key. Only use this if the default key for the MAGIC CARD was changed. ]]..ansicolors.yellow..[[script run hf_mf_ultimatecard -k ffffffff -w 1]]..ansicolors.reset..[[ -- Wipe tag, turn into NTAG215, set sig, version, NTAG pwd/pak, and OTP. ]]..ansicolors.yellow..[[script run hf_mf_ultimatecard -w 1 -t 15 -u 04112233445566 -s 112233445566778899001122334455667788990011223344556677 -p FFFFFFFF -a 8080 -o 11111111]]..ansicolors.reset..[[ ]] usage = [[ script run hf_mf_ultimatecard -h -k -c -w -u -t -p -a -s -o -v -q -g -z -m -n ]] arguments = [[ -h this help -c read magic configuration -u UID (8-14 hexsymbols), set UID on tag -t tag type to impersonate 1 = Mifare Mini S20 4-byte 12 = NTAG 210 2 = Mifare Mini S20 7-byte 13 = NTAG 212 3 = Mifare 1k S50 4-byte 14 = NTAG 213 4 = Mifare 1k S50 7-byte 15 = NTAG 215 5 = Mifare 4k S70 4-byte 16 = NTAG 216 6 = Mifare 4k S70 7-byte 17 = NTAG I2C 1K *** 7 = UL - NOT WORKING FULLY 18 = NTAG I2C 2K *** 8 = UL-C - NOT WORKING FULLY 19 = NTAG I2C 1K PLUS 9 = UL EV1 48b 20 = NTAG I2C 2K PLUS 10 = UL EV1 128b 21 = NTAG 213F *** 11 = UL Plus - NOT WORKING YET 22 = NTAG 216F -p NTAG password (8 hexsymbols), set NTAG password on tag. -a NTAG pack ( 4 hexsymbols), set NTAG pack on tag. -s Signature data (64 hexsymbols), set signature data on tag. -o OTP data (8 hexsymbols), set `One-Time Programmable` data on tag. -v Version data (16 hexsymbols), set version data on tag. -q ATQA/SAK (<2b ATQA><1b SAK> hexsymbols), set ATQA/SAK on tag. -g GTU Mode (1 hexsymbol), set GTU shadow mode. -z ATS (<1b length><0-16 ATS> hexsymbols), Configure ATS. Length set to 00 will disable ATS. -w Wipe tag. 0 for Mifare or 1 for UL. Fills tag with zeros and put default values for type selected. -m Ultralight mode (00 UL EV1, 01 NTAG, 02 UL-C, 03 UL) Set type of UL. -n Ultralight protocol (00 MFC, 01 UL), switches between UL and MFC mode -k Ultimate Magic Card Key (IF DIFFERENT THAN DEFAULT 00000000) ]] --- -- A debug printout-function local function dbg(args) if not DEBUG then return end if type(args) == 'table' then local i = 1 while result[i] do dbg(result[i]) i = i+1 end else print('###', args) end end -- This is only meant to be used when errors occur local function oops(err) print("ERROR: ",err) core.clearCommandBuffer() return nil, err end --- -- Usage help local function help() print(copyright) print(author) print(version) print(date) print(desc) print(ansicolors.cyan..'Usage'..ansicolors.reset) print(usage) print(ansicolors.cyan..'Arguments'..ansicolors.reset) print(arguments) print(ansicolors.cyan..'Example usage'..ansicolors.reset) print(example) end --- -- set the global password variable local function set_ntagpassword(pwd) if pwd == nil then _ntagpassword = nil; return true, 'Ok' end if #pwd ~= 8 then return nil, 'password wrong length. Must be 4 hex bytes' end if #pwd == 0 then _ntagpassword = nil end _ntagpassword = pwd return true, 'Ok' end -- set the global UMC key variable local function set_key(key) print('Key:'..key) if key == nil then _key = '00000000'; return true, 'Ok' end if #key ~= 8 then return nil, 'UMC key is wrong the length. Must be 4 hex bytes' end if #key == 0 then _key = nil end _key = key return true, 'Ok' end --- Picks out and displays the data read from a tag -- Specifically, takes a usb packet, converts to a Command -- (as in commands.lua), takes the data-array and -- reads the number of bytes specified in arg1 (arg0 in c-struct) -- @param usbpacket the data received from the device local function getResponseData(usbpacket) local resp = Command.parse(usbpacket) local len = tonumber(resp.arg1) * 2 return string.sub(tostring(resp.data), 0, len); end --- local function sendRaw(rawdata, options) local flags = lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT + lib14a.ISO14A_COMMAND.ISO14A_RAW + lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC local c = Command:newMIX{cmd = cmds.CMD_HF_ISO14443A_READER, arg1 = flags, arg2 = string.len(rawdata)/2, data = rawdata} return c:sendMIX(options.ignore_response) end --- local function send(payload) local usb, err = sendRaw(payload,{ignore_response = false}) if err then return oops(err) end return getResponseData(usb) end --- local function connect() core.clearCommandBuffer() -- First of all, connect info, err = lib14a.read(true, true) if err then lib14a.disconnect() return oops(err) end core.clearCommandBuffer() --authenticate if needed using global variable if _ntagpassword then send('1B'.._ntagpassword) end return true end --- -- Read magic configuration local function read_config() local info = connect() if not info then return false, "Can't select card" end -- read Ultimate Magic Card CONFIG if magicconfig == nil then magicconfig = send("CF".._key.."C6") else print('No Config') end -- extract data from CONFIG - based on CONFIG in https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/magic_cards_notes.md#gen-4-gtu ulprotocol, uidlength, readpass, gtumode, ats, atqa1, atqa2, sak, ulmode = magicconfig:sub(1,2), magicconfig:sub(3,4), magicconfig:sub(5,12), magicconfig:sub(13,14), magicconfig:sub(15,48), magicconfig:sub(51,52), magicconfig:sub(49,50), magicconfig:sub(53,54), magicconfig:sub(55,56) atqaf = atqa1..' '..atqa2 cardtype, cardprotocol, gtustr, atsstr = 'unknown', 'unknown', 'unknown', 'unknown' if magicconfig == nil then lib14a.disconnect(); return nil, "can't read configuration, "..err_lock end if #magicconfig ~= 64 and #magicconfig ~= 68 then lib14a.disconnect(); return nil, "partial read of configuration, "..err_lock end if gtumode == '00' then gtustr = 'Pre-write/Shadow Mode' elseif gtumode == '01' then gtustr = 'Restore Mode' elseif gtumode == '02' then gtustr = 'Disabled' elseif gtumode == '03' then gtustr = 'Disabled, high speed R/W mode for Ultralight' end if ats:sub(1,2) == '00' then atsstr = 'Disabled' else atsstr = (string.sub(ats, 3)) end if ulprotocol == '00' then cardprotocol = 'MIFARE Classic Protocol' ultype = 'Disabled' if uidlength == '00' then uid = send("CF".._key.."CE00"):sub(1,8) if atqaf == '00 04' and sak == '09' then cardtype = 'MIFARE Mini S20 4-byte UID' elseif atqaf == '00 04' and sak == '08' then cardtype = 'MIFARE 1k S50 4-byte UID' elseif atqaf == '00 02' and sak == '18' then cardtype = 'MIFARE 4k S70 4-byte UID' end elseif uidlength == '01' then uid = send("CF".._key.."CE00"):sub(1,14) if atqaf == '00 44' and sak == '09' then cardtype = 'MIFARE Mini S20 7-byte UID' elseif atqaf == '00 44' and sak == '08' then cardtype = 'MIFARE 1k S50 7-byte UID' elseif atqaf == '00 42' and sak == '18' then cardtype = 'MIFARE 4k S70 7-byte UID' end end elseif ulprotocol == '01' then -- Read Ultralight config only if UL protocol is enabled cardprotocol = 'MIFARE Ultralight/NTAG' block0 = send("3000") uid0 = block0:sub(1,6) uid = uid0..block0:sub(9,16) if ulmode == '00' then ultype = 'Ultralight EV1' elseif ulmode == '01' then ultype = 'NTAG21x' elseif ulmode == '02' then ultype = 'Ultralight-C' elseif ulmode == '03' then ultype = 'Ultralight' end -- read VERSION cversion = send('30FA'):sub(1,16) -- pwdblock must be set since the 30F1 and 30F2 special commands don't work on the ntag21x part of the UMC if ulmode == '03' then versionstr = 'Ultralight' elseif ulmode == '02' then versionstr = 'Ultralight-C' elseif cversion == '0004030101000B03' then versionstr = 'UL EV1 48b' elseif cversion == '0004030101000E03' then versionstr = 'UL EV1 128b' elseif cversion == '0004040101000B03' then versionstr = 'NTAG 210' elseif cversion == '0004040101000E03' then versionstr = 'NTAG 212' elseif cversion == '0004040201000F03' then versionstr = 'NTAG 213' elseif cversion == '0004040201001103' then versionstr = 'NTAG 215' elseif cversion == '0004040201001303' then versionstr = 'NTAG 216' elseif cversion == '0004040502011303' then versionstr = 'NTAG I2C 1K' elseif cversion == '0004040502011503' then versionstr = 'NTAG I2C 2K' elseif cversion == '0004040502021303' then versionstr = 'NTAG I2C 1K PLUS' elseif cversion == '0004040502021503' then versionstr = 'NTAG I2C 2K PLUS' elseif cversion == '0004040401000F03' then versionstr = 'NTAG 213F' elseif cversion == '0004040401001303' then versionstr = 'NTAG 216F' end -- read PWD cpwd = send("30F0"):sub(1,8) pwd = send("30E5"):sub(1,8) -- 04 response indicates that blocks has been locked down. if pwd == '04' then lib14a.disconnect(); return nil, "can't read configuration, "..err_lock end -- read PACK cpack = send("30F1"):sub(1,4) pack = send("30E6"):sub(1,4) -- read SIGNATURE signature1 = send('30F2'):sub(1,32) signature2 = send('30F6'):sub(1,32) lib14a.disconnect() end if _print < 1 then print(string.rep('=', 88)) print('\t\t\tUltimate Magic Card Configuration') print(string.rep('=', 88)) print(' - Raw Config ', string.sub(magicconfig, 1, -9)) print(' - Card Protocol ', cardprotocol) print(' - Ultralight Mode ', ultype) print(' - ULM Backdoor Key ', readpass) print(' - GTU Mode ', gtustr) if ulprotocol == '01' then print(' - Card Type ', versionstr) else print(' - Card Type ', cardtype) end print(' - UID ', uid) print(' - ATQA ', atqaf) print(' - SAK ', sak) if ulprotocol == '01' then print('') print(string.rep('=', 88)) print('\t\t\tMagic UL/NTAG 21* Configuration') print(string.rep('=', 88)) print(' - ATS ', atsstr) print(' - Password ', '[0xE5] '..pwd, '[0xF0] '..cpwd) print(' - Pack ', '[0xE6] '..pack, '[0xF1] '..cpack) print(' - Version ', cversion) print(' - Signature ', signature1..signature2) end end lib14a.disconnect() return true, 'Ok' end -- -- Writes a UID for MFC and MFUL/NTAG cards local function write_uid(useruid) -- read CONFIG if not magicconfig then _print = 1 read_config() end local info = connect() if not info then return false, "Can't select card" end -- Writes a MFC UID with GEN4 magic commands. if ulprotocol == '00' then -- uid string checks if useruid == nil then return nil, 'empty uid string' end if #useruid == 0 then return nil, 'empty uid string' end if (#useruid ~= 8) and (#useruid ~= 14) then return nil, 'UID wrong length. Should be 4 or 7 hex bytes' end print('Writing new UID ', useruid) local uidbytes = utils.ConvertHexToBytes(useruid) local bcc1 = bxor(bxor(bxor(uidbytes[1], uidbytes[2]), uidbytes[3]), uidbytes[4]) local block0 = string.format('%02X%02X%02X%02X%02X', uidbytes[1], uidbytes[2], uidbytes[3], uidbytes[4], bcc1) local resp = send('CF'.._key..'CD00'..block0) -- Writes a MFUL UID with bcc1, bcc2 using NTAG21xx commands. elseif ulprotocol == '01' then -- uid string checks if useruid == nil then return nil, 'empty uid string' end if #useruid == 0 then return nil, 'empty uid string' end if #useruid ~= 14 then return nil, 'uid wrong length. Should be 7 hex bytes' end print('Writing new UID ', useruid) local uidbytes = utils.ConvertHexToBytes(useruid) local bcc1 = bxor(bxor(bxor(uidbytes[1], uidbytes[2]), uidbytes[3]), 0x88) local bcc2 = bxor(bxor(bxor(uidbytes[4], uidbytes[5]), uidbytes[6]), uidbytes[7]) local block0 = string.format('%02X%02X%02X%02X', uidbytes[1], uidbytes[2], uidbytes[3], bcc1) local block1 = string.format('%02X%02X%02X%02X', uidbytes[4], uidbytes[5], uidbytes[6], uidbytes[7]) local block2 = string.format('%02X%02X%02X%02X', bcc2, 0x48, 0x00, 0x00) local resp resp = send('A200'..block0) resp = send('A201'..block1) resp = send('A202'..block2) else print('Incorrect ul') end lib14a.disconnect() if resp ~= nil then return nil, oops('Failed to write UID') else return true, 'Ok' end end --- -- Write ATQA/SAK local function write_atqasak(atqasak) -- read CONFIG if not magicconfig then _print = 1 read_config() end if atqasak == nil then return nil, 'Empty ATQA/SAK string' end if #atqasak == 0 then return nil, 'Empty ATQA/SAK string' end if #atqasak ~= 6 then return nil, 'ATQA/SAK wrong length. Should be 6 hex bytes. I.E. 004408 ATQA(0044) SAK(08)' end local atqauser1 = atqasak:sub(1,2) local atqauser2 = atqasak:sub(3,4) local atqauserf = atqauser2..atqauser1 local sakuser = atqasak:sub(5,6) if sakuser == '04' then print('Never set SAK bit 3 (e.g. SAK=04), it indicates an extra cascade level is required') return nil elseif (sakuser == '20' or sakuser == '28') and atslen == '00' then print('When SAK equals 20 or 28, ATS must be turned on') return nil elseif atqauser2 == '40' then print('ATQA of [00 40] will cause the card to not answer.') return nil else local info = connect() if not info then return false, "Can't select card" end print('New ATQA: '..atqauser1..' '..atqauser2..' New SAK: '..sakuser) local resp = send("CF".._key.."35"..atqauserf..sakuser) lib14a.disconnect() if resp == nil then return nil, oops('Failed to write ATQA/SAK') else return true, 'Ok' end end end --- -- Write NTAG PWD local function write_ntagpwd(ntagpwd) -- read CONFIG if not magicconfig then _print = 1 read_config() end if ulprotocol == '00' then return nil, 'Magic Card is not using the Ultralight Protocol' end -- PWD string checks if ntagpwd == nil then return nil, 'empty NTAG PWD string' end if #ntagpwd == 0 then return nil, 'empty NTAG PWD string' end if #ntagpwd ~= 8 then return nil, 'NTAG PWD wrong length. Should be 4 hex bytes' end local info = connect() if not info then return false, "Can't select card" end print('Writing new NTAG PWD ', ntagpwd) local resp = send('A2E5'..ntagpwd) -- must add both for password to be read by the reader command B1 local resp = send('A2F0'..ntagpwd) lib14a.disconnect() if resp == nil then return nil, 'Failed to write password' else return true, 'Ok' end end --- -- Write PACK local function write_pack(userpack) -- read CONFIG if not magicconfig then _print = 1 read_config() end if ulprotocol == 0 then return nil, 'Magic Card is not using the Ultralight Protocol' end -- PACK string checks if userpack == nil then return nil, 'empty PACK string' end if #userpack == 0 then return nil, 'empty PACK string' end if #userpack ~= 4 then return nil, 'PACK wrong length. Should be 4 hex bytes' end local info = connect() if not info then return false, "Can't select card" end print('Writing new PACK', userpack) send('A2E6'..userpack..'0000') send('A2F1'..userpack..'0000') lib14a.disconnect() return true, 'Ok' end --- -- Write OTP block local function write_otp(block3) -- OTP string checks if block3 == nil then return nil, 'empty OTP string' end if #block3 == 0 then return nil, 'empty OTP string' end if #block3 ~= 8 then return nil, 'OTP wrong length. Should be 4 hex bytes' end -- read CONFIG if not magicconfig then _print = 1 read_config() end if ulprotocol == '00' then return nil, 'Magic Card is not using the Ultralight Protocol' end local info = connect() if not info then return false, "Can't select card" end print('Writing new OTP ', block3) local resp = send('A203'..block3) lib14a.disconnect() if resp ~= '0A' then return false, oops('Failed to write OTP') else return true, 'Ok' end end --- -- Write VERSION data, -- make sure you have correct version data local function write_version(data) -- Version string checks if data == nil then return nil, 'empty version string' end if #data == 0 then return nil, 'empty version string' end if #data ~= 16 then return nil, 'version wrong length. Should be 8 hex bytes' end -- read CONFIG if not magicconfig then _print = 1 read_config() end if ulprotocol == '00' then return nil, 'Magic Card is not using the Ultralight Protocol' end print('Writing new version', data) local b1 = data:sub(1,8) local b2 = data:sub(9,16) local info = connect() if not info then return false, "Can't select card" end local resp resp = send('A2FA'..b1) resp = send('A2FB'..b2) lib14a.disconnect() if resp ~= '0A' then return nil, oops('Failed to write version') else return true, 'Ok' end end --- -- Write SIGNATURE data local function write_signature(data) -- Signature string checks if data == nil then return nil, 'empty data string' end if #data == 0 then return nil, 'empty data string' end if #data ~= 64 then return nil, 'data wrong length. Should be 32 hex bytes' end -- read CONFIG if not magicconfig then _print = 1 read_config() end local info = connect() if not info then return false, "Can't select card" end if ulprotocol == '00' then return nil, 'Magic Card is not using the Ultralight Protocol' end print('Writing new signature',data) local b,c local cmd = 'A2F%d%s' local j = 2 for i = 1, #data, 8 do b = data:sub(i,i+7) c = cmd:format(j,b) local resp = send(c) if resp ~= '0A' then lib14a.disconnect(); return nil, oops('Failed to write signature') end j = j + 1 end lib14a.disconnect() return true, 'Ok' end --- -- Enable/Disable GTU Mode -- 00: pre-write, 01: restore mode, 02: disabled, 03: disabled, high speed R/W mode for Ultralight local function write_gtu(gtu) if gtu == nil then return nil, 'empty GTU string' end if #gtu == 0 then return nil, 'empty GTU string' end if #gtu ~= 2 then return nil, 'type wrong length. Should be 1 hex byte' end local info = connect() if not info then return false, "Can't select card" end if gtu == '00' then print('Enabling GTU Pre-Write') send('CF'.._key..'32'..gtu) elseif gtu == '01' then print('Enabling GTU Restore Mode') send('CF'.._key..'32'..gtu) elseif gtu == '02' then print('Disabled GTU') send('CF'.._key..'32'..gtu) elseif gtu == '03' then print('Disabled GTU, high speed R/W mode for Ultralight') send('CF'.._key..'32'..gtu) else print('Failed to set GTU mode') end lib14a.disconnect() return true, 'Ok' end --- -- Write ATS -- First hexbyte is length. 00 to disable ATS. 16 hexbytes for ATS local function write_ats(atsuser) if atsuser == nil then return nil, 'empty ATS string' end if #atsuser == 0 then return nil, 'empty ATS string' end if #atsuser > 34 then return nil, 'type wrong length. Should be <1b length><0-16b ATS> hex byte' end local atscardlen = atsuser:sub(1,2) local atscardlendecimal = tonumber(atscardlen, 16) local atsf = string.sub(atsuser, 3) if (#atsf / 2) ~= atscardlendecimal then oops('Given length of ATS ('..atscardlendecimal..') does not match the ATS_length ('..(#atsf / 2)..')') return true, 'Ok' else local info = connect() if not info then return false, "Can't select card" end print('Writing '..atscardlendecimal..' ATS bytes of '..atsf) send("CF".._key.."34"..atsuser) end lib14a.disconnect() return true, 'Ok' end --- -- Change UL/MFC protocol local function write_ulp(ulp) if ulp == nil then return nil, 'empty ULP string' end if #ulp == 0 then return nil, 'empty ULP string' end if #ulp > 2 then return nil, 'type wrong length. Should be 1 hex byte' end local info = connect() if not info then return false, "Can't select card" end if ulp == '00' then print('Changing card to Mifare Classic Protocol') send("CF".._key.."69"..ulp) elseif ulp == '01' then print('Changing card to Ultralight Protocol') send("CF".._key.."69"..ulp) else oops('Protocol needs to be either 00 or 01') end lib14a.disconnect() return true, 'Ok' end --- -- Change UL Mode Type local function write_ulm(ulm) if ulm == nil then return nil, 'empty ULM string' end if #ulm == 0 then return nil, 'empty ULM string' end if #ulm > 2 then return nil, 'type wrong length. Should be 1 hex byte' end local info = connect() if not info then return false, "Can't select card" end if ulm == '00' then print('Changing card UL mode to Ultralight EV1') send("CF".._key.."6A"..ulm) elseif ulm == '01' then print('Changing card UL mode to NTAG') send("CF".._key.."6A"..ulm) elseif ulm == '02' then print('Changing card UL mode to Ultralight-C') send("CF".._key.."6A"..ulm) elseif ulm == '03' then print('Changing card UL mode to Ultralight') send("CF".._key.."6A"..ulm) else oops('UL mode needs to be either 00, 01, 02, 03') end lib14a.disconnect() return true, 'Ok' end --- -- Set type for magic card presets. local function set_type(tagtype) -- tagtype checks if type(tagtype) == 'string' then tagtype = tonumber(tagtype, 10) end if tagtype == nil then return nil, oops('empty tagtype') end -- Setting Mifare mini S20 4-byte if tagtype == 1 then print('Setting: Ultimate Magic card to Mifare mini S20 4-byte') connect() send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000900") lib14a.disconnect() write_uid('04112233') -- Setting Mifare mini S20 7-byte elseif tagtype == 2 then print('Setting: Ultimate Magic card to Mifare mini S20 7-byte') connect() send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000900") lib14a.disconnect() write_uid('04112233445566') -- Setting Mifare 1k S50 4--byte elseif tagtype == 3 then print('Setting: Ultimate Magic card to Mifare 1k S50 4-byte') connect() send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000800") lib14a.disconnect() write_uid('04112233') -- Setting Mifare 1k S50 7-byte elseif tagtype == 4 then print('Setting: Ultimate Magic card to Mifare 1k S50 7-byte') connect() send("CF".._key.."F000010000000002000978009102DABC19101011121314151644000800") lib14a.disconnect() write_uid('04112233445566') -- Setting Mifare 4k S70 4-byte elseif tagtype == 5 then print('Setting: Ultimate Magic card to Mifare 4k S70 4-byte') connect() send("CF".._key.."F000000000000002000978009102DABC19101011121314151602001800") lib14a.disconnect() write_uid('04112233') -- Setting Mifare 4k S70 7-byte elseif tagtype == 6 then print('Setting: Ultimate Magic card to Mifare 4k S70 7-byte') connect() send("CF".._key.."F000010000000002000978009102DABC19101011121314151642001800") lib14a.disconnect() write_uid('04112233445566') -- Setting UL elseif tagtype == 7 then print('Setting: Ultimate Magic card to UL') connect() send("CF".._key.."F0010100000000030A0A78008102DBA0C119402AB5BA4D321A44000003") lib14a.disconnect() write_uid('04112233445566') write_otp('00000000') -- Setting OTP to default 00 00 00 00 write_version('0000000000000000') -- UL-C does not have a version -- Setting UL-C elseif tagtype == 8 then print('Setting: Ultimate Magic card to UL-C') connect() send("CF".._key.."F0010100000000030A0A78008102DBA0C119402AB5BA4D321A44000002") print('Setting default permissions and 3des key') send('A22A30000000') -- Auth0 page 48/0x30 and above need authentication send('A22B80000000') -- Auth1 read and write access restricted send('A22C42524541') -- Default 3des key send('A22D4B4D4549') send('A22E46594F55') send('A22F43414E21') lib14a.disconnect() write_uid('04112233445566') write_otp('00000000') -- Setting OTP to default 00 00 00 00 write_version('0000000000000000') -- UL-C does not have a version elseif tagtype == 9 then print('Setting: Ultimate Magic card to UL-EV1 48') connect() send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000000") -- Setting UL-Ev1 default config bl 16,17 send('a2E5FFFFFFFF') -- A2F0 block does not align correctly to actual pwd block send('a2E6FFFFFFFF') -- A2F1 block does not align correctly to actual pack block send('a210000000FF') send('a21100050000') lib14a.disconnect() write_uid('04112233445566') write_otp('00000000') -- Setting OTP to default 00 00 00 00 write_version('0004030101000b03') -- UL-EV1 (48) 00 04 03 01 01 00 0b 03 elseif tagtype == 10 then print('Setting: Ultimate Magic card to UL-EV1 128') connect() send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000000") -- Setting UL-Ev1 default config bl 37,38 send('a2E5FFFFFFFF') -- A2F0 block does not align correctly to actual pwd block send('a2E6FFFFFFFF') -- A2F1 block does not align correctly to actual pack block send('a225000000FF') send('a22600050000') lib14a.disconnect() write_uid('04112233445566') write_otp('00000000') -- Setting OTP to default 00 00 00 00 write_version('0004030101000e03') -- UL-EV1 (128) 00 04 03 01 01 00 0e 03 elseif tagtype == 12 then print('Setting: Ultimate Magic card to NTAG 210') connect() send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") -- Setting NTAG210 default CC block456 send('a203e1100600') send('a2040300fe00') send('a20500000000') -- Setting cfg1/cfg2 send('a210000000FF') send('a21100050000') lib14a.disconnect() write_uid('04112233445566') write_version('0004040101000b03') -- NTAG210 00 04 04 01 01 00 0b 03 elseif tagtype == 13 then print('Setting: Ultimate Magic card to NTAG 212') connect() send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") -- Setting NTAG212 default CC block456 send('a203e1101000') send('a2040103900a') send('a205340300fe') -- Setting cfg1/cfg2 send('a225000000FF') send('a22600050000') lib14a.disconnect() write_uid('04112233445566') write_version('0004040101000E03') -- NTAG212 00 04 04 01 01 00 0E 03 elseif tagtype == 14 then print('Setting: Ultimate Magic card to NTAG 213') connect() send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") -- Setting NTAG213 default CC block456 send('a203e1101200') send('a2040103a00c') send('a205340300fe') -- setting cfg1/cfg2 send('a229000000ff') send('a22a00050000') lib14a.disconnect() write_uid('04112233445566') write_version('0004040201000F03') -- NTAG213 00 04 04 02 01 00 0f 03 elseif tagtype == 15 then print('Setting: Ultimate Magic card to NTAG 215') connect() send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") -- Setting NTAG215 default CC block456 send('a203e1103e00') send('a2040300fe00') send('a20500000000') -- setting cfg1/cfg2 send('a283000000ff') send('a28400050000') lib14a.disconnect() write_uid('04112233445566') write_version('0004040201001103') -- NTAG215 00 04 04 02 01 00 11 03 elseif tagtype == 16 then print('Setting: Ultimate Magic card to NTAG 216') connect() send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") -- Setting NTAG216 default CC block456 send('a203e1106d00') send('a2040300fe00') send('a20500000000') -- setting cfg1/cfg2 send('a2e3000000ff') send('a2e400050000') lib14a.disconnect() write_uid('04112233445566') write_version('0004040201001303') -- NTAG216 00 04 04 02 01 00 13 03 elseif tagtype == 17 then print('Setting: Ultimate Magic card to NTAG I2C 1K') connect() send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") -- Setting NTAG I2C 1K default CC block456 send('a203e1106D00') send('a2040300fe00') send('a20500000000') lib14a.disconnect() write_uid('04112233445566') write_version('0004040502011303') -- NTAG_I2C_1K 00 04 04 05 02 01 13 03 elseif tagtype == 18 then print('Setting: Ultimate Magic card to NTAG I2C 2K') connect() send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") -- Setting NTAG I2C 2K default CC block456 send('a203e110EA00') send('a2040300fe00') send('a20500000000') lib14a.disconnect() write_uid('04112233445566') write_version('0004040502011503') -- NTAG_I2C_2K 00 04 04 05 02 01 15 03 elseif tagtype == 19 then print('Setting: Ultimate Magic card to NTAG I2C plus 1K') connect() send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") -- Setting NTAG I2C 1K default CC block456 send('a203e1106D00') send('a2040300fe00') send('a20500000000') lib14a.disconnect() write_uid('04112233445566') write_version('0004040502021303') -- NTAG_I2C_1K 00 04 04 05 02 02 13 03 elseif tagtype == 20 then print('Setting: Ultimate Magic card to NTAG I2C plus 2K') connect() send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") -- Setting NTAG I2C 2K default CC block456 send('a203e1106D00') send('a2040300fe00') send('a20500000000') write_uid('04112233445566') write_version('0004040502021503') -- NTAG_I2C_2K 00 04 04 05 02 02 15 03 elseif tagtype == 21 then print('Setting: Ultimate Magic card to NTAG 213F') connect() send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") -- Setting NTAG213 default CC block456 send('a203e1101200') send('a2040103a00c') send('a205340300fe') -- setting cfg1/cfg2 send('a229000000ff') send('a22a00050000') lib14a.disconnect() write_uid('04112233445566') write_version('0004040401000F03') -- NTAG213F 00 04 04 04 01 00 0f 03 elseif tagtype == 22 then print('Setting: Ultimate Magic card to NTAG 216F') connect() send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") -- Setting NTAG216 default CC block456 send('a203e1106d00') send('a2040300fe00') send('a20500000000') -- setting cfg1/cfg2 send('a2e3000000ff') send('a2e400050000') lib14a.disconnect() write_uid('04112233445566') write_version('0004040401001303') -- NTAG216F 00 04 04 04 01 00 13 03 else oops('No matching tag types') end lib14a.disconnect() if resp == '04' then return nil, 'Failed to set type' else return true, 'Ok' end end --- -- returns true if b is the index of a sector trailer local function mfIsSectorTrailer(b) n=b+1 if (n < 32*4 ) then if (n % 4 == 0) then return true else return false end end if (n % 16 == 0) then return true end return false end --- -- wipe tag local function wipe(wtype) local info = connect() if not info then return false, "Can't select card" end if wtype == '0' then print('Starting Mifare Wipe') send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000800") send("CF".._key.."CD000102030404080400000000000000BEAF") local err, msg, resp local cmd_empty = 'CF'.._key..'CD%02X00000000000000000000000000000000' local cmd_trail = 'CF'.._key..'CD%02XFFFFFFFFFFFFFF078069FFFFFFFFFFFF' for b = 1, 0xFF do if mfIsSectorTrailer(b) then local cmd = (cmd_trail):format(b) resp = send(cmd) else local cmd = (cmd_empty):format(b) resp = send(cmd) end if resp == nil then io.write('\nwrote block '..b, ' failed\n') err = true else io.write('.') end io.flush() end print('\n') err, msg = set_type(3) if err == nil then return err, msg end lib14a.disconnect() return true, 'Ok' elseif wtype == '1' then print('Starting Ultralight Wipe') local err, msg, resp local cmd_empty = 'A2%02X00000000' local cmd_cfg1 = 'A2%02X000000FF' local cmd_cfg2 = 'A2%02X00050000' print('Wiping tag') local info = connect() if not info then return false, "Can't select card" end send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001") for b = 3, 0xFB do --configuration block 0 if b == 0x29 or b == 0x83 or b == 0xe3 then local cmd = (cmd_cfg1):format(b) resp = send(cmd) --configuration block 1 elseif b == 0x2a or b == 0x84 or b == 0xe4 then local cmd = (cmd_cfg2):format(b) resp = send(cmd) else resp = send(cmd_empty:format(b)) end if resp == '04' or #resp == 0 then io.write('\nwrote block '..b, ' failed\n') err = true else io.write('.') end io.flush() end io.write('\r\n') lib14a.disconnect() print('\n') if err then return nil, "Tag locked down, "..err_lock end -- set NTAG213 default values err, msg = set_type(14) if err == nil then return err, msg end --set UID err, msg = write_uid('04112233445566') if err == nil then return err, msg end --set NTAG pwd err, msg = write_ntagpwd('FFFFFFFF') if err == nil then return err, msg end --set pack err, msg = write_pack('0000') if err == nil then return err, msg end lib14a.disconnect() return true, 'Ok' else oops('Use 0 for Mifare wipe or 1 for Ultralight wipe') end end --- -- The main entry point function main(args) print() local err, msg if #args == 0 then return help() end -- Read the parameters for o, a in getopt.getopt(args, 'hck:u:t:p:a:s:o:v:q:g:z:n:m:w:') do -- help if o == "h" then return help() end -- set Ultimate Magic Card Key for read write if o == "k" then err, msg = set_key(a) end -- configuration if o == "c" then err, msg = read_config() end -- wipe tag if o == "w" then err, msg = wipe(a) end -- write uid if o == "u" then err, msg = write_uid(a) end -- write type/version if o == "t" then err, msg = set_type(a) end -- write NTAG pwd if o == "p" then err, msg = write_ntagpwd(a) end -- write pack if o == "a" then err, msg = write_pack(a) end -- write signature if o == "s" then err, msg = write_signature(a) end -- write otp if o == "o" then err, msg = write_otp(a) end -- write version if o == "v" then err, msg = write_version(a) end -- write atqa/sak if o == "q" then err, msg = write_atqasak(a) end -- write gtu mode if o == "g" then err, msg = write_gtu(a) end -- write ats if o == "z" then err, msg = write_ats(a) end -- write UL mode if o == "m" then err, msg = write_ulm(a) end -- write UL protocol if o == "n" then err, msg = write_ulp(a) end if err == nil then return oops(msg) end end end main(args)