mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 13:53:55 -07:00
style
This commit is contained in:
parent
3210384ef9
commit
a5d02c6ba2
12 changed files with 1643 additions and 1655 deletions
File diff suppressed because it is too large
Load diff
|
@ -1,128 +1,128 @@
|
|||
local getopt = require('getopt')
|
||||
|
||||
|
||||
copyright = ''
|
||||
author = "TheChamp669"
|
||||
version = 'v1.0.0'
|
||||
desc = [[
|
||||
Perform bulk enrollment of 26 bit AWID style RFID Tags
|
||||
For more info, check the comments in the code
|
||||
]]
|
||||
example = [[
|
||||
--
|
||||
script run lf_awid_bulkclone.lua -f 1 -b 1000
|
||||
]]
|
||||
usage = [[
|
||||
script run lf_awid_bulkclone.lua -f facility -b base_id_num
|
||||
]]
|
||||
arguments = [[
|
||||
-h : this help
|
||||
-f : facility id
|
||||
-b : starting card id
|
||||
]]
|
||||
local DEBUG = true
|
||||
---
|
||||
-- A debug printout-function
|
||||
local function dbg(args)
|
||||
if not DEBUG then return end
|
||||
if type(args) == 'table' then
|
||||
local i = 1
|
||||
while args[i] do
|
||||
dbg(args[i])
|
||||
i = i+1
|
||||
end
|
||||
else
|
||||
print('###', args)
|
||||
end
|
||||
end
|
||||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
local function oops(err)
|
||||
print('ERROR:', err)
|
||||
core.clearCommandBuffer()
|
||||
return nil, errr
|
||||
end
|
||||
---
|
||||
-- Usage help
|
||||
local function help()
|
||||
print(copyright)
|
||||
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
|
||||
---
|
||||
-- Exit message
|
||||
local function exitMsg(msg)
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
print(msg)
|
||||
print()
|
||||
end
|
||||
|
||||
local function showHelp()
|
||||
print("Usage: script run <scriptname> [-h]")
|
||||
print("Options:")
|
||||
print("-h \t This help")
|
||||
end
|
||||
|
||||
local function main(args)
|
||||
|
||||
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
print()
|
||||
|
||||
if #args == 0 then return help() end
|
||||
|
||||
for o, a in getopt.getopt(args, 'f:b:c:h') do
|
||||
if o == 'h' then return help() end
|
||||
if o == 'f' then
|
||||
if isempty(a) then
|
||||
print('You did not supply a facility code, using 255')
|
||||
fc = 255
|
||||
else
|
||||
fc = a
|
||||
end
|
||||
end
|
||||
if o == 'b' then
|
||||
if isempty(a) then
|
||||
print('You did not supply a starting card number, using 59615')
|
||||
cn = 59615
|
||||
else
|
||||
cn = a
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Example starting values
|
||||
local sessionStart = os.date("%Y_%m_%d_%H_%M_%S") -- Capture the session start time
|
||||
|
||||
print("Session Start: " .. sessionStart)
|
||||
print("Facility Code,Card Number")
|
||||
|
||||
while true do
|
||||
print(string.format("Preparing to Write: Facility Code %d, Card Number %d", fc, cn))
|
||||
|
||||
local command = string.format("lf awid clone --fmt 26 --fc %d --cn %d", fc, cn)
|
||||
core.console(command)
|
||||
|
||||
print(string.format("%d,%d", fc, cn))
|
||||
|
||||
print("Press Enter to continue with the next card number or type 'q' and press Enter to quit.")
|
||||
local user_input = io.read()
|
||||
|
||||
if user_input:lower() == 'q' then
|
||||
break
|
||||
else
|
||||
cn = cn + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local getopt = require('getopt')
|
||||
|
||||
|
||||
copyright = ''
|
||||
author = "TheChamp669"
|
||||
version = 'v1.0.0'
|
||||
desc = [[
|
||||
Perform bulk enrollment of 26 bit AWID style RFID Tags
|
||||
For more info, check the comments in the code
|
||||
]]
|
||||
example = [[
|
||||
--
|
||||
script run lf_awid_bulkclone.lua -f 1 -b 1000
|
||||
]]
|
||||
usage = [[
|
||||
script run lf_awid_bulkclone.lua -f facility -b base_id_num
|
||||
]]
|
||||
arguments = [[
|
||||
-h : this help
|
||||
-f : facility id
|
||||
-b : starting card id
|
||||
]]
|
||||
local DEBUG = true
|
||||
---
|
||||
-- A debug printout-function
|
||||
local function dbg(args)
|
||||
if not DEBUG then return end
|
||||
if type(args) == 'table' then
|
||||
local i = 1
|
||||
while args[i] do
|
||||
dbg(args[i])
|
||||
i = i+1
|
||||
end
|
||||
else
|
||||
print('###', args)
|
||||
end
|
||||
end
|
||||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
local function oops(err)
|
||||
print('ERROR:', err)
|
||||
core.clearCommandBuffer()
|
||||
return nil, errr
|
||||
end
|
||||
---
|
||||
-- Usage help
|
||||
local function help()
|
||||
print(copyright)
|
||||
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
|
||||
---
|
||||
-- Exit message
|
||||
local function exitMsg(msg)
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
print(msg)
|
||||
print()
|
||||
end
|
||||
|
||||
local function showHelp()
|
||||
print("Usage: script run <scriptname> [-h]")
|
||||
print("Options:")
|
||||
print("-h \t This help")
|
||||
end
|
||||
|
||||
local function main(args)
|
||||
|
||||
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
print()
|
||||
|
||||
if #args == 0 then return help() end
|
||||
|
||||
for o, a in getopt.getopt(args, 'f:b:c:h') do
|
||||
if o == 'h' then return help() end
|
||||
if o == 'f' then
|
||||
if isempty(a) then
|
||||
print('You did not supply a facility code, using 255')
|
||||
fc = 255
|
||||
else
|
||||
fc = a
|
||||
end
|
||||
end
|
||||
if o == 'b' then
|
||||
if isempty(a) then
|
||||
print('You did not supply a starting card number, using 59615')
|
||||
cn = 59615
|
||||
else
|
||||
cn = a
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Example starting values
|
||||
local sessionStart = os.date("%Y_%m_%d_%H_%M_%S") -- Capture the session start time
|
||||
|
||||
print("Session Start: " .. sessionStart)
|
||||
print("Facility Code,Card Number")
|
||||
|
||||
while true do
|
||||
print(string.format("Preparing to Write: Facility Code %d, Card Number %d", fc, cn))
|
||||
|
||||
local command = string.format("lf awid clone --fmt 26 --fc %d --cn %d", fc, cn)
|
||||
core.console(command)
|
||||
|
||||
print(string.format("%d,%d", fc, cn))
|
||||
|
||||
print("Press Enter to continue with the next card number or type 'q' and press Enter to quit.")
|
||||
local user_input = io.read()
|
||||
|
||||
if user_input:lower() == 'q' then
|
||||
break
|
||||
else
|
||||
cn = cn + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
main(args)
|
||||
|
|
|
@ -1,131 +1,131 @@
|
|||
local getopt = require('getopt')
|
||||
local ansicolors = require('ansicolors')
|
||||
local cmds = require('commands')
|
||||
|
||||
copyright = ''
|
||||
author = "TheChamop669"
|
||||
version = 'v1.0.1'
|
||||
desc = [[
|
||||
Perform bulk enrollment of 26 bit H10301 style RFID Tags
|
||||
For more info, check the comments in the code
|
||||
]]
|
||||
example = [[
|
||||
--
|
||||
script run lf_hid_bulkclone_v2.lua -f 1 -b 1000
|
||||
]]
|
||||
usage = [[
|
||||
script run lf_hid_bulkclone_v2.lua -f facility -b base_id_num
|
||||
]]
|
||||
arguments = [[
|
||||
-h : this help
|
||||
-f : facility id
|
||||
-b : starting card id
|
||||
]]
|
||||
local DEBUG = true
|
||||
---
|
||||
-- A debug printout-function
|
||||
local function dbg(args)
|
||||
if not DEBUG then return end
|
||||
if type(args) == 'table' then
|
||||
local i = 1
|
||||
while args[i] do
|
||||
dbg(args[i])
|
||||
i = i+1
|
||||
end
|
||||
else
|
||||
print('###', args)
|
||||
end
|
||||
end
|
||||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
local function oops(err)
|
||||
print('ERROR:', err)
|
||||
core.clearCommandBuffer()
|
||||
return nil, errr
|
||||
end
|
||||
---
|
||||
-- Usage help
|
||||
local function help()
|
||||
print(copyright)
|
||||
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
|
||||
---
|
||||
-- Exit message
|
||||
local function exitMsg(msg)
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
print(msg)
|
||||
print()
|
||||
end
|
||||
|
||||
local function main(args)
|
||||
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
print()
|
||||
|
||||
if #args == 0 then return help() end
|
||||
|
||||
for o, a in getopt.getopt(args, 'f:b:h') do
|
||||
if o == 'h' then return help() end
|
||||
if o == 'f' then
|
||||
if isempty(a) then
|
||||
print('You did not supply a facility code, using 0')
|
||||
fc = 10
|
||||
else
|
||||
fc = a
|
||||
end
|
||||
end
|
||||
if o == 'b' then
|
||||
if isempty(a) then
|
||||
print('You did not supply a starting card number, using 1000')
|
||||
cn = 1000
|
||||
else
|
||||
cn = a
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local successful_writes = {}
|
||||
local timestamp = os.date('%Y-%m-%d %H:%M:%S', os.time())
|
||||
|
||||
while true do
|
||||
print(string.format("Writing Facility Code: %d, Card Number: %d", fc, cn))
|
||||
|
||||
local command = string.format("lf hid clone -w H10301 --fc %d --cn %d", fc, cn)
|
||||
core.console(command)
|
||||
|
||||
table.insert(successful_writes, string.format("%d,%d", fc, cn))
|
||||
|
||||
print("Press Enter to write the next card, type 'r' and press Enter to retry, or type 'q' and press Enter to quit.")
|
||||
local user_input = io.read()
|
||||
|
||||
if user_input:lower() == 'q' then
|
||||
print("Timestamp: ", timestamp)
|
||||
print("Successful Writes:")
|
||||
for _, v in ipairs(successful_writes) do print(v) end
|
||||
break
|
||||
elseif user_input:lower() ~= 'r' then
|
||||
cn = cn + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
main(args)
|
||||
|
||||
--[[
|
||||
Notes:
|
||||
1. The `lf hid clone` command is used to write HID formatted data to T5577 cards, using the H10301 format.
|
||||
2. The script prompts the user for the initial facility code and card number at the start of the session.
|
||||
3. Users can continue to write to the next card, retry the current write, or quit the session by responding to the prompts.
|
||||
4. Upon quitting, the script prints all successful writes along with a timestamp.
|
||||
5. Password-related features have been removed in this version of the script as they are not supported by the `lf hid clone` command.
|
||||
]]
|
||||
local getopt = require('getopt')
|
||||
local ansicolors = require('ansicolors')
|
||||
local cmds = require('commands')
|
||||
|
||||
copyright = ''
|
||||
author = "TheChamop669"
|
||||
version = 'v1.0.1'
|
||||
desc = [[
|
||||
Perform bulk enrollment of 26 bit H10301 style RFID Tags
|
||||
For more info, check the comments in the code
|
||||
]]
|
||||
example = [[
|
||||
--
|
||||
script run lf_hid_bulkclone_v2.lua -f 1 -b 1000
|
||||
]]
|
||||
usage = [[
|
||||
script run lf_hid_bulkclone_v2.lua -f facility -b base_id_num
|
||||
]]
|
||||
arguments = [[
|
||||
-h : this help
|
||||
-f : facility id
|
||||
-b : starting card id
|
||||
]]
|
||||
local DEBUG = true
|
||||
---
|
||||
-- A debug printout-function
|
||||
local function dbg(args)
|
||||
if not DEBUG then return end
|
||||
if type(args) == 'table' then
|
||||
local i = 1
|
||||
while args[i] do
|
||||
dbg(args[i])
|
||||
i = i+1
|
||||
end
|
||||
else
|
||||
print('###', args)
|
||||
end
|
||||
end
|
||||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
local function oops(err)
|
||||
print('ERROR:', err)
|
||||
core.clearCommandBuffer()
|
||||
return nil, errr
|
||||
end
|
||||
---
|
||||
-- Usage help
|
||||
local function help()
|
||||
print(copyright)
|
||||
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
|
||||
---
|
||||
-- Exit message
|
||||
local function exitMsg(msg)
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
print(msg)
|
||||
print()
|
||||
end
|
||||
|
||||
local function main(args)
|
||||
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
print()
|
||||
|
||||
if #args == 0 then return help() end
|
||||
|
||||
for o, a in getopt.getopt(args, 'f:b:h') do
|
||||
if o == 'h' then return help() end
|
||||
if o == 'f' then
|
||||
if isempty(a) then
|
||||
print('You did not supply a facility code, using 0')
|
||||
fc = 10
|
||||
else
|
||||
fc = a
|
||||
end
|
||||
end
|
||||
if o == 'b' then
|
||||
if isempty(a) then
|
||||
print('You did not supply a starting card number, using 1000')
|
||||
cn = 1000
|
||||
else
|
||||
cn = a
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local successful_writes = {}
|
||||
local timestamp = os.date('%Y-%m-%d %H:%M:%S', os.time())
|
||||
|
||||
while true do
|
||||
print(string.format("Writing Facility Code: %d, Card Number: %d", fc, cn))
|
||||
|
||||
local command = string.format("lf hid clone -w H10301 --fc %d --cn %d", fc, cn)
|
||||
core.console(command)
|
||||
|
||||
table.insert(successful_writes, string.format("%d,%d", fc, cn))
|
||||
|
||||
print("Press Enter to write the next card, type 'r' and press Enter to retry, or type 'q' and press Enter to quit.")
|
||||
local user_input = io.read()
|
||||
|
||||
if user_input:lower() == 'q' then
|
||||
print("Timestamp: ", timestamp)
|
||||
print("Successful Writes:")
|
||||
for _, v in ipairs(successful_writes) do print(v) end
|
||||
break
|
||||
elseif user_input:lower() ~= 'r' then
|
||||
cn = cn + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
main(args)
|
||||
|
||||
--[[
|
||||
Notes:
|
||||
1. The `lf hid clone` command is used to write HID formatted data to T5577 cards, using the H10301 format.
|
||||
2. The script prompts the user for the initial facility code and card number at the start of the session.
|
||||
3. Users can continue to write to the next card, retry the current write, or quit the session by responding to the prompts.
|
||||
4. Upon quitting, the script prints all successful writes along with a timestamp.
|
||||
5. Password-related features have been removed in this version of the script as they are not supported by the `lf hid clone` command.
|
||||
]]
|
||||
|
|
|
@ -1,125 +1,125 @@
|
|||
local getopt = require('getopt')
|
||||
local cmds = require('commands')
|
||||
|
||||
|
||||
copyright = ''
|
||||
author = "TheChamp669"
|
||||
version = 'v1.0.0'
|
||||
desc = [[
|
||||
Perform bulk enrollment of 26 bit IO Prox / Kantech style RFID Tags
|
||||
The vnc is set to 2.
|
||||
For more info, check the comments in the code
|
||||
]]
|
||||
example = [[
|
||||
--
|
||||
script run lf_ioprox_bulkclone.lua -f 1 -b 1000
|
||||
]]
|
||||
usage = [[
|
||||
script run lf_ioprox_bulkclone.lua -f facility -b base_id_num
|
||||
]]
|
||||
arguments = [[
|
||||
-h : this help
|
||||
-f : facility id
|
||||
-b : starting card id
|
||||
]]
|
||||
local DEBUG = true
|
||||
|
||||
---
|
||||
-- A debug printout-function
|
||||
local function dbg(args)
|
||||
if not DEBUG then return end
|
||||
if type(args) == 'table' then
|
||||
local i = 1
|
||||
while args[i] do
|
||||
dbg(args[i])
|
||||
i = i+1
|
||||
end
|
||||
else
|
||||
print('###', args)
|
||||
end
|
||||
end
|
||||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
local function oops(err)
|
||||
print('ERROR:', err)
|
||||
core.clearCommandBuffer()
|
||||
return nil, errr
|
||||
end
|
||||
---
|
||||
-- Usage help
|
||||
local function help()
|
||||
print(copyright)
|
||||
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
|
||||
---
|
||||
-- Exit message
|
||||
local function exitMsg(msg)
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
print(msg)
|
||||
print()
|
||||
end
|
||||
|
||||
local function main(args)
|
||||
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
print()
|
||||
|
||||
if #args == 0 then return help() end
|
||||
|
||||
for o, a in getopt.getopt(args, 'f:b:h') do
|
||||
if o == 'h' then return help() end
|
||||
if o == 'f' then
|
||||
if isempty(a) then
|
||||
print('You did not supply a facility code, using 0')
|
||||
fc = 0
|
||||
else
|
||||
fc = a
|
||||
end
|
||||
end
|
||||
if o == 'b' then
|
||||
if isempty(a) then return oops('You must supply the flag -b (starting card number)') end
|
||||
cn = a
|
||||
end
|
||||
end
|
||||
|
||||
local successful_writes = {}
|
||||
local timestamp = os.date('%Y-%m-%d %H:%M:%S', os.time())
|
||||
|
||||
while true do
|
||||
print(string.format("Setting fob to Facility Code: %d, Card Number: %d", fc, cn))
|
||||
|
||||
-- Writing to block 0 with the specific data for ioProx card format
|
||||
core.console("lf t55xx write -b 0 -d 00147040")
|
||||
|
||||
-- Command to set facility code and card number on the fob
|
||||
local command = string.format("lf io clone --vn 2 --fc %d --cn %d", fc, cn)
|
||||
core.console(command)
|
||||
|
||||
table.insert(successful_writes, string.format("%d,%d", fc, cn))
|
||||
print("Fob created successfully.")
|
||||
|
||||
print("Press Enter to create the next fob, type 'r' and press Enter to retry, or type 'q' and press Enter to quit.")
|
||||
local user_input = io.read()
|
||||
|
||||
if user_input:lower() == 'q' then
|
||||
print("Timestamp: ", timestamp)
|
||||
print("Successful Writes:")
|
||||
for _, v in ipairs(successful_writes) do print(v) end
|
||||
break
|
||||
elseif user_input:lower() ~= 'r' then
|
||||
cn = cn + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
main(args)
|
||||
local getopt = require('getopt')
|
||||
local cmds = require('commands')
|
||||
|
||||
|
||||
copyright = ''
|
||||
author = "TheChamp669"
|
||||
version = 'v1.0.0'
|
||||
desc = [[
|
||||
Perform bulk enrollment of 26 bit IO Prox / Kantech style RFID Tags
|
||||
The vnc is set to 2.
|
||||
For more info, check the comments in the code
|
||||
]]
|
||||
example = [[
|
||||
--
|
||||
script run lf_ioprox_bulkclone.lua -f 1 -b 1000
|
||||
]]
|
||||
usage = [[
|
||||
script run lf_ioprox_bulkclone.lua -f facility -b base_id_num
|
||||
]]
|
||||
arguments = [[
|
||||
-h : this help
|
||||
-f : facility id
|
||||
-b : starting card id
|
||||
]]
|
||||
local DEBUG = true
|
||||
|
||||
---
|
||||
-- A debug printout-function
|
||||
local function dbg(args)
|
||||
if not DEBUG then return end
|
||||
if type(args) == 'table' then
|
||||
local i = 1
|
||||
while args[i] do
|
||||
dbg(args[i])
|
||||
i = i+1
|
||||
end
|
||||
else
|
||||
print('###', args)
|
||||
end
|
||||
end
|
||||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
local function oops(err)
|
||||
print('ERROR:', err)
|
||||
core.clearCommandBuffer()
|
||||
return nil, errr
|
||||
end
|
||||
---
|
||||
-- Usage help
|
||||
local function help()
|
||||
print(copyright)
|
||||
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
|
||||
---
|
||||
-- Exit message
|
||||
local function exitMsg(msg)
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
print(msg)
|
||||
print()
|
||||
end
|
||||
|
||||
local function main(args)
|
||||
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
print()
|
||||
|
||||
if #args == 0 then return help() end
|
||||
|
||||
for o, a in getopt.getopt(args, 'f:b:h') do
|
||||
if o == 'h' then return help() end
|
||||
if o == 'f' then
|
||||
if isempty(a) then
|
||||
print('You did not supply a facility code, using 0')
|
||||
fc = 0
|
||||
else
|
||||
fc = a
|
||||
end
|
||||
end
|
||||
if o == 'b' then
|
||||
if isempty(a) then return oops('You must supply the flag -b (starting card number)') end
|
||||
cn = a
|
||||
end
|
||||
end
|
||||
|
||||
local successful_writes = {}
|
||||
local timestamp = os.date('%Y-%m-%d %H:%M:%S', os.time())
|
||||
|
||||
while true do
|
||||
print(string.format("Setting fob to Facility Code: %d, Card Number: %d", fc, cn))
|
||||
|
||||
-- Writing to block 0 with the specific data for ioProx card format
|
||||
core.console("lf t55xx write -b 0 -d 00147040")
|
||||
|
||||
-- Command to set facility code and card number on the fob
|
||||
local command = string.format("lf io clone --vn 2 --fc %d --cn %d", fc, cn)
|
||||
core.console(command)
|
||||
|
||||
table.insert(successful_writes, string.format("%d,%d", fc, cn))
|
||||
print("Fob created successfully.")
|
||||
|
||||
print("Press Enter to create the next fob, type 'r' and press Enter to retry, or type 'q' and press Enter to quit.")
|
||||
local user_input = io.read()
|
||||
|
||||
if user_input:lower() == 'q' then
|
||||
print("Timestamp: ", timestamp)
|
||||
print("Successful Writes:")
|
||||
for _, v in ipairs(successful_writes) do print(v) end
|
||||
break
|
||||
elseif user_input:lower() ~= 'r' then
|
||||
cn = cn + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
main(args)
|
||||
|
|
|
@ -1,488 +1,488 @@
|
|||
local getopt = require('getopt')
|
||||
local utils = require('utils')
|
||||
local ac = require('ansicolors')
|
||||
local os = require('os')
|
||||
local dash = string.rep('--', 32)
|
||||
local dir = os.getenv('HOME') .. '/.proxmark3/logs/'
|
||||
local logfile = (io.popen('dir /a-d /o-d /tw /b/s "' .. dir .. '" 2>nul:'):read("*a"):match("%C+"))
|
||||
local log_file_path = dir .. "Paxton_log.txt"
|
||||
local nam = ""
|
||||
local pm3 = require('pm3')
|
||||
p = pm3.pm3()
|
||||
local command = core.console
|
||||
command('clear')
|
||||
|
||||
author = ' Author: jareckib - 30.01.2025'
|
||||
tutorial = ' Based on Equipter tutorial - Downgrade Paxton to EM4102'
|
||||
version = ' version v1.20'
|
||||
desc = [[
|
||||
The script automates the copying of Paxton fobs read - write.
|
||||
It also allows manual input of data for blocks 4-7.
|
||||
The third option is reading data stored in the log file and create new fob.
|
||||
Additionally, the script calculates the ID for downgrading Paxton to EM4102.
|
||||
|
||||
]]
|
||||
usage = [[
|
||||
script run paxton_clone
|
||||
]]
|
||||
arguments = [[
|
||||
script run paxton_clone -h : this help
|
||||
]]
|
||||
|
||||
local debug = true
|
||||
|
||||
local function dbg(args)
|
||||
if not DEBUG then return end
|
||||
if type(args) == 'table' then
|
||||
local i = 1
|
||||
while args[i] do
|
||||
dbg(args[i])
|
||||
i = i+1
|
||||
end
|
||||
else
|
||||
print('###', args)
|
||||
end
|
||||
end
|
||||
|
||||
local function help()
|
||||
print()
|
||||
print(author)
|
||||
print(tutorial)
|
||||
print(version)
|
||||
print(desc)
|
||||
print(ac.cyan..' Usage'..ac.reset)
|
||||
print(usage)
|
||||
print(ac.cyan..' Arguments'..ac.reset)
|
||||
print(arguments)
|
||||
end
|
||||
|
||||
local function reset_log_file()
|
||||
local file = io.open(logfile, "w+")
|
||||
file:write("")
|
||||
file:close()
|
||||
end
|
||||
|
||||
local function read_log_file(logfile)
|
||||
local file = io.open(logfile, "r")
|
||||
if not file then
|
||||
error(" Could not open the file")
|
||||
end
|
||||
local content = file:read("*all")
|
||||
file:close()
|
||||
return content
|
||||
end
|
||||
|
||||
local function parse_blocks(result)
|
||||
local blocks = {}
|
||||
for line in result:gmatch("[^\r\n]+") do
|
||||
local block_num, block_data = line:match("%[%=%]%s+%d/0x0([4-7])%s+%|%s+([0-9A-F ]+)")
|
||||
if block_num and block_data then
|
||||
block_num = tonumber(block_num)
|
||||
block_data = block_data:gsub("%s+", "")
|
||||
blocks[block_num] = block_data
|
||||
end
|
||||
end
|
||||
return blocks
|
||||
end
|
||||
|
||||
local function hex_to_bin(hex_string)
|
||||
local bin_string = ""
|
||||
local hex_to_bin_map = {
|
||||
['0'] = "0000", ['1'] = "0001", ['2'] = "0010", ['3'] = "0011",
|
||||
['4'] = "0100", ['5'] = "0101", ['6'] = "0110", ['7'] = "0111",
|
||||
['8'] = "1000", ['9'] = "1001", ['A'] = "1010", ['B'] = "1011",
|
||||
['C'] = "1100", ['D'] = "1101", ['E'] = "1110", ['F'] = "1111"
|
||||
}
|
||||
for i = 1, #hex_string do
|
||||
bin_string = bin_string .. hex_to_bin_map[hex_string:sub(i, i)]
|
||||
end
|
||||
return bin_string
|
||||
end
|
||||
|
||||
local function remove_last_two_bits(binary_str)
|
||||
return binary_str:sub(1, #binary_str - 2)
|
||||
end
|
||||
|
||||
local function split_into_5bit_chunks(binary_str)
|
||||
local chunks = {}
|
||||
for i = 1, #binary_str, 5 do
|
||||
table.insert(chunks, binary_str:sub(i, i + 4))
|
||||
end
|
||||
return chunks
|
||||
end
|
||||
|
||||
local function remove_parity_bit(chunks)
|
||||
local no_parity_chunks = {}
|
||||
for _, chunk in ipairs(chunks) do
|
||||
if #chunk == 5 then
|
||||
table.insert(no_parity_chunks, chunk:sub(2))
|
||||
end
|
||||
end
|
||||
return no_parity_chunks
|
||||
end
|
||||
|
||||
local function convert_to_hex(chunks)
|
||||
local hex_values = {}
|
||||
for _, chunk in ipairs(chunks) do
|
||||
if #chunk > 0 then
|
||||
table.insert(hex_values, string.format("%X", tonumber(chunk, 2)))
|
||||
end
|
||||
end
|
||||
return hex_values
|
||||
end
|
||||
|
||||
local function convert_to_decimal(chunks)
|
||||
local decimal_values = {}
|
||||
for _, chunk in ipairs(chunks) do
|
||||
table.insert(decimal_values, tonumber(chunk, 2))
|
||||
end
|
||||
return decimal_values
|
||||
end
|
||||
|
||||
local function find_until_before_f(hex_values)
|
||||
local result = {}
|
||||
for _, value in ipairs(hex_values) do
|
||||
if value == 'F' then
|
||||
break
|
||||
end
|
||||
table.insert(result, value)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function process_block(block)
|
||||
local binary_str = hex_to_bin(block)
|
||||
binary_str = remove_last_two_bits(binary_str)
|
||||
local chunks = split_into_5bit_chunks(binary_str)
|
||||
local no_parity_chunks = remove_parity_bit(chunks)
|
||||
return no_parity_chunks
|
||||
end
|
||||
|
||||
local function calculate_id_net(blocks)
|
||||
local all_hex_values = {}
|
||||
for _, block in ipairs(blocks) do
|
||||
local hex_values = convert_to_hex(process_block(block))
|
||||
for _, hex in ipairs(hex_values) do
|
||||
table.insert(all_hex_values, hex)
|
||||
end
|
||||
end
|
||||
local selected_hex_values = find_until_before_f(all_hex_values)
|
||||
if #selected_hex_values == 0 then
|
||||
error(ac.red..' Error: '..ac.reset..'No valid data found in blocks 4 and 5')
|
||||
end
|
||||
local combined_hex = table.concat(selected_hex_values)
|
||||
if not combined_hex:match("^%x+$") then
|
||||
error(ac.red..' Error: '..ac.reset..'Invalid data in blocks 4 and 5')
|
||||
end
|
||||
local decimal_id = tonumber(combined_hex)
|
||||
local stripped_hex_id = string.format("%X", decimal_id)
|
||||
local padded_hex_id = string.format("%010X", decimal_id)
|
||||
return decimal_id, padded_hex_id
|
||||
end
|
||||
|
||||
local function calculate_id_switch(blocks)
|
||||
local all_decimal_values = {}
|
||||
for _, block in ipairs(blocks) do
|
||||
local decimal_values = convert_to_decimal(process_block(block))
|
||||
for _, dec in ipairs(decimal_values) do
|
||||
table.insert(all_decimal_values, dec)
|
||||
end
|
||||
end
|
||||
if #all_decimal_values < 15 then
|
||||
error(ac.red..' Error:'..ac.reset..' Not enough data after processing blocks 4, 5, 6, and 7')
|
||||
end
|
||||
local id_positions = {9, 11, 13, 15, 2, 4, 6, 8}
|
||||
local id_numbers = {}
|
||||
for _, pos in ipairs(id_positions) do
|
||||
table.insert(id_numbers, all_decimal_values[pos])
|
||||
end
|
||||
local decimal_id = tonumber(table.concat(id_numbers))
|
||||
local padded_hex_id = string.format("%010X", decimal_id)
|
||||
return decimal_id, padded_hex_id
|
||||
end
|
||||
|
||||
local function name_exists_in_log(name)
|
||||
local file = io.open(log_file_path, "r")
|
||||
if not file then
|
||||
return false
|
||||
end
|
||||
local pattern = "^Name:%s*" .. name .. "%s*$"
|
||||
for line in file:lines() do
|
||||
if line:match(pattern) then
|
||||
file:close()
|
||||
return true
|
||||
end
|
||||
end
|
||||
file:close()
|
||||
return false
|
||||
end
|
||||
|
||||
local function log_result(blocks, em410_id, name)
|
||||
local log_file = io.open(log_file_path, "a")
|
||||
if log_file then
|
||||
log_file:write("Name: " .. name .. "\n")
|
||||
log_file:write("Date: ", os.date("%Y-%m-%d %H:%M:%S"), "\n")
|
||||
for i = 4, 7 do
|
||||
log_file:write(string.format("Block %d: %s\n", i, blocks[i] or "nil"))
|
||||
end
|
||||
log_file:write(string.format('EM4102 ID: %s\n', em410_id or "nil"))
|
||||
log_file:write('--------------------------\n')
|
||||
log_file:close()
|
||||
print(' Log saved as: pm3/.proxmark3/logs/' ..ac.yellow..' Paxton_log.txt'..ac.reset)
|
||||
else
|
||||
print(" Failed to open log file for writing.")
|
||||
end
|
||||
end
|
||||
|
||||
local function verify_written_data(original_blocks)
|
||||
p:console('lf hitag read --ht2 -k BDF5E846')
|
||||
local result = read_log_file(logfile)
|
||||
local verified_blocks = parse_blocks(result)
|
||||
local success = true
|
||||
for i = 4, 7 do
|
||||
if original_blocks[i] ~= verified_blocks[i] then
|
||||
print(' Verification failed.. Block '..ac.green.. i ..ac.reset.. ' inconsistent.')
|
||||
success = false
|
||||
end
|
||||
end
|
||||
|
||||
if success then
|
||||
print(ac.green..' Verification successful. Data was written correctly.' .. ac.reset)
|
||||
else
|
||||
print(ac.yellow.. ' Adjust the position of the Paxton fob on the coil.' .. ac.reset)
|
||||
end
|
||||
end
|
||||
|
||||
local function handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3)
|
||||
while true do
|
||||
io.write(" Create Paxton choose " .. ac.cyan .. "1" .. ac.reset .. " or EM4102 choose " .. ac.cyan .. "2 " .. ac.reset)
|
||||
local choice = io.read()
|
||||
if choice == "1" then
|
||||
io.write(" Place the" .. ac.cyan .. " Paxton " .. ac.reset .. "Fob on the coil to write.." .. ac.green .. " ENTER " .. ac.reset .. "to continue..")
|
||||
io.read()
|
||||
print(dash)
|
||||
p:console("lf hitag wrbl --ht2 -p 4 -d " .. blocks[4] .. " -k BDF5E846")
|
||||
p:console("lf hitag wrbl --ht2 -p 5 -d " .. blocks[5] .. " -k BDF5E846")
|
||||
p:console("lf hitag wrbl --ht2 -p 6 -d " .. blocks[6] .. " -k BDF5E846")
|
||||
p:console("lf hitag wrbl --ht2 -p 7 -d " .. blocks[7] .. " -k BDF5E846")
|
||||
reset_log_file()
|
||||
--timer(5)
|
||||
verify_written_data(blocks)
|
||||
elseif choice == "2" then
|
||||
io.write(" Place the" .. ac.cyan .. " T5577 " .. ac.reset .. "tag on the coil and press" .. ac.green .. " ENTER " .. ac.reset .. "to continue..")
|
||||
io.read()
|
||||
p:console("lf em 410x clone --id " .. padded_hex_id)
|
||||
print(' Cloned EM4102 to T5577 with ID ' ..ac.green.. padded_hex_id ..ac.reset)
|
||||
else
|
||||
print(ac.yellow .. " Invalid choice." .. ac.reset .. " Please enter " .. ac.cyan .. "1" .. ac.reset .. " or " .. ac.cyan .. "2" .. ac.reset)
|
||||
goto ask_again
|
||||
end
|
||||
while true do
|
||||
print(dash)
|
||||
io.write(" Make next RFID Fob"..ac.cyan.." (y/n) "..ac.reset)
|
||||
local another = io.read()
|
||||
if another:lower() == "n" then
|
||||
if was_option_3 then
|
||||
print(" No writing to Paxton_log.txt - Name: " ..ac.green.. nam .. ac.reset.. " exist")
|
||||
return
|
||||
end
|
||||
print()
|
||||
print(ac.green .. " Saving Paxton_log file..." .. ac.reset)
|
||||
while true do
|
||||
io.write(" Enter a name for database (cannot be empty/duplicate): "..ac.yellow)
|
||||
name = io.read()
|
||||
io.write(ac.reset..'')
|
||||
if name == nil or name:match("^%s*$") then
|
||||
print(ac.red .. ' ERROR:'..ac.reset..' Name cannot be empty.')
|
||||
else
|
||||
if name_exists_in_log(name) then
|
||||
print(ac.yellow .. ' Name exists!!! '..ac.reset.. 'Please choose a different name.')
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
log_result(blocks, padded_hex_id, name)
|
||||
print(ac.green .. " Log saved successfully!" .. ac.reset)
|
||||
reset_log_file()
|
||||
return
|
||||
elseif another:lower() == "y" then
|
||||
goto ask_again
|
||||
else
|
||||
print(ac.yellow.." Invalid response."..ac.reset.." Please enter"..ac.cyan.." y"..ac.reset.." or"..ac.cyan.." n"..ac.reset)
|
||||
end
|
||||
end
|
||||
::ask_again::
|
||||
end
|
||||
end
|
||||
|
||||
local function is_valid_hex(input)
|
||||
return #input == 8 and input:match("^[0-9A-Fa-f]+$")
|
||||
end
|
||||
|
||||
local function main(args)
|
||||
while true do
|
||||
for o, a in getopt.getopt(args, 'h') do
|
||||
if o == 'h' then return help() end
|
||||
end
|
||||
command('clear')
|
||||
print(dash)
|
||||
print(ac.green .. ' Select option: ' .. ac.reset)
|
||||
print(ac.cyan .. ' 1' .. ac.reset .. ' - Read Paxton blocks 4-7 to make a copy')
|
||||
print(ac.cyan .. ' 2' .. ac.reset .. ' - Manually input data for Paxton blocks 4-7')
|
||||
print(ac.cyan .. " 3" .. ac.reset .. " - Search in Paxton_log by name and use the data")
|
||||
print(dash)
|
||||
while true do
|
||||
io.write(' Your choice '..ac.cyan..'(1/2/3): ' .. ac.reset)
|
||||
input_option = io.read()
|
||||
if input_option == "1" or input_option == "2" or input_option == "3" then
|
||||
break
|
||||
else
|
||||
print(ac.yellow .. ' Invalid choice.' .. ac.reset .. ' Please enter ' .. ac.cyan .. '1' .. ac.reset .. ' or ' .. ac.cyan .. '2' .. ac.reset..' or'..ac.cyan..' 3'..ac.reset)
|
||||
end
|
||||
end
|
||||
local was_option_3 = false
|
||||
if input_option == "1" then
|
||||
local show_place_message = true
|
||||
while true do
|
||||
if show_place_message then
|
||||
io.write(' Place the' .. ac.cyan .. ' Paxton' .. ac.reset .. ' Fob on the coil to read..' .. ac.green .. 'ENTER' .. ac.reset .. ' to continue..')
|
||||
end
|
||||
io.read()
|
||||
print(dash)
|
||||
p:console('lf hitag read --ht2 -k BDF5E846')
|
||||
if not logfile then
|
||||
error(" No files in this directory")
|
||||
end
|
||||
local result = read_log_file(logfile)
|
||||
local blocks = parse_blocks(result)
|
||||
local empty_block = false
|
||||
for i = 4, 7 do
|
||||
if not blocks[i] then
|
||||
empty_block = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if empty_block then
|
||||
io.write(ac.yellow .. ' Adjust the Fob position on the coil.' .. ac.reset .. ' Press' .. ac.green .. ' ENTER' .. ac.reset .. ' to continue..')
|
||||
show_place_message = false
|
||||
else
|
||||
print(' Readed blocks:')
|
||||
print()
|
||||
for i = 4, 7 do
|
||||
if blocks[i] then
|
||||
print(string.format(" Block %d: %s%s%s", i, ac.yellow, blocks[i], ac.reset))
|
||||
end
|
||||
end
|
||||
local decimal_id, padded_hex_id
|
||||
if blocks[5] and (blocks[5]:sub(4, 4) == 'F' or blocks[5]:sub(4, 4) == 'f') then
|
||||
print(dash)
|
||||
print(' Identified Paxton ' .. ac.cyan .. 'Net2' .. ac.reset)
|
||||
decimal_id, padded_hex_id = calculate_id_net({blocks[4], blocks[5]})
|
||||
else
|
||||
print(dash)
|
||||
print(' Identified Paxton ' .. ac.cyan .. 'Switch2' .. ac.reset)
|
||||
decimal_id, padded_hex_id = calculate_id_switch({blocks[4], blocks[5], blocks[6], blocks[7]})
|
||||
end
|
||||
print(string.format(" ID for EM4102 is: %s", ac.green .. padded_hex_id .. ac.reset))
|
||||
print(dash)
|
||||
handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3)
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif input_option == "2" then
|
||||
local blocks = {}
|
||||
for i = 4, 7 do
|
||||
while true do
|
||||
io.write(ac.reset..' Enter data for block ' .. i .. ': ' .. ac.yellow)
|
||||
local input = io.read()
|
||||
input = input:upper()
|
||||
if is_valid_hex(input) then
|
||||
blocks[i] = input
|
||||
break
|
||||
else
|
||||
print(ac.yellow .. ' Invalid input.' .. ac.reset .. ' Each block must be 4 bytes (8 hex characters).')
|
||||
end
|
||||
end
|
||||
end
|
||||
local decimal_id, padded_hex_id
|
||||
if blocks[5] and (blocks[5]:sub(4, 4) == 'F' or blocks[5]:sub(4, 4) == 'f') then
|
||||
print(ac.reset.. dash)
|
||||
print(' Identified Paxton ' .. ac.cyan .. 'Net2' .. ac.reset)
|
||||
decimal_id, padded_hex_id = calculate_id_net({blocks[4], blocks[5]})
|
||||
else
|
||||
print(ac.reset.. dash)
|
||||
print(' Identified Paxton ' .. ac.cyan .. 'Switch2' .. ac.reset)
|
||||
decimal_id, padded_hex_id = calculate_id_switch({blocks[4], blocks[5], blocks[6], blocks[7]})
|
||||
end
|
||||
print(dash)
|
||||
print(string.format(" ID for EM4102 is: %s", ac.green .. padded_hex_id .. ac.reset))
|
||||
print(dash)
|
||||
if not padded_hex_id then
|
||||
print(ac.red..' ERROR: '..ac.reset.. 'Invalid block data provided')
|
||||
return
|
||||
end
|
||||
handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3)
|
||||
break
|
||||
elseif input_option == "3" then
|
||||
was_option_3 = true
|
||||
local retries = 3
|
||||
while retries > 0 do
|
||||
io.write(' Enter the name to search ('..retries..' attempts) : '..ac.yellow)
|
||||
local user_input = io.read()
|
||||
io.write(ac.reset..'')
|
||||
if user_input == nil or user_input:match("^%s*$") then
|
||||
print(ac.yellow..' Error: '..ac.reset.. 'Empty name !!!')
|
||||
end
|
||||
local name_clean = "^Name:%s*" .. user_input:gsub("%s", "%%s") .. "%s*$"
|
||||
local file = io.open(log_file_path, "r")
|
||||
if not file then
|
||||
print(ac.red .. ' Error:'..ac.reset.. 'Could not open log file.')
|
||||
return
|
||||
end
|
||||
local lines = {}
|
||||
for line in file:lines() do
|
||||
table.insert(lines, line)
|
||||
end
|
||||
file:close()
|
||||
local found = false
|
||||
for i = 1, #lines do
|
||||
if lines[i]:match(name_clean) then
|
||||
nam = user_input
|
||||
local blocks = {
|
||||
[4] = lines[i + 2]:match("Block 4: (.+)"),
|
||||
[5] = lines[i + 3]:match("Block 5: (.+)"),
|
||||
[6] = lines[i + 4]:match("Block 6: (.+)"),
|
||||
[7] = lines[i + 5]:match("Block 7: (.+)")
|
||||
}
|
||||
local em4102_id = lines[i + 6]:match("EM4102 ID: (.+)")
|
||||
print(dash)
|
||||
print(' I found the data under the name: '..ac.yellow ..nam.. ac.reset)
|
||||
for j = 4, 7 do
|
||||
print(string.format(" Block %d: %s%s%s", j, ac.yellow, blocks[j] or "N/A", ac.reset))
|
||||
end
|
||||
print(" EM4102 ID: " .. ac.green .. (em4102_id or "N/A") .. ac.reset)
|
||||
print(dash)
|
||||
local decimal_id, padded_hex_id = em4102_id, em4102_id
|
||||
handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3, nam)
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not found then
|
||||
retries = retries - 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
if retries == 0 then
|
||||
print(ac.yellow .. " Name not found after 3 attempts." .. ac.reset)
|
||||
end
|
||||
end
|
||||
print(dash)
|
||||
print(' Exiting script Lua...')
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local getopt = require('getopt')
|
||||
local utils = require('utils')
|
||||
local ac = require('ansicolors')
|
||||
local os = require('os')
|
||||
local dash = string.rep('--', 32)
|
||||
local dir = os.getenv('HOME') .. '/.proxmark3/logs/'
|
||||
local logfile = (io.popen('dir /a-d /o-d /tw /b/s "' .. dir .. '" 2>nul:'):read("*a"):match("%C+"))
|
||||
local log_file_path = dir .. "Paxton_log.txt"
|
||||
local nam = ""
|
||||
local pm3 = require('pm3')
|
||||
p = pm3.pm3()
|
||||
local command = core.console
|
||||
command('clear')
|
||||
|
||||
author = ' Author: jareckib - 30.01.2025'
|
||||
tutorial = ' Based on Equipter tutorial - Downgrade Paxton to EM4102'
|
||||
version = ' version v1.20'
|
||||
desc = [[
|
||||
The script automates the copying of Paxton fobs read - write.
|
||||
It also allows manual input of data for blocks 4-7.
|
||||
The third option is reading data stored in the log file and create new fob.
|
||||
Additionally, the script calculates the ID for downgrading Paxton to EM4102.
|
||||
|
||||
]]
|
||||
usage = [[
|
||||
script run paxton_clone
|
||||
]]
|
||||
arguments = [[
|
||||
script run paxton_clone -h : this help
|
||||
]]
|
||||
|
||||
local debug = true
|
||||
|
||||
local function dbg(args)
|
||||
if not DEBUG then return end
|
||||
if type(args) == 'table' then
|
||||
local i = 1
|
||||
while args[i] do
|
||||
dbg(args[i])
|
||||
i = i+1
|
||||
end
|
||||
else
|
||||
print('###', args)
|
||||
end
|
||||
end
|
||||
|
||||
local function help()
|
||||
print()
|
||||
print(author)
|
||||
print(tutorial)
|
||||
print(version)
|
||||
print(desc)
|
||||
print(ac.cyan..' Usage'..ac.reset)
|
||||
print(usage)
|
||||
print(ac.cyan..' Arguments'..ac.reset)
|
||||
print(arguments)
|
||||
end
|
||||
|
||||
local function reset_log_file()
|
||||
local file = io.open(logfile, "w+")
|
||||
file:write("")
|
||||
file:close()
|
||||
end
|
||||
|
||||
local function read_log_file(logfile)
|
||||
local file = io.open(logfile, "r")
|
||||
if not file then
|
||||
error(" Could not open the file")
|
||||
end
|
||||
local content = file:read("*all")
|
||||
file:close()
|
||||
return content
|
||||
end
|
||||
|
||||
local function parse_blocks(result)
|
||||
local blocks = {}
|
||||
for line in result:gmatch("[^\r\n]+") do
|
||||
local block_num, block_data = line:match("%[%=%]%s+%d/0x0([4-7])%s+%|%s+([0-9A-F ]+)")
|
||||
if block_num and block_data then
|
||||
block_num = tonumber(block_num)
|
||||
block_data = block_data:gsub("%s+", "")
|
||||
blocks[block_num] = block_data
|
||||
end
|
||||
end
|
||||
return blocks
|
||||
end
|
||||
|
||||
local function hex_to_bin(hex_string)
|
||||
local bin_string = ""
|
||||
local hex_to_bin_map = {
|
||||
['0'] = "0000", ['1'] = "0001", ['2'] = "0010", ['3'] = "0011",
|
||||
['4'] = "0100", ['5'] = "0101", ['6'] = "0110", ['7'] = "0111",
|
||||
['8'] = "1000", ['9'] = "1001", ['A'] = "1010", ['B'] = "1011",
|
||||
['C'] = "1100", ['D'] = "1101", ['E'] = "1110", ['F'] = "1111"
|
||||
}
|
||||
for i = 1, #hex_string do
|
||||
bin_string = bin_string .. hex_to_bin_map[hex_string:sub(i, i)]
|
||||
end
|
||||
return bin_string
|
||||
end
|
||||
|
||||
local function remove_last_two_bits(binary_str)
|
||||
return binary_str:sub(1, #binary_str - 2)
|
||||
end
|
||||
|
||||
local function split_into_5bit_chunks(binary_str)
|
||||
local chunks = {}
|
||||
for i = 1, #binary_str, 5 do
|
||||
table.insert(chunks, binary_str:sub(i, i + 4))
|
||||
end
|
||||
return chunks
|
||||
end
|
||||
|
||||
local function remove_parity_bit(chunks)
|
||||
local no_parity_chunks = {}
|
||||
for _, chunk in ipairs(chunks) do
|
||||
if #chunk == 5 then
|
||||
table.insert(no_parity_chunks, chunk:sub(2))
|
||||
end
|
||||
end
|
||||
return no_parity_chunks
|
||||
end
|
||||
|
||||
local function convert_to_hex(chunks)
|
||||
local hex_values = {}
|
||||
for _, chunk in ipairs(chunks) do
|
||||
if #chunk > 0 then
|
||||
table.insert(hex_values, string.format("%X", tonumber(chunk, 2)))
|
||||
end
|
||||
end
|
||||
return hex_values
|
||||
end
|
||||
|
||||
local function convert_to_decimal(chunks)
|
||||
local decimal_values = {}
|
||||
for _, chunk in ipairs(chunks) do
|
||||
table.insert(decimal_values, tonumber(chunk, 2))
|
||||
end
|
||||
return decimal_values
|
||||
end
|
||||
|
||||
local function find_until_before_f(hex_values)
|
||||
local result = {}
|
||||
for _, value in ipairs(hex_values) do
|
||||
if value == 'F' then
|
||||
break
|
||||
end
|
||||
table.insert(result, value)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function process_block(block)
|
||||
local binary_str = hex_to_bin(block)
|
||||
binary_str = remove_last_two_bits(binary_str)
|
||||
local chunks = split_into_5bit_chunks(binary_str)
|
||||
local no_parity_chunks = remove_parity_bit(chunks)
|
||||
return no_parity_chunks
|
||||
end
|
||||
|
||||
local function calculate_id_net(blocks)
|
||||
local all_hex_values = {}
|
||||
for _, block in ipairs(blocks) do
|
||||
local hex_values = convert_to_hex(process_block(block))
|
||||
for _, hex in ipairs(hex_values) do
|
||||
table.insert(all_hex_values, hex)
|
||||
end
|
||||
end
|
||||
local selected_hex_values = find_until_before_f(all_hex_values)
|
||||
if #selected_hex_values == 0 then
|
||||
error(ac.red..' Error: '..ac.reset..'No valid data found in blocks 4 and 5')
|
||||
end
|
||||
local combined_hex = table.concat(selected_hex_values)
|
||||
if not combined_hex:match("^%x+$") then
|
||||
error(ac.red..' Error: '..ac.reset..'Invalid data in blocks 4 and 5')
|
||||
end
|
||||
local decimal_id = tonumber(combined_hex)
|
||||
local stripped_hex_id = string.format("%X", decimal_id)
|
||||
local padded_hex_id = string.format("%010X", decimal_id)
|
||||
return decimal_id, padded_hex_id
|
||||
end
|
||||
|
||||
local function calculate_id_switch(blocks)
|
||||
local all_decimal_values = {}
|
||||
for _, block in ipairs(blocks) do
|
||||
local decimal_values = convert_to_decimal(process_block(block))
|
||||
for _, dec in ipairs(decimal_values) do
|
||||
table.insert(all_decimal_values, dec)
|
||||
end
|
||||
end
|
||||
if #all_decimal_values < 15 then
|
||||
error(ac.red..' Error:'..ac.reset..' Not enough data after processing blocks 4, 5, 6, and 7')
|
||||
end
|
||||
local id_positions = {9, 11, 13, 15, 2, 4, 6, 8}
|
||||
local id_numbers = {}
|
||||
for _, pos in ipairs(id_positions) do
|
||||
table.insert(id_numbers, all_decimal_values[pos])
|
||||
end
|
||||
local decimal_id = tonumber(table.concat(id_numbers))
|
||||
local padded_hex_id = string.format("%010X", decimal_id)
|
||||
return decimal_id, padded_hex_id
|
||||
end
|
||||
|
||||
local function name_exists_in_log(name)
|
||||
local file = io.open(log_file_path, "r")
|
||||
if not file then
|
||||
return false
|
||||
end
|
||||
local pattern = "^Name:%s*" .. name .. "%s*$"
|
||||
for line in file:lines() do
|
||||
if line:match(pattern) then
|
||||
file:close()
|
||||
return true
|
||||
end
|
||||
end
|
||||
file:close()
|
||||
return false
|
||||
end
|
||||
|
||||
local function log_result(blocks, em410_id, name)
|
||||
local log_file = io.open(log_file_path, "a")
|
||||
if log_file then
|
||||
log_file:write("Name: " .. name .. "\n")
|
||||
log_file:write("Date: ", os.date("%Y-%m-%d %H:%M:%S"), "\n")
|
||||
for i = 4, 7 do
|
||||
log_file:write(string.format("Block %d: %s\n", i, blocks[i] or "nil"))
|
||||
end
|
||||
log_file:write(string.format('EM4102 ID: %s\n', em410_id or "nil"))
|
||||
log_file:write('--------------------------\n')
|
||||
log_file:close()
|
||||
print(' Log saved as: pm3/.proxmark3/logs/' ..ac.yellow..' Paxton_log.txt'..ac.reset)
|
||||
else
|
||||
print(" Failed to open log file for writing.")
|
||||
end
|
||||
end
|
||||
|
||||
local function verify_written_data(original_blocks)
|
||||
p:console('lf hitag read --ht2 -k BDF5E846')
|
||||
local result = read_log_file(logfile)
|
||||
local verified_blocks = parse_blocks(result)
|
||||
local success = true
|
||||
for i = 4, 7 do
|
||||
if original_blocks[i] ~= verified_blocks[i] then
|
||||
print(' Verification failed.. Block '..ac.green.. i ..ac.reset.. ' inconsistent.')
|
||||
success = false
|
||||
end
|
||||
end
|
||||
|
||||
if success then
|
||||
print(ac.green..' Verification successful. Data was written correctly.' .. ac.reset)
|
||||
else
|
||||
print(ac.yellow.. ' Adjust the position of the Paxton fob on the coil.' .. ac.reset)
|
||||
end
|
||||
end
|
||||
|
||||
local function handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3)
|
||||
while true do
|
||||
io.write(" Create Paxton choose " .. ac.cyan .. "1" .. ac.reset .. " or EM4102 choose " .. ac.cyan .. "2 " .. ac.reset)
|
||||
local choice = io.read()
|
||||
if choice == "1" then
|
||||
io.write(" Place the" .. ac.cyan .. " Paxton " .. ac.reset .. "Fob on the coil to write.." .. ac.green .. " ENTER " .. ac.reset .. "to continue..")
|
||||
io.read()
|
||||
print(dash)
|
||||
p:console("lf hitag wrbl --ht2 -p 4 -d " .. blocks[4] .. " -k BDF5E846")
|
||||
p:console("lf hitag wrbl --ht2 -p 5 -d " .. blocks[5] .. " -k BDF5E846")
|
||||
p:console("lf hitag wrbl --ht2 -p 6 -d " .. blocks[6] .. " -k BDF5E846")
|
||||
p:console("lf hitag wrbl --ht2 -p 7 -d " .. blocks[7] .. " -k BDF5E846")
|
||||
reset_log_file()
|
||||
--timer(5)
|
||||
verify_written_data(blocks)
|
||||
elseif choice == "2" then
|
||||
io.write(" Place the" .. ac.cyan .. " T5577 " .. ac.reset .. "tag on the coil and press" .. ac.green .. " ENTER " .. ac.reset .. "to continue..")
|
||||
io.read()
|
||||
p:console("lf em 410x clone --id " .. padded_hex_id)
|
||||
print(' Cloned EM4102 to T5577 with ID ' ..ac.green.. padded_hex_id ..ac.reset)
|
||||
else
|
||||
print(ac.yellow .. " Invalid choice." .. ac.reset .. " Please enter " .. ac.cyan .. "1" .. ac.reset .. " or " .. ac.cyan .. "2" .. ac.reset)
|
||||
goto ask_again
|
||||
end
|
||||
while true do
|
||||
print(dash)
|
||||
io.write(" Make next RFID Fob"..ac.cyan.." (y/n) "..ac.reset)
|
||||
local another = io.read()
|
||||
if another:lower() == "n" then
|
||||
if was_option_3 then
|
||||
print(" No writing to Paxton_log.txt - Name: " ..ac.green.. nam .. ac.reset.. " exist")
|
||||
return
|
||||
end
|
||||
print()
|
||||
print(ac.green .. " Saving Paxton_log file..." .. ac.reset)
|
||||
while true do
|
||||
io.write(" Enter a name for database (cannot be empty/duplicate): "..ac.yellow)
|
||||
name = io.read()
|
||||
io.write(ac.reset..'')
|
||||
if name == nil or name:match("^%s*$") then
|
||||
print(ac.red .. ' ERROR:'..ac.reset..' Name cannot be empty.')
|
||||
else
|
||||
if name_exists_in_log(name) then
|
||||
print(ac.yellow .. ' Name exists!!! '..ac.reset.. 'Please choose a different name.')
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
log_result(blocks, padded_hex_id, name)
|
||||
print(ac.green .. " Log saved successfully!" .. ac.reset)
|
||||
reset_log_file()
|
||||
return
|
||||
elseif another:lower() == "y" then
|
||||
goto ask_again
|
||||
else
|
||||
print(ac.yellow.." Invalid response."..ac.reset.." Please enter"..ac.cyan.." y"..ac.reset.." or"..ac.cyan.." n"..ac.reset)
|
||||
end
|
||||
end
|
||||
::ask_again::
|
||||
end
|
||||
end
|
||||
|
||||
local function is_valid_hex(input)
|
||||
return #input == 8 and input:match("^[0-9A-Fa-f]+$")
|
||||
end
|
||||
|
||||
local function main(args)
|
||||
while true do
|
||||
for o, a in getopt.getopt(args, 'h') do
|
||||
if o == 'h' then return help() end
|
||||
end
|
||||
command('clear')
|
||||
print(dash)
|
||||
print(ac.green .. ' Select option: ' .. ac.reset)
|
||||
print(ac.cyan .. ' 1' .. ac.reset .. ' - Read Paxton blocks 4-7 to make a copy')
|
||||
print(ac.cyan .. ' 2' .. ac.reset .. ' - Manually input data for Paxton blocks 4-7')
|
||||
print(ac.cyan .. " 3" .. ac.reset .. " - Search in Paxton_log by name and use the data")
|
||||
print(dash)
|
||||
while true do
|
||||
io.write(' Your choice '..ac.cyan..'(1/2/3): ' .. ac.reset)
|
||||
input_option = io.read()
|
||||
if input_option == "1" or input_option == "2" or input_option == "3" then
|
||||
break
|
||||
else
|
||||
print(ac.yellow .. ' Invalid choice.' .. ac.reset .. ' Please enter ' .. ac.cyan .. '1' .. ac.reset .. ' or ' .. ac.cyan .. '2' .. ac.reset..' or'..ac.cyan..' 3'..ac.reset)
|
||||
end
|
||||
end
|
||||
local was_option_3 = false
|
||||
if input_option == "1" then
|
||||
local show_place_message = true
|
||||
while true do
|
||||
if show_place_message then
|
||||
io.write(' Place the' .. ac.cyan .. ' Paxton' .. ac.reset .. ' Fob on the coil to read..' .. ac.green .. 'ENTER' .. ac.reset .. ' to continue..')
|
||||
end
|
||||
io.read()
|
||||
print(dash)
|
||||
p:console('lf hitag read --ht2 -k BDF5E846')
|
||||
if not logfile then
|
||||
error(" No files in this directory")
|
||||
end
|
||||
local result = read_log_file(logfile)
|
||||
local blocks = parse_blocks(result)
|
||||
local empty_block = false
|
||||
for i = 4, 7 do
|
||||
if not blocks[i] then
|
||||
empty_block = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if empty_block then
|
||||
io.write(ac.yellow .. ' Adjust the Fob position on the coil.' .. ac.reset .. ' Press' .. ac.green .. ' ENTER' .. ac.reset .. ' to continue..')
|
||||
show_place_message = false
|
||||
else
|
||||
print(' Readed blocks:')
|
||||
print()
|
||||
for i = 4, 7 do
|
||||
if blocks[i] then
|
||||
print(string.format(" Block %d: %s%s%s", i, ac.yellow, blocks[i], ac.reset))
|
||||
end
|
||||
end
|
||||
local decimal_id, padded_hex_id
|
||||
if blocks[5] and (blocks[5]:sub(4, 4) == 'F' or blocks[5]:sub(4, 4) == 'f') then
|
||||
print(dash)
|
||||
print(' Identified Paxton ' .. ac.cyan .. 'Net2' .. ac.reset)
|
||||
decimal_id, padded_hex_id = calculate_id_net({blocks[4], blocks[5]})
|
||||
else
|
||||
print(dash)
|
||||
print(' Identified Paxton ' .. ac.cyan .. 'Switch2' .. ac.reset)
|
||||
decimal_id, padded_hex_id = calculate_id_switch({blocks[4], blocks[5], blocks[6], blocks[7]})
|
||||
end
|
||||
print(string.format(" ID for EM4102 is: %s", ac.green .. padded_hex_id .. ac.reset))
|
||||
print(dash)
|
||||
handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3)
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif input_option == "2" then
|
||||
local blocks = {}
|
||||
for i = 4, 7 do
|
||||
while true do
|
||||
io.write(ac.reset..' Enter data for block ' .. i .. ': ' .. ac.yellow)
|
||||
local input = io.read()
|
||||
input = input:upper()
|
||||
if is_valid_hex(input) then
|
||||
blocks[i] = input
|
||||
break
|
||||
else
|
||||
print(ac.yellow .. ' Invalid input.' .. ac.reset .. ' Each block must be 4 bytes (8 hex characters).')
|
||||
end
|
||||
end
|
||||
end
|
||||
local decimal_id, padded_hex_id
|
||||
if blocks[5] and (blocks[5]:sub(4, 4) == 'F' or blocks[5]:sub(4, 4) == 'f') then
|
||||
print(ac.reset.. dash)
|
||||
print(' Identified Paxton ' .. ac.cyan .. 'Net2' .. ac.reset)
|
||||
decimal_id, padded_hex_id = calculate_id_net({blocks[4], blocks[5]})
|
||||
else
|
||||
print(ac.reset.. dash)
|
||||
print(' Identified Paxton ' .. ac.cyan .. 'Switch2' .. ac.reset)
|
||||
decimal_id, padded_hex_id = calculate_id_switch({blocks[4], blocks[5], blocks[6], blocks[7]})
|
||||
end
|
||||
print(dash)
|
||||
print(string.format(" ID for EM4102 is: %s", ac.green .. padded_hex_id .. ac.reset))
|
||||
print(dash)
|
||||
if not padded_hex_id then
|
||||
print(ac.red..' ERROR: '..ac.reset.. 'Invalid block data provided')
|
||||
return
|
||||
end
|
||||
handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3)
|
||||
break
|
||||
elseif input_option == "3" then
|
||||
was_option_3 = true
|
||||
local retries = 3
|
||||
while retries > 0 do
|
||||
io.write(' Enter the name to search ('..retries..' attempts) : '..ac.yellow)
|
||||
local user_input = io.read()
|
||||
io.write(ac.reset..'')
|
||||
if user_input == nil or user_input:match("^%s*$") then
|
||||
print(ac.yellow..' Error: '..ac.reset.. 'Empty name !!!')
|
||||
end
|
||||
local name_clean = "^Name:%s*" .. user_input:gsub("%s", "%%s") .. "%s*$"
|
||||
local file = io.open(log_file_path, "r")
|
||||
if not file then
|
||||
print(ac.red .. ' Error:'..ac.reset.. 'Could not open log file.')
|
||||
return
|
||||
end
|
||||
local lines = {}
|
||||
for line in file:lines() do
|
||||
table.insert(lines, line)
|
||||
end
|
||||
file:close()
|
||||
local found = false
|
||||
for i = 1, #lines do
|
||||
if lines[i]:match(name_clean) then
|
||||
nam = user_input
|
||||
local blocks = {
|
||||
[4] = lines[i + 2]:match("Block 4: (.+)"),
|
||||
[5] = lines[i + 3]:match("Block 5: (.+)"),
|
||||
[6] = lines[i + 4]:match("Block 6: (.+)"),
|
||||
[7] = lines[i + 5]:match("Block 7: (.+)")
|
||||
}
|
||||
local em4102_id = lines[i + 6]:match("EM4102 ID: (.+)")
|
||||
print(dash)
|
||||
print(' I found the data under the name: '..ac.yellow ..nam.. ac.reset)
|
||||
for j = 4, 7 do
|
||||
print(string.format(" Block %d: %s%s%s", j, ac.yellow, blocks[j] or "N/A", ac.reset))
|
||||
end
|
||||
print(" EM4102 ID: " .. ac.green .. (em4102_id or "N/A") .. ac.reset)
|
||||
print(dash)
|
||||
local decimal_id, padded_hex_id = em4102_id, em4102_id
|
||||
handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3, nam)
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not found then
|
||||
retries = retries - 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
if retries == 0 then
|
||||
print(ac.yellow .. " Name not found after 3 attempts." .. ac.reset)
|
||||
end
|
||||
end
|
||||
print(dash)
|
||||
print(' Exiting script Lua...')
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
main(args)
|
||||
|
|
|
@ -1921,7 +1921,7 @@ int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status,
|
|||
// if ((sak & 0x01) == 0x01) { // SAK b2=0 b4=0 b5=1 b1=1, SAK=0x11
|
||||
// } else { // SAK b2=0 b4=0 b5=1 b1=0, SAK=0x10
|
||||
// }
|
||||
type |= MTPLUS;
|
||||
type |= MTPLUS;
|
||||
|
||||
} else { // SAK b2=0 b4=0 b5=0
|
||||
|
||||
|
|
|
@ -327,7 +327,7 @@ static const iclass_config_card_item_t *get_config_card_item(int idx) {
|
|||
static void print_config_cards(void) {
|
||||
PrintAndLogEx(INFO, "---- " _CYAN_("Config cards options") " ------------");
|
||||
for (int i = 0; i < ARRAYLEN(iclass_config_options) ; ++i) {
|
||||
switch (i){
|
||||
switch (i) {
|
||||
case 0:
|
||||
PrintAndLogEx(INFO, _YELLOW_("---- LED Operations ----"));
|
||||
break;
|
||||
|
|
|
@ -567,7 +567,7 @@ static int CmdEM4x70Brute(const char *Cmd) {
|
|||
return PM3_EINVARG;
|
||||
}
|
||||
CLIParserFree(ctx);
|
||||
|
||||
|
||||
// opts structure takes value in BIG ENDIAN form
|
||||
opts.partial_key_start[0] = (uint8_t)((start_key >> 8) & 0xFF);
|
||||
opts.partial_key_start[1] = (uint8_t)((start_key >> 0) & 0xFF);
|
||||
|
@ -628,7 +628,7 @@ static int CmdEM4x70Unlock(const char *Cmd) {
|
|||
PrintAndLogEx(FAILED, "PIN length must be 4 bytes, got %d", pin_len);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
||||
// Client command line parsing and validation complete ... now use the helper function
|
||||
em4x70_tag_info_t info;
|
||||
int result = unlock_em4x70(&opts, &info);
|
||||
|
@ -768,7 +768,7 @@ static int CmdEM4x70SetKey(const char *Cmd) {
|
|||
PrintAndLogEx(FAILED, "Key length must be 12 bytes, got %d", key_len);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
||||
// Client command line parsing and validation complete ... now use the helper function
|
||||
int result = setkey_em4x70(&opts);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue