mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 13:23:51 -07:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
fef7e78957
186 changed files with 10639 additions and 4950 deletions
|
@ -68,9 +68,9 @@ end
|
|||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
local function oops(err)
|
||||
print("ERROR: ",err)
|
||||
print("ERROR: ", err)
|
||||
calypso_switch_off_field()
|
||||
return nil,err
|
||||
return nil, err
|
||||
end
|
||||
---
|
||||
-- Usage help
|
||||
|
|
|
@ -5,7 +5,7 @@ local utils = require('utils')
|
|||
|
||||
copyright = 'Copyright (c) 2018 IceSQL AB. All rights reserved.'
|
||||
author = 'Christian Herrmann'
|
||||
version = 'v1.0.3'
|
||||
version = 'v1.0.4'
|
||||
desc = [[
|
||||
This script tries to set UID on a IS15693 SLIX magic card
|
||||
Remember the UID ->MUST<- start with 0xE0
|
||||
|
@ -15,6 +15,8 @@ example = [[
|
|||
-- ISO15693 slix magic tag
|
||||
|
||||
script run iso15_magic -u E004013344556677
|
||||
|
||||
script run iso15_magic -u E004013344556677 -a
|
||||
]]
|
||||
usage = [[
|
||||
script run iso15_magic -h -u <uid>
|
||||
|
@ -22,6 +24,7 @@ script run iso15_magic -h -u <uid>
|
|||
Arguments:
|
||||
-h : this help
|
||||
-u <UID> : UID (16 hexsymbols)
|
||||
-a : use offical pm3 repo ISO15 commands instead of iceman fork.
|
||||
]]
|
||||
|
||||
local DEBUG = true
|
||||
|
@ -82,11 +85,13 @@ function main(args)
|
|||
print()
|
||||
|
||||
local uid = 'E004013344556677'
|
||||
local use_iceman = true
|
||||
|
||||
-- Read the parameters
|
||||
for o, a in getopt.getopt(args, 'hu:') do
|
||||
for o, a in getopt.getopt(args, 'hu:a') do
|
||||
if o == "h" then return help() end
|
||||
if o == "u" then uid = a end
|
||||
if o == "a" then use_iceman = false end
|
||||
end
|
||||
|
||||
-- uid string checks
|
||||
|
@ -103,8 +108,11 @@ function main(args)
|
|||
|
||||
core.clearCommandBuffer()
|
||||
|
||||
magicUID_iceman(block0, block1)
|
||||
--magicUID_offical(block0, block1)
|
||||
if use_iceman then
|
||||
magicUID_iceman(block0, block1)
|
||||
else
|
||||
magicUID_offical(block0, block1)
|
||||
end
|
||||
end
|
||||
|
||||
main(args)
|
||||
|
|
|
@ -513,8 +513,8 @@ function readFromPM3()
|
|||
return tag
|
||||
end
|
||||
|
||||
function padString(str)
|
||||
if (str:len() == 1) then
|
||||
local function padString(str)
|
||||
if (#str == 1) then
|
||||
return '0'..str
|
||||
end
|
||||
|
||||
|
@ -524,73 +524,84 @@ end
|
|||
---
|
||||
-- write virtual Tag to real Tag
|
||||
function writeToTag(tag)
|
||||
local bytes
|
||||
local filename='MylegicClone.hex'
|
||||
local taglen=22
|
||||
local bytes
|
||||
local filename = 'MylegicClone.hex'
|
||||
local taglen = 22
|
||||
if(utils.confirm(acred.."\nplace the (empty) Tag onto the PM3\nand confirm writing to this Tag: "..acoff) == false) then
|
||||
return
|
||||
end
|
||||
-- get used bytes / tag-len
|
||||
if(istable(tag.SEG)) then
|
||||
if (istable(tag.Bck)) then
|
||||
for i=0, #tag.SEG do
|
||||
taglen=taglen+tag.SEG[i].len+5
|
||||
end
|
||||
end
|
||||
local uid_old=tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2
|
||||
-- read new tag into memory so we can xor the new data with the new MCC
|
||||
outTAG=readFromPM3()
|
||||
outbytes=tagToBytes(outTAG)
|
||||
-- copy 'inputbuffer' to 'outputbuffer'
|
||||
tag.MCD = outbytes[1]
|
||||
tag.MSN0 = outbytes[2]
|
||||
tag.MSN1 = outbytes[3]
|
||||
tag.MSN2 = outbytes[4]
|
||||
tag.MCC = outbytes[5]
|
||||
-- recheck all segments-crc/kghcrc (only on a credential)
|
||||
if(istable(tag.Bck)) then
|
||||
checkAllSegCrc(tag)
|
||||
checkAllKghCrc(tag)
|
||||
local uid_new=tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2
|
||||
for i=0, #tag.SEG do
|
||||
if (check43rdPartyCash1(uid_old, tag.SEG[i].data)) then
|
||||
io.write(accyan.."\nfixing known checksums"..acoff.." ... ")
|
||||
if (fix3rdPartyCash1(uid_new, tag.SEG[i].data)) then
|
||||
io.write(acgreen.." done\n"..acoff)
|
||||
else oops("\nsomething went wrong at the repair of the 3rd-party-cash-segment") end
|
||||
end
|
||||
end
|
||||
end
|
||||
bytes=tagToBytes(tag)
|
||||
-- master-token-crc
|
||||
if (tag.Type ~= "SAM") then bytes[22] = calcMtCrc(bytes) end
|
||||
if (bytes) then
|
||||
print("write temp-file '"..filename.."'")
|
||||
print(accyan)
|
||||
writeFile(bytes, filename..".bin")
|
||||
print(acoff)
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- get used bytes / tag-len
|
||||
if (istable(tag.SEG)) then
|
||||
if (istable(tag.Bck)) then
|
||||
for i=0, #tag.SEG do
|
||||
taglen = taglen + tag.SEG[i] . len + 5
|
||||
end
|
||||
end
|
||||
local uid_old = tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2
|
||||
|
||||
-- read new tag into memory so we can xor the new data with the new MCC
|
||||
outTAG = readFromPM3()
|
||||
outbytes = tagToBytes(outTAG)
|
||||
-- copy 'inputbuffer' to 'outputbuffer'
|
||||
tag.MCD = outbytes[1]
|
||||
tag.MSN0 = outbytes[2]
|
||||
tag.MSN1 = outbytes[3]
|
||||
tag.MSN2 = outbytes[4]
|
||||
tag.MCC = outbytes[5]
|
||||
-- recheck all segments-crc/kghcrc (only on a credential)
|
||||
if (istable(tag.Bck)) then
|
||||
checkAllSegCrc(tag)
|
||||
checkAllKghCrc(tag)
|
||||
local uid_new = tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2
|
||||
for i=0, #tag.SEG do
|
||||
if (check43rdPartyCash1(uid_old, tag.SEG[i].data)) then
|
||||
io.write(accyan.."\nfixing known checksums"..acoff.." ... ")
|
||||
if (fix3rdPartyCash1(uid_new, tag.SEG[i].data)) then
|
||||
io.write(acgreen.." done\n"..acoff)
|
||||
else
|
||||
oops("\nsomething went wrong at the repair of the 3rd-party-cash-segment")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
bytes = tagToBytes(tag)
|
||||
-- master-token-crc
|
||||
if (tag.Type ~= "SAM") then
|
||||
bytes[22] = calcMtCrc(bytes)
|
||||
end
|
||||
if (bytes) then
|
||||
print("write temp-file '"..filename.."'")
|
||||
print(accyan)
|
||||
writeFile(bytes, filename..".bin")
|
||||
print(acoff)
|
||||
end
|
||||
end
|
||||
|
||||
-- write data to file
|
||||
-- write data to file
|
||||
if (taglen > 0) then
|
||||
WriteBytes = utils.input(acyellow.."enter number of bytes to write?"..acoff, taglen)
|
||||
-- load file into pm3-buffer
|
||||
if (type(filename) ~= "string") then filename=input(acyellow.."filename to load to pm3-buffer?"..acoff,"legic.temp") end
|
||||
if (type(filename) ~= "string") then
|
||||
filename = input(acyellow.."filename to load to pm3-buffer?"..acoff, "legic.temp")
|
||||
end
|
||||
|
||||
cmd = 'hf legic eload 2 '..filename
|
||||
core.console(cmd)
|
||||
-- write pm3-buffer to Tag
|
||||
for i=0, WriteBytes do
|
||||
if (i > 6) then
|
||||
cmd = 'hf legic write o '..string.format("%x", i)..' d '..padString(bytes[i])
|
||||
print(acgreen..cmd..acoff)
|
||||
cmd = ("hf legic write o %x d %s "):format(i, padString(bytes[i]))
|
||||
print(acgreen..cmd..acoff)
|
||||
core.console(cmd)
|
||||
core.clearCommandBuffer()
|
||||
elseif (i == 6) then
|
||||
-- write DCF in reverse order (requires 'mosci-patch')
|
||||
cmd = 'hf legic write o 05 d '..padString(bytes[i-1])..padString(bytes[i])
|
||||
print(acgreen..cmd..acoff)
|
||||
-- write DCF in reverse order (requires 'mosci-patch')
|
||||
cmd = ('hf legic write o 05 d %s%s'):format(padString(bytes[i-1]), padString(bytes[i]))
|
||||
print(acgreen..cmd..acoff)
|
||||
core.console(cmd)
|
||||
elseif (i == 5) then
|
||||
core.clearCommandBuffer()
|
||||
elseif (i == 5) then
|
||||
print(acgreen.."skip byte 0x05 - will be written next step"..acoff)
|
||||
else
|
||||
print(acgreen.."skip byte 0x00-0x04 - unwritable area"..acoff)
|
||||
|
@ -603,26 +614,28 @@ end
|
|||
--- File I/O ---
|
||||
---
|
||||
-- read file into virtual-tag
|
||||
function readFile(filename)
|
||||
print(accyan)
|
||||
local bytes = {}
|
||||
local tag = {}
|
||||
if file_check(filename) == false then return oops("input file: "..filename.." not found") end
|
||||
local function readFile(filename)
|
||||
print(accyan)
|
||||
local bytes = {}
|
||||
local tag = {}
|
||||
if file_check(filename) == false then
|
||||
return oops("input file: "..filename.." not found")
|
||||
end
|
||||
|
||||
bytes = getInputBytes(filename)
|
||||
bytes = getInputBytes(filename)
|
||||
|
||||
if bytes == false then return oops('couldnt get input bytes') end
|
||||
if bytes == false then return oops('couldnt get input bytes') end
|
||||
|
||||
-- make plain bytes
|
||||
bytes = xorBytes(bytes,bytes[5])
|
||||
print("create virtual tag from ".. #bytes .. " bytes")
|
||||
-- create Tag for plain bytes
|
||||
tag=createTagTable()
|
||||
-- load plain bytes to tag-table
|
||||
print(acoff)
|
||||
tag=bytesToTag(bytes, tag)
|
||||
-- make plain bytes
|
||||
bytes = xorBytes(bytes,bytes[5])
|
||||
print("create virtual tag from ".. #bytes .. " bytes")
|
||||
-- create Tag for plain bytes
|
||||
tag = createTagTable()
|
||||
-- load plain bytes to tag-table
|
||||
print(acoff)
|
||||
tag = bytesToTag(bytes, tag)
|
||||
|
||||
return tag
|
||||
return tag
|
||||
end
|
||||
|
||||
---
|
||||
|
@ -631,14 +644,16 @@ function writeFile(bytes, filename)
|
|||
if (filename ~= 'MylegicClone.hex') then
|
||||
if (file_check(filename)) then
|
||||
local answer = confirm("\nthe output-file "..filename.." already exists!\nthis will delete the previous content!\ncontinue?")
|
||||
if (answer==false) then return print("user abort") end
|
||||
if not answer then return print("user abort") end
|
||||
end
|
||||
end
|
||||
local line
|
||||
local bcnt=0
|
||||
local fho,err = io.open(filename, "w")
|
||||
if err then oops("OOps ... failed to open output-file ".. filename) end
|
||||
bytes=xorBytes(bytes, bytes[5])
|
||||
local bcnt = 0
|
||||
local fho, err = io.open(filename, "w")
|
||||
if err then
|
||||
return oops("OOps ... failed to open output-file ".. filename)
|
||||
end
|
||||
bytes = xorBytes(bytes, bytes[5])
|
||||
for i = 1, #bytes do
|
||||
if (bcnt == 0) then
|
||||
line = bytes[i]
|
||||
|
@ -662,96 +677,96 @@ end
|
|||
--- Map related ---
|
||||
---
|
||||
-- make tagMap
|
||||
function makeTagMap()
|
||||
local tagMap={}
|
||||
if (#tagMap == 0) then
|
||||
tagMap['name'] = input(accyan.."enter Name for this Map: "..acoff , "newTagMap")
|
||||
tagMap['mappings']={}
|
||||
tagMap['crc8']={}
|
||||
-- insert fixed Tag-CRC
|
||||
table.insert(tagMap.crc8, {name='TAG-CRC', pos=5, seq={1, 4}})
|
||||
tagMap['crc16']={}
|
||||
end
|
||||
print(accyan.."new tagMap created"..acoff)
|
||||
return tagMap
|
||||
local function makeTagMap()
|
||||
local tagMap = {}
|
||||
if (#tagMap == 0) then
|
||||
tagMap['name'] = input(accyan.."enter Name for this Map: "..acoff , "newTagMap")
|
||||
tagMap['mappings'] = {}
|
||||
tagMap['crc8'] = {}
|
||||
-- insert fixed Tag-CRC
|
||||
table.insert(tagMap.crc8, {name = 'TAG-CRC', pos = 5, seq = {1, 4}})
|
||||
tagMap['crc16'] = {}
|
||||
end
|
||||
print(accyan.."new tagMap created"..acoff)
|
||||
return tagMap
|
||||
end
|
||||
|
||||
---
|
||||
-- save mapping to file
|
||||
function saveTagMap(map, filename)
|
||||
if (string.len(filename)>0) then
|
||||
if (file_check(filename)) then
|
||||
local answer = confirm("\nthe output-file "..filename.." alredy exists!\nthis will delete the previous content!\ncontinue?")
|
||||
if (answer==false) then return print("user abort") end
|
||||
end
|
||||
end
|
||||
local function saveTagMap(map, filename)
|
||||
if (string.len(filename)>0) then
|
||||
if (file_check(filename)) then
|
||||
local answer = confirm("\nthe output-file "..filename.." alredy exists!\nthis will delete the previous content!\ncontinue?")
|
||||
if not answer then return print("user abort") end
|
||||
end
|
||||
end
|
||||
|
||||
local line
|
||||
local line
|
||||
local fho,err = io.open(filename, "w")
|
||||
if err then oops("OOps ... faild to open output-file ".. filename) end
|
||||
|
||||
-- write line to new file
|
||||
for k, v in pairs(map) do
|
||||
if (istable(v)) then
|
||||
for k2, v2 in pairs(v) do
|
||||
if (k=='mappings') then
|
||||
fho:write(k..","..k2..","..v2['name']..","..v2['start']..","..v2['end']..","..((v2['highlight']) and "1" or "0").."\n")
|
||||
elseif (k=="crc8") then
|
||||
local tmp=""
|
||||
tmp=k..","..k2..","..v2['name']..","..v2['pos']..","
|
||||
tmp=tmp..tbl2seqstr(v2['seq'])
|
||||
fho:write(tmp.."\n")
|
||||
end
|
||||
end
|
||||
else
|
||||
fho:write(k..","..v.."\n")
|
||||
end
|
||||
end
|
||||
-- write line to new file
|
||||
for k, v in pairs(map) do
|
||||
if (istable(v)) then
|
||||
for k2, v2 in pairs(v) do
|
||||
if (k == 'mappings') then
|
||||
fho:write(k..","..k2..","..v2['name']..","..v2['start']..","..v2['end']..","..((v2['highlight']) and "1" or "0").."\n")
|
||||
elseif (k == "crc8") then
|
||||
local tmp = ""
|
||||
tmp = k..","..k2..","..v2['name']..","..v2['pos']..","
|
||||
tmp=tmp..tbl2seqstr(v2['seq'])
|
||||
fho:write(tmp.."\n")
|
||||
end
|
||||
end
|
||||
else
|
||||
fho:write(k..","..v.."\n")
|
||||
end
|
||||
end
|
||||
fho:close()
|
||||
return true
|
||||
end
|
||||
|
||||
---
|
||||
-- toggle higligh
|
||||
function toggleHighlight(tbl)
|
||||
local function toggleHighlight(tbl)
|
||||
if (tbl['highlight']) then
|
||||
tbl['highlight'] = false
|
||||
else
|
||||
tbl['highlight'] = true
|
||||
end
|
||||
return tbl
|
||||
return tbl
|
||||
end
|
||||
|
||||
---
|
||||
-- return table od seqence-string
|
||||
function seqstr2tbl(seqstr)
|
||||
local s=split(seqstr)
|
||||
local res={}
|
||||
if (#s>=1) then
|
||||
for sk, sv in pairs(s) do
|
||||
s2=split(sv, '-')
|
||||
if(#s2==2) then
|
||||
table.insert(res, s2[1])
|
||||
table.insert(res, s2[2])
|
||||
end
|
||||
end
|
||||
end
|
||||
return res
|
||||
local function seqstr2tbl(seqstr)
|
||||
local s = split(seqstr)
|
||||
local res = {}
|
||||
if (#s >= 1) then
|
||||
for sk, sv in pairs(s) do
|
||||
s2 = split(sv, '-')
|
||||
if(#s2 == 2) then
|
||||
table.insert(res, s2[1])
|
||||
table.insert(res, s2[2])
|
||||
end
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
---
|
||||
-- return sequence-string from table
|
||||
function tbl2seqstr(seqtbl)
|
||||
local res=""
|
||||
if (istable(seqtbl)) then
|
||||
for sk, sv in pairs(seqtbl) do
|
||||
res=res..sv..((sk%2==0) and "," or "-")
|
||||
end
|
||||
if (string.sub(res, string.len(res))==",") then
|
||||
res=string.sub(res, 1, string.len(res)-1)
|
||||
end
|
||||
end
|
||||
return res
|
||||
local function tbl2seqstr(seqtbl)
|
||||
local res = ""
|
||||
if (istable(seqtbl)) then
|
||||
for sk, sv in pairs(seqtbl) do
|
||||
res = res..sv..((sk%2==0) and "," or "-")
|
||||
end
|
||||
if (string.sub(res, string.len(res))== ",") then
|
||||
res = string.sub(res, 1, string.len(res)-1)
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
---
|
||||
|
|
|
@ -12,8 +12,10 @@ This is a script which automates cracking and dumping mifare classic cards. It s
|
|||
place by the device.
|
||||
|
||||
Arguments:
|
||||
-d debug logging on
|
||||
-h this help
|
||||
-h this help
|
||||
-d debug logging on
|
||||
-k known key for Sector 0 , keytype A
|
||||
|
||||
|
||||
Output files from this operation:
|
||||
<uid>.eml - emulator file
|
||||
|
@ -73,12 +75,12 @@ local function nested(key,sak)
|
|||
if 0x18 == sak then --NXP MIFARE Classic 4k | Plus 4k | Ev1 4k
|
||||
typ = 4
|
||||
elseif 0x08 == sak then -- NXP MIFARE CLASSIC 1k | Plus 2k | Ev1 1K
|
||||
typ= 1
|
||||
typ = 1
|
||||
elseif 0x09 == sak then -- NXP MIFARE Mini 0.3k
|
||||
typ = 0
|
||||
elseif 0x10 == sak then-- "NXP MIFARE Plus 2k"
|
||||
elseif 0x10 == sak then-- "NXP MIFARE Plus 2k"
|
||||
typ = 2
|
||||
elseif 0x01 == sak then-- "NXP MIFARE TNP3xxx 1K"
|
||||
elseif 0x01 == sak then-- "NXP MIFARE TNP3xxx 1K"
|
||||
typ = 1
|
||||
else
|
||||
print("I don't know how many sectors there are on this type of card, defaulting to 16")
|
||||
|
@ -87,22 +89,40 @@ local function nested(key,sak)
|
|||
core.console(cmd)
|
||||
end
|
||||
|
||||
local function dump(uid)
|
||||
local function dump(uid, numsectors)
|
||||
dbg('dumping tag memory')
|
||||
|
||||
local typ = 1
|
||||
if 0x18 == sak then --NXP MIFARE Classic 4k | Plus 4k | Ev1 4k
|
||||
typ = 4
|
||||
elseif 0x08 == sak then -- NXP MIFARE CLASSIC 1k | Plus 2k | Ev1 1K
|
||||
typ = 1
|
||||
elseif 0x09 == sak then -- NXP MIFARE Mini 0.3k
|
||||
typ = 0
|
||||
elseif 0x10 == sak then-- "NXP MIFARE Plus 2k"
|
||||
typ = 2
|
||||
elseif 0x01 == sak then-- "NXP MIFARE TNP3xxx 1K"
|
||||
typ = 1
|
||||
end
|
||||
|
||||
if utils.confirm('Do you wish to create a memory dump of tag?') then
|
||||
|
||||
core.console("hf mf dump")
|
||||
local dumpfile = 'hf-mf-'..uid..'-data.bin'
|
||||
|
||||
local dmp = ('hf mf dump %s f %s'):format(typ, dumpfile)
|
||||
core.console(dmp)
|
||||
|
||||
-- Save the global args, those are *our* arguments
|
||||
local myargs = args
|
||||
-- Set the arguments for htmldump script
|
||||
args =("-o %s.html"):format(uid)
|
||||
args =('-i %s -o %s.html'):format(dumpfile, uid)
|
||||
-- call it
|
||||
require('../scripts/htmldump')
|
||||
require('htmldump')
|
||||
|
||||
args =""
|
||||
-- dump to emulator
|
||||
require('../scripts/dumptoemul')
|
||||
args =('-i %s -o %s.eml'):format(dumpfile, uid)
|
||||
require('dumptoemul')
|
||||
|
||||
-- Set back args. Not that it's used, just for the karma...
|
||||
args = myargs
|
||||
end
|
||||
|
@ -177,9 +197,9 @@ local function main(args)
|
|||
print("Found valid key: "..key);
|
||||
end
|
||||
-- Use nested attack
|
||||
nested(key,sak)
|
||||
nested(key, sak)
|
||||
-- Dump info
|
||||
dump(uid)
|
||||
dump(uid, sak)
|
||||
|
||||
if #key == 12 then exit = true end
|
||||
else
|
||||
|
|
|
@ -24,13 +24,13 @@ local example = "script run xxx"
|
|||
local author = "Martin Holst Swende & Asper"
|
||||
---
|
||||
-- PrintAndLog
|
||||
function prlog(...)
|
||||
local function prlog(...)
|
||||
-- TODO; replace this with a call to the proper PrintAndLog
|
||||
print(...)
|
||||
end
|
||||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
function oops(err)
|
||||
local function oops(err)
|
||||
prlog("ERROR: ",err)
|
||||
return nil,err
|
||||
end
|
||||
|
@ -66,23 +66,39 @@ local utils = {
|
|||
end,
|
||||
}
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- Usage help
|
||||
function help()
|
||||
local function help()
|
||||
prlog(desc)
|
||||
prlog("Example usage")
|
||||
prlog(example)
|
||||
end
|
||||
|
||||
function debug(...)
|
||||
local function debug(...)
|
||||
if DEBUG then
|
||||
prlog("debug:", ...)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- This function is a lua-implementation of
|
||||
-- cmdhf14a.c:waitCmd(uint8_t iSelect)
|
||||
local function waitCmd(iSelect)
|
||||
local response = core.WaitForResponseTimeout(cmds.CMD_ACK,1000)
|
||||
if response then
|
||||
local count,cmd,arg0,arg1,arg2 = bin.unpack('LLLL',response)
|
||||
|
||||
local iLen = arg0
|
||||
if iSelect then iLen = arg1 end
|
||||
debug(("Received %i octets (arg0:%d, arg1:%d)"):format(iLen, arg0, arg1))
|
||||
if iLen == 0 then return nil, "No response from tag" end
|
||||
local recv = string.sub(response,count, iLen+count-1)
|
||||
return recv
|
||||
end
|
||||
return nil, "No response from device"
|
||||
end
|
||||
|
||||
|
||||
local function show(data)
|
||||
if DEBUG then
|
||||
local formatString = ("H%d"):format(string.len(data))
|
||||
|
@ -156,23 +172,6 @@ local function getBlock(block)
|
|||
end
|
||||
|
||||
|
||||
--- This function is a lua-implementation of
|
||||
-- cmdhf14a.c:waitCmd(uint8_t iSelect)
|
||||
function waitCmd(iSelect)
|
||||
local response = core.WaitForResponseTimeout(cmds.CMD_ACK,1000)
|
||||
if response then
|
||||
local count,cmd,arg0,arg1,arg2 = bin.unpack('LLLL',response)
|
||||
|
||||
local iLen = arg0
|
||||
if iSelect then iLen = arg1 end
|
||||
debug(("Received %i octets (arg0:%d, arg1:%d)"):format(iLen, arg0, arg1))
|
||||
if iLen == 0 then return nil, "No response from tag" end
|
||||
local recv = string.sub(response,count, iLen+count-1)
|
||||
return recv
|
||||
end
|
||||
return nil, "No response from device"
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function main( args)
|
||||
|
|
|
@ -1,23 +1,32 @@
|
|||
local getopt = require('getopt')
|
||||
local bin = require('bin')
|
||||
|
||||
copyright = 'Copyright (c) 2018 Bogito. All rights reserved.'
|
||||
author = "Bogito"
|
||||
version = 'v1.0.0'
|
||||
desc =[[
|
||||
version = 'v1.0.1'
|
||||
desc =
|
||||
[[
|
||||
This script will read the flash memory of RDV4 and print the stored passwords.
|
||||
It was meant to be used as a help tool after using the BogRun standalone mode.
|
||||
|
||||
(Iceman) script adapted to read and print keys in the default dictionary flashmemory sections.
|
||||
]]
|
||||
usage = [[
|
||||
usage =
|
||||
[[
|
||||
Usage:
|
||||
script run read_pwd_mem -h -o <offset> -l <length>
|
||||
script run read_pwd_mem -h -o <offset> -l <length> -k <keylength>
|
||||
|
||||
Arguments:
|
||||
-h : this help
|
||||
-o <OFFSET> : Memory offset. Default is 0.
|
||||
-l <LENGTH> : Length in bytes. Default is 256.
|
||||
-h : this help
|
||||
-o <offset> : memory offset, default is 0
|
||||
-l <length> : length in bytes, default is 256
|
||||
-k <keylen> : key length in bytes <4|6|8> , default is 4
|
||||
-m : print Mifare dictionary keys
|
||||
-t : print t55xx dictionary passwords
|
||||
-i : print iClass dictionary keys
|
||||
]]
|
||||
example =[[
|
||||
Examples:
|
||||
example =
|
||||
[[
|
||||
-- This will scan the first 256 bytes of flash memory for stored passwords
|
||||
script run read_pwd_mem
|
||||
|
||||
|
@ -26,61 +35,107 @@ Examples:
|
|||
|
||||
-- This will scan 32 bytes of flash memory at offset 64 for stored passwords
|
||||
script run read_pwd_mem -o 64 -l 32
|
||||
|
||||
-- This will print found
|
||||
script run read_pwd_mem -o 241664 -k 6
|
||||
]]
|
||||
|
||||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
local function oops(err)
|
||||
print("ERROR: ", err)
|
||||
return nil, err
|
||||
end
|
||||
---
|
||||
-- Usage help
|
||||
local function help()
|
||||
print(copyright)
|
||||
print(version)
|
||||
print(desc)
|
||||
print(usage)
|
||||
print('Example usage:')
|
||||
print(example)
|
||||
end
|
||||
|
||||
---
|
||||
-- The main entry point
|
||||
local function main(args)
|
||||
|
||||
local data, err, quadlet, pwdcnt
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
print()
|
||||
|
||||
local data, err, quadlet
|
||||
local cnt = 0
|
||||
local offset = 0
|
||||
local length = 256
|
||||
local keylength = 4
|
||||
local usedkey = false
|
||||
|
||||
-- Read the parameters
|
||||
for o, a in getopt.getopt(args, 'ho:l:') do
|
||||
for o, a in getopt.getopt(args, 'ho:l:k:mti') do
|
||||
|
||||
-- help
|
||||
if o == "h" then return help() end
|
||||
|
||||
-- offset
|
||||
if o == "o" then offset = tonumber(a) end
|
||||
|
||||
-- num of bytes to read
|
||||
if o == "l" then length = tonumber(a) end
|
||||
|
||||
-- keylength
|
||||
if o == "k" then keylength = tonumber(a); usedkey = true end
|
||||
|
||||
if o == "m" then keylength =6; usedkey = true; offset = 0x3F000-0x4000; end
|
||||
if o == "t" then keylength =4; usedkey = true; offset = 0x3F000-0x3000; end
|
||||
if o == "i" then keylength =8; usedkey = true; offset = 0x3F000-0x5000; end
|
||||
end
|
||||
|
||||
if length < 0 or length > 256 then
|
||||
return print('Error: Length is not valid. Must be less than 256')
|
||||
return oops('Error: Length is not valid. Must be less than 256')
|
||||
end
|
||||
|
||||
if ((offset < 0) or (offset % 4 ~= 0)) then
|
||||
return print('Error: Offset is not valid. Mod-4 values are only allowed.')
|
||||
if (offset < 0) or (offset % 4 ~= 0) then
|
||||
return oops('Error: Offset is not valid. Mod-4 values are only allowed.')
|
||||
end
|
||||
|
||||
print('Offset: ' .. offset)
|
||||
print('Length: ' .. length)
|
||||
print()
|
||||
print('Memory offset', offset)
|
||||
print('Length ', length)
|
||||
print('Key length ', keylength)
|
||||
print( string.rep('--',20) )
|
||||
|
||||
data, err = core.GetFromFlashMem(offset, length)
|
||||
if usedkey then length = 4096 end
|
||||
|
||||
data, err = core.GetFromFlashMem(offset, length)
|
||||
if err then return oops(err) end
|
||||
|
||||
if err then
|
||||
print(err)
|
||||
return
|
||||
if usedkey then
|
||||
|
||||
_, keys, s = bin.unpack('SH'..length-2, data)
|
||||
if keys == 0xFFFF then return "No keys found in section" end
|
||||
|
||||
local kl = keylength * 2
|
||||
for i = 1, keys do
|
||||
|
||||
key = string.sub(s, (i - 1) * kl + 1, i * kl )
|
||||
print(string.format("[%02d] %s",i, key))
|
||||
end
|
||||
print( string.rep('--',20) )
|
||||
print( ('[+] found %d passwords'):format(keys))
|
||||
else
|
||||
|
||||
_, s = bin.unpack('H'..length, data)
|
||||
|
||||
local cnt = 0, i
|
||||
for i = 1, (length/keylength) do
|
||||
|
||||
key = string.sub(s, (i-1)*8+1, i*8)
|
||||
if key == "FFFFFFFF" then break end
|
||||
print(string.format("[%02d] %s",i, key))
|
||||
cnt = cnt + 1
|
||||
end
|
||||
print( string.rep('--',20) )
|
||||
print( ('[+] found %d passwords'):format(cnt))
|
||||
end
|
||||
|
||||
local count, s = bin.unpack('H'..length, data)
|
||||
|
||||
pwdcnt = 0
|
||||
for i = 1,(length/4),1
|
||||
do
|
||||
quadlet = string.sub(s, (i-1)*8+1, i*8)
|
||||
if quadlet == "FFFFFFFF" then break end
|
||||
print(string.format("[%02d]",i) .. ' ' .. quadlet)
|
||||
pwdcnt = pwdcnt + 1
|
||||
|
||||
end
|
||||
print()
|
||||
print('Found passwords: ' .. pwdcnt)
|
||||
|
||||
print( string.rep('--',20) )
|
||||
end
|
||||
|
||||
main(args)
|
||||
|
|
|
@ -72,6 +72,7 @@ local function sendCmds( cmds )
|
|||
if cmds[i] then
|
||||
print ( cmds[i] )
|
||||
core.console( cmds[i] )
|
||||
core.clearCommandBuffer()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -37,13 +37,12 @@ Arguments:
|
|||
0020 - Swapforce
|
||||
]]
|
||||
|
||||
|
||||
-- This is only meant to be used when errors occur
|
||||
function oops(err)
|
||||
local function oops(err)
|
||||
print("ERROR: ",err)
|
||||
end
|
||||
-- Usage help
|
||||
function help()
|
||||
local function help()
|
||||
print(desc)
|
||||
print("Example usage")
|
||||
print(example)
|
||||
|
@ -64,7 +63,7 @@ local function waitCmd()
|
|||
end
|
||||
|
||||
local function readblock( blocknum, keyA )
|
||||
-- Read block 0
|
||||
-- Read block N
|
||||
cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = blocknum, arg2 = 0, arg3 = 0, data = keyA}
|
||||
err = core.SendCommand(cmd:getBytes())
|
||||
if err then return nil, err end
|
||||
|
@ -72,8 +71,9 @@ local function readblock( blocknum, keyA )
|
|||
if err then return nil, err end
|
||||
return block0
|
||||
end
|
||||
|
||||
local function readmagicblock( blocknum )
|
||||
-- Read block 0
|
||||
-- Read block N
|
||||
local CSETBLOCK_SINGLE_OPERATION = 0x1F
|
||||
cmd = Command:new{cmd = cmds.CMD_MIFARE_CGETBLOCK, arg1 = CSETBLOCK_SINGLE_OPERATION, arg2 = 0, arg3 = blocknum}
|
||||
err = core.SendCommand(cmd:getBytes())
|
||||
|
@ -89,11 +89,13 @@ local function main(args)
|
|||
print( string.rep('--',20) )
|
||||
|
||||
local numBlocks = 64
|
||||
local cset = 'hf mf csetbl '
|
||||
local cset = 'hf mf csetbl '
|
||||
local csetuid = 'hf mf csetuid '
|
||||
local cget = 'hf mf cgetbl '
|
||||
local empty = '00000000000000000000000000000000'
|
||||
local AccAndKeyB = '7F078869000000000000'
|
||||
local AccAndKeyB = '7F0F0869000000000000'
|
||||
local atqa = '0F01'
|
||||
local sak = '81'
|
||||
-- Defaults to Gusto
|
||||
local toytype = 'C201'
|
||||
local subtype = '0030'
|
||||
|
@ -107,42 +109,43 @@ local function main(args)
|
|||
if o == "l" then return toys.List() end
|
||||
end
|
||||
|
||||
if #toytype ~= 4 then return oops('Wrong size - toytype. (4hex symbols)') end
|
||||
if #subtype ~= 4 then return oops('Wrong size - subtype. (4hex symbols)') end
|
||||
if #toytype ~= 4 then return oops('[!] Wrong size - toytype. (4hex symbols)') end
|
||||
if #subtype ~= 4 then return oops('[!] Wrong size - subtype. (4hex symbols)') end
|
||||
|
||||
-- look up type, find & validate types
|
||||
local item = toys.Find( toytype, subtype)
|
||||
if item then
|
||||
print( (' Looking up input: Found %s - %s (%s)'):format(item[6],item[5], item[4]) )
|
||||
print( ('[+] Looking up input: Found %s - %s (%s)'):format(item[6],item[5], item[4]) )
|
||||
else
|
||||
print('Didn\'t find item type. If you are sure about it, report it in')
|
||||
print('[-] Didn\'t find item type. If you are sure about it, post on forum')
|
||||
end
|
||||
--15,16
|
||||
--13-14
|
||||
|
||||
--13-14
|
||||
|
||||
-- find tag
|
||||
result, err = lib14a.read(false, true)
|
||||
if not result then return oops(err) end
|
||||
if not result then return oops(err) end
|
||||
|
||||
-- load keys
|
||||
local akeys = pre.GetAll(result.uid)
|
||||
local keyA = akeys:sub(1, 12 )
|
||||
local keyA = akeys:sub(1, 12 )
|
||||
|
||||
local b0 = readblock(0,keyA)
|
||||
local b0 = readblock(0, keyA)
|
||||
if not b0 then
|
||||
print('failed reading block with factorydefault key. Trying chinese magic read.')
|
||||
print('[-] failed reading block with factorydefault key. Trying chinese magic read.')
|
||||
b0, err = readmagicblock(0)
|
||||
if not b0 then
|
||||
oops(err)
|
||||
return oops('failed reading block with chinese magic command. quitting...')
|
||||
oops('[!] '..err)
|
||||
return oops('[!] failed reading block with chinese magic command. Quitting...')
|
||||
end
|
||||
end
|
||||
|
||||
-- wipe card.
|
||||
local cmd = (csetuid..'%s 0004 08 w'):format(result.uid)
|
||||
core.console(cmd)
|
||||
core.clearCommandBuffer()
|
||||
|
||||
-- wipe card.
|
||||
local cmd = (csetuid..'%s %s %s w'):format(result.uid, atqa, sak)
|
||||
core.console(cmd)
|
||||
core.clearCommandBuffer()
|
||||
|
||||
local b1 = toytype..string.rep('00',10)..subtype
|
||||
|
||||
local calc = utils.Crc16(b0..b1)
|
||||
|
@ -150,6 +153,7 @@ local function main(args)
|
|||
|
||||
local cmd = (cset..'1 %s%04x'):format( b1, calcEndian)
|
||||
core.console(cmd)
|
||||
core.clearCommandBuffer()
|
||||
|
||||
local pos, key
|
||||
for blockNo = 2, numBlocks-1, 1 do
|
||||
|
@ -161,5 +165,10 @@ local function main(args)
|
|||
end
|
||||
end
|
||||
core.clearCommandBuffer()
|
||||
|
||||
-- Set sector trailer S0, since it has different access rights
|
||||
cmd = ('%s 3 %s0f0f0f69000000000000'):format(cset, keyA)
|
||||
core.console(cmd)
|
||||
core.clearCommandBuffer()
|
||||
end
|
||||
main(args)
|
||||
main(args)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue