mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-02-22 15:16:19 +08:00
scripts: Add mfc_hammerlite and ntag_hammertime
This commit is contained in:
parent
1a749d77ed
commit
35d5896012
2 changed files with 271 additions and 0 deletions
82
client/luascripts/mfc_hammerlite.lua
Normal file
82
client/luascripts/mfc_hammerlite.lua
Normal file
|
@ -0,0 +1,82 @@
|
|||
local getopt = require('getopt')
|
||||
local lib14a = require('read14a')
|
||||
local cmds = require('commands')
|
||||
local ansicolors = require('ansicolors')
|
||||
|
||||
copyright = 'Copyright 2020 A. Ozkal, released under GPLv2+.'
|
||||
author = 'Ave'
|
||||
version = 'v0.1.1'
|
||||
desc = [[
|
||||
This script writes a bunch of random blocks to a Mifare Classic card
|
||||
]]
|
||||
example = [[
|
||||
script run mfc_hammerlite -w 1000 -k FFFFFFFFFFFF
|
||||
]]
|
||||
usage = [[
|
||||
script run mfc_hammerlite [-h] [-w <writecount>] [-k <key>]
|
||||
]]
|
||||
arguments = [[
|
||||
-h : This help
|
||||
-w <writeroundcount> : Amount of write rounds to be done to each block (optional, default: 100)
|
||||
-k <key> : A key for the sectors
|
||||
]]
|
||||
|
||||
local function help()
|
||||
print(author)
|
||||
print(version)
|
||||
print(desc)
|
||||
print(ansicolors.cyan..'Usage'..ansicolors.reset)
|
||||
print(usage)
|
||||
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
|
||||
print(arguments)
|
||||
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
|
||||
print(example)
|
||||
end
|
||||
|
||||
function randhex(len)
|
||||
result = ""
|
||||
for i = 1,len,1
|
||||
do
|
||||
-- 48-57 numbers, 65-70 a-f
|
||||
hex = math.random(0, 15)
|
||||
if hex >= 10 then
|
||||
hex = hex + 7
|
||||
end
|
||||
result = result..string.char(48 + hex)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
---
|
||||
-- The main entry point
|
||||
function main(args)
|
||||
-- param defaults
|
||||
loopcount = 100
|
||||
verifyevery = 10
|
||||
key = "FFFFFFFFFFFF"
|
||||
|
||||
-- Read the parameters
|
||||
for o, a in getopt.getopt(args, 'hw:k:') do
|
||||
if o == 'h' then return help() end
|
||||
if o == 'w' then loopcount = tonumber(a) end
|
||||
if o == 'k' then key = a end
|
||||
end
|
||||
|
||||
starttime = os.time()
|
||||
|
||||
for i = 1,loopcount,1
|
||||
do
|
||||
for a = 1,63,1
|
||||
do
|
||||
if ((a + 1) % 4 ~= 0) and a ~= 0 then -- :)
|
||||
data = randhex(32)
|
||||
-- core.console('hf mf rdbl '..a..' A FFFFFFFFFFFF')
|
||||
core.console('hf mf wrbl '..a..' A '..key..' '..data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
print("Hammering complete.")
|
||||
end
|
||||
|
||||
main(args)
|
189
client/luascripts/ntag_hammertime.lua
Normal file
189
client/luascripts/ntag_hammertime.lua
Normal file
|
@ -0,0 +1,189 @@
|
|||
local getopt = require('getopt')
|
||||
local lib14a = require('read14a')
|
||||
local cmds = require('commands')
|
||||
local ansicolors = require('ansicolors')
|
||||
|
||||
copyright = 'Copyright 2020 A. Ozkal, released under GPLv2+.'
|
||||
author = 'Ave'
|
||||
version = 'v2.1.3'
|
||||
desc = [[
|
||||
This script writes a bunch of random blocks to a NTAG or MFUL card to test its actual write limits
|
||||
]]
|
||||
example = [[
|
||||
script run ntag_hammertime -w 1000 -r 50 -z 50 -f 5 -s 4 -e 129
|
||||
]]
|
||||
usage = [[
|
||||
script run ntag_hammertime [-h] [-w <writecount>] [-r <readevery>] [-z <reselectevery>] [-f <maximumfails>] [-s <writestartblock>] [-e <writeendblock>]
|
||||
]]
|
||||
arguments = [[
|
||||
-h : This help
|
||||
-w <writeroundcount> : Amount of write rounds to be done to each block (optional, default: 100)
|
||||
-r <readevery> : Verify frequency (reads and checks written values every x rounds, optional, default: 10)
|
||||
-z <reselectevery> : Reselect frequency (reselects card once every x rounds, optional, default: 10)
|
||||
-f <maximumfails> : Maximum consequent fails (read/write) that will trigger a fail state (optional, default: 3)
|
||||
-s <writestartblock> : Block number for writes to be started to (optional, inclusive, decimal, default: 4)
|
||||
-e <writeendblock> : Block number for writes to be ended on (optional, inclusive, decimal, default: 129)
|
||||
]]
|
||||
|
||||
local function help()
|
||||
print(author)
|
||||
print(version)
|
||||
print(desc)
|
||||
print(ansicolors.cyan..'Usage'..ansicolors.reset)
|
||||
print(usage)
|
||||
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
|
||||
print(arguments)
|
||||
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
|
||||
print(example)
|
||||
end
|
||||
|
||||
function randhex(len)
|
||||
result = ""
|
||||
for i = 1,len,1
|
||||
do
|
||||
-- 48-57 numbers, 65-70 a-f
|
||||
hex = math.random(0, 15)
|
||||
if hex >= 10 then
|
||||
hex = hex + 7
|
||||
end
|
||||
result = result..string.char(48 + hex)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- Used to send raw data to the firmware to subsequently forward the data to the card.
|
||||
-- from mifareplus.lua
|
||||
local function sendRaw(rawdata, crc, power)
|
||||
-- print(("<sent>: %s"):format(rawdata))
|
||||
|
||||
local flags = lib14a.ISO14A_COMMAND.ISO14A_RAW
|
||||
if crc then
|
||||
flags = flags + lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC
|
||||
end
|
||||
if power then
|
||||
flags = flags + lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT
|
||||
end
|
||||
|
||||
local command = Command:newMIX{cmd = cmds.CMD_HF_ISO14443A_READER,
|
||||
arg1 = flags, -- Send raw
|
||||
arg2 = string.len(rawdata) / 2, -- arg2 contains the length, which is half the length of the ASCII-string rawdata
|
||||
data = rawdata
|
||||
}
|
||||
local ignore_response = false
|
||||
local result, err = command:sendMIX(ignore_response)
|
||||
if result then
|
||||
--unpack the first 4 parts of the result as longs, and the last as an extremely long string to later be cut down based on arg1, the number of bytes returned
|
||||
local count,cmd,arg1,arg2,arg3,data = bin.unpack('LLLLH512',result)
|
||||
|
||||
returned_bytes = string.sub(data, 1, arg1 * 2)
|
||||
if #returned_bytes > 0 then
|
||||
-- print(("<recvd>: %s"):format(returned_bytes)) -- need to multiply by 2 because the hex digits are actually two bytes when they are strings
|
||||
return returned_bytes
|
||||
else
|
||||
return nil
|
||||
end
|
||||
else
|
||||
print("Error sending the card raw data.")
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local function selectCard(keepField, arg2, attemptCount)
|
||||
for i = 1,attemptCount,1
|
||||
do
|
||||
if lib14a.read(keepField, arg2) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
---
|
||||
-- The main entry point
|
||||
function main(args)
|
||||
failcounter = 0
|
||||
|
||||
-- param defaults
|
||||
loopcount = 100
|
||||
verifyevery = 10
|
||||
reselectevery = 10
|
||||
failmax = 3
|
||||
blockstart = 4
|
||||
blockend = 129
|
||||
|
||||
-- Read the parameters
|
||||
for o, a in getopt.getopt(args, 'hw:r:z:f:s:e:') do
|
||||
if o == 'h' then return help() end
|
||||
if o == 'w' then loopcount = tonumber(a) end
|
||||
if o == 'r' then verifyevery = tonumber(a) end
|
||||
if o == 'z' then reselectevery = tonumber(a) end
|
||||
if o == 'f' then failmax = tonumber(a) end
|
||||
if o == 's' then blockstart = tonumber(a) end
|
||||
if o == 'e' then blockend = tonumber(a) end
|
||||
end
|
||||
|
||||
starttime = os.time()
|
||||
|
||||
if selectCard(true, false, 3) ~= true then
|
||||
return print("Select failed.")
|
||||
end
|
||||
for i = 1,loopcount,1
|
||||
do
|
||||
for block = blockstart,blockend,1
|
||||
do
|
||||
data = randhex(8)
|
||||
print(i..": Writing "..data.." to block "..block..".")
|
||||
blockhex = string.format("%02x", block)
|
||||
result = sendRaw("A2"..blockhex..data, true, true)
|
||||
if result then -- if false/nil, that's a fail right there
|
||||
print(ansicolors.green.."Got "..result.."."..ansicolors.reset) -- We want this to be 0A
|
||||
failcounter = 0
|
||||
else
|
||||
print(ansicolors.red.."Write FAILED."..ansicolors.reset)
|
||||
failcounter = failcounter + 1
|
||||
goto continue
|
||||
end
|
||||
|
||||
if i % verifyevery == 0 then
|
||||
result = sendRaw("30"..blockhex, true, true)
|
||||
if result then -- if false, that's a fail right there
|
||||
result = string.sub(result, 0, 8)
|
||||
if result ~= data then
|
||||
print(ansicolors.red.."Read IMPROPER, supposed to be "..data..", got "..result.."."..ansicolors.reset)
|
||||
failcounter = failcounter + 1
|
||||
goto continue
|
||||
else
|
||||
print(ansicolors.green.."Read matches the write."..ansicolors.reset)
|
||||
failcounter = 0
|
||||
end
|
||||
else
|
||||
print(ansicolors.red.."Read FAILED."..ansicolors.reset)
|
||||
failcounter = failcounter + 1
|
||||
goto continue
|
||||
end
|
||||
end
|
||||
::continue::
|
||||
|
||||
if failcounter >= failmax then
|
||||
-- close field
|
||||
lib14a.read(false, false)
|
||||
return print(ansicolors.red.."Test failed after "..(os.time() - starttime).." seconds, "..(i*(blockend-blockstart)).." writes and "..math.floor((i*(blockend-blockstart))/verifyevery).." reads."..ansicolors.reset)
|
||||
end
|
||||
end
|
||||
|
||||
if i % reselectevery == 0 then
|
||||
-- reselect
|
||||
sendRaw("", false, false)
|
||||
if selectCard(true, false, 3) ~= true then
|
||||
return print("Reselect failed.")
|
||||
end
|
||||
print("Reselected card, current rate: "..(i*(blockend-blockstart))/(os.time() - starttime).." writes/s.")
|
||||
end
|
||||
end
|
||||
|
||||
-- close field
|
||||
lib14a.read(false, false)
|
||||
print("Successfully completed test in "..(os.time() - starttime).." seconds, did "..(loopcount*(blockend-blockstart)).." writes and "..math.floor((loopcount*(blockend-blockstart))/verifyevery).." reads.")
|
||||
end
|
||||
|
||||
main(args)
|
Loading…
Reference in a new issue