]>
Commit | Line | Data |
---|---|---|
c15d2bdc | 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 | ||
8 | example =[[ | |
9 | 1. script run tnp3 | |
10 | 2. script run tnp3 -k aabbccddeeff | |
11 | ]] | |
12 | author = "Iceman" | |
13 | usage = "script run tnp3 -k <key>" | |
14 | desc =[[ | |
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. | |
17 | Arguments: | |
18 | -h - this help | |
19 | -k <key> - Sector 0 Key A. | |
20 | ]] | |
21 | ||
22 | local hashconstant = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' | |
23 | ||
24 | local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds | |
25 | local DEBUG = true -- the debug flag | |
26 | local numBlocks = 64 | |
27 | local numSectors = 16 | |
28 | --- | |
29 | -- A debug printout-function | |
30 | function dbg(args) | |
31 | if not DEBUG then | |
32 | return | |
33 | end | |
34 | ||
35 | if type(args) == "table" then | |
36 | local i = 1 | |
37 | while result[i] do | |
38 | dbg(result[i]) | |
39 | i = i+1 | |
40 | end | |
41 | else | |
42 | print("###", args) | |
43 | end | |
44 | end | |
45 | --- | |
46 | -- This is only meant to be used when errors occur | |
47 | function oops(err) | |
48 | print("ERROR: ",err) | |
49 | end | |
50 | --- | |
51 | -- Usage help | |
52 | function help() | |
53 | print(desc) | |
54 | print("Example usage") | |
55 | print(example) | |
56 | end | |
57 | -- | |
58 | -- Exit message | |
59 | function ExitMsg(msg) | |
60 | print( string.rep('--',20) ) | |
61 | print( string.rep('--',20) ) | |
62 | print(msg) | |
63 | print() | |
64 | end | |
65 | ||
66 | local function show(data) | |
67 | if DEBUG then | |
68 | local formatString = ("H%d"):format(string.len(data)) | |
69 | local _,hexdata = bin.unpack(formatString, data) | |
70 | dbg("Hexdata" , hexdata) | |
71 | end | |
72 | end | |
73 | ||
74 | function waitCmd() | |
75 | local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) | |
76 | if response then | |
77 | local count,cmd,arg0 = bin.unpack('LL',response) | |
78 | if(arg0==1) then | |
79 | local count,arg1,arg2,data = bin.unpack('LLH511',response,count) | |
80 | return data:sub(1,32) | |
81 | else | |
82 | return nil, "Couldn't read block.." | |
83 | end | |
84 | end | |
85 | return nil, "No response from device" | |
86 | end | |
87 | ||
88 | local function main(args) | |
89 | ||
90 | print( string.rep('--',20) ) | |
91 | print( string.rep('--',20) ) | |
92 | print() | |
93 | ||
94 | local keyA | |
95 | local cmd | |
96 | local err | |
97 | local cmdReadBlockString = 'hf mf rdbl %d A %s' | |
98 | ||
99 | -- Arguments for the script | |
100 | for o, a in getopt.getopt(args, 'hk:') do | |
101 | if o == "h" then return help() end | |
102 | if o == "k" then keyA = a end | |
103 | end | |
104 | ||
105 | -- validate input args. | |
106 | keyA = keyA or '4b0b20107ccb' | |
107 | if #(keyA) ~= 12 then | |
108 | return oops( string.format('Wrong length of write key (was %d) expected 12', #keyA)) | |
109 | end | |
110 | ||
111 | result, err = lib14a.read1443a(false) | |
112 | if not result then | |
113 | print(err) | |
114 | return | |
115 | end | |
116 | print((" Found tag : %s"):format(result.name)) | |
117 | ||
118 | core.clearCommandBuffer() | |
119 | ||
120 | if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx | |
121 | print("This is not a TNP3xxx tag. aborting.") | |
122 | return | |
123 | end | |
124 | ||
125 | -- Show info | |
126 | print(('Using keyA : %s'):format(keyA)) | |
127 | print( string.rep('--',20) ) | |
128 | ||
129 | local cmdNestedString = 'hf mf nested 1 0 A %s d' | |
130 | local cmdDumpString = 'hf mf dump' | |
131 | --core.console(cmdNestedString.format(keyA) ) | |
132 | --core.console(cmdDumpString) | |
133 | ||
134 | print('Reading data need to dump data') | |
135 | ||
136 | -- Read block 0 | |
137 | cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 0,arg2 = 0,arg3 = 0, data = keyA} | |
138 | err = core.SendCommand(cmd:getBytes()) | |
139 | if err then return oops(err) end | |
140 | local block0, err = waitCmd() | |
141 | if err then return oops(err) end | |
142 | ||
143 | -- Read block 1 | |
144 | cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 1,arg2 = 0,arg3 = 0, data = keyA} | |
145 | local err = core.SendCommand(cmd:getBytes()) | |
146 | if err then return oops(err) end | |
147 | local block1, err = waitCmd() | |
148 | if err then return oops(err) end | |
149 | ||
150 | ||
151 | -- Read block 9 | |
152 | cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 9,arg2 = 0,arg3 = 0, data = '56f6313550f9'} | |
153 | local err = core.SendCommand(cmd:getBytes()) | |
154 | if err then return oops(err) end | |
155 | local block9, err = waitCmd() | |
156 | if err then return oops(err) end | |
157 | ||
158 | -- main loop | |
159 | print('BLOCK MD5 DECRYPTED ASCII' ) | |
160 | ||
161 | for block=0,numBlocks-1,1 do | |
162 | ||
163 | if math.fmod(block,4) then | |
164 | ||
165 | end | |
166 | ||
167 | local base = ('%s%s%02d%s'):format(block0, block1, block, hashconstant) | |
168 | local md5hash = md5.sumhexa(base) | |
169 | local aestest = core.aes(md5hash, block9 ) | |
170 | ||
171 | local _,hex = bin.unpack(("H%d"):format(16),aestest) | |
172 | ||
173 | ||
174 | local hexascii = string.gsub(hex, '(%x%x)', | |
175 | function(value) | |
176 | return string.char(tonumber(value, 16)) | |
177 | end | |
178 | ) | |
179 | ||
180 | print( block .. ' :: ' .. md5hash .. ' :: ' .. hex .. ' :: ' .. hexascii ) | |
181 | ||
182 | -- if core.ukbhit() then | |
183 | -- print("aborted by user") | |
184 | -- break | |
185 | -- end | |
186 | end | |
187 | end | |
188 | ||
189 | main(args) |