1 local cmds
= require('commands')
2 local getopt
= require('getopt')
3 local bin
= require('bin')
4 local lib14a
= require('read14a')
5 local utils
= require('utils')
6 local md5
= require('md5')
7 local dumplib
= require('html_dumplib')
8 local toys
= require('default_toys')
9 local ansicolors
= require('ansicolors')
15 This script will try to dump the contents of a Mifare TNP3xxx card.
16 It will need a valid KeyA in order to find the other keys and decode the card.
19 script run hf_mf_tnp3_dump
20 script run hf_mf_tnp3_dump -n
21 script run hf_mf_tnp3_dump -p
22 script run hf_mf_tnp3_dump -k aabbccddeeff
23 script run hf_mf_tnp3_dump -k aabbccddeeff -n
24 script run hf_mf_tnp3_dump -o myfile
25 script run hf_mf_tnp3_dump -n -o myfile
26 script run hf_mf_tnp3_dump -p -o myfile
27 script run hf_mf_tnp3_dump -k aabbccddeeff -n -o myfile
30 script run hf_mf_tnp3_dump [-h] [-k <key>] [-n] [-p] [-o <filename>]
34 -k <key> : Sector 0 Key A.
35 -n : Use the nested cmd to find all keys
36 -p : Use the precalc to find all keys
37 -o : filename for the saved dumps
41 local RANDOM
= '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20'
42 local DEBUG
= false -- the debug flag
46 -- A debug printout-function
47 local function dbg(args
)
48 if not DEBUG
then return end
49 if type(args
) == 'table' then
60 -- This is only meant to be used when errors occur
61 local function oops(err
)
63 core
.clearCommandBuffer()
73 print(ansicolors
.cyan
..'Usage'..ansicolors
.reset
)
75 print(ansicolors
.cyan
..'Arguments'..ansicolors
.reset
)
77 print(ansicolors
.cyan
..'Example usage'..ansicolors
.reset
)
82 local function ExitMsg(msg
)
83 print( string.rep('--',20) )
84 print( string.rep('--',20) )
89 local function readdumpkeys(infile
)
90 t
= infile
:read("*all")
92 local len
,hex
= bin
.unpack(("H%d"):format(len
),t
)
96 local function getblockdata(response
)
98 return nil, 'No response from device'
100 if response
.Status
== PM3_SUCCESS
then
103 return nil, "Couldn't read block.. ["..response
.Status
.."]"
107 local function main(args
)
109 print( string.rep('--',20) )
110 print( string.rep('--',20) )
113 local useNested
= false
114 local usePreCalc
= false
115 local cmdReadBlockString
= 'hf mf rdbl --blk %d -k %s'
116 local outputTemplate
= os
.date("toydump_%Y-%m-%d_%H%M%S");
118 -- Arguments for the script
119 for o
, a
in getopt
.getopt(args
, 'hk:npo:') do
120 if o
== "h" then return help() end
121 if o
== "k" then keyA
= a
end
122 if o
== "n" then useNested
= true end
123 if o
== "p" then usePreCalc
= true end
124 if o
== "o" then outputTemplate
= a
end
127 -- validate input args.
128 keyA
= keyA
or '4b0b20107ccb'
129 if #(keyA
) ~= 12 then
130 return oops( string.format('Wrong length of write key (was %d) expected 12', #keyA
))
134 local cmdSetDbgOff
= "hw dbg -0"
135 core
.console( cmdSetDbgOff
)
138 tag, err
= lib14a
.read(false, true)
139 if not tag then return oops(err
) end
141 core
.clearCommandBuffer()
144 print((' Found tag %s'):format(tag.name
))
146 dbg(('Using keyA : %s'):format(keyA
))
148 --Trying to find the other keys
150 core
.console( ('hf mf nested -t 1 -b 0 --keya -k %s --dumpkeys'):format(keyA
) )
153 core
.clearCommandBuffer()
157 local pre
= require('precalc')
158 akeys
= pre
.GetAll(tag.uid
)
161 local filename
= ('hf-mf-%s-key.bin'):format(tag.uid
);
162 print('loading '..filename
)
163 local hex
, err
= utils
.ReadDumpFile(filename
)
165 print('loading dumpkeys.bin')
166 hex
, err
= utils
.ReadDumpFile('dumpkeys.bin')
171 akeys
= hex
:sub(0,12*16)
176 dbg('Reading block 0')
179 local data
= ('%s%s%s'):format(blockno
, keytype
, keyA
)
180 cmd
= Command
:newNG
{cmd
= cmds
.CMD_HF_MIFARE_READBL
, data
= data
}
181 block0
, err
= getblockdata(cmd
:sendNG(false))
182 if not block0
then return oops(err
) end
184 core
.clearCommandBuffer()
187 dbg('Reading block 1')
189 data
= ('%s%s%s'):format(blockno
, keytype
, keyA
)
190 cmd
= Command
:newNG
{cmd
= cmds
.CMD_HF_MIFARE_READBL
, data
= data
}
191 block1
, err
= getblockdata(cmd
:sendNG(false))
192 if not block1
then return oops(err
) end
194 core
.clearCommandBuffer()
196 local tmpHash
= block0
..block1
..'%02x'..RANDOM
204 io
.write('Reading blocks > ')
205 for blockNo
= 0, numBlocks
-1, 1 do
209 if core
.kbd_enter_pressed() then
210 print("aborted by user")
214 core
.clearCommandBuffer()
216 pos
= (math
.floor( blockNo
/ 4 ) * 12)+1
217 key
= akeys
:sub(pos
, pos
+ 11 )
218 data
= ('%02x%s%s'):format(blockNo
, keytype
, key
)
219 cmd
= Command
:newNG
{cmd
= cmds
.CMD_HF_MIFARE_READBL
, data
= data
}
220 local blockdata
, err
= getblockdata(cmd
:sendNG(false))
221 if not blockdata
then return oops(err
) end
223 if blockNo
%4 ~= 3 then
226 -- Block 0-7 not encrypted
227 blocks
[blockNo
+1] = ('%02d :: %s'):format(blockNo
,blockdata
)
229 -- blocks with zero not encrypted.
230 if string.find(blockdata
, '^0+$') then
231 blocks
[blockNo
+1] = ('%02d :: %s'):format(blockNo
,blockdata
)
233 local baseStr
= utils
.ConvertHexToAscii(tmpHash
:format(blockNo
))
234 local key
= md5
.sumhexa(baseStr
)
235 local aestest
= core
.aes128_decrypt(key
, blockdata
)
236 local hex
= utils
.ConvertAsciiToHex(aestest
)
238 blocks
[blockNo
+1] = ('%02d :: %s'):format(blockNo
,hex
)
239 io
.write(blockNo
..',')
243 -- Sectorblocks, not encrypted
244 blocks
[blockNo
+1] = ('%02d :: %s%s'):format(blockNo
,key
,blockdata
:sub(13,32))
249 core
.clearCommandBuffer()
255 for _
,s
in pairs(blocks
) do
256 local slice
= s
:sub(8,#s
)
257 local str
= utils
.ConvertHexToAscii(slice
)
258 emldata
= emldata
..slice
..'\n'
259 for c
in (str
):gmatch('.') do
260 bindata
[#bindata
+1] = c
264 print( string.rep('--',20) )
266 local uid
= block0
:sub(1,8)
267 local toytype
= block1
:sub(1,4)
268 local cardidLsw
= block1
:sub(9,16)
269 local cardidMsw
= block1
:sub(16,24)
270 local cardid
= block1
:sub(9,24)
271 local subtype
= block1
:sub(25,28)
273 -- Write dump to files
275 local foo
= dumplib
.SaveAsBinary(bindata
, outputTemplate
..'-'..uid
..'.bin')
276 print(("Wrote a BIN dump to: %s"):format(foo
))
277 local bar
= dumplib
.SaveAsText(emldata
, outputTemplate
..'-'..uid
..'.eml')
278 print(("Wrote a EML dump to: %s"):format(bar
))
281 print( string.rep('--',20) )
284 local item
= toys
.Find(toytype
, subtype
)
286 print((' ITEM TYPE : %s - %s (%s)'):format(item
[6],item
[5], item
[4]) )
288 print((' ITEM TYPE : 0x%s 0x%s'):format(toytype
, subtype
))
291 print( (' UID : 0x%s'):format(uid
) )
292 print( (' CARDID : 0x%s'):format(cardid
) )
293 print( string.rep('--',20) )
295 core
.clearCommandBuffer()