1 local getopt
= require('getopt')
2 local ansicolors
= require('ansicolors')
9 .-----------------------------------------------------------------.
12 | |\_. | (bruteforce simulation for multiple tags) | /| |
14 | `---' | Kenzy Carey | `---' |
16 | |-----------------------------------------------------| |
21 *SUPPORTED TAGS: pyramid, awid, fdxb, jablotron, noralsy, presco, visa2000, 14a, hid
23 This script uses the Proxmark3 implementations of simulation to bruteforce given ranges of id.
24 It uses both LF and HF simulations.
27 -- I wrote this as i was doing a PACS audit. This is far from complete, but is easily expandable.
28 -- The idea was based on proxbrute, but i needed more options, and support for different readers.
29 -- I dont know LUA, so I used Brian Redbeards lf_hid_bulkclone.lua script as a starting point, sorry if its kludgy.
33 -- (the above example would bruteforce pyramid tags, starting at 10:1000, ending at 10:991, and waiting 1 second between each card)
35 script run multi_bruteforce -r pyramid -f 10 -b 1000 -c 10 -t 1 -d down
38 script run multi_bruteforce -r rfid_tag -f facility_code -b base_card_number -c count -t timeout -d direction
42 -r *see below RFID Tag: the RFID tag to emulate
53 -f 0-999 facility code (dfx: country id, 14a: type)
54 -b 0-65535 base card number to start from
55 -c 1-65536 number of cards to try
56 -t .0-99999, pause timeout between cards (use the word 'pause' to wait for user input)
57 -d up, down direction to move through card numbers
62 local bxor
= bit32
.bxor
63 local lshift
= bit32
.lshift
65 -- A debug printout-function
66 local function dbg(args
)
67 if not DEBUG
then return end
68 if type(args
) == 'table' then
79 -- This is only meant to be used when errors occur
80 local function oops(err
)
82 core
.clearCommandBuffer()
92 print(ansicolors
.cyan
..'Usage'..ansicolors
.reset
)
94 print(ansicolors
.cyan
..'Arguments'..ansicolors
.reset
)
96 print(ansicolors
.cyan
..'Example usage'..ansicolors
.reset
)
101 local function exitMsg(msg
)
102 print( string.rep('--',20) )
103 print( string.rep('--',20) )
108 -- Check if a string is empty
109 local function isempty(s
)
110 return s
== nil or s
== ''
113 -- The code below was blatantly stolen from Brian Redbeard's lf_hid_bulkclone.lua script
114 local function toBits(num
, bits
)
115 bits
= bits
or math
.max(1, select(2, math
.frexp(num
)))
117 for b
= bits
, 1, -1 do
118 t
[b
] = math
.fmod(num
, 2)
119 num
= math
.floor((num
- t
[b
]) / 2)
121 return table.concat(t
)
124 -- check for parity in bit-string.
125 local function evenparity(s
)
126 local _
, count
= string.gsub(s
, '1', '')
135 local function cardHex(i
, f
)
138 stream
= toBits(id
, 26)
139 high
= evenparity(string.sub(stream
, 0, 12)) and 1 or 0
140 low
= not evenparity(string.sub(stream
, 13)) and 1 or 0
141 bits
= bor(lshift(id
, 1), low
)
142 bits
= bor(bits
, lshift(high
, 25))
143 preamble
= bor(0, lshift(1, 5))
144 bits
= bor(bits
, lshift(1, 26))
145 return ('%04x%08x'):format(preamble
, bits
)
149 local function main(args
)
151 print( string.rep('--',20) )
152 print( string.rep('--',20) )
155 if #args
== 0 then return help() end
157 for o
, a
in getopt
.getopt(args
, 'r:f:b:c:t:d:h') do -- Populate command like arguments
158 if o
== 'r' then rfidtag
= a
end
159 if o
== 'f' then facility
= a
end
160 if o
== 'b' then baseid
= a
end
161 if o
== 'c' then count
= a
end
162 if o
== 't' then timeout
= a
end
163 if o
== 'd' then direction
= a
end
164 if o
== 'h' then return print(usage
) end
167 -- Check to see if -r argument was passed
168 if isempty(rfidtag
) then
169 print('You must supply the flag -r (rfid tag)')
174 -- Check what RFID Tag we are using
175 if rfidtag
== 'pyramid' then
176 consolecommand
= 'lf pyramid sim' -- set the console command
177 rfidtagname
= 'Farpointe/Pyramid' -- set the display name
178 facilityrequired
= 1 -- set if FC is required
179 elseif rfidtag
== 'awid' then
180 consolecommand
= 'lf awid sim'
183 elseif rfidtag
== 'fdxb' then -- I'm not sure why you would need to bruteforce this ¯\_(ツ)_/¯
184 consolecommand
= 'lf fdxb sim'
185 rfidtagname
= 'FDX-B'
187 elseif rfidtag
== 'jablotron' then
188 consolecommand
= 'lf jablotron sim'
189 rfidtagname
= 'Jablotron'
191 elseif rfidtag
== 'noralsy' then
192 consolecommand
= 'lf noralsy sim'
193 rfidtagname
= 'Noralsy'
195 elseif rfidtag
== 'presco' then
196 consolecommand
= 'lf presco sim -d'
197 rfidtagname
= 'Presco'
199 elseif rfidtag
== 'visa2000' then
200 consolecommand
= 'lf visa2000 sim'
201 rfidtagname
= 'Visa2000'
203 elseif rfidtag
== '14a' then
204 consolecommand
= 'hf 14a sim -t'
205 if facility
== '1' then rfidtagname
= 'MIFARE Classic' -- Here we use the -f option to read the 14a type instead of the facility code
206 elseif facility
== '2' then rfidtagname
= 'MIFARE Ultralight'
207 elseif facility
== '3' then rfidtagname
= 'MIFARE Desfire'
208 elseif facility
== '4' then rfidtagname
= 'ISO/IEC 14443-4'
209 elseif facility
== '5' then rfidtagname
= 'MIFARE Tnp3xxx'
211 print('Invalid 14a type (-f) supplied. Must be 1-5')
215 facilityrequired
= 0 -- Disable the FC required check, as we used it for type instead of FC
216 elseif rfidtag
== 'hid' then
217 consolecommand
= 'lf hid sim -r'
220 else -- Display error and exit out if bad RFID tag was supplied
221 print('Invalid rfid tag (-r) supplied')
226 if isempty(baseid
) then -- Display error and exit out if no starting id is set
227 print('You must supply the flag -b (base id)')
232 if isempty(count
) then -- Display error and exit out of no count is set
233 print('You must supply the flag -c (count)')
238 if facilityrequired
== 1 then -- If FC is required
239 facilitymessage
= ' - Facility Code: ' -- Add FC to status message
240 if isempty(facility
) then -- If FC was left blank, display warning and set FC to 0
241 print('Using 0 for the facility code as -f was not supplied')
244 else -- If FC is not required
245 facility
= '' -- Clear FC
246 facilitymessage
= '' -- Remove FC from status message
249 if isempty(timeout
) then -- If timeout was not supplied, show warning and set timeout to 0
250 print('Using 0 for the timeout as -t was not supplied')
254 if isempty(direction
) then -- If direction was not supplied, show warning and set direction to down
255 print("Using down for direction as -d was not supplied")
259 if tonumber(count
) < 1 then
260 print('Count -c must be set to 1 or higher')
263 count
= count
-1 -- Make our count accurate by removing 1, because math
266 if direction
== 'down' then -- If counting down, set up our for loop to count down
267 endid
= baseid
- count
269 elseif direction
== 'up' then -- If counting up, set our for loop to count up
270 endid
= baseid
+ count
272 else -- If invalid direction was set, show warning and set up our for loop to count down
273 print('Invalid direction (-d) supplied, using down')
274 endid
= baseid
- count
279 -- display status message
281 print('BruteForcing '..rfidtagname
..''..facilitymessage
..''..facility
..' - CardNumber Start: '..baseid
..' - CardNumber End: '..endid
..' - TimeOut: '..timeout
)
284 -- loop through for each count (-c)
285 for cardnum
= baseid
, endid
, fordirection
do
287 -- If rfid tag is set to HID, convert card to HEX using the stolen code above
288 if rfidtag
== 'hid' then cardnum
= cardHex(cardnum
, facility
) end
290 -- send command to proxmark
291 core
.console(consolecommand
..' '..facility
..' '..cardnum
)
293 if timeout
== 'pause' then
294 print('Press enter to continue ...')
297 os
.execute('sleep '..timeout
..'')
301 -- ping the proxmark to stop emulation and see if its still responding
302 core
.console('hw ping')