From bd5d0f07e9330f18088f626bc1d18857aeaeaa8e Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 14 Nov 2014 13:24:45 +0100 Subject: [PATCH] REN: renamed tnp3.lua to tnp3dump.lua since that name is more explainatory ADD: added tnp3sim.lua a script which loads a dump and sends it to the pm3 device memory. --- client/cmdhfmf.c | 1 + client/scripts/test.lua | 10 - client/scripts/{tnp3.lua => tnp3dump.lua} | 17 +- client/scripts/tnp3sim.lua | 383 ++++++++++++++++++++++ 4 files changed, 392 insertions(+), 19 deletions(-) delete mode 100644 client/scripts/test.lua rename client/scripts/{tnp3.lua => tnp3dump.lua} (94%) create mode 100644 client/scripts/tnp3sim.lua diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 901ccd49..35bf2a00 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1623,6 +1623,7 @@ int CmdHF14AMfEKeyPrn(const char *Cmd) if (mfEmlGetMem(data, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1)) { PrintAndLog("error get block %d", FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1); break; + break; } keyA = bytes_to_num(data, 6); keyB = bytes_to_num(data + 10, 6); diff --git a/client/scripts/test.lua b/client/scripts/test.lua deleted file mode 100644 index 76adc985..00000000 --- a/client/scripts/test.lua +++ /dev/null @@ -1,10 +0,0 @@ -local foo = "This shows how to use some standard libraries" -print(foo) -local answer -repeat - io.write("Continue with this operation (y/n)? ") - io.flush() - answer=io.read() -until answer=="y" or answer=="n" -local x = "Ok then, %s" -print (x:format("whatever")) \ No newline at end of file diff --git a/client/scripts/tnp3.lua b/client/scripts/tnp3dump.lua similarity index 94% rename from client/scripts/tnp3.lua rename to client/scripts/tnp3dump.lua index 77de766f..520161b9 100644 --- a/client/scripts/tnp3.lua +++ b/client/scripts/tnp3dump.lua @@ -8,16 +8,16 @@ local dumplib = require('html_dumplib') local toyNames = require('default_toys') example =[[ - 1. script run tnp3 - 2. script run tnp3 -n - 3. script run tnp3 -k aabbccddeeff - 4. script run tnp3 -k aabbccddeeff -n - 5. script run tnp3 -o myfile - 6. script run tnp3 -n -o myfile - 7. script run tnp3 -k aabbccddeeff -n -o myfile + 1. script run tnp3dump + 2. script run tnp3dump -n + 3. script run tnp3dump -k aabbccddeeff + 4. script run tnp3dump -k aabbccddeeff -n + 5. script run tnp3dump -o myfile + 6. script run tnp3dump -n -o myfile + 7. script run tnp3dump -k aabbccddeeff -n -o myfile ]] author = "Iceman" -usage = "script run tnp3 -k -n -o " +usage = "script run tnp3dump -k -n -o " desc =[[ This script will try to dump the contents of a Mifare TNP3xxx card. It will need a valid KeyA in order to find the other keys and decode the card. @@ -216,7 +216,6 @@ local function main(args) local hex = utils.ConvertAsciiToBytes(aestest) hex = utils.ConvertBytesToHex(hex) - --local _,hex = bin.unpack(("H%d"):format(16),aestest) -- blocks with zero not encrypted. if string.find(blockdata, '^0+$') then diff --git a/client/scripts/tnp3sim.lua b/client/scripts/tnp3sim.lua new file mode 100644 index 00000000..ce772022 --- /dev/null +++ b/client/scripts/tnp3sim.lua @@ -0,0 +1,383 @@ +local cmds = require('commands') +local getopt = require('getopt') +local bin = require('bin') +local lib14a = require('read14a') +local utils = require('utils') +local md5 = require('md5') +local toyNames = require('default_toys') + +example =[[ + 1. script run tnp3sim + 2. script run tnp3sim -m + 3. script run tnp3sim -m -i myfile +]] +author = "Iceman" +usage = "script run tnp3sim -h -m -i " +desc =[[ +This script will try to dump the contents of a Mifare TNP3xxx card. +It will need a valid KeyA in order to find the other keys and decode the card. +Arguments: + -h : this help + -m : Maxed out item + -i : filename for the datadump to read (bin) +]] + +local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' + +local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds +local DEBUG = true -- the debug flag +--- +-- A debug printout-function +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 +function oops(err) + print("ERROR: ",err) +end +--- +-- Usage help +function help() + print(desc) + print("Example usage") + print(example) +end +-- +-- Exit message +function ExitMsg(msg) + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() +end + +local function writedumpfile(infile) + t = infile:read("*all") + len = string.len(t) + local len,hex = bin.unpack(("H%d"):format(len),t) + return hex +end +-- blocks with data +-- there are two dataareas, in block 8 or block 36, ( 1==8 , +-- checksum type = 0, 1, 2, 3 +local function GetCheckSum(blocks, dataarea, chksumtype) + + local crc + local area = 36 + if dataarea == 1 then + area = 8 + end + + if chksumtype == 0 then + crc = blocks[1]:sub(29,32) + elseif chksumtype == 1 then + crc = blocks[area]:sub(29,32) + elseif chksumtype == 2 then + crc = blocks[area]:sub(25,28) + elseif chksumtype == 3 then + crc = blocks[area]:sub(21,24) + end + return utils.SwapEndianness(crc,16) +end + +local function SetCheckSum(blocks, chksumtype) + + if blocks == nil then return nil, 'Argument \"blocks\" nil' end + local newcrc + local area1 = 8 + local area2 = 36 + + if chksumtype == 0 then + newcrc = ('%04X'):format(CalcCheckSum(blocks,1,0)) + blocks[1] = blocks[1]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2) + elseif chksumtype == 1 then + newcrc = ('%04X'):format(CalcCheckSum(blocks,1,1)) + blocks[area1] = blocks[area1]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2) + newcrc = ('%04X'):format(CalcCheckSum(blocks,2,1)) + blocks[area2] = blocks[area2]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2) + elseif chksumtype == 2 then + newcrc = ('%04X'):format(CalcCheckSum(blocks,1,2)) + blocks[area1] = blocks[area1]:sub(1,24)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area1]:sub(29,32) + newcrc = ('%04X'):format(CalcCheckSum(blocks,2,2)) + blocks[area2] = blocks[area2]:sub(1,24)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area2]:sub(29,32) + elseif chksumtype == 3 then + newcrc = ('%04X'):format(CalcCheckSum(blocks,1,3)) + blocks[area1] = blocks[area1]:sub(1,20)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area1]:sub(25,32) + newcrc = ('%04X'):format(CalcCheckSum(blocks,2,3)) + blocks[area2] = blocks[area2]:sub(1,20)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area2]:sub(25,32) + end +end + +function CalcCheckSum(blocks, dataarea, chksumtype) + local area = 36 + if dataarea == 1 then + area = 8 + end + + if chksumtype == 0 then + data = blocks[0]..blocks[1]:sub(1,28) + elseif chksumtype == 1 then + data = blocks[area]:sub(1,28)..'0500' + elseif chksumtype == 2 then + data = blocks[area+1]..blocks[area+2]..blocks[area+4] + elseif chksumtype == 3 then + data = blocks[area+5]..blocks[area+6]..blocks[area+8]..string.rep('00',0xe0) + end + return utils.Crc16(data) +end + +local function ValidateCheckSums(blocks) + + local isOk, crc, calc + -- Checksum Type 0 + crc = GetCheckSum(blocks,1,0) + calc = CalcCheckSum(blocks, 1, 0) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 0 : %04x = %04x -- %s\n'):format(crc,calc,isOk)) + + -- Checksum Type 1 (DATAAREAHEADER 1) + crc = GetCheckSum(blocks,1,1) + calc = CalcCheckSum(blocks,1,1) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 1 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk)) + + -- Checksum Type 1 (DATAAREAHEADER 2) + crc = GetCheckSum(blocks,2,1) + calc = CalcCheckSum(blocks,2,1) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 1 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk)) + + -- Checksum Type 2 (DATAAREA 1) + crc = GetCheckSum(blocks,1,2) + calc = CalcCheckSum(blocks,1,2) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 2 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk)) + + -- Checksum Type 2 (DATAAREA 2) + crc = GetCheckSum(blocks,2,2) + calc = CalcCheckSum(blocks,2,2) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 2 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk)) + + -- Checksum Type 3 (DATAAREA 1) + crc = GetCheckSum(blocks,1,3) + calc = CalcCheckSum(blocks,1,3) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 3 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk)) + + -- Checksum Type 3 (DATAAREA 2) + crc = GetCheckSum(blocks,2,3) + calc = CalcCheckSum(blocks,2,3) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 3 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk)) +end + +-- function EncryptData() + -- local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' + -- if blockNo%4 ~= 3 then + -- if blockNo < 8 then + -- -- Block 0-7 not encrypted + -- blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) + -- else + -- local base = ('%s%s%02x%s'):format(block0, block1, blockNo, HASHCONSTANT) + -- local baseStr = utils.ConvertHexToAscii(base) + -- local md5hash = md5.sumhexa(baseStr) + -- local aestest = core.aes(md5hash, blockdata) + + -- local hex = utils.ConvertAsciiToBytes(aestest) + -- hex = utils.ConvertBytesToHex(hex) + -- --local _,hex = bin.unpack(("H%d"):format(16),aestest) + + -- -- blocks with zero not encrypted. + -- if string.find(blockdata, '^0+$') then + -- blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) + -- else + -- blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,hex) + -- io.write( blockNo..',') + -- end + -- end + -- else + -- -- Sectorblocks, not encrypted + -- blocks[blockNo+1] = ('%02d :: %s%s'):format(blockNo,key,blockdata:sub(13,32)) + -- end + +-- end + +local function LoadEmulator(blocks) + local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' + local cmd + local blockdata + for _,b in pairs(blocks) do + + blockdata = b + + if _%4 ~= 3 then + if (_ >= 8 and _<=21) or (_ >= 36 and _<=49) then + local base = ('%s%s%02x%s'):format(blocks[0], blocks[1], _ , HASHCONSTANT) + local baseStr = utils.ConvertHexToAscii(base) + local key = md5.sumhexa(baseStr) + local enc = core.aes(key, blockdata) + local hex = utils.ConvertAsciiToBytes(enc) + hex = utils.ConvertBytesToHex(hex) + + blockdata = hex + io.write( _..',') + end + end + + cmd = Command:new{cmd = cmds.CMD_MIFARE_EML_MEMSET, arg1 = _ ,arg2 = 1,arg3 = 0, data = blockdata} + local err = core.SendCommand(cmd:getBytes()) + if err then + return err + end + end + io.write('\n') +end + +local function main(args) + + print( string.rep('--',20) ) + print( string.rep('--',20) ) + + local result, err, hex + local maxed = false + local inputTemplate = "dumpdata.bin" + local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M"); + + -- Arguments for the script + for o, a in getopt.getopt(args, 'hmi:o:') do + if o == "h" then return help() end + if o == "m" then maxed = true end + if o == "o" then outputTemplate = a end + if o == "i" then inputTemplate = a end + end + + -- Turn off Debug + local cmdSetDbgOff = "hf mf dbg 0" + core.console( cmdSetDbgOff) + + -- Look for tag present on reader, + result, err = lib14a.read1443a(false) + if not result then return oops(err) end + + core.clearCommandBuffer() + + if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx + return oops('This is not a TNP3xxx tag. aborting.') + end + + -- Show tag info + print((' Found tag : %s'):format(result.name)) + + -- Load dump.bin file + print( (' Load data from %s'):format(inputTemplate)) + hex, err = utils.ReadDumpFile(inputTemplate) + if not hex then return oops(err) end + + local blocks = {} + local blockindex = 0 + for i = 1, #hex, 32 do + blocks[blockindex] = hex:sub(i,i+31) + blockindex = blockindex + 1 + end + + if DEBUG then + print('Validating checksums in the loaded datadump') + ValidateCheckSums(blocks) + end + + -- + print( string.rep('--',20) ) + print(' Gathering info') + local uid = blocks[0]:sub(1,8) + local itemtype = blocks[1]:sub(1,4) + local cardid = blocks[1]:sub(9,24) + + -- Show info + print( string.rep('--',20) ) + print( (' ITEM TYPE : 0x%s - %s'):format(itemtype, toyNames[itemtype]) ) + print( (' UID : 0x%s'):format(uid) ) + print( (' CARDID : 0x%s'):format(cardid ) ) + print( string.rep('--',20) ) + + -- lets do something. + -- + local experience = blocks[8]:sub(1,6) + print(('Experience : %d'):format(utils.SwapEndianness(experience,24))) + local money = blocks[8]:sub(7,10) + print(('Money : %d'):format(utils.SwapEndianness(money,16))) + local fairy = blocks[9]:sub(1,8) + --FD0F = Left, FF0F = Right + local path = 'not choosen' + if fairy:sub(2,2) == 'D' then + path = 'Left' + elseif fairy:sub(2,2) == 'F' then + path = 'Right' + end + print(('Fairy : %d [Path: %s] '):format(utils.SwapEndianness(fairy,24),path)) + + local hat = blocks[9]:sub(8,11) + print(('Hat : %d'):format(utils.SwapEndianness(hat,16))) + + --0x0D 0x29 0x0A 0x02 16-bit hero points value. Maximum 100. + local heropoints = blocks[13]:sub(20,23) + print(('Hero points : %d'):format(utils.SwapEndianness(heropoints,16))) + + --0x10 0x2C 0x0C 0x04 32 bit flag value indicating heroic challenges completed. + local challenges = blocks[16]:sub(25,32) + print(('Finished hero challenges : %d'):format(utils.SwapEndianness(challenges,32))) + + if maxed then + print('Lets try to max out some values') + -- max out money, experience + --print (blocks[8]) + blocks[8] = 'FFFFFF'..'FFFF'..blocks[8]:sub(11,32) + blocks[36] = 'FFFFFF'..'FFFF'..blocks[36]:sub(11,32) + --print (blocks[8]) + + -- max out hero challenges + --print (blocks[16]) + blocks[16] = blocks[16]:sub(1,24)..'FFFFFFFF' + blocks[44] = blocks[44]:sub(1,24)..'FFFFFFFF' + --print (blocks[16]) + + -- max out heropoints + --print (blocks[13]) + blocks[13] = blocks[13]:sub(1,19)..'0064'..blocks[13]:sub(24,32) + blocks[41] = blocks[41]:sub(1,19)..'0064'..blocks[41]:sub(24,32) + --print (blocks[13]) + + -- Update Checksums + print('Updating all checksums') + SetCheckSum(blocks, 3) + SetCheckSum(blocks, 2) + SetCheckSum(blocks, 1) + SetCheckSum(blocks, 0) + + print('Validating all checksums') + ValidateCheckSums(blocks) + end + + --Load dumpdata to emulator memory + if DEBUG then + print('Sending dumpdata to emulator memory') + err = LoadEmulator(blocks) + if err then return oops(err) end + core.clearCommandBuffer() + print('The simulation is now prepared. run \"hf mf sim\" ') + end +end +main(args) \ No newline at end of file -- 2.39.2