scripts: Add mfc_hammerlite and ntag_hammertime

This commit is contained in:
Ave 2020-11-30 22:27:14 +03:00
parent 1a749d77ed
commit 35d5896012
No known key found for this signature in database
GPG key ID: 398DD7BD03276F6D
2 changed files with 271 additions and 0 deletions

View 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)

View 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)