diff --git a/client/scripts/14araw.lua b/client/scripts/14araw.lua index 01af5422e..e0448d9db 100644 --- a/client/scripts/14araw.lua +++ b/client/scripts/14araw.lua @@ -6,22 +6,22 @@ example = "script run 14araw -x 6000F57b" author = "Martin Holst Swende" desc = [[ -This is a script to allow raw 1444a commands to be sent and received. +This is a script to allow raw 1444a commands to be sent and received. Arguments: - -o do not connect - use this only if you previously used -p to stay connected - -r do not read response - -c calculate and append CRC - -p stay connected - dont inactivate the field - -x Data to send (NO SPACES!) - -d Debug flag - -t Topaz mode - -3 ISO14443-4 (use RATS) + -o do not connect - use this only if you previously used -p to stay connected + -r do not read response + -c calculate and append CRC + -p stay connected - dont inactivate the field + -x Data to send (NO SPACES!) + -d Debug flag + -t Topaz mode + -3 ISO14443-4 (use RATS) -Examples : +Examples : # 1. Connect and don't disconnect -script run 14araw -p +script run 14araw -p # 2. Send mf auth, read response (nonce) script run 14araw -o -x 6000F57b -p # 3. disconnect @@ -33,11 +33,11 @@ script run 14araw -x 6000F57b --[[ -This script communicates with -/armsrc/iso14443a.c, specifically ReaderIso14443a() at around line 1779 and onwards. +This script communicates with +/armsrc/iso14443a.c, specifically ReaderIso14443a() at around line 1779 and onwards. -Check there for details about data format and how commands are interpreted on the -device-side. +Check there for details about data format and how commands are interpreted on the +device-side. ]] -- Some globals @@ -45,143 +45,143 @@ local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds local DEBUG = false -- the debug flag ------------------------------- --- Some utilities +-- Some utilities ------------------------------- ---- +--- -- A debug printout-function local function dbg(args) - if DEBUG then - print("###", args) - end -end ---- + if DEBUG then + print("###", args) + end +end +--- -- This is only meant to be used when errors occur local function oops(err) - print("ERROR: ",err) + print("ERROR: ",err) end ---- +--- -- Usage help local function help() - print(desc) - print("Example usage") - print(example) + print(desc) + print("Example usage") + print(example) end ---- +--- -- The main entry point function main(args) - if args == nil or #args == 0 then return help() end + if args == nil or #args == 0 then return help() end - local ignore_response = false - local append_crc = false - local stayconnected = false - local payload = nil - local doconnect = true - local topaz_mode = false - local no_rats = false - - -- Read the parameters - for o, a in getopt.getopt(args, 'orcpx:dt3') do - if o == "o" then doconnect = false end - if o == "r" then ignore_response = true end - if o == "c" then append_crc = true end - if o == "p" then stayconnected = true end - if o == "x" then payload = a end - if o == "d" then DEBUG = true end - if o == "t" then topaz_mode = true end - if o == "3" then no_rats = true end - end + local ignore_response = false + local append_crc = false + local stayconnected = false + local payload = nil + local doconnect = true + local topaz_mode = false + local no_rats = false - -- First of all, connect - if doconnect then - dbg("doconnect") - -- We reuse the connect functionality from a - -- common library - info, err = lib14a.read(true, no_rats) + -- Read the parameters + for o, a in getopt.getopt(args, 'orcpx:dt3') do + if o == "o" then doconnect = false end + if o == "r" then ignore_response = true end + if o == "c" then append_crc = true end + if o == "p" then stayconnected = true end + if o == "x" then payload = a end + if o == "d" then DEBUG = true end + if o == "t" then topaz_mode = true end + if o == "3" then no_rats = true end + end - if err then return oops(err) end - print(("Connected to card, uid = %s"):format(info.uid)) - end + -- First of all, connect + if doconnect then + dbg("doconnect") + -- We reuse the connect functionality from a + -- common library + info, err = lib14a.read(true, no_rats) - -- The actual raw payload, if any - if payload then - res,err = sendRaw(payload,{ignore_response = ignore_response, topaz_mode = topaz_mode, append_crc = append_crc}) - if err then return oops(err) end - - if not ignoreresponse then - -- Display the returned data - showdata(res) - end - end - -- And, perhaps disconnect? - if not stayconnected then - disconnect() - end + if err then return oops(err) end + print(("Connected to card, uid = %s"):format(info.uid)) + end + + -- The actual raw payload, if any + if payload then + res,err = sendRaw(payload,{ignore_response = ignore_response, topaz_mode = topaz_mode, append_crc = append_crc}) + if err then return oops(err) end + + if not ignoreresponse then + -- Display the returned data + showdata(res) + end + end + -- And, perhaps disconnect? + if not stayconnected then + disconnect() + end end --- Picks out and displays the data read from a tag -- Specifically, takes a usb packet, converts to a Command --- (as in commands.lua), takes the data-array and +-- (as in commands.lua), takes the data-array and -- reads the number of bytes specified in arg1 (arg0 in c-struct) -- and displays the data -- @param usbpacket the data received from the device function showdata(usbpacket) - local cmd_response = Command.parse(usbpacket) - local len = tonumber(cmd_response.arg1) *2 - --print("data length:",len) - local data = string.sub(tostring(cmd_response.data), 0, len); - print("<< ",data) - --print("----------------") + local cmd_response = Command.parse(usbpacket) + local len = tonumber(cmd_response.arg1) *2 + --print("data length:",len) + local data = string.sub(tostring(cmd_response.data), 0, len); + print("<< ",data) + --print("----------------") end function sendRaw(rawdata, options) - print(">> ", rawdata) - - local flags = lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT + lib14a.ISO14A_COMMAND.ISO14A_RAW + print(">> ", rawdata) - if options.topaz_mode then - flags = flags + lib14a.ISO14A_COMMAND.ISO14A_TOPAZMODE - end - if options.append_crc then - flags = flags + lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC - end - - local command = Command:new{cmd = cmds.CMD_READER_ISO_14443a, - arg1 = flags, -- Send raw - -- arg2 contains the length, which is half the length - -- of the ASCII-string rawdata - arg2 = string.len(rawdata)/2, - data = rawdata} - return lib14a.sendToDevice(command, options.ignore_response) + local flags = lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT + lib14a.ISO14A_COMMAND.ISO14A_RAW + + if options.topaz_mode then + flags = flags + lib14a.ISO14A_COMMAND.ISO14A_TOPAZMODE + end + if options.append_crc then + flags = flags + lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC + end + + local command = Command:new{cmd = cmds.CMD_READER_ISO_14443a, + arg1 = flags, -- Send raw + -- arg2 contains the length, which is half the length + -- of the ASCII-string rawdata + arg2 = string.len(rawdata)/2, + data = rawdata} + return lib14a.sendToDevice(command, options.ignore_response) end -- Sends an instruction to do nothing, only disconnect function disconnect() - local command = Command:new{cmd = cmds.CMD_READER_ISO_14443a, arg1 = 0, } - -- We can ignore the response here, no ACK is returned for this command - -- Check /armsrc/iso14443a.c, ReaderIso14443a() for details - return lib14a.sendToDevice(command,true) -end + local command = Command:new{cmd = cmds.CMD_READER_ISO_14443a, arg1 = 0,} + -- We can ignore the response here, no ACK is returned for this command + -- Check /armsrc/iso14443a.c, ReaderIso14443a() for details + return lib14a.sendToDevice(command,true) +end ------------------------- --- Testing +-- Testing ------------------------- function selftest() - DEBUG = true - dbg("Performing test") - main() - main("-p") - main(" -o -x 6000F57b -p") - main("-o") - main("-x 6000F57b") - dbg("Tests done") + DEBUG = true + dbg("Performing test") + main() + main("-p") + main(" -o -x 6000F57b -p") + main("-o") + main("-x 6000F57b") + dbg("Tests done") end --- Flip the switch here to perform a sanity check. +-- Flip the switch here to perform a sanity check. -- It read a nonce in two different ways, as specified in the usage-section -if "--test"==args then - selftest() -else - -- Call the main - main(args) +if "--test"==args then + selftest() +else + -- Call the main + main(args) end diff --git a/client/scripts/Legic_clone.lua b/client/scripts/Legic_clone.lua index 4c638f82f..dcac7f323 100644 --- a/client/scripts/Legic_clone.lua +++ b/client/scripts/Legic_clone.lua @@ -1,87 +1,87 @@ --[[ - script to create a clone-dump with new crc + script to create a clone-dump with new crc Author: mosci my Fork: https://github.com/icsom/proxmark3.git - Upstream: https://github.com/Proxmark/proxmark3.git + Upstream: https://github.com/Proxmark/proxmark3.git - 1. read tag-dump, xor byte 22..end with byte 0x05 of the inputfile - 2. write to outfile - 3. set byte 0x05 to newcrc - 4. until byte 0x21 plain like in inputfile - 5. from 0x22..end xored with newcrc - 6. calculate new crc on each segment (needs to know the new MCD & MSN0..2) - - simplest usage: - read a valid legic tag with 'hf legic reader' - save the dump with 'hf legic save orig.hex' + 1. read tag-dump, xor byte 22..end with byte 0x05 of the inputfile + 2. write to outfile + 3. set byte 0x05 to newcrc + 4. until byte 0x21 plain like in inputfile + 5. from 0x22..end xored with newcrc + 6. calculate new crc on each segment (needs to know the new MCD & MSN0..2) + + simplest usage: + read a valid legic tag with 'hf legic reader' + save the dump with 'hf legic save orig.hex' place your 'empty' tag on the reader and run 'script run Legic_clone -i orig.hex -w' you will see some output like: - read 1024 bytes from legic_dumps/j_0000.hex - - place your empty tag onto the PM3 to read and display the MCD & MSN0..2 - the values will be shown below - confirm whnen ready [y/n] ?y - #db# setting up legic card - #db# MIM 256 card found, reading card ... - #db# Card read, use 'hf legic decode' or - #db# 'data hexsamples 8' to view results - 0b ad c0 de <- !! here you'll see the MCD & MSN of your empty tag, which has to be typed in manually as seen below !! - type in MCD as 2-digit value - e.g.: 00 (default: 79 ) - > 0b - type in MSN0 as 2-digit value - e.g.: 01 (default: 28 ) - > ad - type in MSN1 as 2-digit value - e.g.: 02 (default: d1 ) - > c0 - type in MSN2 as 2-digit value - e.g.: 03 (default: 43 ) - > de - MCD:0b, MSN:ad c0 de, MCC:79 <- this crc is calculated from the MCD & MSN and must match the one on yout empty tag - - wrote 1024 bytes to myLegicClone.hex - enter number of bytes to write? (default: 86 ) - - loaded 1024 samples - #db# setting up legic card - #db# MIM 256 card found, writing 0x00 - 0x01 ... - #db# write successful - ... - #db# setting up legic card - #db# MIM 256 card found, writing 0x56 - 0x01 ... - #db# write successful - proxmark3> - - the default value (number of bytes to write) is calculated over all valid segments and should be ok - just hit enter, wait until write has finished - and your clone should be ready (except there has to be a additional KGH-CRC to be calculated - which credentials are unknown until yet) - - the '-w' switch will only work with my fork - it needs the binary legic_crc8 which is not part of the proxmark3-master-branch - also the ability to write DCF is not possible with the proxmark3-master-branch - but creating dumpfile-clone files will be possible (without valid segment-crc - this has to done manually with) + read 1024 bytes from legic_dumps/j_0000.hex - - (example) Legic-Prime Layout with 'Kaba Group Header' - +----+----+----+----+----+----+----+----+ - 0x00|MCD |MSN0|MSN1|MSN2|MCC | 60 | ea | 9f | - +----+----+----+----+----+----+----+----+ - 0x08| ff | 00 | 00 | 00 | 11 |Bck0|Bck1|Bck2| - +----+----+----+----+----+----+----+----+ - 0x10|Bck3|Bck4|Bck5|BCC | 00 | 00 |Seg0|Seg1| - +----+----+----+----+----+----+----+----+ - 0x18|Seg2|Seg3|SegC|Stp0|Stp1|Stp2|Stp3|UID0| - +----+----+----+----+----+----+----+----+ - 0x20|UID1|UID2|kghC| - +----+----+----+ - - MCD= ManufacturerID (1 Byte) - MSN0..2= ManufactureSerialNumber (3 Byte) - MCC= CRC (1 Byte) calculated over MCD,MSN0..2 - DCF= DecrementalField (2 Byte) 'credential' (enduser-Tag) seems to have always DCF-low=0x60 DCF-high=0xea - Bck0..5= Backup (6 Byte) Bck0 'dirty-flag', Bck1..5 SegmentHeader-Backup - BCC= BackupCRC (1 Byte) CRC calculated over Bck1..5 - Seg0..3= SegmentHeader (on MIM 4 Byte ) - SegC= SegmentCRC (1 Byte) calculated over MCD,MSN0..2,Seg0..3 - Stp0..n= Stamp0... (variable length) length = Segment-Len - UserData - 1 - UID0..n= UserDater (variable length - with KGH hex 0x00-0x63 / dec 0-99) length = Segment-Len - WRP - WRC - 1 - kghC= KabaGroupHeader (1 Byte + addr 0x0c must be 0x11) - as seen on ths example: addr 0x05..0x08 & 0x0c must have been set to this values - otherwise kghCRC will not be created by a official reader (not accepted) + place your empty tag onto the PM3 to read and display the MCD & MSN0..2 + the values will be shown below + confirm whnen ready [y/n] ?y + #db# setting up legic card + #db# MIM 256 card found, reading card ... + #db# Card read, use 'hf legic decode' or + #db# 'data hexsamples 8' to view results + 0b ad c0 de <- !! here you'll see the MCD & MSN of your empty tag, which has to be typed in manually as seen below !! + type in MCD as 2-digit value - e.g.: 00 (default: 79 ) + > 0b + type in MSN0 as 2-digit value - e.g.: 01 (default: 28 ) + > ad + type in MSN1 as 2-digit value - e.g.: 02 (default: d1 ) + > c0 + type in MSN2 as 2-digit value - e.g.: 03 (default: 43 ) + > de + MCD:0b, MSN:ad c0 de, MCC:79 <- this crc is calculated from the MCD & MSN and must match the one on yout empty tag + + wrote 1024 bytes to myLegicClone.hex + enter number of bytes to write? (default: 86 ) + + loaded 1024 samples + #db# setting up legic card + #db# MIM 256 card found, writing 0x00 - 0x01 ... + #db# write successful + ... + #db# setting up legic card + #db# MIM 256 card found, writing 0x56 - 0x01 ... + #db# write successful + proxmark3> + + the default value (number of bytes to write) is calculated over all valid segments and should be ok - just hit enter, wait until write has finished + and your clone should be ready (except there has to be a additional KGH-CRC to be calculated - which credentials are unknown until yet) + + the '-w' switch will only work with my fork - it needs the binary legic_crc8 which is not part of the proxmark3-master-branch + also the ability to write DCF is not possible with the proxmark3-master-branch + but creating dumpfile-clone files will be possible (without valid segment-crc - this has to done manually with) + + + (example) Legic-Prime Layout with 'Kaba Group Header' + +----+----+----+----+----+----+----+----+ + 0x00|MCD |MSN0|MSN1|MSN2|MCC | 60 | ea | 9f | + +----+----+----+----+----+----+----+----+ + 0x08| ff | 00 | 00 | 00 | 11 |Bck0|Bck1|Bck2| + +----+----+----+----+----+----+----+----+ + 0x10|Bck3|Bck4|Bck5|BCC | 00 | 00 |Seg0|Seg1| + +----+----+----+----+----+----+----+----+ + 0x18|Seg2|Seg3|SegC|Stp0|Stp1|Stp2|Stp3|UID0| + +----+----+----+----+----+----+----+----+ + 0x20|UID1|UID2|kghC| + +----+----+----+ + + MCD= ManufacturerID (1 Byte) + MSN0..2= ManufactureSerialNumber (3 Byte) + MCC= CRC (1 Byte) calculated over MCD,MSN0..2 + DCF= DecrementalField (2 Byte) 'credential' (enduser-Tag) seems to have always DCF-low=0x60 DCF-high=0xea + Bck0..5= Backup (6 Byte) Bck0 'dirty-flag', Bck1..5 SegmentHeader-Backup + BCC= BackupCRC (1 Byte) CRC calculated over Bck1..5 + Seg0..3= SegmentHeader (on MIM 4 Byte ) + SegC= SegmentCRC (1 Byte) calculated over MCD,MSN0..2,Seg0..3 + Stp0..n= Stamp0... (variable length) length = Segment-Len - UserData - 1 + UID0..n= UserDater (variable length - with KGH hex 0x00-0x63 / dec 0-99) length = Segment-Len - WRP - WRC - 1 + kghC= KabaGroupHeader (1 Byte + addr 0x0c must be 0x11) + as seen on this example: addr 0x05..0x08 & 0x0c must have been set to this values - otherwise kghCRC will not be created by a official reader (not accepted) --]] example = "Script create a clone-dump of a dump from a Legic Prime Tag" @@ -89,24 +89,24 @@ author = "Mosci" desc = [[ This is a script which create a clone-dump of a dump from a Legic Prime Tag (MIM256 or MIM1024) -(created with 'hf legic save my_dump.hex') +(created with 'hf legic save my_dump.hex') requiered arguments: - -i (file to read data from) - -optional arguments : - -h - Help text - -o - requieres option -c to be given - -c - requieres option -o to be given - -d - Display content of found Segments - -s - Display summary at the end - -w - write directly to Tag - a file myLegicClone.hex wille be generated also - - e.g.: - hint: using the CRC '00' will result in a plain dump ( -c 00 ) + -i (file to read data from) -Examples : - script run legic_clone -i my_dump.hex -o my_clone.hex -c f8 - script run legic_clone -i my_dump.hex -d -s +optional arguments : + -h - Help text + -o - requieres option -c to be given + -c - requieres option -o to be given + -d - Display content of found Segments + -s - Display summary at the end + -w - write directly to Tag - a file myLegicClone.hex wille be generated also + + e.g.: + hint: using the CRC '00' will result in a plain dump ( -c 00 ) + +Examples : + script run legic_clone -i my_dump.hex -o my_clone.hex -c f8 + script run legic_clone -i my_dump.hex -d -s ]] local utils = require('utils') @@ -114,33 +114,33 @@ local getopt = require('getopt') local bxor = bit32.bxor -- we need always 2 digits -function prepend_zero(s) - if (string.len(s)==1) then return "0" .. s - else - if (string.len(s)==0) then return "00" - else return s - end - end +function prepend_zero(s) + if (string.len(s)==1) then return "0" .. s + else + if (string.len(s)==0) then return "00" + else return s + end + end end ---- +--- -- This is only meant to be used when errors occur function oops(err) - print("ERROR: ",err) - return nil, err + print("ERROR: ",err) + return nil, err end ---- +--- -- Usage help function help() - print(desc) - print("Example usage") - print(example) + print(desc) + print("Example usage") + print(example) end -- Check availability of file function file_check(file_name) - local file_found=io.open(file_name, "r") + local file_found=io.open(file_name, "r") if file_found==nil then file_found=false else @@ -152,113 +152,113 @@ end --- xor-wrapper -- xor all from addr 0x22 (start counting from 1 => 23) function xorme(hex, xor, index) - if ( index >= 23 ) then - return ('%02x'):format(bxor( tonumber(hex,16) , tonumber(xor,16) )) - else - return hex - end + if ( index >= 23 ) then + return ('%02x'):format(bxor( tonumber(hex,16) , tonumber(xor,16) )) + else + return hex + end end -- read input-file into array function getInputBytes(infile) - local line - local bytes = {} + local line + local bytes = {} - local fhi,err = io.open(infile) - if err then print("OOps ... faild to read from file ".. infile); return false; end + local fhi,err = io.open(infile) + if err then print("OOps ... faild to read from file ".. infile); return false; end - while true do - line = fhi:read() - if line == nil then break end + while true do + line = fhi:read() + if line == nil then break end - for byte in line:gmatch("%w+") do - table.insert(bytes, byte) - end - end - - fhi:close() + for byte in line:gmatch("%w+") do + table.insert(bytes, byte) + end + end - print("\nread ".. #bytes .." bytes from ".. infile) - return bytes + fhi:close() + + print("\nread ".. #bytes .." bytes from ".. infile) + return bytes end -- write to file function writeOutputBytes(bytes, outfile) - local line - local bcnt=0 - local fho,err = io.open(outfile,"w") - if err then print("OOps ... faild to open output-file ".. outfile); return false; end + local line + local bcnt=0 + local fho,err = io.open(outfile,"w") + if err then print("OOps ... faild to open output-file ".. outfile); return false; end - for i = 1, #bytes do - if (bcnt == 0) then - line=bytes[i] - elseif (bcnt <= 7) then - line=line.." "..bytes[i] - end - if (bcnt == 7) then - -- write line to new file - fho:write(line.."\n") - -- reset counter & line - bcnt=-1 - line="" - end - bcnt=bcnt+1 - end - fho:close() - print("\nwrote ".. #bytes .." bytes to " .. outfile) - return true + for i = 1, #bytes do + if (bcnt == 0) then + line=bytes[i] + elseif (bcnt <= 7) then + line=line.." "..bytes[i] + end + if (bcnt == 7) then + -- write line to new file + fho:write(line.."\n") + -- reset counter & line + bcnt=-1 + line="" + end + bcnt=bcnt+1 + end + fho:close() + print("\nwrote ".. #bytes .." bytes to " .. outfile) + return true end -- xore certain bytes function xorBytes(inBytes, crc) - local bytes = {} - for index = 1, #inBytes do - bytes[index] = xorme(inBytes[index], crc, index) - end - if (#inBytes == #bytes) then - -- replace crc - bytes[5] = string.sub(crc,-2) - return bytes - else - print("error: byte-count missmatch") - return false - end + local bytes = {} + for index = 1, #inBytes do + bytes[index] = xorme(inBytes[index], crc, index) + end + if (#inBytes == #bytes) then + -- replace crc + bytes[5] = string.sub(crc,-2) + return bytes + else + print("error: byte-count missmatch") + return false + end end -- get raw segment-data function getSegmentData(bytes, start, index) - local raw, len, valid, last, wrp, wrc, rd, crc - local segment = {} - segment[0] = bytes[start].." "..bytes[start+1].." "..bytes[start+2].." "..bytes[start+3] - -- flag = high nibble of byte 1 - segment[1] = string.sub(bytes[start+1],0,1) + local raw, len, valid, last, wrp, wrc, rd, crc + local segment = {} + segment[0] = bytes[start].." "..bytes[start+1].." "..bytes[start+2].." "..bytes[start+3] + -- flag = high nibble of byte 1 + segment[1] = string.sub(bytes[start+1],0,1) - -- valid = bit 6 of byte 1 - segment[2] = tonumber(bit32.extract("0x"..bytes[start+1],6,1),16) + -- valid = bit 6 of byte 1 + segment[2] = tonumber(bit32.extract("0x"..bytes[start+1],6,1),16) - -- last = bit 7 of byte 1 - segment[3] = tonumber(bit32.extract("0x"..bytes[start+1],7,1),16) + -- last = bit 7 of byte 1 + segment[3] = tonumber(bit32.extract("0x"..bytes[start+1],7,1),16) - -- len = (byte 0)+(bit0-3 of byte 1) + -- len = (byte 0)+(bit0-3 of byte 1) segment[4] = tonumber(("%03x"):format(tonumber(bit32.extract("0x"..bytes[start+1],0,3),16)..tonumber(bytes[start],16)),16) - - -- wrp (write proteted) = byte 2 - segment[5] = tonumber(bytes[start+2]) - -- wrc (write control) - bit 4-6 of byte 3 - segment[6] = tonumber(bit32.extract("0x"..bytes[start+3],4,3),16) + -- wrp (write proteted) = byte 2 + segment[5] = tonumber(bytes[start+2]) - -- rd (read disabled) - bit 7 of byte 3 - segment[7] = tonumber(bit32.extract("0x"..bytes[start+3],7,1),16) + -- wrc (write control) - bit 4-6 of byte 3 + segment[6] = tonumber(bit32.extract("0x"..bytes[start+3],4,3),16) - -- crc byte 4 - segment[8] = bytes[start+4] + -- rd (read disabled) - bit 7 of byte 3 + segment[7] = tonumber(bit32.extract("0x"..bytes[start+3],7,1),16) - -- segment index - segment[9] = index + -- crc byte 4 + segment[8] = bytes[start+4] - -- # crc-byte - segment[10] = start+4 + -- segment index + segment[9] = index + + -- # crc-byte + segment[10] = start+4 return segment end @@ -276,7 +276,7 @@ function CheckKgh(bytes, segStart, segEnd) local WRP = bytes[(segStart+2)] local WRC = ("%02x"):format(tonumber(bit32.extract("0x"..bytes[segStart+3],4,3),16)) local RD = ("%02x"):format(tonumber(bit32.extract("0x"..bytes[segStart+3],7,1),16)) - local XX = "00" + local XX = "00" cmd = bytes[1]..bytes[2]..bytes[3]..bytes[4]..WRP..WRC..RD..XX for i=(segStart+5), (segStart+5+dataLen-2) do cmd = cmd..bytes[i] @@ -294,247 +294,247 @@ end -- get only the addresses of segemnt-crc's and the length of bytes function getSegmentCrcBytes(bytes) - local start=23 - local index=0 - local crcbytes = {} - repeat - seg = getSegmentData(bytes,start,index) - crcbytes[index]= seg[10] - start = start + seg[4] - index = index + 1 - until (seg[3] == 1 or tonumber(seg[9]) == 126 ) - crcbytes[index] = start - return crcbytes + local start=23 + local index=0 + local crcbytes = {} + repeat + seg = getSegmentData(bytes,start,index) + crcbytes[index]= seg[10] + start = start + seg[4] + index = index + 1 + until (seg[3] == 1 or tonumber(seg[9]) == 126 ) + crcbytes[index] = start + return crcbytes end -- print segment-data (hf legic decode like) function displaySegments(bytes) - --display segment header(s) - start=23 - index="00" - - --repeat until last-flag ist set to 1 or segment-index has reached 126 - repeat - wrc="" - wrp="" - pld="" - Seg = getSegmentData(bytes,start,index) - KGH = CheckKgh(bytes,start,(start+tonumber(Seg[4],10))) - printSegment(Seg) + --display segment header(s) + start=23 + index="00" - -- wrc - if(Seg[6]>0) then - print("WRC protected area:") - -- length of wrc = wrc - for i=1, Seg[6] do - -- starts at (segment-start + segment-header + segment-crc)-1 - wrc = wrc..bytes[(start+4+1+i)-1].." " - end - print(wrc) - elseif(Seg[5]>0) then - print("Remaining write protected area:") - -- length of wrp = (wrp-wrc) - for i=1, (Seg[5]-Seg[6]) do - -- starts at (segment-start + segment-header + segment-crc + wrc)-1 - wrp = wrp..bytes[(start+4+1+Seg[6]+i)-1].." " - end - print(wrp) - end - - -- payload - print("Remaining segment payload:") - --length of payload = segment-len - segment-header - segment-crc - wrp -wrc - for i=1, (Seg[4]-4-1-Seg[5]-Seg[6]) do - -- starts at (segment-start + segment-header + segment-crc + segment-wrp + segemnt-wrc)-1 - pld = pld..bytes[(start+4+1+Seg[5]+Seg[6]+i)-1].." " - end - print(pld) + --repeat until last-flag ist set to 1 or segment-index has reached 126 + repeat + wrc="" + wrp="" + pld="" + Seg = getSegmentData(bytes,start,index) + KGH = CheckKgh(bytes,start,(start+tonumber(Seg[4],10))) + printSegment(Seg) + + -- wrc + if(Seg[6]>0) then + print("WRC protected area:") + -- length of wrc = wrc + for i=1, Seg[6] do + -- starts at (segment-start + segment-header + segment-crc)-1 + wrc = wrc..bytes[(start+4+1+i)-1].." " + end + print(wrc) + elseif(Seg[5]>0) then + print("Remaining write protected area:") + -- length of wrp = (wrp-wrc) + for i=1, (Seg[5]-Seg[6]) do + -- starts at (segment-start + segment-header + segment-crc + wrc)-1 + wrp = wrp..bytes[(start+4+1+Seg[6]+i)-1].." " + end + print(wrp) + end + + -- payload + print("Remaining segment payload:") + --length of payload = segment-len - segment-header - segment-crc - wrp -wrc + for i=1, (Seg[4]-4-1-Seg[5]-Seg[6]) do + -- starts at (segment-start + segment-header + segment-crc + segment-wrp + segemnt-wrc)-1 + pld = pld..bytes[(start+4+1+Seg[5]+Seg[6]+i)-1].." " + end + print(pld) if (KGH) then print("'Kaba Group Header' detected"); end - start = start+Seg[4] - index = prepend_zero(tonumber(Seg[9])+1) - - until (Seg[3] == 1 or tonumber(Seg[9]) == 126 ) + start = start+Seg[4] + index = prepend_zero(tonumber(Seg[9])+1) + + until (Seg[3] == 1 or tonumber(Seg[9]) == 126 ) end -- print Segment values function printSegment(SegmentData) - res = "\nSegment "..SegmentData[9]..": " - res = res.. "raw header="..SegmentData[0]..", " - res = res.. "flag="..SegmentData[1].." (valid="..SegmentData[2].." last="..SegmentData[3].."), " - res = res.. "len="..("%04d"):format(SegmentData[4])..", " - res = res.. "WRP="..prepend_zero(SegmentData[5])..", " - res = res.. "WRC="..prepend_zero(SegmentData[6])..", " - res = res.. "RD="..SegmentData[7]..", " - res = res.. "crc="..SegmentData[8] - print(res) + res = "\nSegment "..SegmentData[9]..": " + res = res.. "raw header="..SegmentData[0]..", " + res = res.. "flag="..SegmentData[1].." (valid="..SegmentData[2].." last="..SegmentData[3].."), " + res = res.. "len="..("%04d"):format(SegmentData[4])..", " + res = res.. "WRP="..prepend_zero(SegmentData[5])..", " + res = res.. "WRC="..prepend_zero(SegmentData[6])..", " + res = res.. "RD="..SegmentData[7]..", " + res = res.. "crc="..SegmentData[8] + print(res) end -- write clone-data to tag function writeToTag(plainBytes) - local SegCrcs = {} - if(utils.confirm("\nplace your empty tag onto the PM3 to read and display the MCD & MSN0..2\nthe values will be shown below\n confirm when ready") == false) then + local SegCrcs = {} + if(utils.confirm("\nplace your empty tag onto the PM3 to read and display the MCD & MSN0..2\nthe values will be shown below\n confirm when ready") == false) then return end - -- gather MCD & MSN from new Tag - this must be enterd manually - cmd = 'hf legic read 0x00 0x04' - core.console(cmd) - print("\nthese are the MCD MSN0 MSN1 MSN2 from the Tag that has being read:") - cmd = 'data hexsamples 4' - core.console(cmd) + -- gather MCD & MSN from new Tag - this must be enterd manually + cmd = 'hf legic read 0x00 0x04' + core.console(cmd) + print("\nthese are the MCD MSN0 MSN1 MSN2 from the Tag that has being read:") + cmd = 'data hexsamples 4' + core.console(cmd) print("^^ use this values as input for the following answers (one 2-digit-value per question/answer):") - -- enter MCD & MSN (in hex) - MCD = utils.input("type in MCD as 2-digit value - e.g.: 00", plainBytes[1]) - MSN0 = utils.input("type in MSN0 as 2-digit value - e.g.: 01", plainBytes[2]) - MSN1 = utils.input("type in MSN1 as 2-digit value - e.g.: 02", plainBytes[3]) - MSN2 = utils.input("type in MSN2 as 2-digit value - e.g.: 03", plainBytes[4]) + -- enter MCD & MSN (in hex) + MCD = utils.input("type in MCD as 2-digit value - e.g.: 00", plainBytes[1]) + MSN0 = utils.input("type in MSN0 as 2-digit value - e.g.: 01", plainBytes[2]) + MSN1 = utils.input("type in MSN1 as 2-digit value - e.g.: 02", plainBytes[3]) + MSN2 = utils.input("type in MSN2 as 2-digit value - e.g.: 03", plainBytes[4]) - -- calculate crc8 over MCD & MSN - cmd = MCD..MSN0..MSN1..MSN2 - MCC = ("%02x"):format(utils.Crc8Legic(cmd)) - print("MCD:"..MCD..", MSN:"..MSN0.." "..MSN1.." "..MSN2..", MCC:"..MCC) + -- calculate crc8 over MCD & MSN + cmd = MCD..MSN0..MSN1..MSN2 + MCC = ("%02x"):format(utils.Crc8Legic(cmd)) + print("MCD:"..MCD..", MSN:"..MSN0.." "..MSN1.." "..MSN2..", MCC:"..MCC) - -- calculate new Segment-CRC for each valid segment - SegCrcs = getSegmentCrcBytes(plainBytes) - for i=0, (#SegCrcs-1) do + -- calculate new Segment-CRC for each valid segment + SegCrcs = getSegmentCrcBytes(plainBytes) + for i=0, (#SegCrcs-1) do -- SegCrcs[i]-4 = address of first byte of segmentHeader (low byte segment-length) segLen=tonumber(("%1x"):format(tonumber(bit32.extract("0x"..plainBytes[(SegCrcs[i]-3)],0,3),16))..("%02x"):format(tonumber(plainBytes[SegCrcs[i]-4],16)),16) segStart=(SegCrcs[i]-4) segEnd=(SegCrcs[i]-4+segLen) KGH=CheckKgh(plainBytes,segStart,segEnd) - if (KGH) then + if (KGH) then print("'Kaba Group Header' detected - re-calculate...") end - cmd = MCD..MSN0..MSN1..MSN2..plainBytes[SegCrcs[i]-4]..plainBytes[SegCrcs[i]-3]..plainBytes[SegCrcs[i]-2]..plainBytes[SegCrcs[i]-1] - plainBytes[SegCrcs[i]] = ("%02x"):format(utils.Crc8Legic(cmd)) - end + cmd = MCD..MSN0..MSN1..MSN2..plainBytes[SegCrcs[i]-4]..plainBytes[SegCrcs[i]-3]..plainBytes[SegCrcs[i]-2]..plainBytes[SegCrcs[i]-1] + plainBytes[SegCrcs[i]] = ("%02x"):format(utils.Crc8Legic(cmd)) + end - -- apply MCD & MSN to plain data - plainBytes[1] = MCD - plainBytes[2] = MSN0 - plainBytes[3] = MSN1 - plainBytes[4] = MSN2 - plainBytes[5] = MCC - - -- prepare plainBytes for writing (xor plain data with new MCC) - bytes = xorBytes(plainBytes, MCC) - - -- write data to file - if (writeOutputBytes(bytes, "myLegicClone.hex")) then - WriteBytes = utils.input("enter number of bytes to write?", SegCrcs[#SegCrcs]) + -- apply MCD & MSN to plain data + plainBytes[1] = MCD + plainBytes[2] = MSN0 + plainBytes[3] = MSN1 + plainBytes[4] = MSN2 + plainBytes[5] = MCC - -- load file into pm3-buffer - cmd = 'hf legic load myLegicClone.hex' - core.console(cmd) - - -- write pm3-buffer to Tag - for i=0, WriteBytes do - if ( i<5 or i>6) then - cmd = ('hf legic write 0x%02x 0x01'):format(i) - core.console(cmd) - elseif (i == 6) then - -- write DCF in reverse order (requires 'mosci-patch') - cmd = 'hf legic write 0x05 0x02' - core.console(cmd) - else - print("skipping byte 0x05 - will be written next step") - end - utils.Sleep(0.2) - end - end + -- prepare plainBytes for writing (xor plain data with new MCC) + bytes = xorBytes(plainBytes, MCC) + + -- write data to file + if (writeOutputBytes(bytes, "myLegicClone.hex")) then + WriteBytes = utils.input("enter number of bytes to write?", SegCrcs[#SegCrcs]) + + -- load file into pm3-buffer + cmd = 'hf legic load myLegicClone.hex' + core.console(cmd) + + -- write pm3-buffer to Tag + for i=0, WriteBytes do + if ( i<5 or i>6) then + cmd = ('hf legic write 0x%02x 0x01'):format(i) + core.console(cmd) + elseif (i == 6) then + -- write DCF in reverse order (requires 'mosci-patch') + cmd = 'hf legic write 0x05 0x02' + core.console(cmd) + else + print("skipping byte 0x05 - will be written next step") + end + utils.Sleep(0.2) + end + end end -- main function function main(args) - -- some variables - local i=0 - local oldcrc, newcrc, infile, outfile - local bytes = {} - local segments = {} - - -- parse arguments for the script - for o, a in getopt.getopt(args, 'hwsdc:i:o:') do - -- output file - if o == "o" then - outfile = a - ofs = true - if (file_check(a)) then - local answer = utils.confirm("\nthe output-file "..a.." alredy exists!\nthis will delete the previous content!\ncontinue?") - if (answer==false) then return oops("quiting") end - end - end - -- input file - if o == "i" then - infile = a - if (file_check(infile)==false) then - return oops("input file: "..infile.." not found") - else - bytes = getInputBytes(infile) - oldcrc = bytes[5] - ifs = true - if (bytes == false) then return oops('couldnt get input bytes') end - end - i = i+1 - end - -- new crc - if o == "c" then - newcrc = a - ncs = true - end - -- display segments switch - if o == "d" then ds = true; end - -- display summary switch - if o == "s" then ss = true; end - -- write to tag switch - if o == "w" then ws = true; end - -- help - if o == "h" then return help() end - end - - if (not ifs) then return oops("option -i is required but missing") end - - -- bytes to plain - bytes = xorBytes(bytes, oldcrc) - - -- show segments (works only on plain bytes) - if (ds) then - print("+------------------------------------------- Segments -------------------------------------------+") - displaySegments(bytes); - end + -- some variables + local i=0 + local oldcrc, newcrc, infile, outfile + local bytes = {} + local segments = {} - if (ofs and ncs) then - -- xor bytes with new crc - newBytes = xorBytes(bytes, newcrc) - -- write output - if (writeOutputBytes(newBytes, outfile)) then - -- show summary if requested - if (ss) then - -- information - res = "\n+-------------------------------------------- Summary -------------------------------------------+" - res = res .."\ncreated clone_dump from\n\t"..infile.." crc: "..oldcrc.."\ndump_file:" - res = res .."\n\t"..outfile.." crc: "..string.sub(newcrc,-2) - res = res .."\nyou may load the new file with: hf legic load "..outfile - res = res .."\n\nif you don't write to tag immediately ('-w' switch) you will need to recalculate each segmentCRC" - res = res .."\nafter writing this dump to a tag!" - res = res .."\n\na segmentCRC gets calculated over MCD,MSN0..3,Segment-Header0..3" - res = res .."\ne.g. (based on Segment00 of the data from "..infile.."):" - res = res .."\nhf legic crc8 "..bytes[1]..bytes[2]..bytes[3]..bytes[4]..bytes[23]..bytes[24]..bytes[25]..bytes[26] - -- this can not be calculated without knowing the new MCD, MSN0..2 - print(res) - end - end - else - if (ss) then - -- show why the output-file was not written - print("\nnew file not written - some arguments are missing ..") - print("output file: ".. (ofs and outfile or "not given")) - print("new crc: ".. (ncs and newcrc or "not given")) - end - end - -- write to tag - if (ws and #bytes == 1024) then - writeToTag(bytes) - end + -- parse arguments for the script + for o, a in getopt.getopt(args, 'hwsdc:i:o:') do + -- output file + if o == "o" then + outfile = a + ofs = true + if (file_check(a)) then + local answer = utils.confirm("\nthe output-file "..a.." alredy exists!\nthis will delete the previous content!\ncontinue?") + if (answer==false) then return oops("quiting") end + end + end + -- input file + if o == "i" then + infile = a + if (file_check(infile)==false) then + return oops("input file: "..infile.." not found") + else + bytes = getInputBytes(infile) + oldcrc = bytes[5] + ifs = true + if (bytes == false) then return oops('couldnt get input bytes') end + end + i = i+1 + end + -- new crc + if o == "c" then + newcrc = a + ncs = true + end + -- display segments switch + if o == "d" then ds = true; end + -- display summary switch + if o == "s" then ss = true; end + -- write to tag switch + if o == "w" then ws = true; end + -- help + if o == "h" then return help() end + end + + if (not ifs) then return oops("option -i is required but missing") end + + -- bytes to plain + bytes = xorBytes(bytes, oldcrc) + + -- show segments (works only on plain bytes) + if (ds) then + print("+------------------------------------------- Segments -------------------------------------------+") + displaySegments(bytes); + end + + if (ofs and ncs) then + -- xor bytes with new crc + newBytes = xorBytes(bytes, newcrc) + -- write output + if (writeOutputBytes(newBytes, outfile)) then + -- show summary if requested + if (ss) then + -- information + res = "\n+-------------------------------------------- Summary -------------------------------------------+" + res = res .."\ncreated clone_dump from\n\t"..infile.." crc: "..oldcrc.."\ndump_file:" + res = res .."\n\t"..outfile.." crc: "..string.sub(newcrc,-2) + res = res .."\nyou may load the new file with: hf legic load "..outfile + res = res .."\n\nif you don't write to tag immediately ('-w' switch) you will need to recalculate each segmentCRC" + res = res .."\nafter writing this dump to a tag!" + res = res .."\n\na segmentCRC gets calculated over MCD,MSN0..3,Segment-Header0..3" + res = res .."\ne.g. (based on Segment00 of the data from "..infile.."):" + res = res .."\nhf legic crc8 "..bytes[1]..bytes[2]..bytes[3]..bytes[4]..bytes[23]..bytes[24]..bytes[25]..bytes[26] + -- this can not be calculated without knowing the new MCD, MSN0..2 + print(res) + end + end + else + if (ss) then + -- show why the output-file was not written + print("\nnew file not written - some arguments are missing ..") + print("output file: ".. (ofs and outfile or "not given")) + print("new crc: ".. (ncs and newcrc or "not given")) + end + end + -- write to tag + if (ws and #bytes == 1024) then + writeToTag(bytes) + end end -- call main with arguments diff --git a/client/scripts/amiibo.lua b/client/scripts/amiibo.lua index cc2459f30..2bcd2a07e 100644 --- a/client/scripts/amiibo.lua +++ b/client/scripts/amiibo.lua @@ -88,10 +88,10 @@ local function emulate_amiibo (amiibo_data) local simCmd = Command:new{cmd = cmds.CMD_SIMULATE_TAG_ISO_14443a, arg1 = 7, arg2 = uid_first, arg3 = uid_second} local _, err = reader.sendToDevice(simCmd) if err then - print('Failed to start simulator', err) - return + print('Failed to start simulator', err) + return else - print('Starting simulator') + print('Starting simulator') end end diff --git a/client/scripts/brutesim.lua b/client/scripts/brutesim.lua index 50e3b5888..9527d8970 100644 --- a/client/scripts/brutesim.lua +++ b/client/scripts/brutesim.lua @@ -21,7 +21,7 @@ desc = [[ This script uses the proxmark3 implementations of simulation to bruteforce given ranges of id. It uses both LF and HF simulations. - + -- Author note -- I wrote this as i was doing a PACS audit. This is far from complete, but is easily expandable. -- The idea was based on proxbrute, but i needed more options, and support for different readers. @@ -38,8 +38,8 @@ usage = [[ script run brutesim -r rfid_tag -f facility_code -b base_card_number -c count -t timeout -d direction Arguments: - -h this help - -r *see below RFID Tag: the RFID tag to emulate + -h this help + -r *see below RFID Tag: the RFID tag to emulate pyramid awid fdx @@ -50,251 +50,251 @@ Arguments: 14a hid - -f 0-999 facility code (dfx: country id, 14a: type) - -b 0-65535 base card number to start from - -c 1-65536 number of cards to try - -t .0-99999, pause timeout between cards (use the word 'pause' to wait for user input) - -d up, down direction to move through card numbers + -f 0-999 facility code (dfx: country id, 14a: type) + -b 0-65535 base card number to start from + -c 1-65536 number of cards to try + -t .0-99999, pause timeout between cards (use the word 'pause' to wait for user input) + -d up, down direction to move through card numbers ]] local DEBUG = true -local bor = bit32.bor -local bxor = bit32.bxor +local bor = bit32.bor +local bxor = bit32.bxor local lshift = bit32.lshift ---- +--- -- A debug printout-function local function dbg(args) if type(args) == "table" then - local i = 1 - while args[i] do - dbg(args[i]) - i = i+1 - end - else - print("###", args) - end + 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) - return nil,err + print("ERROR: ",err) + return nil,err end ---- +--- -- Usage help local function help() - print(copyright) - print(author) - print(version) - print(desc) - print("Example usage") - print(example) + print(copyright) + print(author) + print(version) + print(desc) + print("Example usage") + print(example) end -- -- Exit message function exitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() end -- -- Check if a string is empty local function isempty(s) - return s == nil or s == '' + return s == nil or s == '' end --- The code below was blatantly stolen from Brian Redbeard's lf_bulk_program.lua script +-- The code below was blatantly stolen from Brian Redbeard's lf_bulk_program.lua script local function toBits(num, bits) - bits = bits or math.max(1, select(2, math.frexp(num))) - local t = {} - for b = bits, 1, -1 do - t[b] = math.fmod(num, 2) - num = math.floor((num - t[b]) / 2) - end - return table.concat(t) + bits = bits or math.max(1, select(2, math.frexp(num))) + local t = {} + for b = bits, 1, -1 do + t[b] = math.fmod(num, 2) + num = math.floor((num - t[b]) / 2) + end + return table.concat(t) end -- --- check for parity in bit-string. +-- check for parity in bit-string. local function evenparity(s) - local _, count = string.gsub(s, "1", "") - local p = count % 2 - if (p == 0) then - return false - end - return true + local _, count = string.gsub(s, "1", "") + local p = count % 2 + if (p == 0) then + return false + end + return true end -- --- calcs hex for HID +-- calcs hex for HID local function cardHex(i, f) - fac = lshift(f, 16) - id = bor(i, fac) - stream = toBits(id, 26) - high = evenparity(string.sub(stream, 0, 12)) and 1 or 0 - low = not evenparity(string.sub(stream, 13)) and 1 or 0 - bits = bor(lshift(id, 1), low) - bits = bor(bits, lshift(high, 25)) - preamble = bor(0, lshift(1, 5)) - bits = bor(bits, lshift(1, 26)) - return ("%04x%08x"):format(preamble, bits) + fac = lshift(f, 16) + id = bor(i, fac) + stream = toBits(id, 26) + high = evenparity(string.sub(stream, 0, 12)) and 1 or 0 + low = not evenparity(string.sub(stream, 13)) and 1 or 0 + bits = bor(lshift(id, 1), low) + bits = bor(bits, lshift(high, 25)) + preamble = bor(0, lshift(1, 5)) + bits = bor(bits, lshift(1, 26)) + return ("%04x%08x"):format(preamble, bits) end -- -- local function main(args) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print() - - if #args == 0 then return help() end + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() - for o, a in getopt.getopt(args, 'r:f:b:c:t:d:h') do -- Populate command like arguments - if o == 'r' then rfidtag = a end - if o == 'f' then facility = a end - if o == 'b' then baseid = a end - if o == 'c' then count = a end - if o == 't' then timeout = a end - if o == 'd' then direction = a end - if o == 'h' then return print(usage) end - end + if #args == 0 then return help() end - -- Check to see if -r argument was passed - if isempty(rfidtag) then - print("You must supply the flag -r (rfid tag)") - print(usage) - return - end + for o, a in getopt.getopt(args, 'r:f:b:c:t:d:h') do -- Populate command like arguments + if o == 'r' then rfidtag = a end + if o == 'f' then facility = a end + if o == 'b' then baseid = a end + if o == 'c' then count = a end + if o == 't' then timeout = a end + if o == 'd' then direction = a end + if o == 'h' then return print(usage) end + end - -- Check what RFID Tag we are using - if rfidtag == 'pyramid' then - consolecommand = 'lf pyramid sim' -- set the console command - rfidtagname = 'Farpointe/Pyramid' -- set the display name - facilityrequired = 1 -- set if FC is required - elseif rfidtag == 'awid' then - consolecommand = 'lf awid sim' - rfidtagname = 'AWID' - facilityrequired = 1 - elseif rfidtag == 'fdx' then -- I'm not sure why you would need to bruteforce this ¯\_(ツ)_/¯ - consolecommand = 'lf fdx sim' - rfidtagname = 'FDX-B' - facilityrequired = 1 - elseif rfidtag == 'jablotron' then - consolecommand = 'lf jablotron sim' - rfidtagname = 'Jablotron' - facilityrequired = 0 - elseif rfidtag == 'noralsy' then - consolecommand = 'lf noralsy sim' - rfidtagname = 'Noralsy' - facilityrequired = 0 - elseif rfidtag == 'presco' then - consolecommand = 'lf presco sim d' - rfidtagname = 'Presco' - facilityrequired = 0 - elseif rfidtag == 'visa2000' then - consolecommand = 'lf visa2000 sim' - rfidtagname = 'Visa2000' - facilityrequired = 0 - elseif rfidtag == '14a' then - consolecommand = 'hf 14a sim' - if facility == "1" then rfidtagname = 'MIFARE Classic' -- Here we use the -f option to read the 14a type instead of the facility code - elseif facility == "2" then rfidtagname = 'MIFARE Ultralight' - elseif facility == "3" then rfidtagname = 'MIFARE Desfire' - elseif facility == "4" then rfidtagname = 'ISO/IEC 14443-4' - elseif facility == "5" then rfidtagname = 'MIFARE Tnp3xxx' - else - print("Invalid 14a type (-f) supplied. Must be 1-5") - print(usage) - return - end - facilityrequired = 0 -- Disable the FC required check, as we used it for type instead of FC - elseif rfidtag == 'hid' then - consolecommand = 'lf hid sim' - rfidtagname = 'HID' - facilityrequired = 1 - else -- Display error and exit out if bad RFID tag was supplied - print("Invalid rfid tag (-r) supplied") - print(usage) - return - end - - if isempty(baseid) then -- Display error and exit out if no starting id is set - print("You must supply the flag -b (base id)") - print(usage) - return - end + -- Check to see if -r argument was passed + if isempty(rfidtag) then + print("You must supply the flag -r (rfid tag)") + print(usage) + return + end - if isempty(count) then -- Display error and exit out of no count is set - print("You must supply the flag -c (count)") - print(usage) - return - end - - if facilityrequired == 1 then -- If FC is required - facilitymessage = " - Facility Code: " -- Add FC to status message - if isempty(facility) then -- If FC was left blank, display warning and set FC to 0 - print("Using 0 for the facility code as -f was not supplied") - facility = 0 - end - else -- If FC is not required - facility = "" -- Clear FC - facilitymessage = "" -- Remove FC from status message - end - - if isempty(timeout) then -- If timeout was not supplied, show warning and set timeout to 0 - print("Using 0 for the timeout as -t was not supplied") - timeout = 0 - end - - if isempty(direction) then -- If direction was not supplied, show warning and set direction to down - print("Using down for direction as -d was not supplied") - direction = 'down' - end - - if tonumber(count) < 1 then - print("Count -c must be set to 1 or higher") - return - else - count = count -1 -- Make our count accurate by removing 1, because math - end - - if direction == 'down' then -- If counting down, set up our for loop to count down - endid = baseid - count - fordirection = -1 - elseif direction == 'up' then -- If counting up, set our for loop to count up - endid = baseid + count - fordirection = 1 - else -- If invalid direction was set, show warning and set up our for loop to count down - print("Invalid direction (-d) supplied, using down") - endid = baseid - count - fordirection = -1 - end - + -- Check what RFID Tag we are using + if rfidtag == 'pyramid' then + consolecommand = 'lf pyramid sim' -- set the console command + rfidtagname = 'Farpointe/Pyramid' -- set the display name + facilityrequired = 1 -- set if FC is required + elseif rfidtag == 'awid' then + consolecommand = 'lf awid sim' + rfidtagname = 'AWID' + facilityrequired = 1 + elseif rfidtag == 'fdx' then -- I'm not sure why you would need to bruteforce this ¯\_(ツ)_/¯ + consolecommand = 'lf fdx sim' + rfidtagname = 'FDX-B' + facilityrequired = 1 + elseif rfidtag == 'jablotron' then + consolecommand = 'lf jablotron sim' + rfidtagname = 'Jablotron' + facilityrequired = 0 + elseif rfidtag == 'noralsy' then + consolecommand = 'lf noralsy sim' + rfidtagname = 'Noralsy' + facilityrequired = 0 + elseif rfidtag == 'presco' then + consolecommand = 'lf presco sim d' + rfidtagname = 'Presco' + facilityrequired = 0 + elseif rfidtag == 'visa2000' then + consolecommand = 'lf visa2000 sim' + rfidtagname = 'Visa2000' + facilityrequired = 0 + elseif rfidtag == '14a' then + consolecommand = 'hf 14a sim' + if facility == "1" then rfidtagname = 'MIFARE Classic' -- Here we use the -f option to read the 14a type instead of the facility code + elseif facility == "2" then rfidtagname = 'MIFARE Ultralight' + elseif facility == "3" then rfidtagname = 'MIFARE Desfire' + elseif facility == "4" then rfidtagname = 'ISO/IEC 14443-4' + elseif facility == "5" then rfidtagname = 'MIFARE Tnp3xxx' + else + print("Invalid 14a type (-f) supplied. Must be 1-5") + print(usage) + return + end + facilityrequired = 0 -- Disable the FC required check, as we used it for type instead of FC + elseif rfidtag == 'hid' then + consolecommand = 'lf hid sim' + rfidtagname = 'HID' + facilityrequired = 1 + else -- Display error and exit out if bad RFID tag was supplied + print("Invalid rfid tag (-r) supplied") + print(usage) + return + end - - -- display status message - print("") - print("BruteForcing "..rfidtagname..""..facilitymessage..""..facility.." - CardNumber Start: "..baseid.." - CardNumber End: "..endid.." - TimeOut: "..timeout) - print("") - - -- loop through for each count (-c) - for cardnum = baseid, endid, fordirection do - - -- If rfid tag is set to HID, convert card to HEX using the stolen code above - if rfidtag == 'hid' then cardnum = cardHex(cardnum, facility) end - - -- send command to proxmark - core.console(consolecommand..' '..facility..' '..cardnum) + if isempty(baseid) then -- Display error and exit out if no starting id is set + print("You must supply the flag -b (base id)") + print(usage) + return + end - if timeout == 'pause' then - print("Press enter to continue ...") - io.read() - else - os.execute("sleep "..timeout.."") - end - end - - -- ping the proxmark to stop emulation and see if its still responding - core.console('hw ping') + if isempty(count) then -- Display error and exit out of no count is set + print("You must supply the flag -c (count)") + print(usage) + return + end + + if facilityrequired == 1 then -- If FC is required + facilitymessage = " - Facility Code: " -- Add FC to status message + if isempty(facility) then -- If FC was left blank, display warning and set FC to 0 + print("Using 0 for the facility code as -f was not supplied") + facility = 0 + end + else -- If FC is not required + facility = "" -- Clear FC + facilitymessage = "" -- Remove FC from status message + end + + if isempty(timeout) then -- If timeout was not supplied, show warning and set timeout to 0 + print("Using 0 for the timeout as -t was not supplied") + timeout = 0 + end + + if isempty(direction) then -- If direction was not supplied, show warning and set direction to down + print("Using down for direction as -d was not supplied") + direction = 'down' + end + + if tonumber(count) < 1 then + print("Count -c must be set to 1 or higher") + return + else + count = count -1 -- Make our count accurate by removing 1, because math + end + + if direction == 'down' then -- If counting down, set up our for loop to count down + endid = baseid - count + fordirection = -1 + elseif direction == 'up' then -- If counting up, set our for loop to count up + endid = baseid + count + fordirection = 1 + else -- If invalid direction was set, show warning and set up our for loop to count down + print("Invalid direction (-d) supplied, using down") + endid = baseid - count + fordirection = -1 + end + + + + -- display status message + print("") + print("BruteForcing "..rfidtagname..""..facilitymessage..""..facility.." - CardNumber Start: "..baseid.." - CardNumber End: "..endid.." - TimeOut: "..timeout) + print("") + + -- loop through for each count (-c) + for cardnum = baseid, endid, fordirection do + + -- If rfid tag is set to HID, convert card to HEX using the stolen code above + if rfidtag == 'hid' then cardnum = cardHex(cardnum, facility) end + + -- send command to proxmark + core.console(consolecommand..' '..facility..' '..cardnum) + + if timeout == 'pause' then + print("Press enter to continue ...") + io.read() + else + os.execute("sleep "..timeout.."") + end + end + + -- ping the proxmark to stop emulation and see if its still responding + core.console('hw ping') end main(args) \ No newline at end of file diff --git a/client/scripts/calc_di.lua b/client/scripts/calc_di.lua index b46d45b51..e0b587332 100644 --- a/client/scripts/calc_di.lua +++ b/client/scripts/calc_di.lua @@ -7,170 +7,170 @@ copyright = '' author = "Iceman" version = 'v1.0.0' desc = [[ -This script calculates mifare keys based on uid diversification for DI. +This script calculates mifare keys based on uid diversification for DI. Algo not found by me. ]] example = [[ - -- if called without, it reads tag uid - script run calc_di - - -- - script run calc_di -u 11223344556677 + -- if called without, it reads tag uid + script run calc_di + + -- + script run calc_di -u 11223344556677 ]] usage = [[ script run calc_di -h -u Arguments: - -h : this help - -u : UID + -h : this help + -u : UID ]] local DEBUG = true local BAR = '286329204469736E65792032303133' local MIS = '0A14FD0507FF4BCD026BA83F0A3B89A9' local bxor = bit32.bxor ---- +--- -- 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 ---- + 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) - return nil,err + print("ERROR: ",err) + return nil,err end ---- +--- -- Usage help local function help() - print(copyright) - print(author) - print(version) - print(desc) - print('Example usage') - print(example) + print(copyright) + print(author) + print(version) + print(desc) + print('Example usage') + print(example) end --- -- Exit message local function exitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() end --- -- dumps all keys to file local function dumptofile(keys) - dbg('dumping keys to file') + dbg('dumping keys to file') - if utils.confirm('Do you wish to save the keys to dumpfile?') then - local destination = utils.input('Select a filename to store to', 'dumpkeys.bin') - local file = io.open(destination, 'wb') - if file == nil then - print('Could not write to file ', destination) - return - end + if utils.confirm('Do you wish to save the keys to dumpfile?') then + local destination = utils.input('Select a filename to store to', 'dumpkeys.bin') + local file = io.open(destination, 'wb') + if file == nil then + print('Could not write to file ', destination) + return + end - -- Mifare Mini has 5 sectors, - local key_a = '' - local key_b = '' - - for sector = 0, #keys do - local keyA, keyB = unpack(keys[sector]) - key_a = key_a .. bin.pack('H', keyA); - key_b = key_b .. bin.pack('H', keyB); - end - file:write(key_a) - file:write(key_b) - file:close() - end + -- Mifare Mini has 5 sectors, + local key_a = '' + local key_b = '' + + for sector = 0, #keys do + local keyA, keyB = unpack(keys[sector]) + key_a = key_a .. bin.pack('H', keyA); + key_b = key_b .. bin.pack('H', keyB); + end + file:write(key_a) + file:write(key_b) + file:close() + end end --- -- create key local function keygen(uid) - local data = MIS..uid..BAR - local hash = utils.ConvertAsciiToBytes(utils.Sha1Hex(data)) - return string.format("%02X%02X%02X%02X%02X%02X", - hash[3+1], - hash[2+1], - hash[1+1], - hash[0+1], - hash[7+1], - hash[6+1] - ) + local data = MIS..uid..BAR + local hash = utils.ConvertAsciiToBytes(utils.Sha1Hex(data)) + return string.format("%02X%02X%02X%02X%02X%02X", + hash[3+1], + hash[2+1], + hash[1+1], + hash[0+1], + hash[7+1], + hash[6+1] + ) end --- -- print keys local function printKeys(keys) - print('|---|----------------|---|----------------|---|') - print('|sec|key A |res|key B |res|') - print('|---|----------------|---|----------------|---|') - for sector = 0, #keys do - local keyA, keyB = unpack(keys[sector]) - print(('|%03d| %s | %s | %s | %s |'):format(sector, keyA, 1, keyB, 1)) - end - print('|---|----------------|---|----------------|---|') + print('|---|----------------|---|----------------|---|') + print('|sec|key A |res|key B |res|') + print('|---|----------------|---|----------------|---|') + for sector = 0, #keys do + local keyA, keyB = unpack(keys[sector]) + print(('|%03d| %s | %s | %s | %s |'):format(sector, keyA, 1, keyB, 1)) + end + print('|---|----------------|---|----------------|---|') end --- -- createfull set of keys local function createKeys(uid) - local key = keygen(uid) - local k = {} - for i = 0,4 do - k[i] = { key, key } - end - return k + local key = keygen(uid) + local k = {} + for i = 0,4 do + k[i] = { key, key } + end + return k end --- -- main local function main(args) - print( string.rep('==', 30) ) - print() - - local uid - local useUID = false - - -- Arguments for the script - for o, a in getopt.getopt(args, 'hu:') do - if o == "h" then return help() end - if o == "u" then uid = a; useUID = true end - end + print( string.rep('==', 30) ) + print() - if useUID then - -- uid string checks if supplied - if uid == nil then return oops('empty uid string') end - if #uid == 0 then return oops('empty uid string') end - if #uid ~= 14 then return oops('uid wrong length. Should be 7 hex bytes') end - else - -- GET TAG UID - local tag, err = lib14a.read(false, true) - if not tag then return oops(err) end - core.clearCommandBuffer() + local uid + local useUID = false - -- simple tag check - if 0x09 ~= tag.sak then - if 0x4400 ~= tag.atqa then - return oops(('[fail] found tag %s :: looking for Mifare Mini 0.3k'):format(tag.name)) - end - end - uid = tag.uid - end - - print('|UID|', uid) - - local keys, err = createKeys( uid ) - printKeys( keys ) - dumptofile( keys ) + -- Arguments for the script + for o, a in getopt.getopt(args, 'hu:') do + if o == "h" then return help() end + if o == "u" then uid = a; useUID = true end + end + + if useUID then + -- uid string checks if supplied + if uid == nil then return oops('empty uid string') end + if #uid == 0 then return oops('empty uid string') end + if #uid ~= 14 then return oops('uid wrong length. Should be 7 hex bytes') end + else + -- GET TAG UID + local tag, err = lib14a.read(false, true) + if not tag then return oops(err) end + core.clearCommandBuffer() + + -- simple tag check + if 0x09 ~= tag.sak then + if 0x4400 ~= tag.atqa then + return oops(('[fail] found tag %s :: looking for Mifare Mini 0.3k'):format(tag.name)) + end + end + uid = tag.uid + end + + print('|UID|', uid) + + local keys, err = createKeys( uid ) + printKeys( keys ) + dumptofile( keys ) end main(args) \ No newline at end of file diff --git a/client/scripts/calc_ev1_it.lua b/client/scripts/calc_ev1_it.lua index f7a59dc1e..c6070d20d 100644 --- a/client/scripts/calc_ev1_it.lua +++ b/client/scripts/calc_ev1_it.lua @@ -12,167 +12,167 @@ Algo not found by me. ]] example =[[ -- if called without, it reads tag uid - script run calc_ev1_it - - -- - script run calc_ev1_it -u 11223344556677 + script run calc_ev1_it + + -- + script run calc_ev1_it -u 11223344556677 ]] usage = [[ script run calc_ev1_it -h -u " Arguments: - -h : this help - -u : UID + -h : this help + -u : UID ]] local DEBUG = true local bxor = bit32.bxor ---- +--- -- A debug printout-function local function dbg(args) - if not DEBUG then return end - + 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 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) - return nil,err + print("ERROR: ",err) + return nil,err end ---- +--- -- Usage help local function help() - print(copyright) - print(author) - print(version) - print(desc) - print("Example usage") - print(example) + print(copyright) + print(author) + print(version) + print(desc) + print("Example usage") + print(example) end -- -- Exit message function exitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() end local _xortable = { --[[ position, 4byte xor --]] - {"00","4f2711c1"}, - {"01","07D7BB83"}, - {"02","9636EF07"}, - {"03","B5F4460E"}, - {"04","F271141C"}, - {"05","7D7BB038"}, - {"06","636EF871"}, - {"07","5F4468E3"}, - {"08","271149C7"}, - {"09","D7BB0B8F"}, - {"0A","36EF8F1E"}, - {"0B","F446863D"}, - {"0C","7114947A"}, - {"0D","7BB0B0F5"}, - {"0E","6EF8F9EB"}, - {"0F","44686BD7"}, - {"10","11494fAF"}, - {"11","BB0B075F"}, - {"12","EF8F96BE"}, - {"13","4686B57C"}, - {"14","1494F2F9"}, - {"15","B0B07DF3"}, - {"16","F8F963E6"}, - {"17","686B5FCC"}, - {"18","494F2799"}, - {"19","0B07D733"}, - {"1A","8F963667"}, - {"1B","86B5F4CE"}, - {"1C","94F2719C"}, - {"1D","B07D7B38"}, - {"1E","F9636E70"}, - {"1F","6B5F44E0"}, + {"00","4f2711c1"}, + {"01","07D7BB83"}, + {"02","9636EF07"}, + {"03","B5F4460E"}, + {"04","F271141C"}, + {"05","7D7BB038"}, + {"06","636EF871"}, + {"07","5F4468E3"}, + {"08","271149C7"}, + {"09","D7BB0B8F"}, + {"0A","36EF8F1E"}, + {"0B","F446863D"}, + {"0C","7114947A"}, + {"0D","7BB0B0F5"}, + {"0E","6EF8F9EB"}, + {"0F","44686BD7"}, + {"10","11494fAF"}, + {"11","BB0B075F"}, + {"12","EF8F96BE"}, + {"13","4686B57C"}, + {"14","1494F2F9"}, + {"15","B0B07DF3"}, + {"16","F8F963E6"}, + {"17","686B5FCC"}, + {"18","494F2799"}, + {"19","0B07D733"}, + {"1A","8F963667"}, + {"1B","86B5F4CE"}, + {"1C","94F2719C"}, + {"1D","B07D7B38"}, + {"1E","F9636E70"}, + {"1F","6B5F44E0"}, } local function findEntryByUid( uid ) - -- xor UID4,UID5,UID6,UID7 - -- mod 0x20 (dec 32) - local pos = (bxor(uid[4], uid[5], uid[6], uid[7])) % 32 + -- xor UID4,UID5,UID6,UID7 + -- mod 0x20 (dec 32) + local pos = (bxor(uid[4], uid[5], uid[6], uid[7])) % 32 + + -- convert to hexstring + pos = string.format('%02X', pos) - -- convert to hexstring - pos = string.format('%02X', pos) - for k, v in pairs(_xortable) do - if ( v[1] == pos ) then - return utils.ConvertHexToBytes(v[2]) - end - end - return nil + if ( v[1] == pos ) then + return utils.ConvertHexToBytes(v[2]) + end + end + return nil end --- -- create pwd local function pwdgen(uid) - -- PWD CALC - -- PWD0 = T0 xor B xor C xor D - -- PWD1 = T1 xor A xor C xor E - -- PWD2 = T2 xor A xor B xor F - -- PWD3 = T3 xor G - local uidbytes = utils.ConvertHexToBytes(uid) + -- PWD CALC + -- PWD0 = T0 xor B xor C xor D + -- PWD1 = T1 xor A xor C xor E + -- PWD2 = T2 xor A xor B xor F + -- PWD3 = T3 xor G + local uidbytes = utils.ConvertHexToBytes(uid) local entry = findEntryByUid(uidbytes) - if entry == nil then return nil, "Can't find a xor entry" end + if entry == nil then return nil, "Can't find a xor entry" end local pwd0 = bxor( entry[1], uidbytes[2], uidbytes[3], uidbytes[4]) - local pwd1 = bxor( entry[2], uidbytes[1], uidbytes[3], uidbytes[5]) - local pwd2 = bxor( entry[3], uidbytes[1], uidbytes[2], uidbytes[6]) - local pwd3 = bxor( entry[4], uidbytes[7]) - return string.format('%02X%02X%02X%02X', pwd0, pwd1, pwd2, pwd3) + local pwd1 = bxor( entry[2], uidbytes[1], uidbytes[3], uidbytes[5]) + local pwd2 = bxor( entry[3], uidbytes[1], uidbytes[2], uidbytes[6]) + local pwd3 = bxor( entry[4], uidbytes[7]) + return string.format('%02X%02X%02X%02X', pwd0, pwd1, pwd2, pwd3) end -- -- main local function main(args) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print() - - local uid = '04111211121110' - local useUID = false - - -- Arguments for the script - for o, a in getopt.getopt(args, 'hu:') do - if o == "h" then return help() end - if o == "u" then uid = a; useUID = true end - end + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() - if useUID then - -- uid string checks - if uid == nil then return oops('empty uid string') end - if #uid == 0 then return oops('empty uid string') end - if #uid ~= 14 then return oops('uid wrong length. Should be 7 hex bytes') end - else - -- GET TAG UID - local tag, err = lib14a.read(false, true) - if not tag then return oops(err) end - core.clearCommandBuffer() - uid = tag.uid - end - - print('UID | '..uid) - local pwd, err = pwdgen(uid) - if not pwd then return ooops(err) end - - print(string.format('PWD | %s', pwd)) + local uid = '04111211121110' + local useUID = false + + -- Arguments for the script + for o, a in getopt.getopt(args, 'hu:') do + if o == "h" then return help() end + if o == "u" then uid = a; useUID = true end + end + + if useUID then + -- uid string checks + if uid == nil then return oops('empty uid string') end + if #uid == 0 then return oops('empty uid string') end + if #uid ~= 14 then return oops('uid wrong length. Should be 7 hex bytes') end + else + -- GET TAG UID + local tag, err = lib14a.read(false, true) + if not tag then return oops(err) end + core.clearCommandBuffer() + uid = tag.uid + end + + print('UID | '..uid) + local pwd, err = pwdgen(uid) + if not pwd then return ooops(err) end + + print(string.format('PWD | %s', pwd)) end main(args) \ No newline at end of file diff --git a/client/scripts/calc_mizip.lua b/client/scripts/calc_mizip.lua index 4500c9c0f..42f13c578 100644 --- a/client/scripts/calc_mizip.lua +++ b/client/scripts/calc_mizip.lua @@ -6,192 +6,192 @@ local utils = require('utils') author = 'Iceman' version = 'v1.0.0' desc = [[ -This script calculates mifare keys based on uid diversification for mizip. +This script calculates mifare keys based on uid diversification for mizip. Algo not found by me. ]] example = [[ - -- if called without, it reads tag uid - script run calc_mizip - - -- - script run calc_mizip -u 11223344 + -- if called without, it reads tag uid + script run calc_mizip + + -- + script run calc_mizip -u 11223344 ]] usage = [[ script run calc_mizip -h -u Arguments: - -h : this help - -u : UID + -h : this help + -u : UID ]] local DEBUG = true local bxor = bit32.bxor local _xortable = { --[[ sector key A/B, 6byte xor --]] - {1, "09125a2589e5", "F12C8453D821"}, - {2, "AB75C937922F", "73E799FE3241"}, - {3, "E27241AF2C09", "AA4D137656AE"}, - {4, "317AB72F4490", "B01327272DFD"}, + {1, "09125a2589e5", "F12C8453D821"}, + {2, "AB75C937922F", "73E799FE3241"}, + {3, "E27241AF2C09", "AA4D137656AE"}, + {4, "317AB72F4490", "B01327272DFD"}, } ---- +--- -- 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 ---- + 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) - return nil,err + print("ERROR: ",err) + return nil,err end ---- +--- -- Usage help local function help() - print(copyright) - print(author) - print(version) - print(desc) - print("Example usage") - print(example) + print(copyright) + print(author) + print(version) + print(desc) + print("Example usage") + print(example) end -- -- Exit message local function exitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() end -- -- dumps all keys to file local function dumptofile(keys) - dbg('dumping keys to file') + dbg('dumping keys to file') - if utils.confirm('Do you wish to save the keys to dumpfile?') then - local destination = utils.input('Select a filename to store to', 'dumpkeys.bin') - local file = io.open(destination, 'wb') - if file == nil then - print('Could not write to file ', destination) - return - end + if utils.confirm('Do you wish to save the keys to dumpfile?') then + local destination = utils.input('Select a filename to store to', 'dumpkeys.bin') + local file = io.open(destination, 'wb') + if file == nil then + print('Could not write to file ', destination) + return + end - -- Mifare Mini has 5 sectors, - local key_a = '' - local key_b = '' - - for sector = 0, #keys do - local keyA, keyB = unpack(keys[sector]) - key_a = key_a .. bin.pack('H', keyA); - key_b = key_b .. bin.pack('H', keyB); - end - file:write(key_a) - file:write(key_b) - file:close() - end + -- Mifare Mini has 5 sectors, + local key_a = '' + local key_b = '' + + for sector = 0, #keys do + local keyA, keyB = unpack(keys[sector]) + key_a = key_a .. bin.pack('H', keyA); + key_b = key_b .. bin.pack('H', keyB); + end + file:write(key_a) + file:write(key_b) + file:close() + end end --- -- key bytes to string local function keyStr(p1, p2, p3, p4, p5, p6) - return string.format('%02X%02X%02X%02X%02X%02X',p1, p2, p3, p4, p5, p6) + return string.format('%02X%02X%02X%02X%02X%02X',p1, p2, p3, p4, p5, p6) end --- -- create key local function calckey(uid, xorkey, keytype) - local p1,p2,p3,p4,p5,p6 - if keytype == 'A' then - p1 = bxor( uid[1], xorkey[1]) - p2 = bxor( uid[2], xorkey[2]) - p3 = bxor( uid[3], xorkey[3]) - p4 = bxor( uid[4], xorkey[4]) - p5 = bxor( uid[1], xorkey[5]) - p6 = bxor( uid[2], xorkey[6]) - else - p1 = bxor( uid[3], xorkey[1]) - p2 = bxor( uid[4], xorkey[2]) - p3 = bxor( uid[1], xorkey[3]) - p4 = bxor( uid[2], xorkey[4]) - p5 = bxor( uid[3], xorkey[5]) - p6 = bxor( uid[4], xorkey[6]) - end - return keyStr(p1,p2,p3,p4,p5,p6) -end + local p1,p2,p3,p4,p5,p6 + if keytype == 'A' then + p1 = bxor( uid[1], xorkey[1]) + p2 = bxor( uid[2], xorkey[2]) + p3 = bxor( uid[3], xorkey[3]) + p4 = bxor( uid[4], xorkey[4]) + p5 = bxor( uid[1], xorkey[5]) + p6 = bxor( uid[2], xorkey[6]) + else + p1 = bxor( uid[3], xorkey[1]) + p2 = bxor( uid[4], xorkey[2]) + p3 = bxor( uid[1], xorkey[3]) + p4 = bxor( uid[2], xorkey[4]) + p5 = bxor( uid[3], xorkey[5]) + p6 = bxor( uid[4], xorkey[6]) + end + return keyStr(p1,p2,p3,p4,p5,p6) +end --- -- print keys local function printKeys(keys) - print('|---|----------------|---|----------------|---|') - print('|sec|key A |res|key B |res|') - print('|---|----------------|---|----------------|---|') - for sector = 0, #keys do - local keyA, keyB = unpack(keys[sector]) - print(('|%03d| %s | %s | %s | %s |'):format(sector, keyA, 1, keyB, 1)) - end - print('|---|----------------|---|----------------|---|') + print('|---|----------------|---|----------------|---|') + print('|sec|key A |res|key B |res|') + print('|---|----------------|---|----------------|---|') + for sector = 0, #keys do + local keyA, keyB = unpack(keys[sector]) + print(('|%03d| %s | %s | %s | %s |'):format(sector, keyA, 1, keyB, 1)) + end + print('|---|----------------|---|----------------|---|') end --- -- create a full set of keys local function createKeys(uid) - local uidbytes = utils.ConvertHexToBytes(uid) - - local k = {} - k[0] = { keyStr(0xA0,0xA1,0xA2,0xA3,0xA4,0xA5), keyStr(0xB4,0xC1,0x32,0x43,0x9e,0xef) } + local uidbytes = utils.ConvertHexToBytes(uid) + + local k = {} + k[0] = { keyStr(0xA0,0xA1,0xA2,0xA3,0xA4,0xA5), keyStr(0xB4,0xC1,0x32,0x43,0x9e,0xef) } for _, v in pairs(_xortable) do - local keyA = calckey(uidbytes, utils.ConvertHexToBytes(v[2]), 'A') - local keyB = calckey(uidbytes, utils.ConvertHexToBytes(v[3]), 'B') - k[v[1]] = { keyA, keyB } - end - return k + local keyA = calckey(uidbytes, utils.ConvertHexToBytes(v[2]), 'A') + local keyB = calckey(uidbytes, utils.ConvertHexToBytes(v[3]), 'B') + k[v[1]] = { keyA, keyB } + end + return k end --- -- main local function main(args) - print( string.rep('==', 30) ) - print() - - local uid = '11223344' - local useUID = false - - -- Arguments for the script - for o, a in getopt.getopt(args, 'hu:') do - if o == "h" then return help() end - if o == "u" then uid = a ; useUID = true end - end + print( string.rep('==', 30) ) + print() - if useUID then - -- uid string checks - if uid == nil then return oops('empty uid string') end - if #uid == 0 then return oops('empty uid string') end - if #uid ~= 8 then return oops('uid wrong length. Should be 4 hex bytes') end - else - -- GET TAG UID - local tag, err = lib14a.read(false, true) - if not tag then return oops(err) end - core.clearCommandBuffer() + local uid = '11223344' + local useUID = false - -- simple tag check - if 0x09 ~= tag.sak then - if 0x4400 ~= tag.atqa then - return oops(('[fail] found tag %s :: looking for Mifare Mini 0.3k'):format(tag.name)) - end - end - uid = tag.uid - end - - print('|UID|', uid) - - local keys, err = createKeys( uid ) - printKeys( keys ) - dumptofile( keys ) + -- Arguments for the script + for o, a in getopt.getopt(args, 'hu:') do + if o == "h" then return help() end + if o == "u" then uid = a ; useUID = true end + end + + if useUID then + -- uid string checks + if uid == nil then return oops('empty uid string') end + if #uid == 0 then return oops('empty uid string') end + if #uid ~= 8 then return oops('uid wrong length. Should be 4 hex bytes') end + else + -- GET TAG UID + local tag, err = lib14a.read(false, true) + if not tag then return oops(err) end + core.clearCommandBuffer() + + -- simple tag check + if 0x09 ~= tag.sak then + if 0x4400 ~= tag.atqa then + return oops(('[fail] found tag %s :: looking for Mifare Mini 0.3k'):format(tag.name)) + end + end + uid = tag.uid + end + + print('|UID|', uid) + + local keys, err = createKeys( uid ) + printKeys( keys ) + dumptofile( keys ) end main(args) \ No newline at end of file diff --git a/client/scripts/calypso.lua b/client/scripts/calypso.lua index ce90a25fd..2b7252261 100644 --- a/client/scripts/calypso.lua +++ b/client/scripts/calypso.lua @@ -11,15 +11,15 @@ desc = This is a script to communicate with a CALYSPO / 14443b tag using the '14b raw' commands Arguments: - -b 123 -Examples : - script run f -b 11223344 - script run f + -b 123 +Examples : + script run f -b 11223344 + script run f -Examples : +Examples : # 1. Connect and don't disconnect -script run f +script run f # 2. Send mf auth, read response script run f # 3. disconnect @@ -28,56 +28,56 @@ script run f ]] --[[ -This script communicates with /armsrc/iso14443b.c, -Check there for details about data format and how commands are interpreted on the -device-side. +This script communicates with /armsrc/iso14443b.c, +Check there for details about data format and how commands are interpreted on the +device-side. ]] --- -- local function calypso_switch_on_field() - local flags = lib14b.ISO14B_COMMAND.ISO14B_CONNECT - local c = Command:new{cmd = cmds.CMD_ISO_14443B_COMMAND, arg1 = flags} - return lib14b.sendToDevice(c, true) + local flags = lib14b.ISO14B_COMMAND.ISO14B_CONNECT + local c = Command:new{cmd = cmds.CMD_ISO_14443B_COMMAND, arg1 = flags} + return lib14b.sendToDevice(c, true) end --- -- Disconnect (poweroff) the antenna forcing a disconnect of a 14b tag. local function calypso_switch_off_field() - local flags = lib14b.ISO14B_COMMAND.ISO14B_DISCONNECT - local c = Command:new{cmd = cmds.CMD_ISO_14443B_COMMAND, arg1 = flags} - return lib14b.sendToDevice(c, true) + local flags = lib14b.ISO14B_COMMAND.ISO14B_DISCONNECT + local c = Command:new{cmd = cmds.CMD_ISO_14443B_COMMAND, arg1 = flags} + return lib14b.sendToDevice(c, true) end local function calypso_parse(result) - local r = Command.parse(result) - local len = r.arg2 * 2 - r.data = string.sub(r.data, 0, len); - print('GOT:', r.data) - if r.arg1 == 0 then - return r, nil - end - return nil,nil + local r = Command.parse(result) + local len = r.arg2 * 2 + r.data = string.sub(r.data, 0, len); + print('GOT:', r.data) + if r.arg1 == 0 then + return r, nil + end + return nil,nil end ---- +--- -- A debug printout-function local function dbg(args) - if DEBUG then - print("###", args) - end -end ---- + if DEBUG then + print("###", args) + end +end +--- -- This is only meant to be used when errors occur local function oops(err) - print("ERROR: ", err) - calypso_switch_off_field() - return nil, err + print("ERROR: ", err) + calypso_switch_off_field() + return nil, err end ---- +--- -- Usage help local function help() - print(desc) - print("Example usage") - print(example) + print(desc) + print("Example usage") + print(example) end -- -- helper function, give current count of items in lua-table. @@ -87,7 +87,7 @@ local function tablelen(T) return count end --- --- helper function, gives a sorted table from table t, +-- helper function, gives a sorted table from table t, -- order can be a seperate sorting-order function. local function spairs(t, order) -- collect the keys @@ -95,7 +95,7 @@ local function spairs(t, order) for k in pairs(t) do keys[#keys+1] = k end -- if order function given, sort by it by passing the table and keys a, b, - -- otherwise just sort the keys + -- otherwise just sort the keys if order then table.sort(keys, function(a,b) return order(t, a, b) end) else @@ -112,54 +112,54 @@ local function spairs(t, order) end end --- --- Sends a usbpackage , "hf 14b raw" +-- Sends a usbpackage , "hf 14b raw" -- if it reads the response, it converts it to a lua object "Command" first and the Data is cut to correct length. local function calypso_send_cmd_raw(data, ignoreresponse ) - local command, flags, result, err - flags = lib14b.ISO14B_COMMAND.ISO14B_RAW + - lib14b.ISO14B_COMMAND.ISO14B_APPEND_CRC + local command, flags, result, err + flags = lib14b.ISO14B_COMMAND.ISO14B_RAW + + lib14b.ISO14B_COMMAND.ISO14B_APPEND_CRC - data = data or "00" + data = data or "00" - command = Command:new{cmd = cmds.CMD_ISO_14443B_COMMAND, - arg1 = flags, - arg2 = #data/2, -- LEN of data, half the length of the ASCII-string hex string - arg3 = 0, - data = data} -- data bytes (commands etc) - result, err = lib14b.sendToDevice(command, false) - - if ignoreresponse then return response, err end - - if result then - local r = calypso_parse(result) - return r, nil - end - return respone, err + command = Command:new{cmd = cmds.CMD_ISO_14443B_COMMAND, + arg1 = flags, + arg2 = #data/2, -- LEN of data, half the length of the ASCII-string hex string + arg3 = 0, + data = data} -- data bytes (commands etc) + result, err = lib14b.sendToDevice(command, false) + + if ignoreresponse then return response, err end + + if result then + local r = calypso_parse(result) + return r, nil + end + return respone, err end --- -- calypso_card_num : Reads card number from ATR and -- writes it in the tree in decimal format. local function calypso_card_num(card) - if not card then return end - local card_num = tonumber( card.uid:sub(1,8),16 ) - print('Card UID', card.uid) - print('Card Number', card_num) + if not card then return end + local card_num = tonumber( card.uid:sub(1,8),16 ) + print('Card UID', card.uid) + print('Card Number', card_num) end --- -- analyse CALYPSO apdu status bytes. local function calypso_apdu_status(apdu) - -- last two is CRC - -- next two is APDU status bytes. - local status = false - local mess = 'FAIL' - local sw = apdu:sub( #apdu-7, #apdu-4) - desc, err = iso7816.tostring(sw) - print ('SW', sw, desc, err ) + -- last two is CRC + -- next two is APDU status bytes. + local status = false + local mess = 'FAIL' + local sw = apdu:sub( #apdu-7, #apdu-4) + desc, err = iso7816.tostring(sw) + print ('SW', sw, desc, err ) - status = ( sw == '9000' ) - - return status + status = ( sw == '9000' ) + + return status end local _calypso_cmds = { @@ -167,16 +167,16 @@ local _calypso_cmds = { -- Break down of command bytes: -- A4 = select -- Master File 3F00 --- 0x3F = master file +-- 0x3F = master file -- 0x00 = master file id, is constant to 0x00. -- DF Dedicated File 38nn -- can be seen as directories --- 0x38 +-- 0x38 -- 0xNN id --- ["01.Select ICC file"] = '0294 a4 080004 3f00 0002', +-- ["01.Select ICC file"] = '0294 a4 080004 3f00 0002', --- EF Elementary File +-- EF Elementary File -- EF1 Pin file -- EF2 Key file -- Grey Lock file @@ -184,93 +184,93 @@ local _calypso_cmds = { -- Electronic Purse file -- Electronic Transaction log file - - --["01.Select ICC file"] = '0294 a4 00 0002 3f00', - ["01.Select ICC file"] = '0294 a4 080004 3f00 0002', - ["02.ICC"] = '0394 b2 01 041d', - ["03.Select EnvHol file"] = '0294 a4 080004 2000 2001', - ["04.EnvHol1"] = '0394 b2 01 041d', - ["05.Select EvLog file"] = '0294 a4 080004 2000 2010', - ["06.EvLog1"] = '0394 b2 01 041d', - ["07.EvLog2"] = '0294 b2 02 041d', - ["08.EvLog3"] = '0394 b2 03 041d', - ["09.Select ConList file"] ='0294 a4 080004 2000 2050', - ["10.ConList"] = '0394 b2 01 041d', - ["11.Select Contra file"] = '0294 a4 080004 2000 2020', - ["12.Contra1"] = '0394 b2 01 041d', - ["13.Contra2"] = '0294 b2 02 041d', - ["14.Contra3"] = '0394 b2 03 041d', - ["15.Contra4"] = '0294 b2 04 041d', - ["16.Select Counter file"]= '0394 a4 080004 2000 2069', - ["17.Counter"] = '0294 b2 01 041d', - ["18.Select SpecEv file"]= '0394 a4 080004 2000 2040', - ["19.SpecEv1"] = '0294 b2 01 041d', + + --["01.Select ICC file"] = '0294 a4 00 0002 3f00', + ["01.Select ICC file"] = '0294 a4 080004 3f00 0002', + ["02.ICC"] = '0394 b2 01 041d', + ["03.Select EnvHol file"] = '0294 a4 080004 2000 2001', + ["04.EnvHol1"] = '0394 b2 01 041d', + ["05.Select EvLog file"] = '0294 a4 080004 2000 2010', + ["06.EvLog1"] = '0394 b2 01 041d', + ["07.EvLog2"] = '0294 b2 02 041d', + ["08.EvLog3"] = '0394 b2 03 041d', + ["09.Select ConList file"]= '0294 a4 080004 2000 2050', + ["10.ConList"] = '0394 b2 01 041d', + ["11.Select Contra file"] = '0294 a4 080004 2000 2020', + ["12.Contra1"] = '0394 b2 01 041d', + ["13.Contra2"] = '0294 b2 02 041d', + ["14.Contra3"] = '0394 b2 03 041d', + ["15.Contra4"] = '0294 b2 04 041d', + ["16.Select Counter file"]= '0394 a4 080004 2000 2069', + ["17.Counter"] = '0294 b2 01 041d', + ["18.Select SpecEv file"] = '0394 a4 080004 2000 2040', + ["19.SpecEv1"] = '0294 b2 01 041d', } ---- +--- -- The main entry point function main(args) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print() - - local data, apdu, flags, uid, cid, result, err, card - -- Read the parameters - for o, a in getopt.getopt(args, 'h') do - if o == "h" then return help() end - end - - calypso_switch_on_field() - - -- Select 14b tag. - card, err = lib14b.waitFor14443b() - if not card then return oops(err) end - - calypso_card_num(card) - cid = card.cid + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() - --[[ - NAME VALUE APDU_POS - PCB 0x0A 0 - CID 0x00 1 - CLA 0x94 2 - SELECT FILE 0xA4 3 - READ FILE 0xB2 3 - P1 4 - P2 5 - LEN_ - 0 1 2 3 4 5 6 7 - apdu = '02 94 a4 08 00 04 3f 00 00 02' --select ICC file - DF_NAME = "1TIC.ICA" - --]] - --for i = 1,10 do - --result, err = calypso_send_cmd_raw('0294a40800043f000002',false) --select ICC file - for i, apdu in spairs(_calypso_cmds) do - print('>>', i ) - apdu = apdu:gsub("%s+","") - result, err = calypso_send_cmd_raw(apdu , false) - if result then - calypso_apdu_status(result.data) - print('<<', result.data ) - else - print('<< no answer') - end - end - calypso_switch_off_field() + local data, apdu, flags, uid, cid, result, err, card + -- Read the parameters + for o, a in getopt.getopt(args, 'h') do + if o == "h" then return help() end + end + + calypso_switch_on_field() + + -- Select 14b tag. + card, err = lib14b.waitFor14443b() + if not card then return oops(err) end + + calypso_card_num(card) + cid = card.cid + + --[[ + NAME VALUE APDU_POS + PCB 0x0A 0 + CID 0x00 1 + CLA 0x94 2 + SELECT FILE 0xA4 3 + READ FILE 0xB2 3 + P1 4 + P2 5 + LEN_ + 0 1 2 3 4 5 6 7 + apdu = '02 94 a4 08 00 04 3f 00 00 02' --select ICC file + DF_NAME = "1TIC.ICA" + --]] + --for i = 1,10 do + --result, err = calypso_send_cmd_raw('0294a40800043f000002',false) --select ICC file + for i, apdu in spairs(_calypso_cmds) do + print('>>', i ) + apdu = apdu:gsub("%s+","") + result, err = calypso_send_cmd_raw(apdu , false) + if result then + calypso_apdu_status(result.data) + print('<<', result.data ) + else + print('<< no answer') + end + end + calypso_switch_off_field() end --- --- a simple selftest function, tries to convert +-- a simple selftest function, tries to convert function selftest() - DEBUG = true - dbg("Performing test") - dbg("Tests done") + DEBUG = true + dbg("Performing test") + dbg("Tests done") end --- Flip the switch here to perform a sanity check. +-- Flip the switch here to perform a sanity check. -- It read a nonce in two different ways, as specified in the usage-section -if "--test"==args then - selftest() -else - -- Call the main - main(args) +if "--test"==args then + selftest() +else + -- Call the main + main(args) end \ No newline at end of file diff --git a/client/scripts/cmdline.lua b/client/scripts/cmdline.lua index 9c4df1446..29627afc7 100644 --- a/client/scripts/cmdline.lua +++ b/client/scripts/cmdline.lua @@ -1,12 +1,12 @@ print("This is how a cmd-line interface could be implemented\nPrint 'exit' to exit.\n") local answer repeat - io.write("$>") - io.flush() - answer=io.read() - if answer ~= 'exit' then - local func = assert(loadstring("return " .. answer)) - io.write("\n"..tostring(func() or "").."\n"); - end--]] -until answer=="exit" + io.write("$>") + io.flush() + answer=io.read() + if answer ~= 'exit' then + local func = assert(loadstring("return " .. answer)) + io.write("\n"..tostring(func() or "").."\n"); + end--]] +until answer=="exit" print("Bye\n"); diff --git a/client/scripts/didump.lua b/client/scripts/didump.lua index b63d2ed07..b6bc03a11 100644 --- a/client/scripts/didump.lua +++ b/client/scripts/didump.lua @@ -1,4 +1,4 @@ ---- +--- -- requirements local cmds = require('commands') local getopt = require('getopt') @@ -8,9 +8,9 @@ local json = require('dkjson') local toys = require('default_toys_di') example =[[ - script run didump - script run didump -t - script run didump -r + script run didump + script run didump -t + script run didump -r ]] author = "Iceman" usage = "script run didump -h -t" @@ -18,9 +18,9 @@ desc = [[ This is a script to dump and decrypt the data of a specific type of Mifare Mini token. The dump is decrypted. If a raw dump is wanted, use the -r parameter Arguments: - -h : this help - -r : raw - -t : selftest + -h : this help + -r : raw + -t : selftest ]] local band=bit32.band @@ -40,50 +40,50 @@ local numBlocks = 20 local numSectors = 5 local CHECKSUM_OFFSET = 12; -- +1??? ---- +--- -- 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 - print("###", args[i]) - i = i+1 - end - else - print("###", args) - end -end ---- + if type(args) == "table" then + local i = 1 + while args[i] do + print("###", 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 false + print("ERROR: ",err) + core.clearCommandBuffer() + return false end ---- +--- -- Usage help local function help() - print(desc) - print("Example usage") - print(example) + print(desc) + print("Example usage") + print(example) end --- -- local function print_info(tagdata) - --got table with data. - local h = tagdata[2]:sub(1,8) - local t = tostring( tonumber( h, 16 ) ) - local item = toys.Find(t) - print( ("Modelid : %s , %s, v.%s.0"):format(t, item[3], item[2])) + --got table with data. + local h = tagdata[2]:sub(1,8) + local t = tostring( tonumber( h, 16 ) ) + local item = toys.Find(t) + print( ("Modelid : %s , %s, v.%s.0"):format(t, item[3], item[2])) end --- -- Get checksum, -- called: data is string (32 hex digits) -- returns: number local function getChecksum(data) - local chksum = data:sub(25,32) - return tonumber(chksum,16) + local chksum = data:sub(25,32) + return tonumber(chksum,16) end --- -- calculate checksum @@ -91,8 +91,8 @@ end -- returns: number local function calculateChecksum(data) - -- Generate table - local _tbl = {} + -- Generate table + local _tbl = {} _tbl[0] = { 0x0 } _tbl[1] = { 0x77073096 } _tbl[2] = { 0xEE0E612C } @@ -351,248 +351,248 @@ _tbl[254] = { 0x5A05DF1B } _tbl[255] = { 0x2D02EF8D } - -- Calculate it - local ret = 0 - for i,item in pairs(data) do - local tmp = band(ret, 0xFF) - local index = band( bxor(tmp, item), 0xFF) - ret = bxor(rsh(ret,8), _tbl[index][1]) - end - return ret + -- Calculate it + local ret = 0 + for i,item in pairs(data) do + local tmp = band(ret, 0xFF) + local index = band( bxor(tmp, item), 0xFF) + ret = bxor(rsh(ret,8), _tbl[index][1]) + end + return ret end --- -- update checksum -- called: data is string, ( >= 24 hex digits ) -- returns: string, (data concat new checksum) local function updateChecksum(data) - local part = data:sub(1,24) - local chksum = calculateChecksum( utils.ConvertHexToBytes(part)) - return string.format("%s%X", part, chksum) + local part = data:sub(1,24) + local chksum = calculateChecksum( utils.ConvertHexToBytes(part)) + return string.format("%s%X", part, chksum) end --- -- receives the answer from deviceside, used with a readblock command local function waitCmd() - local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) - if response then - local count,cmd,arg0 = bin.unpack('LL',response) - if(arg0==1) then - local count,arg1,arg2,data = bin.unpack('LLH511',response,count) - return data:sub(1,32) - else - return nil, "Couldn't read block.." - end - end - return nil, "No response from device" + local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) + if response then + local count,cmd,arg0 = bin.unpack('LL',response) + if(arg0==1) then + local count,arg1,arg2,data = bin.unpack('LLH511',response,count) + return data:sub(1,32) + else + return nil, "Couldn't read block.." + end + end + return nil, "No response from device" end local function keygen(uid) - local data = MIS..uid..BAR - local hash = utils.ConvertAsciiToBytes(utils.Sha1Hex(data)) - return string.format("%02X%02X%02X%02X%02X%02X", - hash[3+1], - hash[2+1], - hash[1+1], - hash[0+1], - hash[7+1], - hash[6+1] - ) + local data = MIS..uid..BAR + local hash = utils.ConvertAsciiToBytes(utils.Sha1Hex(data)) + return string.format("%02X%02X%02X%02X%02X%02X", + hash[3+1], + hash[2+1], + hash[1+1], + hash[0+1], + hash[7+1], + hash[6+1] + ) end --- encode 'table' into a json formatted string --- +-- local function convert_to_json( obj ) - if type(obj) == "table" then - return json.encode (obj, { indent = true }) - end - return oops('[fail] input object must be a lua-TABLE') + if type(obj) == "table" then + return json.encode (obj, { indent = true }) + end + return oops('[fail] input object must be a lua-TABLE') end -- --- Save +-- Save local function save_json(filename, data) - jsondata = convert_to_json(data) - filename = filename or 'dumpdata.json' - local f = io.open(filename, "w") - if not f then return oops(string.format("Could not write to file %s", tostring(filename))) end - f:write(jsondata) - io.close(f) - return filename + jsondata = convert_to_json(data) + filename = filename or 'dumpdata.json' + local f = io.open(filename, "w") + if not f then return oops(string.format("Could not write to file %s", tostring(filename))) end + f:write(jsondata) + io.close(f) + return filename end ---- loads a json formatted text file with +--- loads a json formatted text file with -- -- @param filename the file containing the json-dump (defaults to dumpdata.json) local function load_json(filename) - filename = filename or 'dumpdata.json' - local f = io.open(filename, "rb") - if not f then return oops(string.format("Could not read file %s", tostring(filename))) end - - -- Read file - local t = f:read("*all") - io.close(f) + filename = filename or 'dumpdata.json' + local f = io.open(filename, "rb") + if not f then return oops(string.format("Could not read file %s", tostring(filename))) end - local obj, pos, err = json.decode(t, 1, nil) - if err then return oops(string.format("importing json file failed. %s", err)) end + -- Read file + local t = f:read("*all") + io.close(f) - dbg(string.format('loaded file %s', input)) - return obj + local obj, pos, err = json.decode(t, 1, nil) + if err then return oops(string.format("importing json file failed. %s", err)) end --- local len, hex = bin.unpack( ("H%d"):format(#t), t) + dbg(string.format('loaded file %s', input)) + return obj + +-- local len, hex = bin.unpack( ("H%d"):format(#t), t) end --- -- Generate encryption key local function create_key(uid) - local key = '' - local sha = utils.Sha1Hex( FOO..BAR..uid ) - sha = utils.ConvertBytesToHex( utils.ConvertAsciiToBytes(sha:sub(1,16)) ) - key = utils.SwapEndiannessStr( sha:sub(1,8) , 32 ) - key = key..utils.SwapEndiannessStr( sha:sub(9,16), 32 ) - key = key..utils.SwapEndiannessStr( sha:sub(17,24), 32 ) - key = key..utils.SwapEndiannessStr( sha:sub(25,32), 32 ) - return key + local key = '' + local sha = utils.Sha1Hex( FOO..BAR..uid ) + sha = utils.ConvertBytesToHex( utils.ConvertAsciiToBytes(sha:sub(1,16)) ) + key = utils.SwapEndiannessStr( sha:sub(1,8) , 32 ) + key = key..utils.SwapEndiannessStr( sha:sub(9,16), 32 ) + key = key..utils.SwapEndiannessStr( sha:sub(17,24), 32 ) + key = key..utils.SwapEndiannessStr( sha:sub(25,32), 32 ) + return key end --- reads all blocks from tag -- local function readtag(mfkey, aeskey ) - - local tagdata = {} - - for blockNo = 0, numBlocks-1 do - if core.ukbhit() then - print("[fail] aborted by user") - return nil - end + local tagdata = {} - -- read block from tag. - cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = blockNo ,arg2 = 0,arg3 = 0, data = mfkey} - local err = core.SendCommand(cmd:getBytes()) - if err then return oops(err) end - local blockdata, err = waitCmd() - if err then return oops(err) end + for blockNo = 0, numBlocks-1 do - -- rules: - -- the following blocks is NOT encrypted - -- block 0 (manufacturing) and 18 - -- block with all zeros - -- sector trailor - if blockNo == 0 or blockNo == 18 then - - elseif blockNo%4 ~= 3 then - - if not string.find(blockdata, '^0+$') then - if aeskey then - local decrypted, err = core.aes128_decrypt_ecb(aeskey, blockdata) - if err then dbg(err) end - blockdata = utils.ConvertAsciiToHex(decrypted) - end - end - else - -- Sectorblocks, not encrypted, but we add our known key to it since it is normally zeros. - blockdata = mfkey..blockdata:sub(13,20)..mfkey - --dbg(blockdata:sub(13,20)) - end - table.insert(tagdata, blockdata) - end - return tagdata + if core.ukbhit() then + print("[fail] aborted by user") + return nil + end + + -- read block from tag. + cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = blockNo ,arg2 = 0,arg3 = 0, data = mfkey} + local err = core.SendCommand(cmd:getBytes()) + if err then return oops(err) end + local blockdata, err = waitCmd() + if err then return oops(err) end + + -- rules: + -- the following blocks is NOT encrypted + -- block 0 (manufacturing) and 18 + -- block with all zeros + -- sector trailor + if blockNo == 0 or blockNo == 18 then + + elseif blockNo%4 ~= 3 then + + if not string.find(blockdata, '^0+$') then + if aeskey then + local decrypted, err = core.aes128_decrypt_ecb(aeskey, blockdata) + if err then dbg(err) end + blockdata = utils.ConvertAsciiToHex(decrypted) + end + end + else + -- Sectorblocks, not encrypted, but we add our known key to it since it is normally zeros. + blockdata = mfkey..blockdata:sub(13,20)..mfkey + --dbg(blockdata:sub(13,20)) + end + table.insert(tagdata, blockdata) + end + return tagdata end --- -- simple selftest of functionality local function selftest() - local testdata = '000F42430D0A14000001D11F'..'5D738517' - local chksum = getChecksum(testdata) - local calc = calculateChecksum( utils.ConvertHexToBytes(testdata:sub(1,24))) - print ( testdata:sub(1,24) ) - print ( ('%x - %x'):format(chksum, calc)) - - local isValid = false - local validStr = "FAIL" - if calc == chksum then - isValid = true - validStr = "OK" - end - local newtestdata = updateChecksum(testdata) - local revalidated = "FAIL" - if newtestdata == testdata then - revalidated = "OK" - end - print ('TESTDATA :: '..testdata) - print ('DATA :: '..testdata:sub(1,24)) - print (('VALID CHKSUM :: %s'):format(validStr )) - print (('UPDATE CHKSUM :: %s'):format(revalidated)) - - local testkey = keygen('0456263a873a80') - print ('TEST KEY :: '..testkey) - print ('VALID KEY :: 29564af75805') + local testdata = '000F42430D0A14000001D11F'..'5D738517' + local chksum = getChecksum(testdata) + local calc = calculateChecksum( utils.ConvertHexToBytes(testdata:sub(1,24))) + print ( testdata:sub(1,24) ) + print ( ('%x - %x'):format(chksum, calc)) + + local isValid = false + local validStr = "FAIL" + if calc == chksum then + isValid = true + validStr = "OK" + end + local newtestdata = updateChecksum(testdata) + local revalidated = "FAIL" + if newtestdata == testdata then + revalidated = "OK" + end + print ('TESTDATA :: '..testdata) + print ('DATA :: '..testdata:sub(1,24)) + print (('VALID CHKSUM :: %s'):format(validStr )) + print (('UPDATE CHKSUM :: %s'):format(revalidated)) + + local testkey = keygen('0456263a873a80') + print ('TEST KEY :: '..testkey) + print ('VALID KEY :: 29564af75805') end local function setdevicedebug( status ) - local c = 'hf mf dbg ' - if status then - c = c..'1' - else - c = c..'0' - end - core.console(c) + local c = 'hf mf dbg ' + if status then + c = c..'1' + else + c = c..'0' + end + core.console(c) end ---- +--- -- The main entry point -- -d decrypt -- -e encrypt -- -v validate function main(args) - local cmd, tag, err, blockNo, mfkey - local shall_validate = false - local shall_dec = false - local shall_enc = false - local blocks = {} - local aeskey = '' - local input = '' - - -- Read the parameters - for o, a in getopt.getopt(args, 'htdevi:') do - if o == "h" then help() return end - if o == "t" then return selftest() end - if o == "d" then shall_dec = true end - if o == "e" then shall_enc = true end - if o == "v" then shall_validate = true end - if o == "i" then input = load_json(a) end - end + local cmd, tag, err, blockNo, mfkey + local shall_validate = false + local shall_dec = false + local shall_enc = false + local blocks = {} + local aeskey = '' + local input = '' - -- Turn off Debug - setdevicedebug(false) + -- Read the parameters + for o, a in getopt.getopt(args, 'htdevi:') do + if o == "h" then help() return end + if o == "t" then return selftest() end + if o == "d" then shall_dec = true end + if o == "e" then shall_enc = true end + if o == "v" then shall_validate = true end + if o == "i" then input = load_json(a) end + end - -- GET TAG UID - tag, err = lib14a.read(false, true) - if not tag then return oops(err) end - core.clearCommandBuffer() - - -- simple tag check - if 0x09 ~= tag.sak then - if 0x4400 ~= tag.atqa then - return oops(('[fail] found tag %s :: looking for Mifare Mini 0.3k'):format(tag.name)) - end - end - dbg ('[ok] found '..tag.name) - - -- tag key - mfkey = keygen(tag.uid) - dbg('[ok] using mf keyA : '.. mfkey) - - -- AES key - aeskey = create_key(tag.uid) - dbg('[ok] using AES key : '.. aeskey) + -- Turn off Debug + setdevicedebug(false) - -- read tag data, complete, enc/dec - tagdata = readtag(mfkey, aeskey) - dbg('[ok] read card data') + -- GET TAG UID + tag, err = lib14a.read(false, true) + if not tag then return oops(err) end + core.clearCommandBuffer() - -- show information? - print_info(tagdata) + -- simple tag check + if 0x09 ~= tag.sak then + if 0x4400 ~= tag.atqa then + return oops(('[fail] found tag %s :: looking for Mifare Mini 0.3k'):format(tag.name)) + end + end + dbg ('[ok] found '..tag.name) - -- save - res = save_json(nil, tagdata) - if not res then return oops('[fail] saving json file') end - - dbg('[ok] read card data') + -- tag key + mfkey = keygen(tag.uid) + dbg('[ok] using mf keyA : '.. mfkey) + + -- AES key + aeskey = create_key(tag.uid) + dbg('[ok] using AES key : '.. aeskey) + + -- read tag data, complete, enc/dec + tagdata = readtag(mfkey, aeskey) + dbg('[ok] read card data') + + -- show information? + print_info(tagdata) + + -- save + res = save_json(nil, tagdata) + if not res then return oops('[fail] saving json file') end + + dbg('[ok] read card data') end main(args) diff --git a/client/scripts/dumptoemul-mfu.lua b/client/scripts/dumptoemul-mfu.lua index bb04008e9..34fbdc1d0 100644 --- a/client/scripts/dumptoemul-mfu.lua +++ b/client/scripts/dumptoemul-mfu.lua @@ -13,120 +13,120 @@ This script takes a dumpfile from 'hf mfu dump' and converts it to a format that by the emulator Arguments: - -h This help - -i Specifies the dump-file (input). If omitted, 'dumpdata.bin' is used - -o Specifies the output file. If omitted, .eml is used. + -h This help + -i Specifies the dump-file (input). If omitted, 'dumpdata.bin' is used + -o Specifies the output file. If omitted, .eml is used. ]] local DEBUG = false ---- +--- -- A debug printout-function local function dbg(args) - if not DEBUG then return end - - if type(args) == 'table' then - local i = 1 - while result[i] do - dbg(result[i]) - i = i+1 - end - else - print('###', args) - end -end ---- + if not DEBUG then return end + + if type(args) == 'table' then + local i = 1 + while result[i] do + dbg(result[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) - return nil,err + print('ERROR: ',err) + return nil,err end ---- +--- -- Usage help function help() - print(desc) - print(author) - print("Example usage") - print(example) + print(desc) + print(author) + print("Example usage") + print(example) end local function convert_to_ascii(hexdata) - if string.len(hexdata) % 8 ~= 0 then - return oops(("Bad data, length should be a multiple of 8 (was %d)"):format(string.len(hexdata))) - end + if string.len(hexdata) % 8 ~= 0 then + return oops(("Bad data, length should be a multiple of 8 (was %d)"):format(string.len(hexdata))) + end - local js,i = "["; - for i = 1, string.len(hexdata),8 do - js = js .."'" ..string.sub(hexdata,i,i+7).."',\n" - end - js = js .. "]" - return js + local js,i = "["; + for i = 1, string.len(hexdata),8 do + js = js .."'" ..string.sub(hexdata,i,i+7).."',\n" + end + js = js .. "]" + return js end local function readdump(infile) - t = infile:read("*all") - len = string.len(t) - local len,hex = bin.unpack(("H%d"):format(len),t) - return hex + t = infile:read("*all") + len = string.len(t) + local len,hex = bin.unpack(("H%d"):format(len),t) + return hex end local function convert_to_emulform(hexdata) - if string.len(hexdata) % 8 ~= 0 then - return oops(("Bad data, length should be a multiple of 8 (was %d)"):format(string.len(hexdata))) - end - local ascii,i = ""; - for i = 1, string.len(hexdata), 8 do - ascii = ascii..string.sub(hexdata, i, i+7).."\n" - end - return string.sub(ascii, 1, -2) + if string.len(hexdata) % 8 ~= 0 then + return oops(("Bad data, length should be a multiple of 8 (was %d)"):format(string.len(hexdata))) + end + local ascii,i = ""; + for i = 1, string.len(hexdata), 8 do + ascii = ascii..string.sub(hexdata, i, i+7).."\n" + end + return string.sub(ascii, 1, -2) end local function main(args) - local input = "dumpdata.bin" - local output + local input = "dumpdata.bin" + local output - for o, a in getopt.getopt(args, 'i:o:h') do - if o == "h" then return help() end - if o == "i" then input = a end - if o == "o" then output = a end - end - -- Validate the parameters - - local infile = io.open(input, "rb") - if infile == nil then - return oops("Could not read file ", input) - end - local dumpdata = readdump(infile) - -- The hex-data is now in ascii-format, + for o, a in getopt.getopt(args, 'i:o:h') do + if o == "h" then return help() end + if o == "i" then input = a end + if o == "o" then output = a end + end + -- Validate the parameters - -- But first, check the uid - -- lua uses start index and endindex, not count. - -- UID is 3three skip bcc0 then 4bytes. - -- 1 lua is one-index. - -- 1 + 96 (48*2) new dump format has version/signature/counter data here - -- 97,98,99,100,101,102 UID first three bytes - -- 103,104 bcc0 - -- 105--- UID last four bytes - local uid = string.sub(dumpdata, 97, 97+5)..string.sub(dumpdata, 97+8, 97+8+7) - output = output or (uid .. ".eml") + local infile = io.open(input, "rb") + if infile == nil then + return oops("Could not read file ", input) + end + local dumpdata = readdump(infile) + -- The hex-data is now in ascii-format, - -- Format some linebreaks - dumpdata = convert_to_emulform(dumpdata) + -- But first, check the uid + -- lua uses start index and endindex, not count. + -- UID is 3three skip bcc0 then 4bytes. + -- 1 lua is one-index. + -- 1 + 96 (48*2) new dump format has version/signature/counter data here + -- 97,98,99,100,101,102 UID first three bytes + -- 103,104 bcc0 + -- 105--- UID last four bytes + local uid = string.sub(dumpdata, 97, 97+5)..string.sub(dumpdata, 97+8, 97+8+7) + output = output or (uid .. ".eml") - local outfile = io.open(output, "w") - if outfile == nil then - return oops("Could not write to file ", output) - end - - outfile:write(dumpdata:lower()) - io.close(outfile) - print(("Wrote an emulator-dump to the file %s"):format(output)) + -- Format some linebreaks + dumpdata = convert_to_emulform(dumpdata) + + local outfile = io.open(output, "w") + if outfile == nil then + return oops("Could not write to file ", output) + end + + outfile:write(dumpdata:lower()) + io.close(outfile) + print(("Wrote an emulator-dump to the file %s"):format(output)) end --[[ -In the future, we may implement so that scripts are invoked directly +In the future, we may implement so that scripts are invoked directly into a 'main' function, instead of being executed blindly. For future -compatibility, I have done so, but I invoke my main from here. +compatibility, I have done so, but I invoke my main from here. --]] main(args) diff --git a/client/scripts/dumptoemul.lua b/client/scripts/dumptoemul.lua index 1e4d6323a..08e5e03dd 100644 --- a/client/scripts/dumptoemul.lua +++ b/client/scripts/dumptoemul.lua @@ -11,117 +11,117 @@ This script takes a dumpfile from 'hf mf dump' and converts it to a format that by the emulator Arguments: - -h This help - -i Specifies the dump-file (input). If omitted, 'dumpdata.bin' is used - -o Specifies the output file. If omitted, .eml is used. + -h This help + -i Specifies the dump-file (input). If omitted, 'dumpdata.bin' is used + -o Specifies the output file. If omitted, .eml is used. ]] local DEBUG = false ------------------------------- --- Some utilities +-- Some utilities ------------------------------- ---- +--- -- A debug printout-function local function dbg(args) - if not DEBUG then return end - - if type(args) == 'table' then - local i = 1 - while result[i] do - dbg(result[i]) - i = i+1 - end - else - print('###', args) - end -end ---- + if not DEBUG then return end + + if type(args) == 'table' then + local i = 1 + while result[i] do + dbg(result[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) - return nil,err + print('ERROR: ',err) + return nil,err end ---- +--- -- Usage help function help() - print(desc) - print(author) - print("Example usage") - print(example) + print(desc) + print(author) + print("Example usage") + print(example) end local function convert_to_ascii(hexdata) - if string.len(hexdata) % 32 ~= 0 then - return oops(("Bad data, length should be a multiple of 32 (was %d)"):format(string.len(hexdata))) - end + if string.len(hexdata) % 32 ~= 0 then + return oops(("Bad data, length should be a multiple of 32 (was %d)"):format(string.len(hexdata))) + end - local js,i = "["; - for i = 1, string.len(hexdata),32 do - js = js .."'" ..string.sub(hexdata,i,i+31).."',\n" - end - js = js .. "]" - return js + local js,i = "["; + for i = 1, string.len(hexdata),32 do + js = js .."'" ..string.sub(hexdata,i,i+31).."',\n" + end + js = js .. "]" + return js end local function readdump(infile) - t = infile:read("*all") - len = string.len(t) - local len,hex = bin.unpack(("H%d"):format(len),t) - return hex + t = infile:read("*all") + len = string.len(t) + local len,hex = bin.unpack(("H%d"):format(len),t) + return hex end local function convert_to_emulform(hexdata) - if string.len(hexdata) % 32 ~= 0 then - return oops(("Bad data, length should be a multiple of 32 (was %d)"):format(string.len(hexdata))) - end - local ascii,i = ""; - for i = 1, string.len(hexdata),32 do - ascii = ascii..string.sub(hexdata,i,i+31).."\n" - end - return string.sub(ascii, 1, -2) + if string.len(hexdata) % 32 ~= 0 then + return oops(("Bad data, length should be a multiple of 32 (was %d)"):format(string.len(hexdata))) + end + local ascii,i = ""; + for i = 1, string.len(hexdata),32 do + ascii = ascii..string.sub(hexdata,i,i+31).."\n" + end + return string.sub(ascii, 1, -2) end local function main(args) - local input = "dumpdata.bin" - local output + local input = "dumpdata.bin" + local output - for o, a in getopt.getopt(args, 'i:o:h') do - if o == "h" then return help() end - if o == "i" then input = a end - if o == "o" then output = a end - end - -- Validate the parameters - - local infile = io.open(input, "rb") - if infile == nil then - return oops("Could not read file ", input) - end - local dumpdata = readdump(infile) - -- The hex-data is now in ascii-format, + for o, a in getopt.getopt(args, 'i:o:h') do + if o == "h" then return help() end + if o == "i" then input = a end + if o == "o" then output = a end + end + -- Validate the parameters - -- But first, check the uid - local uid = string.sub(dumpdata,1,8) - output = output or (uid .. ".eml") + local infile = io.open(input, "rb") + if infile == nil then + return oops("Could not read file ", input) + end + local dumpdata = readdump(infile) + -- The hex-data is now in ascii-format, - -- Format some linebreaks - dumpdata = convert_to_emulform(dumpdata) + -- But first, check the uid + local uid = string.sub(dumpdata,1,8) + output = output or (uid .. ".eml") - local outfile = io.open(output, "w") - if outfile == nil then - return oops("Could not write to file ", output) - end - - outfile:write(dumpdata:lower()) - io.close(outfile) - print(("Wrote an emulator-dump to the file %s"):format(output)) + -- Format some linebreaks + dumpdata = convert_to_emulform(dumpdata) + + local outfile = io.open(output, "w") + if outfile == nil then + return oops("Could not write to file ", output) + end + + outfile:write(dumpdata:lower()) + io.close(outfile) + print(("Wrote an emulator-dump to the file %s"):format(output)) end --[[ -In the future, we may implement so that scripts are invoked directly +In the future, we may implement so that scripts are invoked directly into a 'main' function, instead of being executed blindly. For future -compatibility, I have done so, but I invoke my main from here. +compatibility, I have done so, but I invoke my main from here. --]] main(args) diff --git a/client/scripts/e.lua b/client/scripts/e.lua index 4e032337e..6b9d80364 100644 --- a/client/scripts/e.lua +++ b/client/scripts/e.lua @@ -5,73 +5,73 @@ example = "script calculates many different checksums (CRC) over the provided he author = "Iceman" desc = [[ -This script calculates many checksums (CRC) over the provided hex input. +This script calculates many checksums (CRC) over the provided hex input. Arguments: - -b data in hex - -w bitwidth of the CRC family of algorithm. defaults to all known CRC presets. -Examples : - script run e -b 010203040506070809 - script run e -b 010203040506070809 -w 16 + -b data in hex + -w bitwidth of the CRC family of algorithm. defaults to all known CRC presets. +Examples : + script run e -b 010203040506070809 + script run e -b 010203040506070809 -w 16 ]] ---- +--- -- A debug printout-function function dbg(args) - if DEBUG then - print("###", args) - end -end ---- + if DEBUG then + print("###", args) + end +end +--- -- This is only meant to be used when errors occur function oops(err) - print("[!] ERROR: ",err) - return nil,err + print("[!] ERROR: ",err) + return nil,err end ---- +--- -- Usage help function help() - print(desc) - print("Example usage") - print(example) + print(desc) + print("Example usage") + print(example) end ---- +--- -- The main entry point function main(args) - local data - local width = 0 + local data + local width = 0 - -- Read the parameters - for o, a in getopt.getopt(args, 'hb:w:') do - if o == "h" then return help() end - if o == "b" then data = a end - if o == "w" then width = a end - end + -- Read the parameters + for o, a in getopt.getopt(args, 'hb:w:') do + if o == "h" then return help() end + if o == "b" then data = a end + if o == "w" then width = a end + end - data = data or '01020304' - width = width or 0 - - print( string.rep('-',60) ) - print('Bit width of CRC | '..width) - print('Bytes | '..data) - print('') - print( ('%-20s| %-16s| %s'):format('Model','CRC', 'CRC reverse','bigEnd', 'bigEnd','little','little')) - print( string.rep('-',60) ) - local lists, err = core.reveng_models(width) - if lists == nil then return oops(err) end - - for _,i in pairs(lists) do - if string.len(i) > 1 then - local a1 = core.reveng_runmodel(i, data, false, '0') - local a2 = core.reveng_runmodel(i, data, true, '0') - local a3 = core.reveng_runmodel(i, data, false, 'b') - local a4 = core.reveng_runmodel(i, data, false, 'B') - local a5 = core.reveng_runmodel(i, data, false, 'l') - local a6 = core.reveng_runmodel(i, data, false, 'L') - print( ('%-20s| %-16s| %-16s| %-16s| %-16s| %-16s| %-16s'):format(i, a1:upper(), a2:upper(),a3:upper(),a4:upper(),a5:upper(),a6:upper() ) ) - end - end + data = data or '01020304' + width = width or 0 + + print( string.rep('-',60) ) + print('Bit width of CRC | '..width) + print('Bytes | '..data) + print('') + print( ('%-20s| %-16s| %s'):format('Model','CRC', 'CRC reverse','bigEnd', 'bigEnd','little','little')) + print( string.rep('-',60) ) + local lists, err = core.reveng_models(width) + if lists == nil then return oops(err) end + + for _,i in pairs(lists) do + if string.len(i) > 1 then + local a1 = core.reveng_runmodel(i, data, false, '0') + local a2 = core.reveng_runmodel(i, data, true, '0') + local a3 = core.reveng_runmodel(i, data, false, 'b') + local a4 = core.reveng_runmodel(i, data, false, 'B') + local a5 = core.reveng_runmodel(i, data, false, 'l') + local a6 = core.reveng_runmodel(i, data, false, 'L') + print( ('%-20s| %-16s| %-16s| %-16s| %-16s| %-16s| %-16s'):format(i, a1:upper(), a2:upper(),a3:upper(),a4:upper(),a5:upper(),a6:upper() ) ) + end + end end main(args) \ No newline at end of file diff --git a/client/scripts/emul2dump.lua b/client/scripts/emul2dump.lua index 315ad99ab..04b9da12b 100644 --- a/client/scripts/emul2dump.lua +++ b/client/scripts/emul2dump.lua @@ -1,60 +1,60 @@ -local getopt = require('getopt') -local bin = require('bin') -local dumplib = require('html_dumplib') - -example =[[ - 1. script run emul2dump - 2. script run emul2dump -i myfile.eml - 3. script run emul2dump -i myfile.eml -o myfile.bin -]] -author = "Iceman" -usage = "script run emul2dump [-i ] [-o ]" -desc =[[ -This script takes an dumpfile on EML (ASCII) format and converts it to the PM3 dumpbin file to be used with "hf mf restore" - -Arguments: - -h This help - -i Specifies the dump-file (input). If omitted, 'dumpdata.eml' is used - -o Specifies the output file. If omitted, .bin is used. -]] - ---- --- This is only meant to be used when errors occur -function oops(err) - print("ERROR: ",err) -end ---- --- Usage help -function help() - print(desc) - print("Example usage") - print(example) -end --- --- Exit message -function ExitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() -end - -local function main(args) - - local input = "dumpdata.eml" - local output = os.date("%Y-%m-%d_%H%M%S.bin"); - - -- Arguments for the script - for o, a in getopt.getopt(args, 'hi:o:') do - if o == "h" then return help() end - if o == "i" then input = a end - if o == "o" then output = a end - end - - local filename, err = dumplib.convert_eml_to_bin(input,output) - if err then return oops(err) end - - ExitMsg(("Wrote a BIN dump to the file %s"):format(filename)) -end - +local getopt = require('getopt') +local bin = require('bin') +local dumplib = require('html_dumplib') + +example =[[ + 1. script run emul2dump + 2. script run emul2dump -i myfile.eml + 3. script run emul2dump -i myfile.eml -o myfile.bin +]] +author = "Iceman" +usage = "script run emul2dump [-i ] [-o ]" +desc =[[ +This script takes an dumpfile on EML (ASCII) format and converts it to the PM3 dumpbin file to be used with "hf mf restore" + +Arguments: + -h This help + -i Specifies the dump-file (input). If omitted, 'dumpdata.eml' is used + -o Specifies the output file. If omitted, .bin is used. +]] + +--- +-- This is only meant to be used when errors occur +function oops(err) + print("ERROR: ",err) +end +--- +-- Usage help +function help() + print(desc) + print("Example usage") + print(example) +end +-- +-- Exit message +function ExitMsg(msg) + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() +end + +local function main(args) + + local input = "dumpdata.eml" + local output = os.date("%Y-%m-%d_%H%M%S.bin"); + + -- Arguments for the script + for o, a in getopt.getopt(args, 'hi:o:') do + if o == "h" then return help() end + if o == "i" then input = a end + if o == "o" then output = a end + end + + local filename, err = dumplib.convert_eml_to_bin(input,output) + if err then return oops(err) end + + ExitMsg(("Wrote a BIN dump to the file %s"):format(filename)) +end + main(args) \ No newline at end of file diff --git a/client/scripts/emul2html.lua b/client/scripts/emul2html.lua index 52d4dacb0..db76ec9c0 100644 --- a/client/scripts/emul2html.lua +++ b/client/scripts/emul2html.lua @@ -8,60 +8,60 @@ example = "script run emul2html -o dumpdata.eml " author = "Martin Holst Swende" usage = "script run htmldump [-i ] [-o ]" desc =[[ -This script takes a dumpfile on EML (ASCII) format and produces a html based dump, which is a -bit more easily analyzed. +This script takes a dumpfile on EML (ASCII) format and produces a html based dump, which is a +bit more easily analyzed. Arguments: - -h This help - -i Specifies the dump-file (input). If omitted, 'dumpdata.eml' is used - -o Speciies the output file. If omitted, .html is used. + -h This help + -i Specifies the dump-file (input). If omitted, 'dumpdata.eml' is used + -o Speciies the output file. If omitted, .html is used. ]] ------------------------------- --- Some utilities +-- Some utilities ------------------------------- ---- +--- -- A debug printout-function function dbg(args) - if DEBUG then - print("###", args) - end -end ---- + if DEBUG then + print("###", args) + end +end +--- -- This is only meant to be used when errors occur function oops(err) - print("ERROR: ",err) + print("ERROR: ",err) end ---- +--- -- Usage help function help() - print(desc) - print("Example usage") - print(example) + print(desc) + print("Example usage") + print(example) end local function main(args) - local input = "dumpdata.eml" - local output = os.date("%Y-%m-%d_%H%M%S.html"); - for o, a in getopt.getopt(args, 'i:o:h') do - if o == "h" then return help() end - if o == "i" then input = a end - if o == "o" then output = a end - end - local filename, err = dumplib.convert_eml_to_html(input,output) - if err then return oops(err) end + local input = "dumpdata.eml" + local output = os.date("%Y-%m-%d_%H%M%S.html"); + for o, a in getopt.getopt(args, 'i:o:h') do + if o == "h" then return help() end + if o == "i" then input = a end + if o == "o" then output = a end + end + local filename, err = dumplib.convert_eml_to_html(input,output) + if err then return oops(err) end - print(("Wrote a HTML dump to the file %s"):format(filename)) + print(("Wrote a HTML dump to the file %s"):format(filename)) end --[[ -In the future, we may implement so that scripts are invoked directly +In the future, we may implement so that scripts are invoked directly into a 'main' function, instead of being executed blindly. For future -compatibility, I have done so, but I invoke my main from here. +compatibility, I have done so, but I invoke my main from here. --]] main(args) \ No newline at end of file diff --git a/client/scripts/formatMifare.lua b/client/scripts/formatMifare.lua index 35475db84..90801b2a2 100644 --- a/client/scripts/formatMifare.lua +++ b/client/scripts/formatMifare.lua @@ -1,216 +1,216 @@ -local cmds = require('commands') -local getopt = require('getopt') -local bin = require('bin') -local lib14a = require('read14a') -local utils = require('utils') - -example = [[ - -- generate commands - 1. script run formatMifare - - -- generate command, replacing key with new key. - 2. script run formatMifare -k aabbccddeeff -n 112233445566 -a FF0780 - - -- generate commands and excute them against card. - 3. script run formatMifare -x -]] -copyright = '' -version = '' -author = 'Iceman' -usage = [[ - script run formatMifare -k -n -a -x -]] -desc = [[ -This script will generate 'hf mf wrbl' commands for each block to format a Mifare card. - -Alla datablocks gets 0x00 -As default the script sets the keys A/B to 0xFFFFFFFFFFFF -and the access bytes will become 0x78,0x77,0x88 -The GDB will become 0x00 - -The script will skip the manufactoring block 0. - - -Arguments: - -h - this help - -k - the current six byte key with write access - -n - the new key that will be written to the card - -a - the new access bytes that will be written to the card - -x - execute the commands aswell. -]] -local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds -local DEBUG = true -- the debug flag -local CmdString = 'hf mf wrbl %d B %s %s' -local numBlocks = 64 -local numSectors = 16 ---- --- A debug printout-function -function dbg(args) - if not DEBUG then - return - end - - if type(args) == "table" then - local i = 1 - while result[i] do - dbg(result[i]) - i = i+1 - end - else - print("###", args) - end -end ---- --- This is only meant to be used when errors occur -function oops(err) - print("ERROR: ",err) -end ---- --- Usage help -function help() - print(copyright) - print(author) - print(version) - print(desc) - print("Example usage") - print(example) -end --- --- Exit message -function ExitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() -end --- --- Read information from a card -function GetCardInfo() - result, err = lib14a.read(false, true) - if not result then - print(err) - return - end - print(("Found: %s"):format(result.name)) - - core.clearCommandBuffer() - - if 0x18 == result.sak then -- NXP MIFARE Classic 4k | Plus 4k - -- IFARE Classic 4K offers 4096 bytes split into forty sectors, - -- of which 32 are same size as in the 1K with eight more that are quadruple size sectors. - numSectors = 40 - elseif 0x08 == result.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k - -- 1K offers 1024 bytes of data storage, split into 16 sector - numSectors = 16 - elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k - -- MIFARE Classic mini offers 320 bytes split into five sectors. - numSectors = 5 - elseif 0x10 == result.sak then -- NXP MIFARE Plus 2k - numSectors = 32 - elseif 0x01 == result.sak then -- NXP MIFARE TNP3xxx 1K - numSectors = 16 - else - print("I don't know how many sectors there are on this type of card, defaulting to 16") - end - --[[ - The mifare Classic 1k card has 16 sectors of 4 data blocks each. - The first 32 sectors of a mifare Classic 4k card consists of 4 data blocks and the remaining - 8 sectors consist of 16 data blocks. - --]] - - -- Defaults to 16 * 4 = 64 - 1 = 63 - numBlocks = numSectors * 4 - 1 - - if numSectors > 32 then - numBlocks = 32*4+ (numSectors-32)*16 -1 - end - -end - -local function main(args) - - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print() - - local OldKey, NewKey, Accessbytes - local x = false - - -- Arguments for the script - for o, a in getopt.getopt(args, 'hk:n:a:x') do - if o == "h" then return help() end - if o == "k" then OldKey = a end - if o == "n" then NewKey = a end - if o == "a" then Accessbytes = a end - if o == "x" then x = true end - end - - -- validate input args. - OldKey = OldKey or 'FFFFFFFFFFFF' - if #(OldKey) ~= 12 then - return oops( string.format('Wrong length of write key (was %d) expected 12', #OldKey)) - end - - NewKey = NewKey or 'FFFFFFFFFFFF' - if #(NewKey) ~= 12 then - return oops( string.format('Wrong length of new key (was %d) expected 12', #NewKey)) - end - - --Accessbytes = Accessbytes or '787788' - Accessbytes = Accessbytes or 'FF0780' - if #(Accessbytes) ~= 6 then - return oops( string.format('Wrong length of accessbytes (was %d) expected 12', #Accessbytes)) - end - - GetCardInfo() - - -- Show info - print( string.format('Estimating number of blocks: %d', numBlocks)) - print( string.format('Old key: %s', OldKey)) - print( string.format('New key: %s', NewKey)) - print( string.format('New Access: %s', Accessbytes)) - print( string.rep('--',20) ) - - -- Set new block data - local EMPTY_BL = string.rep('00',16) - local EMPTY_SECTORTRAIL = string.format('%s%s%s%s',NewKey,Accessbytes,'00',NewKey) - - dbg( string.format('New sector-trailer : %s',EMPTY_SECTORTRAIL)) - dbg( string.format('New emptyblock: %s',EMPTY_BL)) - dbg('') - - if x then - print('[Warning] you have used the EXECUTE parameter, which means this will run these commands against card.') - end - -- Ask - local dialogResult = utils.confirm("Do you want to erase this card") - if dialogResult == false then - return ExitMsg('Quiting it is then. Your wish is my command...') - end - - print( string.rep('--',20) ) - - -- main loop - for block=0,numBlocks,1 do - - local reminder = (block+1) % 4 - local cmd - if reminder == 0 then - cmd = CmdString:format(block, OldKey , EMPTY_SECTORTRAIL) - else - cmd = CmdString:format(block, OldKey , EMPTY_BL) - end - - if block ~= 0 then - print(cmd) - if x then core.console(cmd) end - end - - if core.ukbhit() then - print("aborted by user") - break - end - end -end - +local cmds = require('commands') +local getopt = require('getopt') +local bin = require('bin') +local lib14a = require('read14a') +local utils = require('utils') + +example = [[ + -- generate commands + 1. script run formatMifare + + -- generate command, replacing key with new key. + 2. script run formatMifare -k aabbccddeeff -n 112233445566 -a FF0780 + + -- generate commands and excute them against card. + 3. script run formatMifare -x +]] +copyright = '' +version = '' +author = 'Iceman' +usage = [[ + script run formatMifare -k -n -a -x +]] +desc = [[ +This script will generate 'hf mf wrbl' commands for each block to format a Mifare card. + +Alla datablocks gets 0x00 +As default the script sets the keys A/B to 0xFFFFFFFFFFFF +and the access bytes will become 0x78,0x77,0x88 +The GDB will become 0x00 + +The script will skip the manufactoring block 0. + + +Arguments: + -h - this help + -k - the current six byte key with write access + -n - the new key that will be written to the card + -a - the new access bytes that will be written to the card + -x - execute the commands aswell. +]] +local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds +local DEBUG = true -- the debug flag +local CmdString = 'hf mf wrbl %d B %s %s' +local numBlocks = 64 +local numSectors = 16 +--- +-- A debug printout-function +function dbg(args) + if not DEBUG then + return + end + + if type(args) == "table" then + local i = 1 + while result[i] do + dbg(result[i]) + i = i+1 + end + else + print("###", args) + end +end +--- +-- This is only meant to be used when errors occur +function oops(err) + print("ERROR: ",err) +end +--- +-- Usage help +function help() + print(copyright) + print(author) + print(version) + print(desc) + print("Example usage") + print(example) +end +-- +-- Exit message +function ExitMsg(msg) + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() +end +-- +-- Read information from a card +function GetCardInfo() + result, err = lib14a.read(false, true) + if not result then + print(err) + return + end + print(("Found: %s"):format(result.name)) + + core.clearCommandBuffer() + + if 0x18 == result.sak then -- NXP MIFARE Classic 4k | Plus 4k + -- IFARE Classic 4K offers 4096 bytes split into forty sectors, + -- of which 32 are same size as in the 1K with eight more that are quadruple size sectors. + numSectors = 40 + elseif 0x08 == result.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k + -- 1K offers 1024 bytes of data storage, split into 16 sector + numSectors = 16 + elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k + -- MIFARE Classic mini offers 320 bytes split into five sectors. + numSectors = 5 + elseif 0x10 == result.sak then -- NXP MIFARE Plus 2k + numSectors = 32 + elseif 0x01 == result.sak then -- NXP MIFARE TNP3xxx 1K + numSectors = 16 + else + print("I don't know how many sectors there are on this type of card, defaulting to 16") + end + --[[ + The mifare Classic 1k card has 16 sectors of 4 data blocks each. + The first 32 sectors of a mifare Classic 4k card consists of 4 data blocks and the remaining + 8 sectors consist of 16 data blocks. + --]] + + -- Defaults to 16 * 4 = 64 - 1 = 63 + numBlocks = numSectors * 4 - 1 + + if numSectors > 32 then + numBlocks = 32*4+ (numSectors-32)*16 -1 + end + +end + +local function main(args) + + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() + + local OldKey, NewKey, Accessbytes + local x = false + + -- Arguments for the script + for o, a in getopt.getopt(args, 'hk:n:a:x') do + if o == "h" then return help() end + if o == "k" then OldKey = a end + if o == "n" then NewKey = a end + if o == "a" then Accessbytes = a end + if o == "x" then x = true end + end + + -- validate input args. + OldKey = OldKey or 'FFFFFFFFFFFF' + if #(OldKey) ~= 12 then + return oops( string.format('Wrong length of write key (was %d) expected 12', #OldKey)) + end + + NewKey = NewKey or 'FFFFFFFFFFFF' + if #(NewKey) ~= 12 then + return oops( string.format('Wrong length of new key (was %d) expected 12', #NewKey)) + end + + --Accessbytes = Accessbytes or '787788' + Accessbytes = Accessbytes or 'FF0780' + if #(Accessbytes) ~= 6 then + return oops( string.format('Wrong length of accessbytes (was %d) expected 12', #Accessbytes)) + end + + GetCardInfo() + + -- Show info + print( string.format('Estimating number of blocks: %d', numBlocks)) + print( string.format('Old key: %s', OldKey)) + print( string.format('New key: %s', NewKey)) + print( string.format('New Access: %s', Accessbytes)) + print( string.rep('--',20) ) + + -- Set new block data + local EMPTY_BL = string.rep('00',16) + local EMPTY_SECTORTRAIL = string.format('%s%s%s%s',NewKey,Accessbytes,'00',NewKey) + + dbg( string.format('New sector-trailer : %s',EMPTY_SECTORTRAIL)) + dbg( string.format('New emptyblock: %s',EMPTY_BL)) + dbg('') + + if x then + print('[Warning] you have used the EXECUTE parameter, which means this will run these commands against card.') + end + -- Ask + local dialogResult = utils.confirm("Do you want to erase this card") + if dialogResult == false then + return ExitMsg('Quiting it is then. Your wish is my command...') + end + + print( string.rep('--',20) ) + + -- main loop + for block=0,numBlocks,1 do + + local reminder = (block+1) % 4 + local cmd + if reminder == 0 then + cmd = CmdString:format(block, OldKey , EMPTY_SECTORTRAIL) + else + cmd = CmdString:format(block, OldKey , EMPTY_BL) + end + + if block ~= 0 then + print(cmd) + if x then core.console(cmd) end + end + + if core.ukbhit() then + print("aborted by user") + break + end + end +end + main(args) \ No newline at end of file diff --git a/client/scripts/hf_read.lua b/client/scripts/hf_read.lua index 82655a364..7653e6e75 100644 --- a/client/scripts/hf_read.lua +++ b/client/scripts/hf_read.lua @@ -1,18 +1,18 @@ local reader = require('hf_reader') local function main(args) - print("WORK IN PROGRESS - not expected to be functional yet") - info, err = reader.waitForTag() + print("WORK IN PROGRESS - not expected to be functional yet") + info, err = reader.waitForTag() - if err then - print(err) - return - end - local k,v - print("Tag info") - for k,v in pairs(info) do - print(string.format(" %s : %s", tostring(k), tostring(v))) - end - return + if err then + print(err) + return + end + local k,v + print("Tag info") + for k,v in pairs(info) do + print(string.format(" %s : %s", tostring(k), tostring(v))) + end + return end main(args) \ No newline at end of file diff --git a/client/scripts/htmldump.lua b/client/scripts/htmldump.lua index 0299e13c5..40f3028b4 100644 --- a/client/scripts/htmldump.lua +++ b/client/scripts/htmldump.lua @@ -8,58 +8,58 @@ example = "script run htmldump -o mifarecard_foo.html" author = "Martin Holst Swende" usage = "script run htmldump [-i ] [-o ]" desc =[[ -This script takes a dumpfile and produces a html based dump, which is a -bit more easily analyzed. +This script takes a dumpfile and produces a html based dump, which is a +bit more easily analyzed. Arguments: - -h This help - -i Specifies the dump-file (input). If omitted, 'dumpdata.bin' is used - -o Speciies the output file. If omitted, .html is used. + -h This help + -i Specifies the dump-file (input). If omitted, 'dumpdata.bin' is used + -o Speciies the output file. If omitted, .html is used. ]] ------------------------------- --- Some utilities +-- Some utilities ------------------------------- ---- +--- -- A debug printout-function function dbg(args) - if DEBUG then - print("###", args) - end -end ---- + if DEBUG then + print("###", args) + end +end +--- -- This is only meant to be used when errors occur function oops(err) - print("ERROR: ",err) + print("ERROR: ",err) end ---- +--- -- Usage help function help() - print(desc) - print("Example usage") - print(example) + print(desc) + print("Example usage") + print(example) end local function main(args) - local input = "dumpdata.bin" - local output = os.date("%Y-%m-%d_%H%M%S.html"); - for o, a in getopt.getopt(args, 'i:o:h') do - if o == "h" then return help() end - if o == "i" then input = a end - if o == "o" then output = a end - end - local filename, err = dumplib.convert_bin_to_html(input,output,16) - if err then return oops(err) end + local input = "dumpdata.bin" + local output = os.date("%Y-%m-%d_%H%M%S.html"); + for o, a in getopt.getopt(args, 'i:o:h') do + if o == "h" then return help() end + if o == "i" then input = a end + if o == "o" then output = a end + end + local filename, err = dumplib.convert_bin_to_html(input,output,16) + if err then return oops(err) end - print(("Wrote a HTML dump to the file %s"):format(filename)) + print(("Wrote a HTML dump to the file %s"):format(filename)) end --[[ -In the future, we may implement so that scripts are invoked directly +In the future, we may implement so that scripts are invoked directly into a 'main' function, instead of being executed blindly. For future -compatibility, I have done so, but I invoke my main from here. +compatibility, I have done so, but I invoke my main from here. --]] main(args) \ No newline at end of file diff --git a/client/scripts/iso15_magic.lua b/client/scripts/iso15_magic.lua index 3923f2b1e..939c7a943 100644 --- a/client/scripts/iso15_magic.lua +++ b/client/scripts/iso15_magic.lua @@ -7,112 +7,112 @@ copyright = 'Copyright (c) 2018 IceSQL AB. All rights reserved.' author = 'Christian Herrmann' version = 'v1.0.4' desc = [[ -This script tries to set UID on a IS15693 SLIX magic card +This script tries to set UID on a IS15693 SLIX magic card Remember the UID ->MUST<- start with 0xE0 ]] example = [[ - -- ISO15693 slix magic tag + -- ISO15693 slix magic tag - script run iso15_magic -u E004013344556677 - - script run iso15_magic -u E004013344556677 -a + script run iso15_magic -u E004013344556677 + + script run iso15_magic -u E004013344556677 -a ]] usage = [[ script run iso15_magic -h -u Arguments: - -h : this help - -u : UID (16 hexsymbols) - -a : use offical pm3 repo ISO15 commands instead of iceman fork. + -h : this help + -u : UID (16 hexsymbols) + -a : use offical pm3 repo ISO15 commands instead of iceman fork. ]] 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 ---- + 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) - return nil, err + print("ERROR: ",err) + return nil, err end ---- +--- -- Usage help local function help() - print(copyright) - print(author) - print(version) - print(desc) - print('Example usage') - print(example) + print(copyright) + print(author) + print(version) + print(desc) + print('Example usage') + print(example) end -- --- Set UID on magic command enabled on a ICEMAN based REPO local function magicUID_iceman(b0, b1) - print('Using backdoor Magic tag function') - core.console("hf 15 raw -2 -c 02213E00000000") - core.console("hf 15 raw -2 -c 02213F69960000") - core.console("hf 15 raw -2 -c 022138"..b1) - core.console("hf 15 raw -2 -c 022139"..b0) + print('Using backdoor Magic tag function') + core.console("hf 15 raw -2 -c 02213E00000000") + core.console("hf 15 raw -2 -c 02213F69960000") + core.console("hf 15 raw -2 -c 022138"..b1) + core.console("hf 15 raw -2 -c 022139"..b0) end -- --- Set UID on magic command enabled, OFFICAL REPO local function magicUID_offical(b0, b1) - print('Using backdoor Magic tag function OFFICAL REPO') - core.console("hf 15 cmd raw -c 02213E00000000") - core.console("hf 15 cmd raw -c 02213F69960000") - core.console("hf 15 cmd raw -c 022138"..b1) - core.console("hf 15 cmd raw -c 022139"..b0) + print('Using backdoor Magic tag function OFFICAL REPO') + core.console("hf 15 cmd raw -c 02213E00000000") + core.console("hf 15 cmd raw -c 02213F69960000") + core.console("hf 15 cmd raw -c 022138"..b1) + core.console("hf 15 cmd raw -c 022139"..b0) end ---- +--- -- The main entry point function main(args) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print() + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() - local uid = 'E004013344556677' - local use_iceman = true - - -- Read the parameters - 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 - if uid == nil then return oops('empty uid string') end - if #uid == 0 then return oops('empty uid string') end - if #uid ~= 16 then return oops('uid wrong length. Should be 8 hex bytes') end + local uid = 'E004013344556677' + local use_iceman = true - local bytes = utils.ConvertHexToBytes(uid) - - local block0 = string.format('%02X%02X%02X%02X', bytes[4], bytes[3], bytes[2], bytes[1]) - local block1 = string.format('%02X%02X%02X%02X', bytes[8], bytes[7], bytes[6], bytes[5]) - - print('new UID | '..uid) - - core.clearCommandBuffer() - - if use_iceman then - magicUID_iceman(block0, block1) - else - magicUID_offical(block0, block1) - end + -- Read the parameters + 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 + if uid == nil then return oops('empty uid string') end + if #uid == 0 then return oops('empty uid string') end + if #uid ~= 16 then return oops('uid wrong length. Should be 8 hex bytes') end + + local bytes = utils.ConvertHexToBytes(uid) + + local block0 = string.format('%02X%02X%02X%02X', bytes[4], bytes[3], bytes[2], bytes[1]) + local block1 = string.format('%02X%02X%02X%02X', bytes[8], bytes[7], bytes[6], bytes[5]) + + print('new UID | '..uid) + + core.clearCommandBuffer() + + if use_iceman then + magicUID_iceman(block0, block1) + else + magicUID_offical(block0, block1) + end end main(args) diff --git a/client/scripts/legic.lua b/client/scripts/legic.lua index 264d4dfef..97fd64f11 100644 --- a/client/scripts/legic.lua +++ b/client/scripts/legic.lua @@ -3,7 +3,7 @@ if it don't works with you tag-layout - be so kind and let me know ;-) Tested on Tags with those Layouts: -(example) Legic-Prime Layout with 'Kaba Group Header' +(example) Legic-Prime Layout with 'Kaba Group Header' +----+----+----+----+----+----+----+----+ 0x00|MCD |MSN0|MSN1|MSN2|MCC | 60 | ea | 9f | +----+----+----+----+----+----+----+----+ @@ -31,7 +31,7 @@ UID = dec User-ID for online-Mapping kghC = crc8 over MCD + MSN0..MSN2 + UID -(example) Legic-Cash on MIM256/1024 tag' (37 bytes) +(example) Legic-Cash on MIM256/1024 tag' (37 bytes) +----+----+----+----+----+----+----+----+ 0x00|Seg0|Seg1|Seg2|Seg3|SegC|STP0|STP1|STP2| +----+----+----+----+----+----+----+----+ @@ -56,7 +56,7 @@ LRS = ID of the reader that changed the shadow balance (?? should be always the CV = Counter value for transactions CHK = crc16 over SHD + LRS + CV -(example) Legic-Prime Layout 'gantner unsegmented user-credential' +(example) Legic-Prime Layout 'gantner unsegmented user-credential' +----+----+----+----+----+----+----+----+ 0x00|MCD |MSN0|MSN1|MSN2|MCC | 60 | ea | 08 | +----+----+----+----+----+----+----+----+ @@ -73,7 +73,7 @@ Dat = Online-Mapping Data uCRC = crc8 over addr 0x00..0x03+0x07..0x0E -(example) Legic-Prime Layout 'gantner unsegmented Master-Token (IAM) with a stamp_len of 4' +(example) Legic-Prime Layout 'gantner unsegmented Master-Token (IAM) with a stamp_len of 4' +----+----+----+----+----+----+----+----+ 0x00|MCD |MSN0|MSN1|MSN2|MCC | 20 | f8 | 08 | +----+----+----+----+----+----+----+----+ @@ -224,16 +224,16 @@ local currency = { --- -- This is only meant to be used when errors occur function oops(err) - print(acred.."ERROR: "..acoff ,err) - return nil, err + print(acred.."ERROR: "..acoff ,err) + return nil, err end --- -- Usage help function help() - print(desc) - print("Version: "..version) - print("Example usage: "..example) + print(desc) + print("Version: "..version) + print("Example usage: "..example) end --- @@ -265,28 +265,28 @@ end --- -- xor single byte function xorme(hex, xor, index) - if ( index >= 23 ) then - return ('%02x'):format(bxor( tonumber(hex,16) , tonumber(xor,16) )) - else - return hex - end + if ( index >= 23 ) then + return ('%02x'):format(bxor( tonumber(hex,16) , tonumber(xor,16) )) + else + return hex + end end --- -- (de)obfuscate bytes function xorBytes(inBytes, crc) - local bytes = {} - for index = 1, #inBytes do - bytes[index] = xorme(inBytes[index], crc, index) - end - if (#inBytes == #bytes) then - -- replace crc - bytes[5] = string.sub(crc,-2) - return bytes - else - print("error: byte-count missmatch") - return false - end + local bytes = {} + for index = 1, #inBytes do + bytes[index] = xorme(inBytes[index], crc, index) + end + if (#inBytes == #bytes) then + -- replace crc + bytes[5] = string.sub(crc,-2) + return bytes + else + print("error: byte-count missmatch") + return false + end end --- @@ -317,9 +317,9 @@ end --- -- put a string into a bytes-table function str2bytes(s) - if (string.len(s)%2 ~= 0) then - return print("stamp should be a even hexstring e.g.: deadbeef or 0badc0de") - end + if (string.len(s)%2 ~= 0) then + return print("stamp should be a even hexstring e.g.: deadbeef or 0badc0de") + end local res={} for i=1, string.len(s), 2 do table.insert(res, string.sub(s,i,(i+1))) @@ -330,29 +330,29 @@ end --- -- put certain bytes into a new table function bytesToTable(bytes, bstart, bend) - local t={} - for i=0, (bend-bstart) do - t[i]=bytes[bstart+i] - end - return t + local t={} + for i=0, (bend-bstart) do + t[i]=bytes[bstart+i] + end + return t end --- -- read file into table function getInputBytes(infile) - local line - local bytes = {} - local fhi,err = io.open(infile,"rb") - if err then oops("faild to read from file ".. infile); return false; end + local line + local bytes = {} + local fhi,err = io.open(infile,"rb") + if err then oops("faild to read from file ".. infile); return false; end - file_data = fhi:read("*a"); - for i = 1, #file_data do - bytes[i] = string.format("%x",file_data:byte(i)) - end - fhi:close() - if (bytes[7]=='00') then return false end - print(#bytes .. " bytes from "..infile.." loaded") - return bytes + file_data = fhi:read("*a"); + for i = 1, #file_data do + bytes[i] = string.format("%x",file_data:byte(i)) + end + fhi:close() + if (bytes[7]=='00') then return false end + print(#bytes .. " bytes from "..infile.." loaded") + return bytes end --- @@ -385,7 +385,7 @@ end --- -- put bytes into tag-table function bytesToTag(bytes, tag) - if istable(tag) == false then return oops("tag is no table in: bytesToTag ("..type(tag)..")") end + if istable(tag) == false then return oops("tag is no table in: bytesToTag ("..type(tag)..")") end tag.MCD =bytes[1]; tag.MSN0=bytes[2]; @@ -453,7 +453,7 @@ end --- -- read Tag-Table in bytes-table function tagToBytes(tag) - if istable(tag) == false then return oops("tag is no table in tagToBytes ("..type(tag)..")") end + if istable(tag) == false then return oops("tag is no table in tagToBytes ("..type(tag)..")") end local bytes = {} local i, i2 @@ -524,249 +524,249 @@ end --- -- write virtual Tag to real Tag function writeToTag(tag) - 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 + 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 - -- 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 - - 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 %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 %s%s'):format(padString(bytes[i-1]), padString(bytes[i])) - print(acgreen..cmd..acoff) - core.console(cmd) - 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) - end - utils.Sleep(0.2) - end - 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 + 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 + + 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 %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 %s%s'):format(padString(bytes[i-1]), padString(bytes[i])) + print(acgreen..cmd..acoff) + core.console(cmd) + 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) + end + utils.Sleep(0.2) + end + end end --- File I/O --- --- -- read file into virtual-tag local function readFile(filename) - print(accyan) - local bytes = {} - local tag = {} - if file_check(filename) == false then - return oops("input file: "..filename.." not found") - end + 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 --- -- write bytes to file 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 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 - 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] - elseif (bcnt <= 7) then - line = line.." "..bytes[i] - end - if (bcnt == 7) then - -- write line to new file - fho:write(line.."\n") - -- reset counter & line - bcnt = -1 - line = "" - end - bcnt = bcnt + 1 - end - fho:close() - print("\nwrote ".. #bytes .." bytes to " .. filename) - return true + 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 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 + 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] + elseif (bcnt <= 7) then + line = line.." "..bytes[i] + end + if (bcnt == 7) then + -- write line to new file + fho:write(line.."\n") + -- reset counter & line + bcnt = -1 + line = "" + end + bcnt = bcnt + 1 + end + fho:close() + print("\nwrote ".. #bytes .." bytes to " .. filename) + return true end --- Map related --- --- -- make 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 + 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 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 + 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 fho,err = io.open(filename, "w") - if err then oops("OOps ... faild to open output-file ".. filename) end + 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 - fho:close() - return true + -- 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 local function toggleHighlight(tbl) - if (tbl['highlight']) then - tbl['highlight'] = false - else - tbl['highlight'] = true - end - return tbl + if (tbl['highlight']) then + tbl['highlight'] = false + else + tbl['highlight'] = true + end + return tbl end --- -- return table od seqence-string 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 + 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 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 + 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 --- @@ -778,18 +778,18 @@ function loadTagMap(filename) local line, fields local temp={} local offset=0 - if (file_check(filename)==false) then - return oops("input file: "..filename.." not found") - else - local fhi,err = io.open(filename) - while true do - line = fhi:read() - if line == nil then + if (file_check(filename)==false) then + return oops("input file: "..filename.." not found") + else + local fhi,err = io.open(filename) + while true do + line = fhi:read() + if line == nil then break else fields=split(line) end - if (#fields==2) then + if (#fields==2) then if (fields[1]=='offset') then offset=tonumber(fields[2],10) end @@ -823,9 +823,9 @@ function loadTagMap(filename) end table.insert(map.crc8, temp) end - end - fhi:close() - end + end + fhi:close() + end return map end @@ -1127,10 +1127,10 @@ function mapAllSegments(tag, tagMap) segs=getSegmentStats(bytes) if (istable(segs)) then for k, v in pairs(segs) do - -- wrp (write proteted) = byte 2 - WRP = tonumber(bytes[v['start']+2],16) - -- wrc (write control) - bit 4-6 of byte 3 - WRC = tonumber(bbit("0x"..bytes[v['start']+3],4,3),16) + -- wrp (write proteted) = byte 2 + WRP = tonumber(bytes[v['start']+2],16) + -- wrc (write control) - bit 4-6 of byte 3 + WRC = tonumber(bbit("0x"..bytes[v['start']+3],4,3),16) --tagMap=mapTokenData(tagMap, 'Segment '..("%02d"):format(v['index']).." HDR", v['start'], v['start']+3) tagMap=mapTokenData(tagMap, 'Segment '..("%02d"):format(v['index']).." CRC", v['start']+4, v['start']+4, true) table.insert(tagMap.crc8, {name = 'Segment '..("%02d"):format(v['index']).." CRC", pos=v['start']+4, seq={1,4,v['start'],v['start']+3}} ) @@ -1327,11 +1327,11 @@ function dumpTable(tab, header, tstart, tend) for i=tstart, tend do res=res..tab[i].." " end - if (#header == 0) then - return res - else - return (header.." #"..(tend-tstart+1).."\n"..res) - end + if (#header == 0) then + return res + else + return (header.." #"..(tend-tstart+1).."\n"..res) + end end --- @@ -1377,7 +1377,7 @@ end -- dump Legic-Cash data function dumpLegicCash(tag, x) - if istable(tag.SEG[x]) == false then return end + if istable(tag.SEG[x]) == false then return end io.write("in Segment "..tag.SEG[x].index.." :\n") print("--------------------------------\n\tLegic-Cash Values\n--------------------------------") @@ -1403,7 +1403,7 @@ function dumpLegicCash(tag, x) -- raw 3rd-party function print3rdPartyCash1(tag, x) - if istable(tag.SEG[x]) == false then return end + if istable(tag.SEG[x]) == false then return end local uid=tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2 print("\n\t\tStamp : "..dumpTable(tag.SEG[x].data, "", 0 , 2)) @@ -1608,25 +1608,25 @@ function getSegmentData(bytes, start, index) if (bytes[start]) then local i -- #index - segment.index = index - -- flag = high nibble of byte 1 - segment.flag = string.sub(bytes[start+1],0,1) - -- valid = bit 6 of byte 1 - segment.valid = bbit("0x"..bytes[start+1],6,1) - -- last = bit 7 of byte 1 - segment.last = bbit("0x"..bytes[start+1],7,1) - -- len = (byte 0)+(bit0-3 of byte 1) + segment.index = index + -- flag = high nibble of byte 1 + segment.flag = string.sub(bytes[start+1],0,1) + -- valid = bit 6 of byte 1 + segment.valid = bbit("0x"..bytes[start+1],6,1) + -- last = bit 7 of byte 1 + segment.last = bbit("0x"..bytes[start+1],7,1) + -- len = (byte 0)+(bit0-3 of byte 1) segment.len = tonumber(bbit("0x"..bytes[start+1],0,4)..bytes[start],16) -- raw segment header segment.raw = {bytes[start], bytes[start+1], bytes[start+2], bytes[start+3]} - -- wrp (write proteted) = byte 2 - segment.WRP = tonumber(bytes[start+2],16) - -- wrc (write control) - bit 4-6 of byte 3 - segment.WRC = tonumber(bbit("0x"..bytes[start+3],4,3),16) - -- rd (read disabled) - bit 7 of byte 3 - segment.RD = tonumber(bbit("0x"..bytes[start+3],7,1),16) - -- crc byte 4 - segment.crc = bytes[start+4] + -- wrp (write proteted) = byte 2 + segment.WRP = tonumber(bytes[start+2],16) + -- wrc (write control) - bit 4-6 of byte 3 + segment.WRC = tonumber(bbit("0x"..bytes[start+3],4,3),16) + -- rd (read disabled) - bit 7 of byte 3 + segment.RD = tonumber(bbit("0x"..bytes[start+3],7,1),16) + -- crc byte 4 + segment.crc = bytes[start+4] -- segment-data starts at segment.len - segment.header - segment.crc for i=0, (segment.len-5) do segment.data[i]=bytes[start+5+i] @@ -1645,11 +1645,11 @@ function getSegmentStats(bytes) x=0 repeat local s={} - -- valid = bit 6 of byte 1 - sValid = bbit("0x"..bytes[sStart+1],6,1) - -- last = bit 7 of byte 1 - sLast = bbit("0x"..bytes[sStart+1],7,1) - -- len = (byte 0)+(bit0-3 of byte 1) + -- valid = bit 6 of byte 1 + sValid = bbit("0x"..bytes[sStart+1],6,1) + -- last = bit 7 of byte 1 + sLast = bbit("0x"..bytes[sStart+1],7,1) + -- len = (byte 0)+(bit0-3 of byte 1) sLen = tonumber(bbit("0x"..bytes[sStart+1],0,4)..bytes[sStart],16) --print("index: "..("%02d"):format(x).." Len: "..sLen.." start:"..sStart.." end: "..(sStart+sLen-1)) s['index']=x @@ -1721,18 +1721,18 @@ end --- -- edit Segment Data function editSegmentData(data) - io.write("\n") - if istable(data) == false then print("no Segment-Data found") end + io.write("\n") + if istable(data) == false then print("no Segment-Data found") end - local lc = check4LegicCash(data) + local lc = check4LegicCash(data) for i=0, #data-1 do - data[i]=input(accyan.."Data"..i..acoff..": ", data[i]) + data[i]=input(accyan.."Data"..i..acoff..": ", data[i]) end - if (lc) then - data = fixLegicCash(data) - end - return data + if (lc) then + data = fixLegicCash(data) + end + return data end --- @@ -2302,10 +2302,10 @@ function modifyMode() ["lf"] = function(x) if (type(x)=='string' and file_check(x)) then - filename = x + filename = x else - filename = input("enter filename: ", "legic.temp") - end + filename = input("enter filename: ", "legic.temp") + end inTAG=readFile(filename) -- check for existing tagMap if (file_check(filename..".map")) then @@ -2408,10 +2408,10 @@ function modifyMode() -- dump single segment ["ds"] = function(x) if (type(x)=="string" and string.len(x)>0) then - sel = tonumber(x,10) + sel = tonumber(x,10) else - sel = selectSegment(inTAG) - end + sel = selectSegment(inTAG) + end if (sel) then print("\n"..(dumpSegment(inTAG, sel) or acred.."no Segments available") ..acoff.."\n") end end, --- @@ -2423,9 +2423,9 @@ function modifyMode() if(istable(inTAG.SEG[0])) then inTAG=editSegment(inTAG, sel) inTAG.SEG[sel]=regenSegmentHeader(inTAG.SEG[sel]) - else - print(acyellow.."no Segments in Tag"..acoff) - end + else + print(acyellow.."no Segments in Tag"..acoff) + end end end, --- @@ -2481,15 +2481,15 @@ function modifyMode() ["tk"] = function(x) if (istable(inTAG) and istable(inTAG.SEG[0])) then if (type(x)=="string" and string.len(x)>0) then - sel = tonumber(x,10) - else - sel = selectSegment(inTAG) - end - if(inTAG.SEG[sel].kgh) then - inTAG.SEG[sel].kgh = false + sel = tonumber(x,10) else - inTAG.SEG[sel].kgh = true - end + sel = selectSegment(inTAG) + end + if(inTAG.SEG[sel].kgh) then + inTAG.SEG[sel].kgh = false + else + inTAG.SEG[sel].kgh = true + end end end, --- @@ -2508,10 +2508,10 @@ function modifyMode() ["xc"] = function(x) if (istable(inTAG) and istable(inTAG.SEG[0])) then if (type(x)=="string" and string.len(x)>0) then - sel = tonumber(x,10) + sel = tonumber(x,10) else - sel = selectSegment(inTAG) - end + sel = selectSegment(inTAG) + end print("k "..kghCrcCredentials(inTAG, sel)) end end, @@ -2519,10 +2519,10 @@ function modifyMode() -- fix legic-cash checksums ["flc"] = function(x) if (type(x)=="string" and string.len(x)>0) then - x = tonumber(x,10) + x = tonumber(x,10) else - x = selectSegment(inTAG) - end + x = selectSegment(inTAG) + end inTAG.SEG[x].data=fixLegicCash(inTAG.SEG[x].data) end, --- @@ -2540,8 +2540,8 @@ function modifyMode() print(string.format("User-Selected Index %02d", x)) else -- or try to find match - x = autoSelectSegment(inTAG, "legiccash") - end + x = autoSelectSegment(inTAG, "legiccash") + end -- dump it dumpLegicCash(inTAG, x) end, @@ -2555,8 +2555,8 @@ function modifyMode() print(string.format("User-Selected Index %02d", x)) else -- or try to find match - x = autoSelectSegment(inTAG, "3rdparty") - end + x = autoSelectSegment(inTAG, "3rdparty") + end if (istable(inTAG) and istable(inTAG.SEG[x]) and inTAG.SEG[x].len == 100) then uid=inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2 if (check43rdPartyCash1(uid, inTAG.SEG[x].data)) then @@ -2574,8 +2574,8 @@ function modifyMode() print(string.format("User-Selected Index %02d", x)) else -- or try to find match - x = autoSelectSegment(inTAG, "3rdparty") - end + x = autoSelectSegment(inTAG, "3rdparty") + end print3rdPartyCash1(inTAG, x) end, --- @@ -2589,8 +2589,8 @@ function modifyMode() else -- or try to find match - x = autoSelectSegment(inTAG, "3rdparty") - end + x = autoSelectSegment(inTAG, "3rdparty") + end if (istable(inTAG) and istable(inTAG.SEG[x]) and inTAG.SEG[x].len == 100) then inTAG=edit3rdPartyCash1(inTAG, x) dump3rdPartyCash1(inTAG, x) @@ -2600,10 +2600,10 @@ function modifyMode() -- force fixing 3rd-party-checksums ["f3p"] = function(x) if(type(x)=="string" and string.len(x)>=2) then - x = tonumber(x, 10) - else - x = selectSegment(inTAG) - end + x = tonumber(x, 10) + else + x = selectSegment(inTAG) + end if (istable(inTAG.SEG[x])) then local uid=inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2 inTAG.SEG[x].data=fix3rdPartyCash1(uid, inTAG.SEG[x].data) @@ -2613,10 +2613,10 @@ function modifyMode() -- get stamp from single segment ["gs"] = function(x) if(type(x)=="string" and string.len(x)>=2) then - x = tonumber(x, 10) + x = tonumber(x, 10) else - x = selectSegment(inTAG) - end + x = selectSegment(inTAG) + end local stamp=getSegmentStamp(inTAG.SEG[x]) print("Stamp : "..stamp) stamp=str2bytes(stamp) @@ -2663,8 +2663,8 @@ function modifyMode() elseif (type(actions[string.lower(string.sub(ic,0,1))])=='function') then actions[string.lower(string.sub(ic,0,1))](string.sub(ic,3)) else - actions.h('') - end + actions.h('') + end until (string.sub(ic,0,1)=="q") end @@ -2673,40 +2673,40 @@ end function main(args) -- set init colors/switch (can be toggled with 'tac' => 'toggle ansicolors') load_colors(colored_output) - if (#args == 0 ) then modifyMode() end + if (#args == 0 ) then modifyMode() end --- variables local inTAG, backupTAG, outTAG, outfile, interactive, crc, ofs, cfs, dfs - -- just a spacer for better readability + -- just a spacer for better readability print() --- parse arguments - for o, a in getopt.getopt(args, 'hrmi:do:c:') do + for o, a in getopt.getopt(args, 'hrmi:do:c:') do -- display help if o == "h" then return help(); end -- read tag from PM3 if o == "r" then inTAG=readFromPM3() end -- input file - if o == "i" then inTAG=readFile(a) end + if o == "i" then inTAG=readFile(a) end -- dump virtual-Tag if o == "d" then dfs=true end -- interacive modifying if o == "m" then - interactive = true - modifyMode() - end + interactive = true + modifyMode() + end -- xor (e.g. for clone or plain file) if o == "c" then - cfs = true - crc = a - end + cfs = true + crc = a + end -- output file - if o == "o" then - outfile = a - ofs = true - end + if o == "o" then + outfile = a + ofs = true + end end -- file conversion (output to file) - if ofs == false then return end + if ofs == false then return end -- dump infile / tag-read if (dfs) then diff --git a/client/scripts/legic_buffer2card.lua b/client/scripts/legic_buffer2card.lua index 845e8e8e5..68440b8ac 100644 --- a/client/scripts/legic_buffer2card.lua +++ b/client/scripts/legic_buffer2card.lua @@ -4,51 +4,51 @@ author = "Mosci" desc = [[ This is a script which writes value 0x01 to bytes from position 0x07 until 0xFF on a Legic Prime Tag (MIM256 or MIM1024) -(created with 'hf legic save my_dump.hex') - -optional arguments : - -h - Help text +(created with 'hf legic save my_dump.hex') -Examples : - script run legic_buffer2card +optional arguments : + -h - Help text + +Examples : + script run legic_buffer2card ]] local utils = require('utils') local getopt = require('getopt') ---- +--- -- This is only meant to be used when errors occur function oops(err) - print("ERROR: ",err) - return nil, err + print("ERROR: ",err) + return nil, err end ---- +--- -- Usage help function help() - print(desc) - print("Example usage") - print(example) + print(desc) + print("Example usage") + print(example) end -- -- simple loop-write from 0x07 to 0xff function main() - -- parse arguments for the script - for o, a in getopt.getopt(args, 'h') do - if o == "h" then return help() end - end + -- parse arguments for the script + for o, a in getopt.getopt(args, 'h') do + if o == "h" then return help() end + end - local cmd = '' - local i - for i = 7, 255 do - cmd = ('hf legic write 0x%02x 0x01'):format(i) - print(cmd) - core.clearCommandBuffer() - core.console(cmd) - - -- got a 'cmd-buffer overflow' on my mac - so just wait a little - -- works without that pause on my linux-box - utils.Sleep(0.1) - end + local cmd = '' + local i + for i = 7, 255 do + cmd = ('hf legic write 0x%02x 0x01'):format(i) + print(cmd) + core.clearCommandBuffer() + core.console(cmd) + + -- got a 'cmd-buffer overflow' on my mac - so just wait a little + -- works without that pause on my linux-box + utils.Sleep(0.1) + end end main() diff --git a/client/scripts/lf_bulk.lua b/client/scripts/lf_bulk.lua index 7f02094b8..b4604bebb 100644 --- a/client/scripts/lf_bulk.lua +++ b/client/scripts/lf_bulk.lua @@ -12,59 +12,59 @@ Perform bulk enrollment of 26 bit H10301 style RFID Tags For more info, check the comments in the code ]] example = [[ - -- - script run lf_bulk.lua -f 1 -b 1000 -c 10 + -- + script run lf_bulk.lua -f 1 -b 1000 -c 10 ]] usage = [[ script run lf_bulk.lua -f facility -b base_id_num -c count Arguments: - -h : this help - -f : facility id - -b : starting card id - -c : count, number of cards to make + -h : this help + -f : facility id + -b : starting card id + -c : count, number of cards to make ]] local DEBUG = true --local bxor = bit32.bxor local bor = bit32.bor local lshift = bit32.lshift ---- +--- -- 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 ---- + 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) - return nil,err + print("ERROR: ",err) + return nil,err end ---- +--- -- Usage help local function help() - print(copyright) - print(author) - print(version) - print(desc) - print('Example usage') - print(example) + print(copyright) + print(author) + print(version) + print(desc) + print('Example usage') + print(example) end --- -- Exit message local function exitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() end --[[Implement a function to simply visualize the bitstream in a text format --This is especially helpful for troubleshooting bitwise math issues]]-- @@ -81,22 +81,22 @@ end --[[ Likely, I'm an idiot, but I couldn't find any parity functions in Lua - This can also be done with a combination of bitwise operations (in fact, + This can also be done with a combination of bitwise operations (in fact, is the canonically "correct" way to do it, but my brain doesn't just default to this and so counting some ones is good enough for me ]]-- local function evenparity(s) - local _, count = string.gsub(s, "1", "") - local p = count % 2 - if (p == 0) then - return false - else - return true - end + local _, count = string.gsub(s, "1", "") + local p = count % 2 + if (p == 0) then + return false + else + return true + end end - + local function isempty(s) - return s == nil or s == '' + return s == nil or s == '' end --[[ @@ -105,89 +105,89 @@ end hex. This should be easy enough to extend to non 26bit formats ]]-- local function cardHex(i, f) - fac = lshift(f, 16) - id = bor(i, fac) - stream = toBits(id, 24) + fac = lshift(f, 16) + id = bor(i, fac) + stream = toBits(id, 24) - --As the function defaults to even parity and returns a boolean, - --perform a 'not' function to get odd parity - high = evenparity(string.sub(stream,1,12)) and 1 or 0 - low = not evenparity(string.sub(stream,13)) and 1 or 0 - bits = bor( lshift(id, 1), low) - bits = bor( bits, lshift(high, 25)) + --As the function defaults to even parity and returns a boolean, + --perform a 'not' function to get odd parity + high = evenparity(string.sub(stream,1,12)) and 1 or 0 + low = not evenparity(string.sub(stream,13)) and 1 or 0 + bits = bor( lshift(id, 1), low) + bits = bor( bits, lshift(high, 25)) - --Since the lua library bit32 is (obviously) 32 bits and we need to - --encode 36 bits to properly do a 26 bit tag with the preamble we need - --to create a higher order and lower order component which we will - --then assemble in the return. The math above defines the proper - --encoding as per HID/Weigand/etc. These bit flips are due to the - --format length check on bit 38 (cmdlfhid.c:64) and - --bit 31 (cmdlfhid.c:66). - preamble = bor(0, lshift(1, 5)) - bits = bor(bits, lshift(1, 26)) + --Since the lua library bit32 is (obviously) 32 bits and we need to + --encode 36 bits to properly do a 26 bit tag with the preamble we need + --to create a higher order and lower order component which we will + --then assemble in the return. The math above defines the proper + --encoding as per HID/Weigand/etc. These bit flips are due to the + --format length check on bit 38 (cmdlfhid.c:64) and + --bit 31 (cmdlfhid.c:66). + preamble = bor(0, lshift(1, 5)) + bits = bor(bits, lshift(1, 26)) - return ("%04x%08x"):format(preamble, bits) + return ("%04x%08x"):format(preamble, bits) end --- -- main local function main(args) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print() - - if #args == 0 then return help() end - - --I really wish a better getopt function would be brought in supporting - --long arguments, but it seems this library was chosen for BSD style - --compatibility - 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 0") - facility = 0 - else - facility = a - end - end - if o == 'b' then - if isempty(a) then return oops("You must supply the flag -b (base id)") end - baseid = a - end - if o == 'c' then - if isempty(a) then return oops("You must supply the flag -c (count)") end - count = a - end - end + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() - --Due to my earlier complaints about how this specific getopt library - --works, specifying ":" does not enforce supplying a value, thus we - --need to do these checks all over again. - if isempty(baseid) then return oops("You must supply the flag -b (base id)") end - if isempty(count) then return oops("You must supply the flag -c (count)") end + if #args == 0 then return help() end - --If the facility ID is non specified, ensure we code it as zero - if isempty(facility) then - print("Using 0 for the facility code as -f was not supplied") - facility = 0 - end + --I really wish a better getopt function would be brought in supporting + --long arguments, but it seems this library was chosen for BSD style + --compatibility + 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 0") + facility = 0 + else + facility = a + end + end + if o == 'b' then + if isempty(a) then return oops("You must supply the flag -b (base id)") end + baseid = a + end + if o == 'c' then + if isempty(a) then return oops("You must supply the flag -c (count)") end + count = a + end + end - --The next baseid + count function presents a logic/UX conflict - --where users specifying -c 1 (count = 1) would try to program two - --tags. This makes it so that -c 0 & -c 1 both code one tag, and all - --other values encode the expected amount. - if tonumber(count) > 0 then count = count - 1 end + --Due to my earlier complaints about how this specific getopt library + --works, specifying ":" does not enforce supplying a value, thus we + --need to do these checks all over again. + if isempty(baseid) then return oops("You must supply the flag -b (base id)") end + if isempty(count) then return oops("You must supply the flag -c (count)") end - endid = baseid + count + --If the facility ID is non specified, ensure we code it as zero + if isempty(facility) then + print("Using 0 for the facility code as -f was not supplied") + facility = 0 + end - for cardnum = baseid, endid do - local card = cardHex(cardnum, facility) - print("Press enter to program card "..cardnum..":"..facility.." (hex: "..card..")") - --This would be better with "press any key", but we'll take what we can get. - io.read() - core.console( ('lf hid clone %s'):format(card) ) - end + --The next baseid + count function presents a logic/UX conflict + --where users specifying -c 1 (count = 1) would try to program two + --tags. This makes it so that -c 0 & -c 1 both code one tag, and all + --other values encode the expected amount. + if tonumber(count) > 0 then count = count - 1 end + + endid = baseid + count + + for cardnum = baseid, endid do + local card = cardHex(cardnum, facility) + print("Press enter to program card "..cardnum..":"..facility.." (hex: "..card..")") + --This would be better with "press any key", but we'll take what we can get. + io.read() + core.console( ('lf hid clone %s'):format(card) ) + end end main(args) \ No newline at end of file diff --git a/client/scripts/mfkeys.lua b/client/scripts/mfkeys.lua index 085390526..18078b822 100644 --- a/client/scripts/mfkeys.lua +++ b/client/scripts/mfkeys.lua @@ -1,12 +1,12 @@ --[[ - This is an example of Lua-scripting within proxmark3. This is a lua-side - implementation of hf mf chk + This is an example of Lua-scripting within proxmark3. This is a lua-side + implementation of hf mf chk - This code is licensed to you under the terms of the GNU GPL, version 2 or, - at your option, any later version. See the LICENSE.txt file for the text of - the license. + This code is licensed to you under the terms of the GNU GPL, version 2 or, + at your option, any later version. See the LICENSE.txt file for the text of + the license. - Copyright (C) 2013 m h swende + Copyright (C) 2013 m h swende --]] -- Loads the commands-library local cmds = require('commands') @@ -19,7 +19,7 @@ local getopt = require('getopt') local utils = require('utils') example =[[ - script run mfkeys + script run mfkeys ]] author = "Holiman" usage = "script run mfkeys" @@ -29,247 +29,247 @@ If you want to add more, just put them inside /lualibs/mf_default_keys.lua\n"):f [[ Arguments: - -h : this help - -p : print keys + -h : this help + -p : print keys ]] local TIMEOUT = 10000 -- 10 seconds ---- +--- -- This is only meant to be used when errors occur local function oops(err) - print('ERROR: ',err) - return nil,err + print('ERROR: ',err) + return nil,err end ---- +--- -- Usage help local function help() - print(desc) - print("Example usage") - print(example) + print(desc) + print("Example usage") + print(example) end -- -- waits for answer from pm3 device local function checkCommand(command) - core.clearCommandBuffer() - local usb = command:getBytes() - core.SendCommand(usb) - local result = core.WaitForResponseTimeout(cmds.CMD_ACK, TIMEOUT) - if result then - local count, cmd, arg0 = bin.unpack('LL',result) - if(arg0==1) then - local count, arg1, arg2, data = bin.unpack('LLH511',result,count) - key = data:sub(1,12) - return key - else - return nil - end - else - print("Timeout while waiting for response. Increase TIMEOUT in mfkeys.lua to wait longer") - return nil, "Timeout while waiting for device to respond" - end + core.clearCommandBuffer() + local usb = command:getBytes() + core.SendCommand(usb) + local result = core.WaitForResponseTimeout(cmds.CMD_ACK, TIMEOUT) + if result then + local count, cmd, arg0 = bin.unpack('LL',result) + if(arg0==1) then + local count, arg1, arg2, data = bin.unpack('LLH511',result,count) + key = data:sub(1,12) + return key + else + return nil + end + else + print("Timeout while waiting for response. Increase TIMEOUT in mfkeys.lua to wait longer") + return nil, "Timeout while waiting for device to respond" + end end local function checkBlock(blockno, testkeys, keytype) - -- The command data is only 512 bytes, each key is 6 bytes, meaning that we can send max 85 keys in one go. - -- If there's more, we need to split it up - local arg1 = bit32.bor(bit32.lshift(keytype, 8), blockno) + -- The command data is only 512 bytes, each key is 6 bytes, meaning that we can send max 85 keys in one go. + -- If there's more, we need to split it up + local arg1 = bit32.bor(bit32.lshift(keytype, 8), blockno) - local start, remaining = 1, #testkeys - local chunksize = remaining - if remaining > 85 then chunksize = 85 end - local n = chunksize - - while remaining > 0 do - --print('start', start, 'chunksize', chunksize, 'testkeys kvar', remaining, 'N-index=', n) + local start, remaining = 1, #testkeys + local chunksize = remaining + if remaining > 85 then chunksize = 85 end + local n = chunksize - local d1 = table.concat(testkeys, "", start, n) - - print(("Testing block %d, keytype %d, with %d keys"):format(blockno, keytype, chunksize)) - local command = Command:new{cmd = cmds.CMD_MIFARE_CHKKEYS, - arg1 = arg1, - arg2 = 0, - arg3 = chunksize, - data = d1} - local status = checkCommand(command) - if status then return status, blockno end - start = start + chunksize - remaining = remaining - chunksize - - if remaining < 85 then chunksize = remaining end - n = n + chunksize - end - return nil + while remaining > 0 do + --print('start', start, 'chunksize', chunksize, 'testkeys kvar', remaining, 'N-index=', n) + + local d1 = table.concat(testkeys, "", start, n) + + print(("Testing block %d, keytype %d, with %d keys"):format(blockno, keytype, chunksize)) + local command = Command:new{cmd = cmds.CMD_MIFARE_CHKKEYS, + arg1 = arg1, + arg2 = 0, + arg3 = chunksize, + data = d1} + local status = checkCommand(command) + if status then return status, blockno end + start = start + chunksize + remaining = remaining - chunksize + + if remaining < 85 then chunksize = remaining end + n = n + chunksize + end + return nil end -- A function to display the results local function display_results(keys) - local sector, keyA, keyB, succA, succB - print('') - print('|---|----------------|---|----------------|---|') - print('|sec|key A |res|key B |res|') - print('|---|----------------|---|----------------|---|') + local sector, keyA, keyB, succA, succB + print('') + print('|---|----------------|---|----------------|---|') + print('|sec|key A |res|key B |res|') + print('|---|----------------|---|----------------|---|') - for sector = 0, #keys do - succA, succB, keyA, keyB = unpack(keys[sector]) - print(('|%03d| %s | %s | %s | %s |'):format(sector, keyA, succA, keyB, succB)) - end - print('|---|----------------|---|----------------|---|') + for sector = 0, #keys do + succA, succB, keyA, keyB = unpack(keys[sector]) + print(('|%03d| %s | %s | %s | %s |'):format(sector, keyA, succA, keyB, succB)) + end + print('|---|----------------|---|----------------|---|') end -- A little helper to place an item first in the list local function placeFirst(akey, list) - akey = akey:lower() - if list[1] == akey then - -- Already at pole position - return list - end - local result = {akey} - --print(("Putting '%s' first"):format(akey)) - for i,v in ipairs(list) do - if v ~= akey then - result[#result+1] = v - end - end - return result + akey = akey:lower() + if list[1] == akey then + -- Already at pole position + return list + end + local result = {akey} + --print(("Putting '%s' first"):format(akey)) + for i,v in ipairs(list) do + if v ~= akey then + result[#result+1] = v + end + end + return result end --[[ -The mifare Classic 1k card has 16 sectors of 4 data blocks each. +The mifare Classic 1k card has 16 sectors of 4 data blocks each. The first 32 sectors of a mifare Classic 4k card consists of 4 data blocks and the remaining -8 sectors consist of 16 data blocks. +8 sectors consist of 16 data blocks. --]] local function get_blockno(s) - local b, sector + local b, sector - if type(s) == 'string' then - sector = tonumber(s) - else - sector = s - end + if type(s) == 'string' then + sector = tonumber(s) + else + sector = s + end - if sector < 32 then - b = sector * 4 - else - b = 32 * 4 + (sector - 32) * 16 + if sector < 32 then + b = sector * 4 + else + b = 32 * 4 + (sector - 32) * 16 end - return ('%02x'):format(b) + return ('%02x'):format(b) end -- -- dumps all keys to file local function dumptofile(keys) - if utils.confirm('Do you wish to save the keys to dumpfile?') then - local destination = utils.input('Select a filename to store to', 'dumpkeys.bin') - local file = io.open(destination, 'wb') - if file == nil then - print('Could not write to file ', destination) - return - end + if utils.confirm('Do you wish to save the keys to dumpfile?') then + local destination = utils.input('Select a filename to store to', 'dumpkeys.bin') + local file = io.open(destination, 'wb') + if file == nil then + print('Could not write to file ', destination) + return + end - local key_a = '' - local key_b = '' + local key_a = '' + local key_b = '' - --for sector,_ in pairs(keys) do - for sector = 0, #keys do - local succA, succB, keyA, keyB = unpack(keys[sector]) - key_a = key_a .. bin.pack('H', keyA); - key_b = key_b .. bin.pack('H', keyB); - end - file:write(key_a) - file:write(key_b) - file:close() - end + --for sector,_ in pairs(keys) do + for sector = 0, #keys do + local succA, succB, keyA, keyB = unpack(keys[sector]) + key_a = key_a .. bin.pack('H', keyA); + key_b = key_b .. bin.pack('H', keyB); + end + file:write(key_a) + file:write(key_b) + file:close() + end end -local function printkeys() - for i=1, #keylist do - print(i, keylist[i]) - end - print ('Number of keys: '..#keylist) +local function printkeys() + for i=1, #keylist do + print(i, keylist[i]) + end + print ('Number of keys: '..#keylist) end local function perform_check(numsectors) - local keyType = 0 -- A=0, B=1 + local keyType = 0 -- A=0, B=1 - -- empty list of found keys - local keys = {} - for i = 0, numsectors-1 do - keys[i] = {0,0,'',''} - end + -- empty list of found keys + local keys = {} + for i = 0, numsectors-1 do + keys[i] = {0,0,'',''} + end - for sector = 0, #keys do - -- Check if user aborted - if core.ukbhit() then - print('Aborted by user') - break - end + for sector = 0, #keys do + -- Check if user aborted + if core.ukbhit() then + print('Aborted by user') + break + end - local targetblock = tonumber(get_blockno(sector), 16) - - local succA, succB, keyA, keyB = unpack(keys[sector]) - - local keyA = checkBlock(targetblock, keylist, 0) - if keyA then succA = 1; keylist = placeFirst(keyA, keylist) end - keyA = keyA or '------------' + local targetblock = tonumber(get_blockno(sector), 16) - local keyB = checkBlock(targetblock, keylist, 1) - if keyB then succB = 1; keylist = placeFirst(keyB, keylist) end - keyB = keyB or '------------' + local succA, succB, keyA, keyB = unpack(keys[sector]) - keys[sector] = {succA, succB, keyA, keyB} - end - - display_results(keys) + local keyA = checkBlock(targetblock, keylist, 0) + if keyA then succA = 1; keylist = placeFirst(keyA, keylist) end + keyA = keyA or '------------' - -- save to dumpkeys.bin - dumptofile(keys) + local keyB = checkBlock(targetblock, keylist, 1) + if keyB then succB = 1; keylist = placeFirst(keyB, keylist) end + keyB = keyB or '------------' + + keys[sector] = {succA, succB, keyA, keyB} + end + + display_results(keys) + + -- save to dumpkeys.bin + dumptofile(keys) end -- -- shows tag information local function taginfo(tag) - local sectors = 16 - -- Show tag info - print((' Found tag %s'):format(tag.name)) + local sectors = 16 + -- Show tag info + print((' Found tag %s'):format(tag.name)) - if 0x18 == tag.sak then --NXP MIFARE Classic 4k | Plus 4k - -- MIFARE Classic 4K offers 4096 bytes split into forty sectors, - -- of which 32 are same size as in the 1K with eight more that are quadruple size sectors. - sectors = 40 - elseif 0x08 == tag.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k - -- 1K offers 1024 bytes of data storage, split into 16 sector - sectors = 16 - elseif 0x09 == tag.sak then -- NXP MIFARE Mini 0.3k - -- MIFARE Classic mini offers 320 bytes split into five sectors. - sectors = 5 - elseif 0x10 == tag.sak then-- "NXP MIFARE Plus 2k" - sectors = 32 - else - print("I don't know how many sectors there are on this type of card, defaulting to 16") - end - return sectors + if 0x18 == tag.sak then --NXP MIFARE Classic 4k | Plus 4k + -- MIFARE Classic 4K offers 4096 bytes split into forty sectors, + -- of which 32 are same size as in the 1K with eight more that are quadruple size sectors. + sectors = 40 + elseif 0x08 == tag.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k + -- 1K offers 1024 bytes of data storage, split into 16 sector + sectors = 16 + elseif 0x09 == tag.sak then -- NXP MIFARE Mini 0.3k + -- MIFARE Classic mini offers 320 bytes split into five sectors. + sectors = 5 + elseif 0x10 == tag.sak then-- "NXP MIFARE Plus 2k" + sectors = 32 + else + print("I don't know how many sectors there are on this type of card, defaulting to 16") + end + return sectors end --- -- The main entry point local function main(args) - local start_time = os.time() - local numSectors = 16 + local start_time = os.time() + local numSectors = 16 - -- Arguments for the script - for o, a in getopt.getopt(args, 'hp') do - if o == "h" then return help() end - if o == "p" then return printkeys() end - end - -- identify tag - tag, err = lib14a.read(false, true) - if not tag then return oops(err) end + -- Arguments for the script + for o, a in getopt.getopt(args, 'hp') do + if o == "h" then return help() end + if o == "p" then return printkeys() end + end + -- identify tag + tag, err = lib14a.read(false, true) + if not tag then return oops(err) end - -- detect sectors and print taginfo - numsectors = taginfo(tag) + -- detect sectors and print taginfo + numsectors = taginfo(tag) - perform_check(numsectors) + perform_check(numsectors) - local end_time = os.time() - print('mfkeys - Total execution time: '..os.difftime(end_time, start_time)..' sec') + local end_time = os.time() + print('mfkeys - Total execution time: '..os.difftime(end_time, start_time)..' sec') end main( args) \ No newline at end of file diff --git a/client/scripts/mifare_access.lua b/client/scripts/mifare_access.lua index 273d524c8..20120aced 100644 --- a/client/scripts/mifare_access.lua +++ b/client/scripts/mifare_access.lua @@ -11,8 +11,8 @@ usage = [[ script run mifare_access -h -a Arguments: - -h : this help - -a : 4 bytes ACCESS CONDITIONS + -h : this help + -a : 4 bytes ACCESS CONDITIONS ]] local DEBUG = true @@ -20,35 +20,35 @@ local bxor = bit32.bxor local band = bit32.band local rshift = bit32.rshift ---- +--- -- 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 ---- + 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) - return nil, err + print("ERROR: ",err) + return nil, err end ---- +--- -- Usage help local function help() - print(copyright) - print(author) - print(version) - print(desc) - print('Example usage') - print(example) + print(copyright) + print(author) + print(version) + print(desc) + print('Example usage') + print(example) end local access_condition_sector_trailer = {} @@ -73,58 +73,58 @@ access_condition_data_block[0x7] = {'never','never','never','never'} local function main(args) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print() + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() - local access = '' - - -- Read the parameters - for o, a in getopt.getopt(args, 'ha:') do - if o == "h" then return help() end - if o == "a" then access = a end - end - - if access == nil then return oops('empty ACCESS CONDITIONS') end - if #access == 0 then return oops('empty ACCESS CONDITIONS') end - if #access ~= 8 then return oops("Wrong length. Should be 4 hex bytes ACCESS CONDITIONS (e.g. 7F0F0869)") end - - local c2_b = tonumber(string.sub(access, 1, 1), 16) - local c1_b = tonumber(string.sub(access, 2, 2), 16) - local c1 = tonumber(string.sub(access, 3, 3), 16) - local c3_b = tonumber(string.sub(access, 4, 4), 16) - local c3 = tonumber(string.sub(access, 5, 5), 16) - local c2 = tonumber(string.sub(access, 6, 6), 16) - local gpb = string.sub(access, 7, 8) + local access = '' - if bxor(c1, c1_b) ~= 0xF then print("!!! bitflip in c1") end - if bxor(c2, c2_b) ~= 0xF then print("!!! bitflip in c2") end - if bxor(c3, c3_b) ~= 0xF then print("!!! bitflip in c3") end + -- Read the parameters + for o, a in getopt.getopt(args, 'ha:') do + if o == "h" then return help() end + if o == "a" then access = a end + end - local ab = c1 * 256 + c2 * 16 + c3 + if access == nil then return oops('empty ACCESS CONDITIONS') end + if #access == 0 then return oops('empty ACCESS CONDITIONS') end + if #access ~= 8 then return oops("Wrong length. Should be 4 hex bytes ACCESS CONDITIONS (e.g. 7F0F0869)") end - for block = 0,3 do - print("--> block "..block) - -- mask bits for block - local abi = band(rshift(ab, block), 0x111) - -- compress bits - abi = band(abi + rshift(abi, 3) + rshift(abi, 6),7) --- print(abi) - if block == 3 then - print(" KEYSECXA read: "..access_condition_sector_trailer[abi][1]) - print(" KEYSECXA write: "..access_condition_sector_trailer[abi][2]) - print(" ACCESS COND. read: "..access_condition_sector_trailer[abi][3]) - print("ACCESS COND. write: "..access_condition_sector_trailer[abi][4]) - print(" KEYSECXB read: "..access_condition_sector_trailer[abi][5]) - print(" KEYSECXB write: "..access_condition_sector_trailer[abi][6]) - else - print(" read: "..access_condition_data_block[abi][1]) - print(" write: "..access_condition_data_block[abi][2]) - print(" inc: "..access_condition_data_block[abi][3]) - print("decr, transfer, restore: "..access_condition_data_block[abi][4]) - end - end + local c2_b = tonumber(string.sub(access, 1, 1), 16) + local c1_b = tonumber(string.sub(access, 2, 2), 16) + local c1 = tonumber(string.sub(access, 3, 3), 16) + local c3_b = tonumber(string.sub(access, 4, 4), 16) + local c3 = tonumber(string.sub(access, 5, 5), 16) + local c2 = tonumber(string.sub(access, 6, 6), 16) + local gpb = string.sub(access, 7, 8) - print("GPB: "..gpb) + if bxor(c1, c1_b) ~= 0xF then print("!!! bitflip in c1") end + if bxor(c2, c2_b) ~= 0xF then print("!!! bitflip in c2") end + if bxor(c3, c3_b) ~= 0xF then print("!!! bitflip in c3") end + + local ab = c1 * 256 + c2 * 16 + c3 + + for block = 0,3 do + print("--> block "..block) + -- mask bits for block + local abi = band(rshift(ab, block), 0x111) + -- compress bits + abi = band(abi + rshift(abi, 3) + rshift(abi, 6),7) + -- print(abi) + if block == 3 then + print(" KEYSECXA read: "..access_condition_sector_trailer[abi][1]) + print(" KEYSECXA write: "..access_condition_sector_trailer[abi][2]) + print(" ACCESS COND. read: "..access_condition_sector_trailer[abi][3]) + print("ACCESS COND. write: "..access_condition_sector_trailer[abi][4]) + print(" KEYSECXB read: "..access_condition_sector_trailer[abi][5]) + print(" KEYSECXB write: "..access_condition_sector_trailer[abi][6]) + else + print(" read: "..access_condition_data_block[abi][1]) + print(" write: "..access_condition_data_block[abi][2]) + print(" inc: "..access_condition_data_block[abi][3]) + print("decr, transfer, restore: "..access_condition_data_block[abi][4]) + end + end + + print("GPB: "..gpb) end main(args) diff --git a/client/scripts/mifare_autopwn.lua b/client/scripts/mifare_autopwn.lua index 738ca6950..b99488d96 100644 --- a/client/scripts/mifare_autopwn.lua +++ b/client/scripts/mifare_autopwn.lua @@ -7,208 +7,208 @@ example = "script run mifare_autopwn" author = "Martin Holst Swende" desc = [[ -This is a script which automates cracking and dumping mifare classic cards. It sets itself into -'listening'-mode, after which it cracks and dumps any mifare classic card that you -place by the device. +This is a script which automates cracking and dumping mifare classic cards. It sets itself into +'listening'-mode, after which it cracks and dumps any mifare classic card that you +place by the device. Arguments: - -h this help - -d debug logging on - -k known key for Sector 0 , keytype A + -h this help + -d debug logging on + -k known key for Sector 0 , keytype A Output files from this operation: - .eml - emulator file - .html - html file containing card data - dumpkeys.bin - keys are dumped here. OBS! This file is volatile, as other commands overwrite it sometimes. - dumpdata.bin - card data in binary form. OBS! This file is volatile, as other commands (hf mf dump) overwrite it. + .eml - emulator file + .html - html file containing card data + dumpkeys.bin - keys are dumped here. OBS! This file is volatile, as other commands overwrite it sometimes. + dumpdata.bin - card data in binary form. OBS! This file is volatile, as other commands (hf mf dump) overwrite it. ]] ------------------------------- --- Some utilities +-- Some utilities ------------------------------- local DEBUG = false ---- +--- -- A debug printout-function local function dbg(args) - if not DEBUG then return end - - if type(args) == 'table' then - local i = 1 - while result[i] do - dbg(result[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) - return nil,err -end ---- --- Usage help -local function help() - print(desc) - print("Example usage") - print(example) + if not DEBUG then return end + + if type(args) == 'table' then + local i = 1 + while result[i] do + dbg(result[i]) + i = i+1 + end + else + print('###', args) + end end --- --- Waits for a mifare card to be placed within the vicinity of the reader. +-- 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(desc) + print("Example usage") + print(example) +end +--- +-- Waits for a mifare card to be placed within the vicinity of the reader. -- @return if successfull: an table containing card info -- @return if unsuccessfull : nil, error local function wait_for_mifare() - while not core.ukbhit() do - res, err = lib14a.read() - if res then return res end - -- err means that there was no response from card - end - return nil, "Aborted by user" + while not core.ukbhit() do + res, err = lib14a.read() + if res then return res end + -- err means that there was no response from card + end + return nil, "Aborted by user" end local function nested(key,sak) - 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 - else - print("I don't know how many sectors there are on this type of card, defaulting to 16") - end - local cmd = string.format("hf mf nested %d 0 A %s d", typ, key) - core.console(cmd) + 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 + else + print("I don't know how many sectors there are on this type of card, defaulting to 16") + end + local cmd = string.format("hf mf nested %d 0 A %s d", typ, key) + core.console(cmd) end local function dump(uid, numsectors) - dbg('dumping tag memory') + 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 + 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 + if utils.confirm('Do you wish to create a memory dump of tag?') then - local dumpfile = 'hf-mf-'..uid..'-data.bin' + local dumpfile = 'hf-mf-'..uid..'-data.bin' - local dmp = ('hf mf dump %s f %s'):format(typ, dumpfile) - core.console(dmp) + 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 =('-i %s -o %s.html'):format(dumpfile, uid) - -- call it - require('htmldump') + -- Save the global args, those are *our* arguments + local myargs = args + -- Set the arguments for htmldump script + args =('-i %s -o %s.html'):format(dumpfile, uid) + -- call it + require('htmldump') - -- dump to emulator - args =('-i %s -o %s.eml'):format(dumpfile, uid) - require('dumptoemul') + -- dump to emulator + 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 + -- Set back args. Not that it's used, just for the karma... + args = myargs + end end -- -- performs a test if tag nonce uses weak or hardend prng local function perform_prng_test() - local isweak = core.detect_prng() - if isweak == 1 then - dbg('PRNG detection : WEAK nonce detected') - elseif isweak == 0 then - dbg('PRNG detection : HARDEND nonce detected') - else - dbg('PRNG detection : failed') - end - return isweak + local isweak = core.detect_prng() + if isweak == 1 then + dbg('PRNG detection : WEAK nonce detected') + elseif isweak == 0 then + dbg('PRNG detection : HARDEND nonce detected') + else + dbg('PRNG detection : failed') + end + return isweak end ---- +--- -- The main entry point local function main(args) - local verbose, exit, res, uid, err, _, sak - local seen_uids = {} - local key = '' - local print_message = true - -- Read the parameters - for o, a in getopt.getopt(args, 'hdk:') do - if o == "h" then help() return end - if o == "d" then DEBUG = true end - if o == 'k' then key = a end - end + local verbose, exit, res, uid, err, _, sak + local seen_uids = {} + local key = '' + local print_message = true + -- Read the parameters + for o, a in getopt.getopt(args, 'hdk:') do + if o == "h" then help() return end + if o == "d" then DEBUG = true end + if o == 'k' then key = a end + end - while not exit do - if print_message then - print("Waiting for card or press any key to stop") - print_message = false - end - res, err = wait_for_mifare() - if err then return oops(err) end - -- Seen already? - uid = res.uid - sak = res.sak - - if not seen_uids[uid] then - -- Store it - seen_uids[uid] = uid - - -- check if PRNG is WEAK - if perform_prng_test() == 1 then - print("Card found, commencing crack on UID", uid) + while not exit do + if print_message then + print("Waiting for card or press any key to stop") + print_message = false + end + res, err = wait_for_mifare() + if err then return oops(err) end + -- Seen already? + uid = res.uid + sak = res.sak - if #key == 12 then - print("Using key: "..key); - else - -- Crack it - local cnt - err, res = core.mfDarkside() - if err == -1 then return oops("Button pressed. Aborted.") - elseif err == -2 then return oops("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).") - elseif err == -3 then return oops("Card is not vulnerable to Darkside attack (its random number generator is not predictable).") - elseif err == -4 then return oops([[ - Card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown - generating polynomial with 16 effective bits only, but shows unexpected behaviour.]]) - elseif err == -5 then return oops("Aborted via keyboard.") - end - -- The key is actually 8 bytes, so a - -- 6-byte key is sent as 00XXXXXX - -- This means we unpack it as first - -- two bytes, then six bytes actual key data - -- We can discard first and second return values - _,_,key = bin.unpack("H2H6",res) - print("Found valid key: "..key); - end - -- Use nested attack - nested(key, sak) - -- Dump info - dump(uid, sak) + if not seen_uids[uid] then + -- Store it + seen_uids[uid] = uid - if #key == 12 then exit = true end - else - print("Card found, darkside attack useless PRNG hardend on UID", uid) - end - print_message = true - end - end + -- check if PRNG is WEAK + if perform_prng_test() == 1 then + print("Card found, commencing crack on UID", uid) + + if #key == 12 then + print("Using key: "..key); + else + -- Crack it + local cnt + err, res = core.mfDarkside() + if err == -1 then return oops("Button pressed. Aborted.") + elseif err == -2 then return oops("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).") + elseif err == -3 then return oops("Card is not vulnerable to Darkside attack (its random number generator is not predictable).") + elseif err == -4 then return oops([[ + Card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown + generating polynomial with 16 effective bits only, but shows unexpected behaviour.]]) + elseif err == -5 then return oops("Aborted via keyboard.") + end + -- The key is actually 8 bytes, so a + -- 6-byte key is sent as 00XXXXXX + -- This means we unpack it as first + -- two bytes, then six bytes actual key data + -- We can discard first and second return values + _,_,key = bin.unpack("H2H6",res) + print("Found valid key: "..key); + end + -- Use nested attack + nested(key, sak) + -- Dump info + dump(uid, sak) + + if #key == 12 then exit = true end + else + print("Card found, darkside attack useless PRNG hardend on UID", uid) + end + print_message = true + end + end end --- Call the main +-- Call the main main(args) diff --git a/client/scripts/mifareplus.lua b/client/scripts/mifareplus.lua index 39462360a..b559b6beb 100644 --- a/client/scripts/mifareplus.lua +++ b/client/scripts/mifareplus.lua @@ -9,19 +9,19 @@ desc = [[ Purpose: Lua script to communicate with the Mifare Plus EV1, including personalization (setting the keys) and proximity check. Manually edit the file to add to the commands you can send the card. Please read the NXP manual before running this script to prevent making irreversible changes. Also note: - - The Mifare Plus must start in SL0 for personalization. Card can then be moved to SL1 or SL3. - - The keys are hardcoded in the script to "00...". Unless you change this, only use this script for testing purposes. - - Make sure you choose your card size correctly (2kB or 4kB). + - The Mifare Plus must start in SL0 for personalization. Card can then be moved to SL1 or SL3. + - The keys are hardcoded in the script to "00...". Unless you change this, only use this script for testing purposes. + - Make sure you choose your card size correctly (2kB or 4kB). Small changes can be to made this script to communicate with the Mifare Plus S, X, or SE. ]] usage = [[ script run mifareplus -h Arguments: - -h : this help + -h : this help ]] --- Default +-- Default SIXTEEN_BYTES_ZEROS = '00000000000000000000000000000000' -- ISO7816 commands used @@ -38,264 +38,264 @@ PROXIMITYCHECK = '03F2' VERIFYPC = '03FD' READPLAINNOMACUNMACED = '0336' ---- +--- -- This is only meant to be used when errors occur local function oops(err) - print('ERROR: ',err) - return nil, err + print('ERROR: ',err) + return nil, err end --- -- Usage help local function help() - print(copyright) - print(author) - print(version) - print(desc) - print('Example usage') - print(example) + print(copyright) + print(author) + print(version) + print(desc) + print('Example usage') + print(example) end --- -- Used to send raw data to the firmware to subsequently forward the data to the card. local function sendRaw(rawdata, crc, power) - print((": %s"):format(rawdata)) + print((": %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 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:new{cmd = cmds.CMD_READER_ISO_14443a, - 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 = lib14a.sendToDevice(command, 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) + local command = Command:new{cmd = cmds.CMD_READER_ISO_14443a, + 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 = lib14a.sendToDevice(command, 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((": %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 - oops("Error sending the card raw data.") - return nil - end + returned_bytes = string.sub(data, 1, arg1 * 2) + if #returned_bytes > 0 then + print((": %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 + oops("Error sending the card raw data.") + return nil + end end -- Sends an instruction to do nothing, only disconnect local function disconnect() - local command = Command:new{cmd = cmds.CMD_READER_ISO_14443a, arg1 = 0, } - -- We can ignore the response here, no ACK is returned for this command - -- Check /armsrc/iso14443a.c, ReaderIso14443a() for details - return lib14a.sendToDevice(command,true) -end + local command = Command:new{cmd = cmds.CMD_READER_ISO_14443a, arg1 = 0,} + -- We can ignore the response here, no ACK is returned for this command + -- Check /armsrc/iso14443a.c, ReaderIso14443a() for details + return lib14a.sendToDevice(command,true) +end local function writePerso() - -- Used to write any data, including the keys (Key A and Key B), for all the sectors. - -- writePerso() command parameters: - -- 1 byte - 0xA8 - Command Code - -- 2 bytes - Address of the first block or key to be written to (40 blocks are numbered from 0x0000 to 0x00FF) - -- X bytes - The data bytes to be written, starting from the first block. Amount of data sent can be from 16 to 240 bytes in 16 byte increments. This allows - -- up to 15 blocks to be written at once. - -- response from PICC: - -- 0x90 - OK - -- 0x09 - targeted block is invalid for writes, i.e. block 0, which contains manufacturer data - -- 0x0B - command invalid - -- 0x0C - unexpected command length - + -- Used to write any data, including the keys (Key A and Key B), for all the sectors. + -- writePerso() command parameters: + -- 1 byte - 0xA8 - Command Code + -- 2 bytes - Address of the first block or key to be written to (40 blocks are numbered from 0x0000 to 0x00FF) + -- X bytes - The data bytes to be written, starting from the first block. Amount of data sent can be from 16 to 240 bytes in 16 byte increments. This allows + -- up to 15 blocks to be written at once. + -- response from PICC: + -- 0x90 - OK + -- 0x09 - targeted block is invalid for writes, i.e. block 0, which contains manufacturer data + -- 0x0B - command invalid + -- 0x0C - unexpected command length - cardsize = 4 --need to set to 4 for 4k or 2 for 2k - if(cardsize == 4) then - numsectors = 39 - elseif(cardsize == 2) then - numsectors = 31 - else - oops("Invalid card size") - end - -- Write to the AES sector keys - print("Setting AES Sector keys") - for i=0,numsectors do --for each sector number - local keyA_block = "40" .. string.format("%02x", i * 2) - local keyB_block = "40" .. string.format("%02x", (i * 2) + 1) - --Can also calculate the keys fancily to make them unique, if desired - keyA = SIXTEEN_BYTES_ZEROS - keyB = SIXTEEN_BYTES_ZEROS - writeBlock(keyA_block, keyA) - writeBlock(keyB_block, keyB) - end - print("Finished setting AES Sector keys") + cardsize = 4 --need to set to 4 for 4k or 2 for 2k + if(cardsize == 4) then + numsectors = 39 + elseif(cardsize == 2) then + numsectors = 31 + else + oops("Invalid card size") + end - print("Setting misc keys which haven't been set yet.") - --CardMasterKey - blocknum = "9000" - writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) - --CardConfigurationKey - blocknum = "9001" - writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) - --L3SwitchKey - blocknum = "9003" - writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) - --SL1CardAuthKey - blocknum = "9004" - writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) - --L3SectorSwitchKey - blocknum = "9006" - writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) - --L1L3MixSectorSwitchKey - blocknum = "9007" - writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) - --VC Keys - --VCProximityKey - blocknum = "A001" - writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) - --VCSelectENCKey - blocknum = "A080" - writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) - --VCSelectMACKey - blocknum = "A081" - writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) - --TransactionMACKey1 - blocknum = "C000" - writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) - --TransactionMACConfKey1 - blocknum = "C001" - writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) - print("Finished setting misc keys.") + -- Write to the AES sector keys + print("Setting AES Sector keys") + for i=0,numsectors do --for each sector number + local keyA_block = "40" .. string.format("%02x", i * 2) + local keyB_block = "40" .. string.format("%02x", (i * 2) + 1) + --Can also calculate the keys fancily to make them unique, if desired + keyA = SIXTEEN_BYTES_ZEROS + keyB = SIXTEEN_BYTES_ZEROS + writeBlock(keyA_block, keyA) + writeBlock(keyB_block, keyB) + end + print("Finished setting AES Sector keys") - print("WritePerso finished! Card is ready to move into new security level.") + print("Setting misc keys which haven't been set yet.") + --CardMasterKey + blocknum = "9000" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --CardConfigurationKey + blocknum = "9001" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --L3SwitchKey + blocknum = "9003" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --SL1CardAuthKey + blocknum = "9004" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --L3SectorSwitchKey + blocknum = "9006" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --L1L3MixSectorSwitchKey + blocknum = "9007" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --VC Keys + --VCProximityKey + blocknum = "A001" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --VCSelectENCKey + blocknum = "A080" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --VCSelectMACKey + blocknum = "A081" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --TransactionMACKey1 + blocknum = "C000" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + --TransactionMACConfKey1 + blocknum = "C001" + writeBlock(blocknum, SIXTEEN_BYTES_ZEROS) + print("Finished setting misc keys.") + + print("WritePerso finished! Card is ready to move into new security level.") end local function writeBlock(blocknum, data) - -- Method writes 16 bytes of the string sent (data) to the specified block number - -- The block numbers sent to the card need to be in little endian format (i.e. block 0x0001 is sent as 0x1000) - blocknum_little_endian = string.sub(blocknum, 3, 4) .. string.sub(blocknum, 1, 2) - commandString = WRITEPERSO .. blocknum_little_endian .. data --Write 16 bytes (32 hex chars). - response = sendRaw(commandString, true, true) --0x90 is returned upon success - if string.sub(response, 3, 4) ~= "90" then - oops(("error occurred while trying to write to block %s"):format(blocknum)) - end + -- Method writes 16 bytes of the string sent (data) to the specified block number + -- The block numbers sent to the card need to be in little endian format (i.e. block 0x0001 is sent as 0x1000) + blocknum_little_endian = string.sub(blocknum, 3, 4) .. string.sub(blocknum, 1, 2) + commandString = WRITEPERSO .. blocknum_little_endian .. data --Write 16 bytes (32 hex chars). + response = sendRaw(commandString, true, true) --0x90 is returned upon success + if string.sub(response, 3, 4) ~= "90" then + oops(("error occurred while trying to write to block %s"):format(blocknum)) + end end local function authenticateAES() - -- Used to try to authenticate with the AES keys we programmed into the card, to ensure the authentication works correctly. - commandString = AUTH_FIRST - commandString = commandString .. '' + -- Used to try to authenticate with the AES keys we programmed into the card, to ensure the authentication works correctly. + commandString = AUTH_FIRST + commandString = commandString .. '' end local function getVersion() - sendRaw(GETVERS_INIT, true, true) - sendRaw(GETVERS_CONT, true, true) - sendRaw(GETVERS_CONT, true, true) + sendRaw(GETVERS_INIT, true, true) + sendRaw(GETVERS_CONT, true, true) + sendRaw(GETVERS_CONT, true, true) end local function commitPerso(SL) - --pass SL as "01" to move to SL1 or "03" to move to SL3. - commandString = COMMITPERSO .. SL - response = sendRaw(commandString, true, true) --0x90 is returned upon success - if string.sub(response, 3, 4) ~= "90" then - oops("error occurred while trying to switch security level") - end + --pass SL as "01" to move to SL1 or "03" to move to SL3. + commandString = COMMITPERSO .. SL + response = sendRaw(commandString, true, true) --0x90 is returned upon success + if string.sub(response, 3, 4) ~= "90" then + oops("error occurred while trying to switch security level") + end end local function calculateMAC(MAC_input) - -- Pad the input if it is not a multiple of 16 bytes (32 nibbles). - if(string.len(MAC_input) % 32 ~= 0) then - MAC_input = MAC_input .. "80" - end - while(string.len(MAC_input) % 32 ~= 0) do - MAC_input = MAC_input .. "0" - end - print("Padded MAC Input = " .. MAC_input .. ", length (bytes) = " .. string.len(MAC_input) / 2) + -- Pad the input if it is not a multiple of 16 bytes (32 nibbles). + if(string.len(MAC_input) % 32 ~= 0) then + MAC_input = MAC_input .. "80" + end + while(string.len(MAC_input) % 32 ~= 0) do + MAC_input = MAC_input .. "0" + end + print("Padded MAC Input = " .. MAC_input .. ", length (bytes) = " .. string.len(MAC_input) / 2) - --The MAC would actually be calculated here, and the output stored in raw_output - raw_output = "00010203040506070001020304050607" -- Dummy filler for now of 16-byte output. To be filled with actual MAC for testing purposes. + --The MAC would actually be calculated here, and the output stored in raw_output + raw_output = "00010203040506070001020304050607" -- Dummy filler for now of 16-byte output. To be filled with actual MAC for testing purposes. - -- The final 8-byte MAC output is a concatenation of every 2nd byte starting from the second MSB. - final_output = "" - j = 3 - for i = 1,8 do - final_output = final_output .. string.sub(RndR, j, j + 1) .. string.sub(RndC, j, j + 1) - j = j + 4 - end - return final_output + -- The final 8-byte MAC output is a concatenation of every 2nd byte starting from the second MSB. + final_output = "" + j = 3 + for i = 1,8 do + final_output = final_output .. string.sub(RndR, j, j + 1) .. string.sub(RndC, j, j + 1) + j = j + 4 + end + return final_output end local function proximityCheck() - --PreparePC-- - commandString = PREPAREPC - response = sendRaw(commandString, true, true) - if not response then return oops("This card is not support the proximity check command.") end - - OPT = string.sub(response, 5, 6) - if tonumber(OPT) == 1 then - pps_present = true - else - pps_present = false - end - pubRespTime = string.sub(response, 7, 10) - if(pps_present == true) then - pps = string.sub(response, 11, 12) - else - pps = '' - end - print("OPT = " .. OPT .. " pubRespTime = " .. pubRespTime .. " pps = " .. pps) + --PreparePC-- + commandString = PREPAREPC + response = sendRaw(commandString, true, true) + if not response then return oops("This card is not support the proximity check command.") end - --PC-- - RndC = "0001020304050607" --Random Challenge - num_rounds = 8 --Needs to be 1, 2, 4, or 8 - part_len = 8 / num_rounds - j = 1 - RndR = "" - for i = 1,num_rounds do - pRndC = "" - for q = 1,(part_len*2) do - pRndC = pRndC .. string.sub(RndC,j,j) - j = j + 1 - end - commandString = PROXIMITYCHECK .. "0" .. tostring(part_len) .. pRndC - pRndR = string.sub(sendRaw(commandString, true, true), 3, 3+part_len) - RndR = RndR .. pRndR - end - print("RndC = " .. RndC .. " RndR = " .. RndR) + OPT = string.sub(response, 5, 6) + if tonumber(OPT) == 1 then + pps_present = true + else + pps_present = false + end + pubRespTime = string.sub(response, 7, 10) + if(pps_present == true) then + pps = string.sub(response, 11, 12) + else + pps = '' + end + print("OPT = " .. OPT .. " pubRespTime = " .. pubRespTime .. " pps = " .. pps) - --VerifyPC-- - MAC_input = "FD" .. OPT .. pubRespTime - if pps_present then - MAC_input = MAC_input .. pps - end - rnum_concat = "" - rnum_concat = RndR .. RndC --temporary (only works for when a single random challenge (8 bytes) is sent) - -- j = 1 - -- for i = 1,8 do - -- rnum_concat = rnum_concat .. string.sub(RndR, j, j + 1) .. string.sub(RndC, j, j + 1) - -- j = j + 2 - -- end - MAC_input = MAC_input .. rnum_concat - print("Concatenation of random numbers = " .. rnum_concat) - print("Final PCD concatenation before input into MAC function = " .. MAC_input) - MAC_tag = calculateMAC(MAC_input) - print("8-byte PCD MAC_tag (placeholder - currently incorrect) = " .. MAC_tag) - commandString = VERIFYPC .. MAC_tag - response = sendRaw(commandString, true, true) - print(#response, response) - if #response < 20 then return oops("Wrong response length (expected 20, got "..#response..") exiting") end - - PICC_MAC = string.sub(response, 5, 20) - print("8-byte MAC returned by PICC = " .. PICC_MAC) - MAC_input = "90" .. string.sub(MAC_input, 3) - print("Final PICC concatenation before input into MAC function = " .. MAC_input) - MAC_tag = calculateMAC(MAC_input) - print("8-byte PICC MAC_tag (placeholder - currently incorrect) = " .. MAC_tag) + --PC-- + RndC = "0001020304050607" --Random Challenge + num_rounds = 8 --Needs to be 1, 2, 4, or 8 + part_len = 8 / num_rounds + j = 1 + RndR = "" + for i = 1,num_rounds do + pRndC = "" + for q = 1,(part_len*2) do + pRndC = pRndC .. string.sub(RndC,j,j) + j = j + 1 + end + commandString = PROXIMITYCHECK .. "0" .. tostring(part_len) .. pRndC + pRndR = string.sub(sendRaw(commandString, true, true), 3, 3+part_len) + RndR = RndR .. pRndR + end + print("RndC = " .. RndC .. " RndR = " .. RndR) + + --VerifyPC-- + MAC_input = "FD" .. OPT .. pubRespTime + if pps_present then + MAC_input = MAC_input .. pps + end + rnum_concat = "" + rnum_concat = RndR .. RndC --temporary (only works for when a single random challenge (8 bytes) is sent) + -- j = 1 + -- for i = 1,8 do + -- rnum_concat = rnum_concat .. string.sub(RndR, j, j + 1) .. string.sub(RndC, j, j + 1) + -- j = j + 2 + -- end + MAC_input = MAC_input .. rnum_concat + print("Concatenation of random numbers = " .. rnum_concat) + print("Final PCD concatenation before input into MAC function = " .. MAC_input) + MAC_tag = calculateMAC(MAC_input) + print("8-byte PCD MAC_tag (placeholder - currently incorrect) = " .. MAC_tag) + commandString = VERIFYPC .. MAC_tag + response = sendRaw(commandString, true, true) + print(#response, response) + if #response < 20 then return oops("Wrong response length (expected 20, got "..#response..") exiting") end + + PICC_MAC = string.sub(response, 5, 20) + print("8-byte MAC returned by PICC = " .. PICC_MAC) + MAC_input = "90" .. string.sub(MAC_input, 3) + print("Final PICC concatenation before input into MAC function = " .. MAC_input) + MAC_tag = calculateMAC(MAC_input) + print("8-byte PICC MAC_tag (placeholder - currently incorrect) = " .. MAC_tag) end @@ -303,47 +303,47 @@ end -- The main entry point function main(args) - local o, a - for o, a in getopt.getopt(args, 'h') do -- Populate command line arguments - if o == "h" then return help() end - end + local o, a + for o, a in getopt.getopt(args, 'h') do -- Populate command line arguments + if o == "h" then return help() end + end - -- Initialize the card using the already-present read14a library - -- Perform RATS and PPS (Protocol and Parameter Selection) check to finish the ISO 14443-4 protocol. - info,err = lib14a.read(true, false) - if not info then oops(err); disconnect(); return; end - - -- - response = sendRaw("D01100", true, true) - if not response then oops("No response from PPS check"); disconnect(); return; end + -- Initialize the card using the already-present read14a library + -- Perform RATS and PPS (Protocol and Parameter Selection) check to finish the ISO 14443-4 protocol. + info,err = lib14a.read(true, false) + if not info then oops(err); disconnect(); return; end - print("Connected to") - print(" Type : "..info.name) - print(" UID : "..info.uid) - - -- Now, the card is initialized and we can do more interesting things. + -- + response = sendRaw("D01100", true, true) + if not response then oops("No response from PPS check"); disconnect(); return; end - --writePerso() - --commitPerso("03") --move to SL3 - --getVersion() - proximityCheck() + print("Connected to") + print(" Type : "..info.name) + print(" UID : "..info.uid) - --commandString = VERIFYPC .. "186EFDE8DDC7D30B" - -- MAC = f5180d6e 40fdeae8 e9dd6ac7 bcd3350b - -- response = sendRaw(commandString, true, true) + -- Now, the card is initialized and we can do more interesting things. - -- attempt to read VCProximityKey at block A001 - -- commandString = READPLAINNOMACUNMACED .. "01A0" .. "01" - -- response = sendRaw(commandString, true, true) + --writePerso() + --commitPerso("03") --move to SL3 + --getVersion() + proximityCheck() - -- authenticate with CardConfigurationKey - -- commandString = AUTH_FIRST .. "0190" .. "00" - -- response = sendRaw(commandString, true, true) + --commandString = VERIFYPC .. "186EFDE8DDC7D30B" + -- MAC = f5180d6e 40fdeae8 e9dd6ac7 bcd3350b + -- response = sendRaw(commandString, true, true) - -- Power off the Proxmark - sendRaw(POWEROFF, false, false) - - disconnect() + -- attempt to read VCProximityKey at block A001 + -- commandString = READPLAINNOMACUNMACED .. "01A0" .. "01" + -- response = sendRaw(commandString, true, true) + + -- authenticate with CardConfigurationKey + -- commandString = AUTH_FIRST .. "0190" .. "00" + -- response = sendRaw(commandString, true, true) + + -- Power off the Proxmark + sendRaw(POWEROFF, false, false) + + disconnect() end main(args) diff --git a/client/scripts/ndef_dump.lua b/client/scripts/ndef_dump.lua index f1bf70ddd..4a740d7e6 100644 --- a/client/scripts/ndef_dump.lua +++ b/client/scripts/ndef_dump.lua @@ -4,20 +4,20 @@ local getopt = require('getopt') local cmds = require('commands') local taglib = require('taglib') -local desc = +local desc = [[This script will automatically recognize and dump full content of a NFC NDEF Initialized tag; non-initialized tags will be ignored. It also write the dump to an eml-file .eml. (The difference between an .eml-file and a .bin-file is that the eml file contains -ASCII representation of the hex-data, with linebreaks between 'rows'. A .bin-file contains the -raw data, but when saving into that for, we lose the infromation about how the memory is structured. -For example: 24 bytes could be 6 blocks of 4 bytes, or vice versa. +ASCII representation of the hex-data, with linebreaks between 'rows'. A .bin-file contains the +raw data, but when saving into that for, we lose the infromation about how the memory is structured. +For example: 24 bytes could be 6 blocks of 4 bytes, or vice versa. Therefore, the .eml is better to use file when saving dumps.) Arguments: - -d debug logging on - -h this help + -h this help + -d debug logging on ]] local example = "script run xxx" @@ -25,116 +25,116 @@ local author = "Martin Holst Swende & Asper" --- -- PrintAndLog local function prlog(...) - -- TODO; replace this with a call to the proper PrintAndLog - print(...) + -- TODO; replace this with a call to the proper PrintAndLog + print(...) end ---- +--- -- This is only meant to be used when errors occur local function oops(err) - prlog("ERROR: ",err) - return nil,err + prlog("ERROR: ",err) + return nil,err end -- Perhaps this will be moved to a separate library at one point local utils = { - --- Writes an eml-file. - -- @param uid - the uid of the tag. Used in filename - -- @param blockData. Assumed to be on the format {'\0\1\2\3,'\b\e\e\f' ..., - -- that is, blockData[row] contains a string with the actual data, not ascii hex representation - -- return filename if all went well, - -- @reurn nil, error message if unsuccessfull - writeDumpFile = function(uid, blockData) - local destination = string.format("%s.eml", uid) - local file = io.open(destination, "w") - if file == nil then - return nil, string.format("Could not write to file %s", destination) - end - local rowlen = string.len(blockData[1]) + --- Writes an eml-file. + -- @param uid - the uid of the tag. Used in filename + -- @param blockData. Assumed to be on the format {'\0\1\2\3,'\b\e\e\f' ..., + -- that is, blockData[row] contains a string with the actual data, not ascii hex representation + -- return filename if all went well, + -- @reurn nil, error message if unsuccessfull + writeDumpFile = function(uid, blockData) + local destination = string.format("%s.eml", uid) + local file = io.open(destination, "w") + if file == nil then + return nil, string.format("Could not write to file %s", destination) + end + local rowlen = string.len(blockData[1]) - for i,block in ipairs(blockData) do - if rowlen ~= string.len(block) then - prlog(string.format("WARNING: Dumpdata seems corrupted, line %d was not the same length as line 1",i)) - end + for i,block in ipairs(blockData) do + if rowlen ~= string.len(block) then + prlog(string.format("WARNING: Dumpdata seems corrupted, line %d was not the same length as line 1",i)) + end - local formatString = string.format("H%d", string.len(block)) - local _,hex = bin.unpack(formatString,block) - file:write(hex.."\n") - end - file:close() - return destination - end, + local formatString = string.format("H%d", string.len(block)) + local _,hex = bin.unpack(formatString,block) + file:write(hex.."\n") + end + file:close() + return destination + end, } ---- +--- -- Usage help local function help() - prlog(desc) - prlog("Example usage") - prlog(example) + prlog(desc) + prlog("Example usage") + prlog(example) end local function debug(...) - if DEBUG then - prlog("debug:", ...) - end + 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" + 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)) - local _,hexdata = bin.unpack(formatString, data) - debug("Hexdata" , hexdata) - end + if DEBUG then + local formatString = ("H%d"):format(string.len(data)) + local _,hexdata = bin.unpack(formatString, data) + debug("Hexdata" , hexdata) + end end --- Fire up a connection with a tag, return uid -- @return UID if successfull -- @return nil, errormessage if unsuccessfull local function open() - debug("Opening connection") - core.clearCommandBuffer() - local x = string.format("hf 14a raw -r -p -s") - debug(x) - core.console(x) - debug("done") - data, err = waitCmd(true) - if err then return oops(err) end - show(data) - local formatString = ("H%d"):format(string.len(data)) - local _,uid = bin.unpack(formatString, data) - return uid + debug("Opening connection") + core.clearCommandBuffer() + local x = string.format("hf 14a raw -r -p -s") + debug(x) + core.console(x) + debug("done") + data, err = waitCmd(true) + if err then return oops(err) end + show(data) + local formatString = ("H%d"):format(string.len(data)) + local _,uid = bin.unpack(formatString, data) + return uid end --- Shut down tag communication -- return no return values local function close() - debug("Closing connection") - core.clearCommandBuffer() - local x = string.format("hf 14a raw -r") - debug(x) - core.console(x) - debug("done") - --data, err = waitCmd(true) - --data, err = waitCmd(false) + debug("Closing connection") + core.clearCommandBuffer() + local x = string.format("hf 14a raw -r") + debug(x) + core.console(x) + debug("done") + --data, err = waitCmd(true) + --data, err = waitCmd(false) end @@ -143,105 +143,105 @@ end -- @return {block, block+1, block+2, block+3} if successfull -- @return nil, errormessage if unsuccessfull local function getBlock(block) - local data, err + local data, err - core.clearCommandBuffer() - - local x = string.format("hf 14a raw -r -c -p 30 %02x", block) - debug(x) - core.console(x) - debug("done") - -- By now, there should be an ACK waiting from the device, since - -- we used the -r flag (don't read response). + core.clearCommandBuffer() - data, err = waitCmd(false) - if err then return oops(err) end - show(data) - - if string.len(data) < 18 then - return nil, ("Expected at least 18 bytes, got %d - this tag is not NDEF-compliant"):format(string.len(data)) - end - -- Now, parse out the block data - -- 0534 00B9 049C AD7F 4A00 0000 E110 1000 2155 - -- b0b0 b0b0 b1b1 b1b1 b2b2 b2b2 b3b3 b3b3 CRCC - b0 = string.sub(data,1,4) - b1 = string.sub(data,5,8) - b2 = string.sub(data,9,12) - b3 = string.sub(data,13,16) - return {b0,b1,b2,b3} + local x = string.format("hf 14a raw -r -c -p 30 %02x", block) + debug(x) + core.console(x) + debug("done") + -- By now, there should be an ACK waiting from the device, since + -- we used the -r flag (don't read response). + + data, err = waitCmd(false) + if err then return oops(err) end + show(data) + + if string.len(data) < 18 then + return nil, ("Expected at least 18 bytes, got %d - this tag is not NDEF-compliant"):format(string.len(data)) + end + -- Now, parse out the block data + -- 0534 00B9 049C AD7F 4A00 0000 E110 1000 2155 + -- b0b0 b0b0 b1b1 b1b1 b2b2 b2b2 b3b3 b3b3 CRCC + b0 = string.sub(data,1,4) + b1 = string.sub(data,5,8) + b2 = string.sub(data,9,12) + b3 = string.sub(data,13,16) + return {b0,b1,b2,b3} end local function main( args) - debug("script started") - local err, data, data2,k,v,i - -- Read the parameters - for o, a in getopt.getopt(args, 'hd') do - if o == "h" then help() return end - if o == "d" then DEBUG = true end - end + debug("script started") + local err, data, data2,k,v,i + -- Read the parameters + for o, a in getopt.getopt(args, 'hd') do + if o == "h" then help() return end + if o == "d" then DEBUG = true end + end - -- Info contained within the tag (block 0 example) - -- 0534 00B9 049C AD7F 4A00 0000 E110 1000 2155 - -- b0b0 b0b0 b1b1 b1b1 b2b2 b2b2 b3b3 b3b3 CRCC - -- MM?? ???? ???? ???? ???? ???? NNVV SS?? ---- - -- M = Manufacturer info - -- N = NDEF-Structure-Compliant (if value is E1) - -- V = NFC Forum Specification version (if 10 = v1.0) + -- Info contained within the tag (block 0 example) + -- 0534 00B9 049C AD7F 4A00 0000 E110 1000 2155 + -- b0b0 b0b0 b1b1 b1b1 b2b2 b2b2 b3b3 b3b3 CRCC + -- MM?? ???? ???? ???? ???? ???? NNVV SS?? ---- + -- M = Manufacturer info + -- N = NDEF-Structure-Compliant (if value is E1) + -- V = NFC Forum Specification version (if 10 = v1.0) - -- First, 'connect' (fire up the field) and get the uid - local uidHexstr = open() + -- First, 'connect' (fire up the field) and get the uid + local uidHexstr = open() - -- First, get blockt 3 byte 2 - local blocks, err = getBlock(0) - if err then return oops(err) end - -- Block 3 contains number of blocks - local b3chars = {string.byte(blocks[4], 1,4)} - local numBlocks = b3chars[3] * 2 + 6 - prlog("Number of blocks:", numBlocks) + -- First, get blockt 3 byte 2 + local blocks, err = getBlock(0) + if err then return oops(err) end + -- Block 3 contains number of blocks + local b3chars = {string.byte(blocks[4], 1,4)} + local numBlocks = b3chars[3] * 2 + 6 + prlog("Number of blocks:", numBlocks) - -- NDEF compliant? - if b3chars[1] ~= 0xE1 then - return oops("This tag is not NDEF-Compliant") - end + -- NDEF compliant? + if b3chars[1] ~= 0xE1 then + return oops("This tag is not NDEF-Compliant") + end - local ndefVersion = b3chars[2] + local ndefVersion = b3chars[2] - -- Block 1, byte 1 contains manufacturer info - local bl1_b1 = string.byte(blocks[1], 1) - local manufacturer = taglib.lookupManufacturer(bl1_b1) + -- Block 1, byte 1 contains manufacturer info + local bl1_b1 = string.byte(blocks[1], 1) + local manufacturer = taglib.lookupManufacturer(bl1_b1) - -- Reuse existing info - local blockData = {blocks[1],blocks[2],blocks[3],blocks[4]} + -- Reuse existing info + local blockData = {blocks[1],blocks[2],blocks[3],blocks[4]} - --[[ Due to the infineon my-d move bug - (if I send 30 0F i receive block0f+block00+block01+block02 insted of block0f+block10+block11+block12) - the only way to avoid this is to send the read command as many times as block numbers - removing bytes from 5 to 18 from each answer. - --]] - prlog("Dumping data...please wait") - for i=4,numBlocks-1,1 do - blocks, err = getBlock(i) - if err then return oops(err) end - table.insert(blockData,blocks[1]) - end - -- Deactivate field - close() - -- Print results - prlog(string.format("Tag manufacturer: %s", manufacturer)) - prlog(string.format("Tag UID: %s", uidHexstr)) - prlog(string.format("Tag NDEF version: 0x%02x", ndefVersion)) - - for k,v in ipairs(blockData) do - prlog(string.format("Block %02x: %02x %02x %02x %02x",k-1, string.byte(v, 1,4))) - end - local filename, err = utils.writeDumpFile(uidHexstr, blockData) - if err then return oops(err) end + --[[ Due to the infineon my-d move bug + (if I send 30 0F i receive block0f+block00+block01+block02 insted of block0f+block10+block11+block12) + the only way to avoid this is to send the read command as many times as block numbers + removing bytes from 5 to 18 from each answer. + --]] + prlog("Dumping data...please wait") + for i=4,numBlocks-1,1 do + blocks, err = getBlock(i) + if err then return oops(err) end + table.insert(blockData,blocks[1]) + end + -- Deactivate field + close() + -- Print results + prlog(string.format("Tag manufacturer: %s", manufacturer)) + prlog(string.format("Tag UID: %s", uidHexstr)) + prlog(string.format("Tag NDEF version: 0x%02x", ndefVersion)) - prlog(string.format("Dumped data into %s", filename)) + for k,v in ipairs(blockData) do + prlog(string.format("Block %02x: %02x %02x %02x %02x",k-1, string.byte(v, 1,4))) + end + local filename, err = utils.writeDumpFile(uidHexstr, blockData) + if err then return oops(err) end + + prlog(string.format("Dumped data into %s", filename)) end main(args) \ No newline at end of file diff --git a/client/scripts/ntag_3d.lua b/client/scripts/ntag_3d.lua index 278f800be..890f29d94 100644 --- a/client/scripts/ntag_3d.lua +++ b/client/scripts/ntag_3d.lua @@ -12,25 +12,25 @@ Thanks to @jack for his invaluable input on some of the configuration. example =[[ -- This will generate GOLD, PLA, TH, EU, 200m, tagbased uid. script run ntag_3d -c 46 -m 50 -p 5448 -s 4555 -l 200 - + -- This will generate GOLD, PLA, TH, EU, 200m, userbased uid. script run ntag_3d -u 11223344556677 -c 46 -m 50 -p 5448 -s 4555 -l 200 - - -- This will generate GOLD, PLA, TH, EU, 200m, userbased uid. and configure a MAGIC NTAG. - script run ntag_3d -u 11223344556677 -c 46 -m 50 -p 5448 -s 4555 -l 200 -1 + + -- This will generate GOLD, PLA, TH, EU, 200m, userbased uid. and configure a MAGIC NTAG. + script run ntag_3d -u 11223344556677 -c 46 -m 50 -p 5448 -s 4555 -l 200 -1 ]] usage = [[ script run calc_ntag_3d -h -t -u -c -m -p -s -l Arguments: - -h : this help - -t : selftest - -u : UID - -c : color of filament - -m : material of filament - -p : Manufacturer region - -s : Sales region - -l : Spool length. Use only 100,200,300. 300 has problems on OSX + -h : this help + -t : selftest + -u : UID + -c : color of filament + -m : material of filament + -p : Manufacturer region + -s : Sales region + -l : Spool length. Use only 100,200,300. 300 has problems on OSX ]] local DEBUG = true @@ -40,344 +40,344 @@ local band = bit32.band local rshift = bit32.rshift local _regions = { - {'4742', 'GB'}, - {'5457', 'TW'}, - {'4555', 'EU'}, - {'5553', 'US'}, - {'454E', 'EN'}, - {'4A50', 'JP'}, - {'434E', 'CN'}, - {'5448', 'TH'}, - {'4153', 'AS'}, - {'5246', 'RF'}, - {'4746', 'GF'}, - {'4341', 'CA'}, - {'504D', 'PM'}, - {'5044', 'PD'}, + {'4742', 'GB'}, + {'5457', 'TW'}, + {'4555', 'EU'}, + {'5553', 'US'}, + {'454E', 'EN'}, + {'4A50', 'JP'}, + {'434E', 'CN'}, + {'5448', 'TH'}, + {'4153', 'AS'}, + {'5246', 'RF'}, + {'4746', 'GF'}, + {'4341', 'CA'}, + {'504D', 'PM'}, + {'5044', 'PD'}, } local _manufacturers = { - {'5457', 'TW'}, - {'434E', 'CN'}, - {'5448', 'TH'}, + {'5457', 'TW'}, + {'434E', 'CN'}, + {'5448', 'TH'}, } local _sales = { - {'4742', 'GB'}, - {'4555', 'EU'}, - {'5553', 'US'}, - {'454E', 'EN'}, - {'504D', 'PM'}, + {'4742', 'GB'}, + {'4555', 'EU'}, + {'5553', 'US'}, + {'454E', 'EN'}, + {'504D', 'PM'}, } local _materials = { - {'20', 'Other material'}, - {'41', 'ABS'}, - {'46', 'Flexible TPE Tree'}, - {'46', 'TPE'}, - {'46', 'PVA'}, - {'47', 'PETG'}, - {'50', 'PLA'}, - {'51', 'PLA'}, - {'54', 'Tough PLA'}, - {'55', 'UVCR'}, - {'56', 'Water Soluble PVA'}, + {'20', 'Other material'}, + {'41', 'ABS'}, + {'46', 'Flexible TPE Tree'}, + {'46', 'TPE'}, + {'46', 'PVA'}, + {'47', 'PETG'}, + {'50', 'PLA'}, + {'51', 'PLA'}, + {'54', 'Tough PLA'}, + {'55', 'UVCR'}, + {'56', 'Water Soluble PVA'}, } local _colors = { - {'30', 'Bronze'}, - {'31', 'Silver'}, - {'32', 'Clear Red'}, - {'33', 'Clear'}, - {'34', 'Bottle Green'}, - {'35', 'Neon Magenta'}, - {'36', 'SteelBlue'}, - {'37', 'Sun Orange'}, - {'38', 'Pearl White'}, - {'39', 'Copper'}, - {'41', 'Purple'}, - {'42', 'Blue'}, - {'43', 'Neon Tangerine'}, - {'44', 'Viridity'}, - {'45', 'Olivine'}, - {'46', 'Gold'}, - {'47', 'Green'}, - {'48', 'Neon Green'}, - {'49', 'Snow White'}, - {'4A', 'Neon Yellow'}, - {'4B', 'Black'}, - {'4C', 'Violet'}, - {'4D', 'Grape Purple'}, - {'4E', 'Purpurine'}, - {'4F', 'Clear Yellow'}, - {'50', 'Clear Green'}, - {'51', 'Clear Tangerine'}, - {'52', 'Red'}, - {'53', 'Cyber Yellow'}, - {'54', 'Tangerine'}, - {'55', 'Clear Blue'}, - {'56', 'Clear Purple'}, - {'57', 'White'}, - {'58', 'Clear Magenta'}, - {'59', 'Yellow'}, - {'5A', 'Nature'}, + {'30', 'Bronze'}, + {'31', 'Silver'}, + {'32', 'Clear Red'}, + {'33', 'Clear'}, + {'34', 'Bottle Green'}, + {'35', 'Neon Magenta'}, + {'36', 'SteelBlue'}, + {'37', 'Sun Orange'}, + {'38', 'Pearl White'}, + {'39', 'Copper'}, + {'41', 'Purple'}, + {'42', 'Blue'}, + {'43', 'Neon Tangerine'}, + {'44', 'Viridity'}, + {'45', 'Olivine'}, + {'46', 'Gold'}, + {'47', 'Green'}, + {'48', 'Neon Green'}, + {'49', 'Snow White'}, + {'4A', 'Neon Yellow'}, + {'4B', 'Black'}, + {'4C', 'Violet'}, + {'4D', 'Grape Purple'}, + {'4E', 'Purpurine'}, + {'4F', 'Clear Yellow'}, + {'50', 'Clear Green'}, + {'51', 'Clear Tangerine'}, + {'52', 'Red'}, + {'53', 'Cyber Yellow'}, + {'54', 'Tangerine'}, + {'55', 'Clear Blue'}, + {'56', 'Clear Purple'}, + {'57', 'White'}, + {'58', 'Clear Magenta'}, + {'59', 'Yellow'}, + {'5A', 'Nature'}, } --- -- local function find( arr, name ) - if not name then return nil end + if not name then return nil end name = name:lower() for k, v in pairs(arr) do - if ( v[2]:lower() == name or v[1]:lower() == name ) then - return v - end - end - return nil + if ( v[2]:lower() == name or v[1]:lower() == name ) then + return v + end + end + return nil end --- -- local function list( arr, desc ) - print ('Value\t'..desc) - print (string.rep('=', 20)) + print ('Value\t'..desc) + print (string.rep('=', 20)) for k, v in pairs(arr) do - print(("%s\t%s"):format(v[1],v[2])) - end + print(("%s\t%s"):format(v[1],v[2])) + end end ---- +--- -- A debug printout-function local function dbg(args) - if not DEBUG then return end - - if type(args) == 'table' then - local i = 1 - while result[i] do - dbg(result[i]) - i = i+1 - end - else - print('###', args) - end -end ---- + if not DEBUG then return end + + if type(args) == 'table' then + local i = 1 + while result[i] do + dbg(result[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) - return nil,err + print('ERROR: ',err) + return nil,err end ---- +--- -- Usage help local function help() - print(copyright) - print(version) - print(desc) - print('Example usage') - print(example) + print(copyright) + print(version) + print(desc) + print('Example usage') + print(example) end -- -- Exit message local function ExitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() end --- -- local function write_tag(uid, t) - print('Writing to tag') - core.console('hf mf dbg 0') - - local cmd = '' - local pwd, pack = core.keygen_algo_d(uid) - - for i= 8, 23 do - cmd = ('hf mfu wrbl b %02d d %s k %08X'):format(i, t[i], pwd) - core.console(cmd) - end - - --cfg1 - core.console(('hf mfu wrbl b 42 d %s k %08X'):format(t[42], pwd)) - --cfg0 - core.console(('hf mfu wrbl b 41 d %s k %08X'):format(t[41], pwd)) - --dynamic - core.console(('hf mfu wrbl b 40 d %s k %08X'):format(t[40], pwd)) - - core.console('hf mf dbg 1') - print('Done') + print('Writing to tag') + core.console('hf mf dbg 0') + + local cmd = '' + local pwd, pack = core.keygen_algo_d(uid) + + for i= 8, 23 do + cmd = ('hf mfu wrbl b %02d d %s k %08X'):format(i, t[i], pwd) + core.console(cmd) + end + + --cfg1 + core.console(('hf mfu wrbl b 42 d %s k %08X'):format(t[42], pwd)) + --cfg0 + core.console(('hf mfu wrbl b 41 d %s k %08X'):format(t[41], pwd)) + --dynamic + core.console(('hf mfu wrbl b 40 d %s k %08X'):format(t[40], pwd)) + + core.console('hf mf dbg 1') + print('Done') end --- -- configures a magic NTAG for NTAG213, with UID and PWD,PACK. local function configure_magic_ntag(uid) - print('Configuring MAGIC NTAG') - -- Save the global args, those are *our* arguments - local myargs = args - - local pwd, pack = core.keygen_algo_d(uid) - - -- Set the arguments for mfu_magic script v1.0.8 - -- -t 12 == configure NTAG213F - -- -u == set UID - -- -p == set pwd - -- -a == set pack - args =('-t 12 -u %s -p %08X -a %04X'):format(uid, pwd, pack) - require('../scripts/mfu_magic') - - -- Set back args. Not that it's used, just for the karma... - args = myargs - - print('Done') + print('Configuring MAGIC NTAG') + -- Save the global args, those are *our* arguments + local myargs = args + + local pwd, pack = core.keygen_algo_d(uid) + + -- Set the arguments for mfu_magic script v1.0.8 + -- -t 12 == configure NTAG213F + -- -u == set UID + -- -p == set pwd + -- -a == set pack + args =('-t 12 -u %s -p %08X -a %04X'):format(uid, pwd, pack) + require('../scripts/mfu_magic') + + -- Set back args. Not that it's used, just for the karma... + args = myargs + + print('Done') end --- -- generates random hex numbers between 31-39 local function random_num_hex(length) - local str = "" - local i - for i = 1, length, 1 do - str = str..math.random(31, 39) - end - return str + local str = "" + local i + for i = 1, length, 1 do + str = str..math.random(31, 39) + end + return str end --- -- local function nwo( val ) - local b1 = band(val, 0xFF) - local b2 = band( rshift(val, 8), 0xFF) - local b3 = band( rshift(val, 16), 0xFF) - local b4 = band( rshift(val, 24), 0xFF) - return ('%02X%02X%02X%02X'):format(b1, b2, b3, b4) + local b1 = band(val, 0xFF) + local b2 = band( rshift(val, 8), 0xFF) + local b3 = band( rshift(val, 16), 0xFF) + local b4 = band( rshift(val, 24), 0xFF) + return ('%02X%02X%02X%02X'):format(b1, b2, b3, b4) end --- -- NTAG213 template local function template_NTAG213(uid, material, color, length, manufacture, sales) - local pwd, pack = core.keygen_algo_d(uid) + local pwd, pack = core.keygen_algo_d(uid) - local m = tonumber(length, 10) * 1000 - local m_str = nwo(m) - - local t = {} - -- default empty file - for i = 0,42 do - t[i] = '00000000' - end --- t[4] = '0103A00C' -- --- t[5] = '340300FE' -- + local m = tonumber(length, 10) * 1000 + local m_str = nwo(m) + + local t = {} + -- default empty file + for i = 0,42 do + t[i] = '00000000' + end +-- t[4] = '0103A00C' -- +-- t[5] = '340300FE' -- -- 6,7 - t[8] = '5A'..material..color..'00' -- 5A, material, color, 00 - t[9] = '00'..random_num_hex(3) -- 00, three bytes serial number - t[10] = m_str -- total capacity - t[11] = m_str -- total capacity - t[12] = 'D2002D00' -- fixed - t[13] = manufacture..sales -- regioner, - t[14] = random_num_hex(4) -- serial number + t[8] = '5A'..material..color..'00' -- 5A, material, color, 00 + t[9] = '00'..random_num_hex(3) -- 00, three bytes serial number + t[10] = m_str -- total capacity + t[11] = m_str -- total capacity + t[12] = 'D2002D00' -- fixed + t[13] = manufacture..sales -- regioner, + t[14] = random_num_hex(4) -- serial number -- 15,16 - t[17] = '34000000' -- fixed + t[17] = '34000000' -- fixed -- 18,19 - -- remaining capacity of spool - t[20] = m_str - t[21] = nwo( bxor( m, 0x54321248)) - t[22] = nwo( bxor( (m - 3876923 ), 0x31275455)) - t[23] = nwo( bxor( (m + 6923923 ), 0x76235481)) --- 24-39 - t[40] = '000000BD' --dynamic - t[41] = '07000008' --cfg0 - t[42] = '80050000' --cfg1 - t[43] = ('%08X'):format(pwd) - t[44] = ('%04X0000'):format(pack) - return t + -- remaining capacity of spool + t[20] = m_str + t[21] = nwo( bxor( m, 0x54321248)) + t[22] = nwo( bxor( (m - 3876923 ), 0x31275455)) + t[23] = nwo( bxor( (m + 6923923 ), 0x76235481)) +-- 24-39 + t[40] = '000000BD' --dynamic + t[41] = '07000008' --cfg0 + t[42] = '80050000' --cfg1 + t[43] = ('%08X'):format(pwd) + t[44] = ('%04X0000'):format(pack) + return t end --- -- outputs the called arguments local function print_conf(uid, material, color, length, producer, sales ) - print('Create tag as following') - print( string.rep('--',16) ) - print('UID ', uid) - print('Material ', material[2]) - print('Color ', color[2]) - print('Spool length ', length) - print('Region') - print(' manufacturer', producer[2]) - print(' sales ', sales[2]) - print( string.rep('--',16) ) + print('Create tag as following') + print( string.rep('--',16) ) + print('UID ', uid) + print('Material ', material[2]) + print('Color ', color[2]) + print('Spool length ', length) + print('Region') + print(' manufacturer', producer[2]) + print(' sales ', sales[2]) + print( string.rep('--',16) ) end --- -- self test -local function selftest() - list(_regions, 'Regions') - list(_materials, 'Materials') - list(_colors, 'Colors') - return nil +local function selftest() + list(_regions, 'Regions') + list(_materials, 'Materials') + list(_colors, 'Colors') + return nil end ---- +--- -- The main entry point local function main(args) - math.randomseed(os.time()); - math.random(); + math.randomseed(os.time()); + math.random(); - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print() - - local uid = '04C5DF4A6D5180' - local useUID = false - local useMAGIC = false - local material, color, length, producer, sales - - if #args == 0 then return help() end + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() - -- Read the parameters - for o, a in getopt.getopt(args, 'ht1u:l:m:c:p:s:') do - if o == "h" then return help() end - if o == "t" then return selftest() end - if o == "u" then uid = a; useUID = true end - if o == "m" then material = a end - if o == "c" then color = a end - if o == "l" then length = tonumber(a) end - if o == "p" then producer = a end - if o == "s" then sales = a end - if o == "1" then useMAGIC = true end - end + local uid = '04C5DF4A6D5180' + local useUID = false + local useMAGIC = false + local material, color, length, producer, sales - color = find(_colors, color) - if not color then list(_colors, 'Colors'); return oops('\n\nNot valid color') end - - material = find(_materials, material) - if not material then list(_materials, 'Materials'); return oops('\n\nNot valid material') end - - producer = find(_manufacturers, producer) - if not producer then list(_manufacturers, 'Regions Manufacturers'); return oops('\n\nNo valid manufacturer region') end + if #args == 0 then return help() end - sales = find(_sales, sales) - if not sales then list(_sales, 'Regions Sales'); return oops('\n\nNo valid sales region') end - - if length > 300 then - return oops('\n\nNot valid spool length. Must be lesser than 300') - end - - if useUID then - -- uid string checks - if uid == nil then return oops('empty uid string') end - if #uid == 0 then return oops('empty uid string') end - if #uid ~= 14 then return oops('uid wrong length. Should be 7 hex bytes') end - else - -- GET TAG UID - local tag, err = lib14a.read(false, true) - if not tag then return oops(err) end - core.clearCommandBuffer() - uid = tag.uid - end + -- Read the parameters + for o, a in getopt.getopt(args, 'ht1u:l:m:c:p:s:') do + if o == "h" then return help() end + if o == "t" then return selftest() end + if o == "u" then uid = a; useUID = true end + if o == "m" then material = a end + if o == "c" then color = a end + if o == "l" then length = tonumber(a) end + if o == "p" then producer = a end + if o == "s" then sales = a end + if o == "1" then useMAGIC = true end + end - --print - print_conf(uid, material, color, length, producer, sales ) - - -- create template - local t = template_NTAG213(uid, material[1], color[1], length, producer[1], sales[1]) + color = find(_colors, color) + if not color then list(_colors, 'Colors'); return oops('\n\nNot valid color') end - -- using MAGIC NTAG - if useMAGIC then - configure_magic_ntag(uid) - end - - -- write template data to tag - write_tag(uid, t) + material = find(_materials, material) + if not material then list(_materials, 'Materials'); return oops('\n\nNot valid material') end + + producer = find(_manufacturers, producer) + if not producer then list(_manufacturers, 'Regions Manufacturers'); return oops('\n\nNo valid manufacturer region') end + + sales = find(_sales, sales) + if not sales then list(_sales, 'Regions Sales'); return oops('\n\nNo valid sales region') end + + if length > 300 then + return oops('\n\nNot valid spool length. Must be lesser than 300') + end + + if useUID then + -- uid string checks + if uid == nil then return oops('empty uid string') end + if #uid == 0 then return oops('empty uid string') end + if #uid ~= 14 then return oops('uid wrong length. Should be 7 hex bytes') end + else + -- GET TAG UID + local tag, err = lib14a.read(false, true) + if not tag then return oops(err) end + core.clearCommandBuffer() + uid = tag.uid + end + + --print + print_conf(uid, material, color, length, producer, sales ) + + -- create template + local t = template_NTAG213(uid, material[1], color[1], length, producer[1], sales[1]) + + -- using MAGIC NTAG + if useMAGIC then + configure_magic_ntag(uid) + end + + -- write template data to tag + write_tag(uid, t) end main(args) \ No newline at end of file diff --git a/client/scripts/parameters.lua b/client/scripts/parameters.lua index fa260204f..f51266f7f 100644 --- a/client/scripts/parameters.lua +++ b/client/scripts/parameters.lua @@ -6,40 +6,40 @@ getopt = require('getopt') usage = "script run parameters.lua -a 1 -blala -c -de" author = "Martin Holst Swende" desc =[[ -This is an example script to demonstrate handle parameters in scripts. +This is an example script to demonstrate handle parameters in scripts. For more info, check the comments in the code ]] local function main(args) - print(desc) - print("These parameters were passed") - --[[ - When passing parameters, - x: means that a value should follow x - y means that 'y' is a flag, either on or off - So, the string a:b:def means that we support up to - 5 parameters; two with values and three flags. The following - should be valid: + print(desc) + print("These parameters were passed") + --[[ + When passing parameters, + x: means that a value should follow x + y means that 'y' is a flag, either on or off + So, the string a:b:def means that we support up to + 5 parameters; two with values and three flags. The following + should be valid: - script run parameters.lua -a 1 -blala -c -de + script run parameters.lua -a 1 -blala -c -de - Notice two things: - 1. 'blala' works just like 'b lala', both set 'b' to 'lala' - 2. Flags can be put together, '-de' is the same as '-d -e' - 3. The format -b=lala is *not* supported - 4. The format b lala (without -) is *not* supported - --]] + Notice two things: + 1. 'blala' works just like 'b lala', both set 'b' to 'lala' + 2. Flags can be put together, '-de' is the same as '-d -e' + 3. The format -b=lala is *not* supported + 4. The format b lala (without -) is *not* supported + --]] - for o, a in getopt.getopt(args, 'a:b:ced') do - print(o, a) - end + for o, a in getopt.getopt(args, 'a:b:ced') do + print(o, a) + end end --[[ -In the future, we may implement so that scripts are invoked directly +In the future, we may implement so that scripts are invoked directly into a 'main' function, instead of being executed blindly. For future -compatibility, I have done so, but I invoke my main from here. +compatibility, I have done so, but I invoke my main from here. --]] main(args) \ No newline at end of file diff --git a/client/scripts/read_pwd_mem.lua b/client/scripts/read_pwd_mem.lua index a0688a639..4611c32cc 100644 --- a/client/scripts/read_pwd_mem.lua +++ b/client/scripts/read_pwd_mem.lua @@ -1,141 +1,141 @@ -local getopt = require('getopt') -local bin = require('bin') - -copyright = 'Copyright (c) 2018 Bogito. All rights reserved.' -author = "Bogito" -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: - script run read_pwd_mem -h -o -l -k - -Arguments: - -h : this help - -o : memory offset, default is 0 - -l : length in bytes, default is 256 - -k : 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 = -[[ - -- This will scan the first 256 bytes of flash memory for stored passwords - script run read_pwd_mem - - -- This will scan 256 bytes of flash memory at offset 64 for stored passwords - script run read_pwd_mem -o 64 - - -- 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) - - 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 - - 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 oops('Error: Length is not valid. Must be less than 256') - end - - if (offset < 0) or (offset % 4 ~= 0) then - return oops('Error: Offset is not valid. Mod-4 values are only allowed.') - end - - print('Memory offset', offset) - print('Length ', length) - print('Key length ', keylength) - print( string.rep('--',20) ) - - if usedkey then length = 4096 end - - data, err = core.GetFromFlashMem(offset, length) - if err then return oops(err) end - - 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 - print( string.rep('--',20) ) -end - -main(args) +local getopt = require('getopt') +local bin = require('bin') + +copyright = 'Copyright (c) 2018 Bogito. All rights reserved.' +author = "Bogito" +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: + script run read_pwd_mem -h -o -l -k + +Arguments: + -h : this help + -o : memory offset, default is 0 + -l : length in bytes, default is 256 + -k : 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 = +[[ + -- This will scan the first 256 bytes of flash memory for stored passwords + script run read_pwd_mem + + -- This will scan 256 bytes of flash memory at offset 64 for stored passwords + script run read_pwd_mem -o 64 + + -- 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) + + 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 + + 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 oops('Error: Length is not valid. Must be less than 256') + end + + if (offset < 0) or (offset % 4 ~= 0) then + return oops('Error: Offset is not valid. Mod-4 values are only allowed.') + end + + print('Memory offset', offset) + print('Length ', length) + print('Key length ', keylength) + print( string.rep('--',20) ) + + if usedkey then length = 4096 end + + data, err = core.GetFromFlashMem(offset, length) + if err then return oops(err) end + + 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 + print( string.rep('--',20) ) +end + +main(args) diff --git a/client/scripts/remagic.lua b/client/scripts/remagic.lua index 10e25583a..29e9a2c56 100644 --- a/client/scripts/remagic.lua +++ b/client/scripts/remagic.lua @@ -4,100 +4,100 @@ example = "script run remagic" author = "Iceman" desc = [[ -This is a script that tries to bring back a chinese magic card (1k generation1) +This is a script that tries to bring back a chinese magic card (1k generation1) from the dead when it's block 0 has been written with bad values. or mifare Ultralight magic card which answers to chinese backdoor commands Arguments: - -h this help - -u remagic a Ultralight tag w 7 bytes UID. + -h this help + -u remagic a Ultralight tag w 7 bytes UID. ]] ---- +--- -- A debug printout-function local function dbg(args) - if DEBUG then - print('###', args) - end -end ---- + if DEBUG then + print('###', args) + end +end +--- -- This is only meant to be used when errors occur local function oops(err) - print('ERROR: ',err) + print('ERROR: ',err) end ---- +--- -- Usage help local function help() - print(desc) - print('Example usage') - print(example) + print(desc) + print('Example usage') + print(example) end local function cmdUltralight() - return { + return { --[[ --]] - [0] = "hf 14a raw -p -a -b 7 40", - [1] = "hf 14a raw -p -a 43", - [2] = "hf 14a raw -c -a A2005380712A", - [3] = "hf 14a raw -p -a -b 7 40", - [4] = "hf 14a raw -p -a 43", - [5] = "hf 14a raw -c -a A2010200D980", - [6] = "hf 14a raw -p -a -b 7 40", - [7] = "hf 14a raw -p -a 43", - [8] = "hf 14a raw -c -a A2025B480000", - [9] = "hf 14a raw -c -a 5000", - } + [0] = "hf 14a raw -p -a -b 7 40", + [1] = "hf 14a raw -p -a 43", + [2] = "hf 14a raw -c -a A2005380712A", + [3] = "hf 14a raw -p -a -b 7 40", + [4] = "hf 14a raw -p -a 43", + [5] = "hf 14a raw -c -a A2010200D980", + [6] = "hf 14a raw -p -a -b 7 40", + [7] = "hf 14a raw -p -a 43", + [8] = "hf 14a raw -c -a A2025B480000", + [9] = "hf 14a raw -c -a 5000", + } end local function cmdClassic() - return { + return { --[[ --]] - [0] = "hf 14a raw -p -a -b 7 40", - [1] = "hf 14a raw -p -a 43", - [2] = "hf 14a raw -c -p -a A000", - [3] = "hf 14a raw -c -p -a 01020304049802000000000000001001", - [4] = "hf 14a raw -c -a 5000", - } + [0] = "hf 14a raw -p -a -b 7 40", + [1] = "hf 14a raw -p -a 43", + [2] = "hf 14a raw -c -p -a A000", + [3] = "hf 14a raw -c -p -a 01020304049802000000000000001001", + [4] = "hf 14a raw -c -a 5000", + } end local function cmdRestoreST() - local arr = {} - for i = 0, 15 do - local blk = 3 + (4*i) - arr[i] = "hf mf csetbl "..blk.." FFFFFFFFFFFFFF078000FFFFFFFFFFFF" - end - return arr -end -local function sendCmds( cmds ) - for i = 0, #cmds do - if cmds[i] then - print ( cmds[i] ) - core.console( cmds[i] ) - core.clearCommandBuffer() - end - end + local arr = {} + for i = 0, 15 do + local blk = 3 + (4*i) + arr[i] = "hf mf csetbl "..blk.." FFFFFFFFFFFFFF078000FFFFFFFFFFFF" + end + return arr end ---- +local function sendCmds( cmds ) + for i = 0, #cmds do + if cmds[i] then + print ( cmds[i] ) + core.console( cmds[i] ) + core.clearCommandBuffer() + end + end +end +--- -- The main entry point function main(args) - local i - local cmds = {} - local isUltralight = false - - -- Read the parameters - for o, a in getopt.getopt(args, 'hu') do - if o == "h" then return help() end - if o == "u" then isUltralight = true end - end + local i + local cmds = {} + local isUltralight = false - core.clearCommandBuffer() - - if isUltralight then - sendCmds ( cmdUltralight() ) - else - sendCmds( cmdClassic() ) - sendCmds( cmdRestoreST() ) - end + -- Read the parameters + for o, a in getopt.getopt(args, 'hu') do + if o == "h" then return help() end + if o == "u" then isUltralight = true end + end + + core.clearCommandBuffer() + + if isUltralight then + sendCmds ( cmdUltralight() ) + else + sendCmds( cmdClassic() ) + sendCmds( cmdRestoreST() ) + end end main(args) diff --git a/client/scripts/test_t55x7_ask.lua b/client/scripts/test_t55x7_ask.lua index 189cc4734..3f224b28a 100644 --- a/client/scripts/test_t55x7_ask.lua +++ b/client/scripts/test_t55x7_ask.lua @@ -7,7 +7,7 @@ local format=string.format local floor=math.floor example =[[ - 1. script run test_t55x7_ask + 1. script run test_t55x7_ask ]] author = "Iceman" usage = "script run test_t55x7_ask" @@ -15,32 +15,32 @@ desc =[[ This script will program a T55x7 TAG with the configuration: block 0x00 data 0x000100 The outlined procedure is as following: ---ASK - 00 00 80 40 +--ASK + 00 00 80 40 -- max 2 -- manchester -- bit rate - + "lf t55xx write b 0 d 00008040" "lf t55xx detect" "lf t55xx info" Loop: - change the configuretion block 0 with: - -xx 00 xxxx = RF/8 - -xx 04 xxxx = RF/16 - -xx 08 xxxx = RF/32 - -xx 0C xxxx = RF/40 - -xx 10 xxxx = RF/50 - -xx 14 xxxx = RF/64 - -xx 18 xxxx = RF/100 - -xx 1C xxxx = RF/128 + change the configuretion block 0 with: + -xx 00 xxxx = RF/8 + -xx 04 xxxx = RF/16 + -xx 08 xxxx = RF/32 + -xx 0C xxxx = RF/40 + -xx 10 xxxx = RF/50 + -xx 14 xxxx = RF/64 + -xx 18 xxxx = RF/100 + -xx 1C xxxx = RF/128 testsuit for the ASK/MANCHESTER demod Arguments: - -h : this help + -h : this help ]] local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds @@ -51,90 +51,90 @@ local config1 = '00' local config2 = '8040' local procedurecmds = { - [1] = '%s%02X%s', - [2] = 'lf t55xx detect', - [3] = 'lf t55xx info', + [1] = '%s%02X%s', + [2] = 'lf t55xx detect', + [3] = 'lf t55xx info', } ---- +--- -- A debug printout-function local function dbg(args) - if not DEBUG then - return - end - + 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 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) + print("ERROR: ",err) end ---- +--- -- Usage help local function help() - print(desc) - print("Example usage") - print(example) + print(desc) + print("Example usage") + print(example) end -- -- Exit message local function ExitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() end local function test() - local y - local block = "00" - for y = 0x0, 0x1d, 0x4 do - for _ = 1, #procedurecmds do - local pcmd = procedurecmds[_] - - if #pcmd == 0 then - - elseif _ == 1 then + local y + local block = "00" + for y = 0x0, 0x1d, 0x4 do + for _ = 1, #procedurecmds do + local pcmd = procedurecmds[_] - local config = pcmd:format(config1, y, config2) - dbg(('lf t55xx write b 0 d %s'):format(config)) - config = tonumber(config,16) - - local writecmd = Command:new{cmd = cmds.CMD_T55XX_WRITE_BLOCK,arg1 = config, arg2 = block, arg3 = "00", data = "00"} - local err = core.SendCommand(writecmd:getBytes()) - if err then return oops(err) end - local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) + if #pcmd == 0 then - else - dbg(pcmd) - core.console( pcmd ) - end - end - core.clearCommandBuffer() - end - print( string.rep('--',20) ) + elseif _ == 1 then + + local config = pcmd:format(config1, y, config2) + dbg(('lf t55xx write b 0 d %s'):format(config)) + config = tonumber(config,16) + + local writecmd = Command:new{cmd = cmds.CMD_T55XX_WRITE_BLOCK,arg1 = config, arg2 = block, arg3 = "00", data = "00"} + local err = core.SendCommand(writecmd:getBytes()) + if err then return oops(err) end + local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) + + else + dbg(pcmd) + core.console( pcmd ) + end + end + core.clearCommandBuffer() + end + print( string.rep('--',20) ) end local function main(args) - print( string.rep('--',20) ) - print( string.rep('--',20) ) + print( string.rep('--',20) ) + print( string.rep('--',20) ) - -- Arguments for the script - for o, arg in getopt.getopt(args, 'h') do - if o == "h" then return help() end - end + -- Arguments for the script + for o, arg in getopt.getopt(args, 'h') do + if o == "h" then return help() end + end - core.clearCommandBuffer() - test() - print( string.rep('--',20) ) + core.clearCommandBuffer() + test() + print( string.rep('--',20) ) end main(args) \ No newline at end of file diff --git a/client/scripts/test_t55x7_bi.lua b/client/scripts/test_t55x7_bi.lua index f9a0688fe..dce5350dc 100644 --- a/client/scripts/test_t55x7_bi.lua +++ b/client/scripts/test_t55x7_bi.lua @@ -4,7 +4,7 @@ local bin = require('bin') local utils = require('utils') example =[[ - 1. script run test_t55x7_bi + 1. script run test_t55x7_bi ]] author = "Iceman" usage = "script run test_t55x7_bi" @@ -20,21 +20,21 @@ The outlined procedure is as following: "lf t55xx info" Loop: - change the configuretion block 0 with: - -xx01xxxx = RF/8 + change the configuretion block 0 with: + -xx01xxxx = RF/8 -xx05xxxx = RF/16 - -xx09xxxx = RF/32 - -xx0Dxxxx = RF/40 - -xx11xxxx = RF/50 - -xx15xxxx = RF/64 - -xx19xxxx = RF/100 - -xx1Dxxxx = RF/128 + -xx09xxxx = RF/32 + -xx0Dxxxx = RF/40 + -xx11xxxx = RF/50 + -xx15xxxx = RF/64 + -xx19xxxx = RF/100 + -xx1Dxxxx = RF/128 testsuit for the BIPHASE demod Arguments: - -h : this help + -h : this help ]] local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds @@ -45,90 +45,90 @@ local config1 = '00' local config2 = '0040' local procedurecmds = { - [1] = '%s%02X%s', - [2] = 'lf t55xx detect', - [3] = 'lf t55xx info', + [1] = '%s%02X%s', + [2] = 'lf t55xx detect', + [3] = 'lf t55xx info', } ---- +--- -- A debug printout-function local function dbg(args) - if not DEBUG then - return - end - + 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 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) + print("ERROR: ",err) end ---- +--- -- Usage help local function help() - print(desc) - print("Example usage") - print(example) + print(desc) + print("Example usage") + print(example) end -- -- Exit message local function ExitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() end local function test() - local y - local block = "00" - for y = 1, 0x1D, 4 do - for _ = 1, #procedurecmds do - local pcmd = procedurecmds[_] - - if #pcmd == 0 then - - elseif _ == 1 then + local y + local block = "00" + for y = 1, 0x1D, 4 do + for _ = 1, #procedurecmds do + local pcmd = procedurecmds[_] - local config = pcmd:format(config1, y, config2) - dbg(('lf t55xx write b 0 d %s'):format(config)) - - config = tonumber(config,16) - local writecmd = Command:new{cmd = cmds.CMD_T55XX_WRITE_BLOCK,arg1 = config, arg2 = block, arg3 = "00", data = "00"} - local err = core.SendCommand(writecmd:getBytes()) - if err then return oops(err) end - local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) - else - dbg(pcmd) - core.console( pcmd ) - end - end - core.clearCommandBuffer() - end - print( string.rep('--',20) ) + if #pcmd == 0 then + + elseif _ == 1 then + + local config = pcmd:format(config1, y, config2) + dbg(('lf t55xx write b 0 d %s'):format(config)) + + config = tonumber(config,16) + local writecmd = Command:new{cmd = cmds.CMD_T55XX_WRITE_BLOCK,arg1 = config, arg2 = block, arg3 = "00", data = "00"} + local err = core.SendCommand(writecmd:getBytes()) + if err then return oops(err) end + local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) + else + dbg(pcmd) + core.console( pcmd ) + end + end + core.clearCommandBuffer() + end + print( string.rep('--',20) ) end local function main(args) - print( string.rep('--',20) ) - print( string.rep('--',20) ) + print( string.rep('--',20) ) + print( string.rep('--',20) ) - -- Arguments for the script - for o, arg in getopt.getopt(args, 'h') do - if o == "h" then return help() end - end + -- Arguments for the script + for o, arg in getopt.getopt(args, 'h') do + if o == "h" then return help() end + end - core.clearCommandBuffer() - test() - print( string.rep('--',20) ) + core.clearCommandBuffer() + test() + print( string.rep('--',20) ) end main(args) diff --git a/client/scripts/test_t55x7_fsk.lua b/client/scripts/test_t55x7_fsk.lua index 0d067b96a..9dbb1b6bb 100644 --- a/client/scripts/test_t55x7_fsk.lua +++ b/client/scripts/test_t55x7_fsk.lua @@ -4,7 +4,7 @@ local bin = require('bin') local utils = require('utils') example =[[ - 1. script run test_t55x7_fsk + 1. script run test_t55x7_fsk ]] author = "Iceman" usage = "script run test_t55x7_fsk" @@ -12,32 +12,32 @@ desc =[[ This script will program a T55x7 TAG with the configuration: block 0x00 data 0x000100 The outlined procedure is as following: ---ASK - 00 00 80 40 +--ASK + 00 00 80 40 -- max 2 blocks -- FSK1 -- bit rate - + "lf t55xx write b 0 d 00007040" "lf t55xx detect" "lf t55xx info" Loop: - change the configuretion block 0 with: - -xx 00 xxxx = RF/8 + change the configuretion block 0 with: + -xx 00 xxxx = RF/8 -xx 04 xxxx = RF/16 - -xx 08 xxxx = RF/32 - -xx 0C xxxx = RF/40 - -xx 10 xxxx = RF/50 - -xx 14 xxxx = RF/64 - -xx 18 xxxx = RF/100 - -xx 1C xxxx = RF/128 + -xx 08 xxxx = RF/32 + -xx 0C xxxx = RF/40 + -xx 10 xxxx = RF/50 + -xx 14 xxxx = RF/64 + -xx 18 xxxx = RF/100 + -xx 1C xxxx = RF/128 testsuit for the ASK/MANCHESTER demod Arguments: - -h : this help + -h : this help ]] local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds @@ -48,93 +48,93 @@ local config1 = '00' local config2 = '040' local procedurecmds = { - [1] = '%s%02X%X%s', - [2] = 'lf t55xx detect', - [3] = 'lf t55xx info', + [1] = '%s%02X%X%s', + [2] = 'lf t55xx detect', + [3] = 'lf t55xx info', } ---- +--- -- A debug printout-function local function dbg(args) - if not DEBUG then - return - end - + 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 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) + print("ERROR: ",err) end ---- +--- -- Usage help local function help() - print(desc) - print("Example usage") - print(example) + print(desc) + print("Example usage") + print(example) end -- -- Exit message local function ExitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() end local function test(modulation) - local y - local block = "00" - for y = 0x0, 0x1d, 0x4 do - for _ = 1, #procedurecmds do - local pcmd = procedurecmds[_] - - if #pcmd == 0 then - - elseif _ == 1 then + local y + local block = "00" + for y = 0x0, 0x1d, 0x4 do + for _ = 1, #procedurecmds do + local pcmd = procedurecmds[_] - local config = pcmd:format(config1, y, modulation, config2) - dbg(('lf t55xx write b 0 d %s'):format(config)) - - config = tonumber(config,16) - local writecmd = Command:new{cmd = cmds.CMD_T55XX_WRITE_BLOCK,arg1 = config, arg2 = block, arg3 = "00", data = "00"} - local err = core.SendCommand(writecmd:getBytes()) - if err then return oops(err) end - local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) + if #pcmd == 0 then - else - dbg(pcmd) - core.console( pcmd ) - end - end - core.clearCommandBuffer() - end - print( string.rep('--',20) ) + elseif _ == 1 then + + local config = pcmd:format(config1, y, modulation, config2) + dbg(('lf t55xx write b 0 d %s'):format(config)) + + config = tonumber(config,16) + local writecmd = Command:new{cmd = cmds.CMD_T55XX_WRITE_BLOCK,arg1 = config, arg2 = block, arg3 = "00", data = "00"} + local err = core.SendCommand(writecmd:getBytes()) + if err then return oops(err) end + local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) + + else + dbg(pcmd) + core.console( pcmd ) + end + end + core.clearCommandBuffer() + end + print( string.rep('--',20) ) end local function main(args) - print( string.rep('--',20) ) - print( string.rep('--',20) ) + print( string.rep('--',20) ) + print( string.rep('--',20) ) - -- Arguments for the script - for o, arg in getopt.getopt(args, 'h') do - if o == "h" then return help() end - end + -- Arguments for the script + for o, arg in getopt.getopt(args, 'h') do + if o == "h" then return help() end + end - core.clearCommandBuffer() - test(4) - test(5) - test(6) - test(7) - print( string.rep('--',20) ) + core.clearCommandBuffer() + test(4) + test(5) + test(6) + test(7) + print( string.rep('--',20) ) end main(args) \ No newline at end of file diff --git a/client/scripts/test_t55x7_psk.lua b/client/scripts/test_t55x7_psk.lua index 15bdb71d3..bd3aa2f79 100644 --- a/client/scripts/test_t55x7_psk.lua +++ b/client/scripts/test_t55x7_psk.lua @@ -4,8 +4,8 @@ local bin = require('bin') local utils = require('utils') example =[[ - 1. script run test_t55x7_psk - 2. script run test_t55x7_psk -o + 1. script run test_t55x7_psk + 2. script run test_t55x7_psk -o ]] author = "Iceman" usage = "script run test_t55x7_psk" @@ -18,21 +18,21 @@ The outlined procedure is as following: "lf t55xx info" Loop OUTER: - change the configuretion block 0 with: + change the configuretion block 0 with: -xxxx8xxx = PSK RF/2 with Manchester modulation -xxxx1xxx = PSK RF/2 with PSK1 modulation (phase change when input changes) -xxxx2xxx = PSK RF/2 with PSk2 modulation (phase change on bitclk if input high) -xxxx3xxx = PSK RF/2 with PSk3 modulation (phase change on rising edge of input) - Loop INNER - for each outer configuration, also do - XXXXX0XX = PSK RF/2 - XXXXX4XX = PSK RF/4 - XXXXX8XX = PSK RF/8 + Loop INNER + for each outer configuration, also do + XXXXX0XX = PSK RF/2 + XXXXX4XX = PSK RF/4 + XXXXX8XX = PSK RF/8 In all 12 individual test for the PSK demod Arguments: - -h : this help + -h : this help ]] local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds @@ -40,111 +40,111 @@ local DEBUG = true -- the debug flag -- --BLOCK 0 = 00 08 80 40 PSK -- ----------- - -- 08------- bitrate - -- 8----- modulation PSK1 - -- 0---- PSK ClockRate - -- 40 max 2 blocks + -- 08------- bitrate + -- 8----- modulation PSK1 + -- 0---- PSK ClockRate + -- 40 max 2 blocks local procedurecmds = { - [1] = '00%02X%X%X40', - [2] = 'lf t55xx detect', - [3] = 'lf t55xx info', + [1] = '00%02X%X%X40', + [2] = 'lf t55xx detect', + [3] = 'lf t55xx info', } ---- +--- -- A debug printout-function local function dbg(args) - if not DEBUG then - return - end - + 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 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) + print("ERROR: ",err) end ---- +--- -- Usage help local function help() - print(desc) - print("Example usage") - print(example) + print(desc) + print("Example usage") + print(example) end -- -- Exit message local function ExitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() end local function test(modulation) - local bitrate - local clockrate - local block = "00" - for bitrate = 0x0, 0x1d, 0x4 do - - for clockrate = 0,8,4 do + local bitrate + local clockrate + local block = "00" + for bitrate = 0x0, 0x1d, 0x4 do - for _ = 1, #procedurecmds do - local cmd = procedurecmds[_] - - if #cmd == 0 then - - elseif _ == 1 then + for clockrate = 0,8,4 do - dbg("Writing to T55x7 TAG") + for _ = 1, #procedurecmds do + local cmd = procedurecmds[_] - local config = cmd:format(bitrate, modulation, clockrate) - dbg(('lf t55xx write b 0 d %s'):format(config)) - - config = tonumber(config,16) - local writecmd = Command:new{cmd = cmds.CMD_T55XX_WRITE_BLOCK,arg1 = config, arg2 = block, arg3 = "00", data = "00"} - local err = core.SendCommand(writecmd:getBytes()) - if err then return oops(err) end - local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) - else - dbg(cmd) - core.console( cmd ) - end - end - core.clearCommandBuffer() - end - end - print( string.rep('--',20) ) + if #cmd == 0 then + + elseif _ == 1 then + + dbg("Writing to T55x7 TAG") + + local config = cmd:format(bitrate, modulation, clockrate) + dbg(('lf t55xx write b 0 d %s'):format(config)) + + config = tonumber(config,16) + local writecmd = Command:new{cmd = cmds.CMD_T55XX_WRITE_BLOCK,arg1 = config, arg2 = block, arg3 = "00", data = "00"} + local err = core.SendCommand(writecmd:getBytes()) + if err then return oops(err) end + local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) + else + dbg(cmd) + core.console( cmd ) + end + end + core.clearCommandBuffer() + end + end + print( string.rep('--',20) ) end local function main(args) - print( string.rep('--',20) ) - print( string.rep('--',20) ) + print( string.rep('--',20) ) + print( string.rep('--',20) ) - -- Arguments for the script - for o, arg in getopt.getopt(args, 'h') do - if o == "h" then return help() end - end + -- Arguments for the script + for o, arg in getopt.getopt(args, 'h') do + if o == "h" then return help() end + end - core.clearCommandBuffer() + core.clearCommandBuffer() - test(1) -- PSK1 - --test(2) -- PSK2 - --test(3) -- PSK3 - - print( string.rep('--',20) ) + test(1) -- PSK1 + --test(2) -- PSK2 + --test(3) -- PSK3 + + print( string.rep('--',20) ) end main(args) --- Where it iterates over +-- Where it iterates over -- xxxx8xxx = PSK RF/2 with Manchester modulation -- xxxx1xxx = PSK RF/2 with PSK1 modulation (phase change when input changes) -- xxxx2xxx = PSK RF/2 with PSk2 modulation (phase change on bitclk if input high) diff --git a/client/scripts/tnp3clone.lua b/client/scripts/tnp3clone.lua index b17cf2661..386a7e25c 100644 --- a/client/scripts/tnp3clone.lua +++ b/client/scripts/tnp3clone.lua @@ -11,10 +11,10 @@ local bor = bit32.bor local band = bit32.band example =[[ - script run tnp3clone - script run tnp3clone -h - script run tnp3clone -l - script run tnp3clone -t aa00 -s 0030 + script run tnp3clone + script run tnp3clone -h + script run tnp3clone -l + script run tnp3clone -t aa00 -s 0030 ]] author = "Iceman" @@ -23,152 +23,152 @@ desc =[[ This script will try making a barebone clone of a tnp3 tag on to a magic generation1 card. Arguments: - -h : this help - -l : list all known toy tokens - -t : toytype id, 4hex symbols - -s : subtype id, 4hex symbols - - For fun, try the following subtype id: - 0612 - Lightcore - 0118 - Series 1 - 0138 - Series 2 - 0234 - Special - 023c - Special - 0020 - Swapforce + -h : this help + -l : list all known toy tokens + -t : toytype id, 4hex symbols + -s : subtype id, 4hex symbols + + For fun, try the following subtype id: + 0612 - Lightcore + 0118 - Series 1 + 0138 - Series 2 + 0234 - Special + 023c - Special + 0020 - Swapforce ]] -- This is only meant to be used when errors occur local function oops(err) - print("ERROR: ",err) + print("ERROR: ",err) end -- Usage help local function help() - print(desc) - print("Example usage") - print(example) + print(desc) + print("Example usage") + print(example) end local function waitCmd() - local response = core.WaitForResponseTimeout(cmds.CMD_ACK,2000) - if response then - local count,cmd,arg0 = bin.unpack('LL',response) - if(arg0==1) then - local count,arg1,arg2,data = bin.unpack('LLH511',response,count) - return data:sub(1,32) - else - return nil, "Couldn't read block." - end - end - return nil, "No response from device" + local response = core.WaitForResponseTimeout(cmds.CMD_ACK,2000) + if response then + local count,cmd,arg0 = bin.unpack('LL',response) + if(arg0==1) then + local count,arg1,arg2,data = bin.unpack('LLH511',response,count) + return data:sub(1,32) + else + return nil, "Couldn't read block." + end + end + return nil, "No response from device" end local function readblock( blocknum, keyA ) - -- 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 - local block0, err = waitCmd() - if err then return nil, err end - return block0 + -- 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 + local block0, err = waitCmd() + if err then return nil, err end + return block0 end local function readmagicblock( blocknum ) - -- 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()) - if err then return nil, err end - local block0, err = waitCmd() - if err then return nil, err end - return block0 + -- 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()) + if err then return nil, err end + local block0, err = waitCmd() + if err then return nil, err end + return block0 end local function main(args) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - - local numBlocks = 64 - local cset = 'hf mf csetbl ' - local csetuid = 'hf mf csetuid ' - local cget = 'hf mf cgetbl ' - local empty = '00000000000000000000000000000000' - local AccAndKeyB = '7F0F0869000000000000' - local atqa = '0F01' - local sak = '81' - -- Defaults to Gusto - local toytype = 'C201' - local subtype = '0030' - local DEBUG = true - - -- Arguments for the script - for o, a in getopt.getopt(args, 'ht:s:l') do - if o == "h" then return help() end - if o == "t" then toytype = a end - if o == "s" then subtype = a end - if o == "l" then return toys.List() end - end + print( string.rep('--',20) ) + print( string.rep('--',20) ) - if #toytype ~= 4 then return oops('[!] Wrong size - toytype. (4hex symbols)') end - if #subtype ~= 4 then return oops('[!] Wrong size - subtype. (4hex symbols)') end + local numBlocks = 64 + local cset = 'hf mf csetbl ' + local csetuid = 'hf mf csetuid ' + local cget = 'hf mf cgetbl ' + local empty = '00000000000000000000000000000000' + local AccAndKeyB = '7F0F0869000000000000' + local atqa = '0F01' + local sak = '81' + -- Defaults to Gusto + local toytype = 'C201' + local subtype = '0030' + local DEBUG = true - -- 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]) ) - else - print('[-] Didn\'t find item type. If you are sure about it, post on forum') - end - --15,16 - --13-14 - - -- find tag - result, err = lib14a.read(false, true) - if not result then return oops(err) end + -- Arguments for the script + for o, a in getopt.getopt(args, 'ht:s:l') do + if o == "h" then return help() end + if o == "t" then toytype = a end + if o == "s" then subtype = a end + if o == "l" then return toys.List() end + end - -- load keys - local akeys = pre.GetAll(result.uid) - local keyA = akeys:sub(1, 12 ) + if #toytype ~= 4 then return oops('[!] Wrong size - toytype. (4hex symbols)') end + if #subtype ~= 4 then return oops('[!] Wrong size - subtype. (4hex symbols)') end - local b0 = readblock(0, keyA) - if not b0 then - 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...') - end - end - core.clearCommandBuffer() + -- 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]) ) + else + print('[-] Didn\'t find item type. If you are sure about it, post on forum') + end + --15,16 + --13-14 - -- 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) - local calcEndian = bor(rsh(calc,8), lsh(band(calc, 0xff), 8)) - - local cmd = (cset..'1 %s%04x'):format( b1, calcEndian) - core.console(cmd) - core.clearCommandBuffer() - - local pos, key - for blockNo = 2, numBlocks-1, 1 do - pos = (math.floor( blockNo / 4 ) * 12)+1 - key = akeys:sub(pos, pos + 11 ) - if blockNo%4 == 3 then - cmd = ('%s %d %s%s'):format(cset,blockNo,key,AccAndKeyB) - core.console(cmd) - 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() + -- find tag + result, err = lib14a.read(false, true) + if not result then return oops(err) end + + -- load keys + local akeys = pre.GetAll(result.uid) + local keyA = akeys:sub(1, 12 ) + + local b0 = readblock(0, keyA) + if not b0 then + 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...') + end + end + 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) + local calcEndian = bor(rsh(calc,8), lsh(band(calc, 0xff), 8)) + + local cmd = (cset..'1 %s%04x'):format( b1, calcEndian) + core.console(cmd) + core.clearCommandBuffer() + + local pos, key + for blockNo = 2, numBlocks-1, 1 do + pos = (math.floor( blockNo / 4 ) * 12)+1 + key = akeys:sub(pos, pos + 11 ) + if blockNo%4 == 3 then + cmd = ('%s %d %s%s'):format(cset,blockNo,key,AccAndKeyB) + core.console(cmd) + 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) diff --git a/client/scripts/tnp3dump.lua b/client/scripts/tnp3dump.lua index 8c354ef89..2a5545497 100644 --- a/client/scripts/tnp3dump.lua +++ b/client/scripts/tnp3dump.lua @@ -8,15 +8,15 @@ local dumplib = require('html_dumplib') local toys = require('default_toys') example =[[ - script run tnp3dump - script run tnp3dump -n - script run tnp3dump -p - script run tnp3dump -k aabbccddeeff - script run tnp3dump -k aabbccddeeff -n - script run tnp3dump -o myfile - script run tnp3dump -n -o myfile - script run tnp3dump -p -o myfile - script run tnp3dump -k aabbccddeeff -n -o myfile + script run tnp3dump + script run tnp3dump -n + script run tnp3dump -p + script run tnp3dump -k aabbccddeeff + script run tnp3dump -k aabbccddeeff -n + script run tnp3dump -o myfile + script run tnp3dump -n -o myfile + script run tnp3dump -p -o myfile + script run tnp3dump -k aabbccddeeff -n -o myfile ]] author = "Iceman" usage = "script run tnp3dump -k -n -p -o " @@ -24,262 +24,262 @@ desc =[[ This script will try to dump the contents of a Mifare TNP3xxx card. It will need a valid KeyA in order to find the other keys and decode the card. Arguments: - -h : this help - -k : Sector 0 Key A. - -n : Use the nested cmd to find all keys - -p : Use the precalc to find all keys - -o : filename for the saved dumps + -h : this help + -k : Sector 0 Key A. + -n : Use the nested cmd to find all keys + -p : Use the precalc to find all keys + -o : filename for the saved dumps ]] local RANDOM = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' local TIMEOUT = 2500 -- Shouldn't take longer than 2 seconds local DEBUG = false -- the debug flag local numBlocks = 64 local numSectors = 16 ---- +--- -- A debug printout-function function dbg(args) - if not DEBUG then return end - + if not DEBUG then return end + if type(args) == "table" then - local i = 1 - while result[i] do - dbg(result[i]) - i = i+1 - end - else - print("###", args) - end -end ---- + local i = 1 + while result[i] do + dbg(result[i]) + i = i+1 + end + else + print("###", args) + end +end +--- -- This is only meant to be used when errors occur function oops(err) - print("ERROR: ",err) - return nil,err + print("ERROR: ",err) + return nil,err end ---- +--- -- Usage help function help() - print(desc) - print("Example usage") - print(example) + print(desc) + print("Example usage") + print(example) end -- -- Exit message function ExitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() end local function readdumpkeys(infile) - t = infile:read("*all") - len = string.len(t) - local len,hex = bin.unpack(("H%d"):format(len),t) - return hex + t = infile:read("*all") + len = string.len(t) + local len,hex = bin.unpack(("H%d"):format(len),t) + return hex end local function waitCmd() - local response = core.WaitForResponseTimeout(cmds.CMD_ACK, TIMEOUT) - if response then - local count, cmd, arg0 = bin.unpack('LL',response) - if(arg0==1) then - local count,arg1,arg2,data = bin.unpack('LLH511',response,count) - return data:sub(1,32) - else - return nil, "Couldn't read block.. ["..arg0.."]" - end - end - return nil, 'No response from device' + local response = core.WaitForResponseTimeout(cmds.CMD_ACK, TIMEOUT) + if response then + local count, cmd, arg0 = bin.unpack('LL',response) + if(arg0==1) then + local count,arg1,arg2,data = bin.unpack('LLH511',response,count) + return data:sub(1,32) + else + return nil, "Couldn't read block.. ["..arg0.."]" + end + end + return nil, 'No response from device' end local function main(args) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - - local keyA - local cmd - local err - local useNested = false - local usePreCalc = false - local cmdReadBlockString = 'hf mf rdbl %d A %s' - local input = "dumpkeys.bin" - local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M%S"); + print( string.rep('--',20) ) + print( string.rep('--',20) ) - -- Arguments for the script - for o, a in getopt.getopt(args, 'hk:npo:') do - if o == "h" then return help() end - if o == "k" then keyA = a end - if o == "n" then useNested = true end - if o == "p" then usePreCalc = true end - if o == "o" then outputTemplate = a end - end - - -- validate input args. - keyA = keyA or '4b0b20107ccb' - if #(keyA) ~= 12 then - return oops( string.format('Wrong length of write key (was %d) expected 12', #keyA)) - end + local keyA + local cmd + local err + local useNested = false + local usePreCalc = false + local cmdReadBlockString = 'hf mf rdbl %d A %s' + local input = "dumpkeys.bin" + local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M%S"); - -- Turn off Debug - local cmdSetDbgOff = "hf mf dbg 0" - core.console( cmdSetDbgOff) - - result, err = lib14a.read(false, true) - if not result then - return oops(err) - end + -- Arguments for the script + for o, a in getopt.getopt(args, 'hk:npo:') do + if o == "h" then return help() end + if o == "k" then keyA = a end + if o == "n" then useNested = true end + if o == "p" then usePreCalc = true end + if o == "o" then outputTemplate = a end + end - core.clearCommandBuffer() - - -- Show tag info - print((' Found tag %s'):format(result.name)) + -- validate input args. + keyA = keyA or '4b0b20107ccb' + if #(keyA) ~= 12 then + return oops( string.format('Wrong length of write key (was %d) expected 12', #keyA)) + end - dbg(('Using keyA : %s'):format(keyA)) + -- Turn off Debug + local cmdSetDbgOff = "hf mf dbg 0" + core.console( cmdSetDbgOff) - --Trying to find the other keys - if useNested then - core.console( ('hf mf nested 1 0 A %s d'):format(keyA) ) - end + result, err = lib14a.read(false, true) + if not result then + return oops(err) + end - core.clearCommandBuffer() - - local akeys = '' - if usePreCalc then - local pre = require('precalc') - akeys = pre.GetAll(result.uid) - dbg(akeys) - else - print('Loading dumpkeys.bin') - local hex, err = utils.ReadDumpFile(input) - if not hex then - return oops(err) - end - akeys = hex:sub(0,12*16) - end - - -- Read block 0 - dbg('Reading block 0') - cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 0, arg2 = 0, arg3 = 0, data = keyA} - err = core.SendCommand(cmd:getBytes()) - if err then return oops(err) end - local block0, err = waitCmd() - if err then return oops(err) end - - core.clearCommandBuffer() - - -- Read block 1 - dbg('Reading block 1') - cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 1, arg2 = 0, arg3 = 0, data = keyA} - err = core.SendCommand(cmd:getBytes()) - if err then return oops(err) end - local block1, err = waitCmd() - if err then return oops(err) end + core.clearCommandBuffer() - core.clearCommandBuffer() - - local tmpHash = block0..block1..'%02x'..RANDOM + -- Show tag info + print((' Found tag %s'):format(result.name)) - local key - local pos = 0 - local blockNo - local blocks = {} - - -- main loop - io.write('Reading blocks > ') - for blockNo = 0, numBlocks-1, 1 do + dbg(('Using keyA : %s'):format(keyA)) - io.flush() - - if core.ukbhit() then - print("aborted by user") - break - end - - core.clearCommandBuffer() - - pos = (math.floor( blockNo / 4 ) * 12)+1 - key = akeys:sub(pos, pos + 11 ) - cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = blockNo ,arg2 = 0,arg3 = 0, data = key} - local err = core.SendCommand(cmd:getBytes()) - if err then return oops(err) end - local blockdata, err = waitCmd() - if err then return oops(err) end + --Trying to find the other keys + if useNested then + core.console( ('hf mf nested 1 0 A %s d'):format(keyA) ) + end + + core.clearCommandBuffer() + + local akeys = '' + if usePreCalc then + local pre = require('precalc') + akeys = pre.GetAll(result.uid) + dbg(akeys) + else + print('Loading dumpkeys.bin') + local hex, err = utils.ReadDumpFile(input) + if not hex then + return oops(err) + end + akeys = hex:sub(0,12*16) + end + + -- Read block 0 + dbg('Reading block 0') + cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 0, arg2 = 0, arg3 = 0, data = keyA} + err = core.SendCommand(cmd:getBytes()) + if err then return oops(err) end + local block0, err = waitCmd() + if err then return oops(err) end + + core.clearCommandBuffer() + + -- Read block 1 + dbg('Reading block 1') + cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 1, arg2 = 0, arg3 = 0, data = keyA} + err = core.SendCommand(cmd:getBytes()) + if err then return oops(err) end + local block1, err = waitCmd() + if err then return oops(err) end + + core.clearCommandBuffer() + + local tmpHash = block0..block1..'%02x'..RANDOM + + local key + local pos = 0 + local blockNo + local blocks = {} + + -- main loop + io.write('Reading blocks > ') + for blockNo = 0, numBlocks-1, 1 do + + io.flush() + + if core.ukbhit() then + print("aborted by user") + break + end + + core.clearCommandBuffer() + + pos = (math.floor( blockNo / 4 ) * 12)+1 + key = akeys:sub(pos, pos + 11 ) + cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = blockNo ,arg2 = 0,arg3 = 0, data = key} + local err = core.SendCommand(cmd:getBytes()) + if err then return oops(err) end + local blockdata, err = waitCmd() + if err then return oops(err) end - if blockNo%4 ~= 3 then - - if blockNo < 8 then - -- Block 0-7 not encrypted - blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) - else - -- blocks with zero not encrypted. - if string.find(blockdata, '^0+$') then - blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) - else - local baseStr = utils.ConvertHexToAscii(tmpHash:format(blockNo)) - local key = md5.sumhexa(baseStr) - local aestest = core.aes128_decrypt(key, blockdata) - local hex = utils.ConvertAsciiToHex(aestest) - - blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,hex) - io.write(blockNo..',') - end - end - else - -- Sectorblocks, not encrypted - blocks[blockNo+1] = ('%02d :: %s%s'):format(blockNo,key,blockdata:sub(13,32)) - end - end - io.write('\n') - - core.clearCommandBuffer() - - -- Print results - local bindata = {} - local emldata = '' + if blockNo%4 ~= 3 then - for _,s in pairs(blocks) do - local slice = s:sub(8,#s) - local str = utils.ConvertHexToAscii(slice) - emldata = emldata..slice..'\n' - for c in (str):gmatch('.') do - bindata[#bindata+1] = c - end - end + if blockNo < 8 then + -- Block 0-7 not encrypted + blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) + else + -- blocks with zero not encrypted. + if string.find(blockdata, '^0+$') then + blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) + else + local baseStr = utils.ConvertHexToAscii(tmpHash:format(blockNo)) + local key = md5.sumhexa(baseStr) + local aestest = core.aes128_decrypt(key, blockdata) + local hex = utils.ConvertAsciiToHex(aestest) - print( string.rep('--',20) ) - - local uid = block0:sub(1,8) - local toytype = block1:sub(1,4) - local cardidLsw = block1:sub(9,16) - local cardidMsw = block1:sub(16,24) - local cardid = block1:sub(9,24) - local subtype = block1:sub(25,28) - - -- Write dump to files - if not DEBUG then - local foo = dumplib.SaveAsBinary(bindata, outputTemplate..'-'..uid..'.bin') - print(("Wrote a BIN dump to: %s"):format(foo)) - local bar = dumplib.SaveAsText(emldata, outputTemplate..'-'..uid..'.eml') - print(("Wrote a EML dump to: %s"):format(bar)) - end - - print( string.rep('--',20) ) - -- Show info + blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,hex) + io.write(blockNo..',') + end + end + else + -- Sectorblocks, not encrypted + blocks[blockNo+1] = ('%02d :: %s%s'):format(blockNo,key,blockdata:sub(13,32)) + end + end + io.write('\n') - local item = toys.Find(toytype, subtype) - if item then - print((' ITEM TYPE : %s - %s (%s)'):format(item[6],item[5], item[4]) ) - else - print((' ITEM TYPE : 0x%s 0x%s'):format(toytype, subtype)) - end + core.clearCommandBuffer() - print( (' UID : 0x%s'):format(uid) ) - print( (' CARDID : 0x%s'):format(cardid ) ) - print( string.rep('--',20) ) - - core.clearCommandBuffer() + -- Print results + local bindata = {} + local emldata = '' + + for _,s in pairs(blocks) do + local slice = s:sub(8,#s) + local str = utils.ConvertHexToAscii(slice) + emldata = emldata..slice..'\n' + for c in (str):gmatch('.') do + bindata[#bindata+1] = c + end + end + + print( string.rep('--',20) ) + + local uid = block0:sub(1,8) + local toytype = block1:sub(1,4) + local cardidLsw = block1:sub(9,16) + local cardidMsw = block1:sub(16,24) + local cardid = block1:sub(9,24) + local subtype = block1:sub(25,28) + + -- Write dump to files + if not DEBUG then + local foo = dumplib.SaveAsBinary(bindata, outputTemplate..'-'..uid..'.bin') + print(("Wrote a BIN dump to: %s"):format(foo)) + local bar = dumplib.SaveAsText(emldata, outputTemplate..'-'..uid..'.eml') + print(("Wrote a EML dump to: %s"):format(bar)) + end + + print( string.rep('--',20) ) + -- Show info + + local item = toys.Find(toytype, subtype) + if item then + print((' ITEM TYPE : %s - %s (%s)'):format(item[6],item[5], item[4]) ) + else + print((' ITEM TYPE : 0x%s 0x%s'):format(toytype, subtype)) + end + + print( (' UID : 0x%s'):format(uid) ) + print( (' CARDID : 0x%s'):format(cardid ) ) + print( string.rep('--',20) ) + + core.clearCommandBuffer() end main(args) \ No newline at end of file diff --git a/client/scripts/tnp3sim.lua b/client/scripts/tnp3sim.lua index ca729f38d..f64bebfce 100644 --- a/client/scripts/tnp3sim.lua +++ b/client/scripts/tnp3sim.lua @@ -6,11 +6,11 @@ local utils = require('utils') local md5 = require('md5') local toys = require('default_toys') local pre = require('precalc') - + example =[[ - 1. script run tnp3sim - 2. script run tnp3sim -m - 3. script run tnp3sim -m -i myfile + 1. script run tnp3sim + 2. script run tnp3sim -m + 3. script run tnp3sim -m -i myfile ]] author = "Iceman" usage = "script run tnp3sim -h -m -i " @@ -21,11 +21,11 @@ For an experimental mode, it tries to manipulate some data. At last it sends all data to the PM3 device memory where it can be used in the command "hf mf sim" Arguments: - -h : this help - -m : Maxed out items (experimental) - -i : filename for the datadump to read (bin) + -h : this help + -m : Maxed out items (experimental) + -i : filename for the datadump to read (bin) - ]] + ]] local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds local DEBUG = true -- the debug flag @@ -40,239 +40,239 @@ local char = string.char local sub = string.sub local format = string.format ---- +--- -- A debug printout-function function dbg(args) - if not DEBUG then return end - + if not DEBUG then return end + if type(args) == "table" then - local i = 1 - while result[i] do - dbg(result[i]) - i = i+1 - end - else - print("###", args) - end -end ---- + local i = 1 + while result[i] do + dbg(result[i]) + i = i+1 + end + else + print("###", args) + end +end +--- -- This is only meant to be used when errors occur function oops(err) - print("ERROR: ",err) - return nil,err + print("ERROR: ",err) + return nil,err end ---- +--- -- Usage help function help() - print(desc) - print("Example usage") - print(example) + print(desc) + print("Example usage") + print(example) end -- -- Exit message function ExitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() end local function writedumpfile(infile) - t = infile:read("*all") - len = string.len(t) - local len,hex = bin.unpack(("H%d"):format(len),t) - return hex + t = infile:read("*all") + len = string.len(t) + local len,hex = bin.unpack(("H%d"):format(len),t) + return hex end -- blocks with data -- there are two dataareas, in block 8 or block 36, ( 1==8 , -- checksum type = 0, 1, 2, 3 local function GetCheckSum(blocks, dataarea, chksumtype) - local crc - local area = 36 - if dataarea == 1 then - area = 8 - end - - if chksumtype == 0 then - crc = blocks[1]:sub(29,32) - elseif chksumtype == 1 then - crc = blocks[area]:sub(29,32) - elseif chksumtype == 2 then - crc = blocks[area]:sub(25,28) - elseif chksumtype == 3 then - crc = blocks[area]:sub(21,24) - end - return utils.SwapEndianness(crc,16) + local crc + local area = 36 + if dataarea == 1 then + area = 8 + end + + if chksumtype == 0 then + crc = blocks[1]:sub(29,32) + elseif chksumtype == 1 then + crc = blocks[area]:sub(29,32) + elseif chksumtype == 2 then + crc = blocks[area]:sub(25,28) + elseif chksumtype == 3 then + crc = blocks[area]:sub(21,24) + end + return utils.SwapEndianness(crc,16) end local function SetAllCheckSum(blocks) - print('Updating all checksums') - SetCheckSum(blocks, 3) - SetCheckSum(blocks, 2) - SetCheckSum(blocks, 1) - SetCheckSum(blocks, 0) + print('Updating all checksums') + SetCheckSum(blocks, 3) + SetCheckSum(blocks, 2) + SetCheckSum(blocks, 1) + SetCheckSum(blocks, 0) end local function SetCheckSum(blocks, chksumtype) - if blocks == nil then return nil, 'Argument \"blocks\" nil' end - local newcrc - local area1 = 8 - local area2 = 36 - - if chksumtype == 0 then - newcrc = ('%04X'):format(CalcCheckSum(blocks,1,0)) - blocks[1] = blocks[1]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2) - elseif chksumtype == 1 then - newcrc = ('%04X'):format(CalcCheckSum(blocks,1,1)) - blocks[area1] = blocks[area1]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2) - newcrc = ('%04X'):format(CalcCheckSum(blocks,2,1)) - blocks[area2] = blocks[area2]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2) - elseif chksumtype == 2 then - newcrc = ('%04X'):format(CalcCheckSum(blocks,1,2)) - blocks[area1] = blocks[area1]:sub(1,24)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area1]:sub(29,32) - newcrc = ('%04X'):format(CalcCheckSum(blocks,2,2)) - blocks[area2] = blocks[area2]:sub(1,24)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area2]:sub(29,32) - elseif chksumtype == 3 then - newcrc = ('%04X'):format(CalcCheckSum(blocks,1,3)) - blocks[area1] = blocks[area1]:sub(1,20)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area1]:sub(25,32) - newcrc = ('%04X'):format(CalcCheckSum(blocks,2,3)) - blocks[area2] = blocks[area2]:sub(1,20)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area2]:sub(25,32) - end + if blocks == nil then return nil, 'Argument \"blocks\" nil' end + local newcrc + local area1 = 8 + local area2 = 36 + + if chksumtype == 0 then + newcrc = ('%04X'):format(CalcCheckSum(blocks,1,0)) + blocks[1] = blocks[1]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2) + elseif chksumtype == 1 then + newcrc = ('%04X'):format(CalcCheckSum(blocks,1,1)) + blocks[area1] = blocks[area1]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2) + newcrc = ('%04X'):format(CalcCheckSum(blocks,2,1)) + blocks[area2] = blocks[area2]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2) + elseif chksumtype == 2 then + newcrc = ('%04X'):format(CalcCheckSum(blocks,1,2)) + blocks[area1] = blocks[area1]:sub(1,24)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area1]:sub(29,32) + newcrc = ('%04X'):format(CalcCheckSum(blocks,2,2)) + blocks[area2] = blocks[area2]:sub(1,24)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area2]:sub(29,32) + elseif chksumtype == 3 then + newcrc = ('%04X'):format(CalcCheckSum(blocks,1,3)) + blocks[area1] = blocks[area1]:sub(1,20)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area1]:sub(25,32) + newcrc = ('%04X'):format(CalcCheckSum(blocks,2,3)) + blocks[area2] = blocks[area2]:sub(1,20)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area2]:sub(25,32) + end end function CalcCheckSum(blocks, dataarea, chksumtype) - local area = 36 - if dataarea == 1 then - area = 8 - end - - if chksumtype == 0 then - data = blocks[0]..blocks[1]:sub(1,28) - elseif chksumtype == 1 then - data = blocks[area]:sub(1,28)..'0500' - elseif chksumtype == 2 then - data = blocks[area+1]..blocks[area+2]..blocks[area+4] - elseif chksumtype == 3 then - data = blocks[area+5]..blocks[area+6]..blocks[area+8]..string.rep('00',0xe0) - end - return utils.Crc16(data) + local area = 36 + if dataarea == 1 then + area = 8 + end + + if chksumtype == 0 then + data = blocks[0]..blocks[1]:sub(1,28) + elseif chksumtype == 1 then + data = blocks[area]:sub(1,28)..'0500' + elseif chksumtype == 2 then + data = blocks[area+1]..blocks[area+2]..blocks[area+4] + elseif chksumtype == 3 then + data = blocks[area+5]..blocks[area+6]..blocks[area+8]..string.rep('00',0xe0) + end + return utils.Crc16(data) end local function ValidateCheckSums(blocks) - print(' Validating checksums') - - local isOk, crc, calc - -- Checksum Type 0 - crc = GetCheckSum(blocks,1,0) - calc = CalcCheckSum(blocks, 1, 0) - if crc == calc then isOk='Ok' else isOk = 'Error' end - io.write( ('TYPE 0 : %04x = %04x -- %s\n'):format(crc,calc,isOk)) + print(' Validating checksums') - -- Checksum Type 1 (DATAAREAHEADER 1) - crc = GetCheckSum(blocks,1,1) - calc = CalcCheckSum(blocks,1,1) - if crc == calc then isOk='Ok' else isOk = 'Error' end - io.write( ('TYPE 1 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk)) - - -- Checksum Type 1 (DATAAREAHEADER 2) - crc = GetCheckSum(blocks,2,1) - calc = CalcCheckSum(blocks,2,1) - if crc == calc then isOk='Ok' else isOk = 'Error' end - io.write( ('TYPE 1 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk)) - - -- Checksum Type 2 (DATAAREA 1) - crc = GetCheckSum(blocks,1,2) - calc = CalcCheckSum(blocks,1,2) - if crc == calc then isOk='Ok' else isOk = 'Error' end - io.write( ('TYPE 2 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk)) + local isOk, crc, calc + -- Checksum Type 0 + crc = GetCheckSum(blocks,1,0) + calc = CalcCheckSum(blocks, 1, 0) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 0 : %04x = %04x -- %s\n'):format(crc,calc,isOk)) - -- Checksum Type 2 (DATAAREA 2) - crc = GetCheckSum(blocks,2,2) - calc = CalcCheckSum(blocks,2,2) - if crc == calc then isOk='Ok' else isOk = 'Error' end - io.write( ('TYPE 2 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk)) + -- Checksum Type 1 (DATAAREAHEADER 1) + crc = GetCheckSum(blocks,1,1) + calc = CalcCheckSum(blocks,1,1) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 1 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk)) - -- Checksum Type 3 (DATAAREA 1) - crc = GetCheckSum(blocks,1,3) - calc = CalcCheckSum(blocks,1,3) - if crc == calc then isOk='Ok' else isOk = 'Error' end - io.write( ('TYPE 3 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk)) + -- Checksum Type 1 (DATAAREAHEADER 2) + crc = GetCheckSum(blocks,2,1) + calc = CalcCheckSum(blocks,2,1) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 1 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk)) - -- Checksum Type 3 (DATAAREA 2) - crc = GetCheckSum(blocks,2,3) - calc = CalcCheckSum(blocks,2,3) - if crc == calc then isOk='Ok' else isOk = 'Error' end - io.write( ('TYPE 3 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk)) + -- Checksum Type 2 (DATAAREA 1) + crc = GetCheckSum(blocks,1,2) + calc = CalcCheckSum(blocks,1,2) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 2 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk)) + + -- Checksum Type 2 (DATAAREA 2) + crc = GetCheckSum(blocks,2,2) + calc = CalcCheckSum(blocks,2,2) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 2 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk)) + + -- Checksum Type 3 (DATAAREA 1) + crc = GetCheckSum(blocks,1,3) + calc = CalcCheckSum(blocks,1,3) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 3 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk)) + + -- Checksum Type 3 (DATAAREA 2) + crc = GetCheckSum(blocks,2,3) + calc = CalcCheckSum(blocks,2,3) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 3 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk)) end local function AddKey(keys, blockNo, data) - local pos = (math.floor( blockNo / 4 ) * 12)+1 - local key = keys:sub(pos, pos + 11 ) - return key..data:sub(13) + local pos = (math.floor( blockNo / 4 ) * 12)+1 + local key = keys:sub(pos, pos + 11 ) + return key..data:sub(13) end local function LoadEmulator(uid, blocks) - print('Sending dumpdata to emulator memory') - local keys = pre.GetAll(uid) - local cmd, blockdata - for _,b in pairs(blocks) do - - blockdata = b - - if _%4 ~= 3 then - if (_ >= 8 and _<=21) or (_ >= 36 and _<=49) then - local base = ('%s%s%02x%s'):format(blocks[0], blocks[1], _ , RANDOM) - local baseStr = utils.ConvertHexToAscii(base) - local key = md5.sumhexa(baseStr) - local enc = core.aes128_encrypt(key, blockdata) - blockdata = utils.ConvertAsciiToHex(enc) - io.write( _..',') - end - else - -- add keys if not existing.. - if ( blockdata:sub(1,12) == '000000000000' ) then - blockdata = AddKey(keys, _, blockdata) - end - end - core.clearCommandBuffer() - cmd = Command:new{cmd = cmds.CMD_MIFARE_EML_MEMSET, arg1 = _ ,arg2 = 1,arg3 = 16, data = blockdata} - local err = core.SendCommand(cmd:getBytes()) - if err then return err end - end - io.write('\n') + print('Sending dumpdata to emulator memory') + local keys = pre.GetAll(uid) + local cmd, blockdata + for _,b in pairs(blocks) do + + blockdata = b + + if _%4 ~= 3 then + if (_ >= 8 and _<=21) or (_ >= 36 and _<=49) then + local base = ('%s%s%02x%s'):format(blocks[0], blocks[1], _ , RANDOM) + local baseStr = utils.ConvertHexToAscii(base) + local key = md5.sumhexa(baseStr) + local enc = core.aes128_encrypt(key, blockdata) + blockdata = utils.ConvertAsciiToHex(enc) + io.write( _..',') + end + else + -- add keys if not existing.. + if ( blockdata:sub(1,12) == '000000000000' ) then + blockdata = AddKey(keys, _, blockdata) + end + end + core.clearCommandBuffer() + cmd = Command:new{cmd = cmds.CMD_MIFARE_EML_MEMSET, arg1 = _ ,arg2 = 1,arg3 = 16, data = blockdata} + local err = core.SendCommand(cmd:getBytes()) + if err then return err end + end + io.write('\n') end local function Num2Card(m, l) - local k = { - 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, - 0x4C, 0x4D, 0x4E, 0x50, 0x51, 0x52, 0x53, 0x54,0x56, 0x57, 0x58, 0x59, 0x5A, 0x00 - } - local msw = tonumber(utils.SwapEndiannessStr(m,32),16) - local lsw = tonumber(utils.SwapEndiannessStr(l,32),16) + local k = { + 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, + 0x4C, 0x4D, 0x4E, 0x50, 0x51, 0x52, 0x53, 0x54,0x56, 0x57, 0x58, 0x59, 0x5A, 0x00 + } + local msw = tonumber(utils.SwapEndiannessStr(m,32),16) + local lsw = tonumber(utils.SwapEndiannessStr(l,32),16) - if msw > 0x17ea1 then - return "too big" - end + if msw > 0x17ea1 then + return "too big" + end - if msw == 0x17ea1 and lsw > 0x8931fee8 then - return "out of range" - end + if msw == 0x17ea1 and lsw > 0x8931fee8 then + return "out of range" + end - local s = "" - local index - for i = 1,10 do - index, msw, lsw = DivideByK( msw, lsw) - if ( index <= 1 ) then - s = char(k[index]) .. s - else - s = char(k[index-1]) .. s - end - print (index-1, msw, lsw) - end + local s = "" + local index + for i = 1,10 do + index, msw, lsw = DivideByK( msw, lsw) + if ( index <= 1 ) then + s = char(k[index]) .. s + else + s = char(k[index-1]) .. s + end + print (index-1, msw, lsw) + end return s end --33LRT-LM9Q9 @@ -289,43 +289,43 @@ end function DivideByK(msw, lsw) - local lowLSW - local highLSW - local remainder = 0 - local RADIX = 29 + local lowLSW + local highLSW + local remainder = 0 + local RADIX = 29 - --local num = 0 | band( rshift(msw,16), 0xffff) - local num = band( rshift(msw, 16), 0xffff) - - --highLSW = 0 | lshift( (num / RADIX) , 16) - highLSW = lshift( (num / RADIX) , 16) - remainder = num % RADIX + --local num = 0 | band( rshift(msw,16), 0xffff) + local num = band( rshift(msw, 16), 0xffff) - num = bor( lshift(remainder,16), band(msw, 0xffff)) + --highLSW = 0 | lshift( (num / RADIX) , 16) + highLSW = lshift( (num / RADIX) , 16) + remainder = num % RADIX - --highLSW |= num / RADIX - highLSW = highLSW or (num / RADIX) - remainder = num % RADIX + num = bor( lshift(remainder,16), band(msw, 0xffff)) - num = bor( lshift(remainder,16), ( band(rshift(lsw,16), 0xffff))) + --highLSW |= num / RADIX + highLSW = highLSW or (num / RADIX) + remainder = num % RADIX - --lowLSW = 0 | (num / RADIX) << 16 - lowLSW = 0 or (lshift( (num / RADIX), 16)) - remainder = num % RADIX + num = bor( lshift(remainder,16), ( band(rshift(lsw,16), 0xffff))) - num = bor( lshift(remainder,16) , band(lsw, 0xffff) ) + --lowLSW = 0 | (num / RADIX) << 16 + lowLSW = 0 or (lshift( (num / RADIX), 16)) + remainder = num % RADIX + + num = bor( lshift(remainder,16) , band(lsw, 0xffff) ) + + lowLSW = bor(lowLSW, (num / RADIX)) + remainder = num % RADIX + return remainder, highLSW, lowLSW + + -- uint num = 0 | (msw >> 16) & 0xffff; - lowLSW = bor(lowLSW, (num / RADIX)) - remainder = num % RADIX - return remainder, highLSW, lowLSW - - -- uint num = 0 | (msw >> 16) & 0xffff; - -- highLSW = 0 | (num / RADIX) << 16; -- remainder = num % RADIX; -- num = (remainder << 16) | (msw & 0xffff); - + -- highLSW |= num / RADIX; -- remainder = num % RADIX; @@ -343,147 +343,147 @@ end local function main(args) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - - local result, err, hex - local maxed = false - local inputTemplate = "dumpdata.bin" - local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M"); - - -- Arguments for the script - for o, a in getopt.getopt(args, 'hmi:o:') do - if o == "h" then return help() end - if o == "m" then maxed = true end - if o == "o" then outputTemplate = a end - if o == "i" then inputTemplate = a end - end - - -- Turn off Debug - local cmdSetDbgOff = "hf mf dbg 0" - core.console( cmdSetDbgOff) - - -- Load dump.bin file - print( (' Load data from %s'):format(inputTemplate)) - hex, err = utils.ReadDumpFile(inputTemplate) - if not hex then return oops(err) end - - local blocks = {} - local blockindex = 0 - for i = 1, #hex, 32 do - blocks[blockindex] = hex:sub(i,i+31) - blockindex = blockindex + 1 - end + print( string.rep('--',20) ) + print( string.rep('--',20) ) - if DEBUG then ValidateCheckSums(blocks) end - - -- - print( string.rep('--',20) ) - print(' Gathering info') - local uid = blocks[0]:sub(1,8) - local toytype = blocks[1]:sub(1,4) - local cardidLsw = blocks[1]:sub(9,16) - local cardidMsw = blocks[1]:sub(17,24) - local subtype = blocks[1]:sub(25,28) + local result, err, hex + local maxed = false + local inputTemplate = "dumpdata.bin" + local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M"); - -- Show info - print( string.rep('--',20) ) - - local item = toys.Find( toytype, subtype) - if item then - local itemStr = ('%s - %s (%s)'):format(item[6],item[5], item[4]) - print(' ITEM TYPE : '..itemStr ) - else - print( (' ITEM TYPE : 0x%s 0x%s'):format(toytype, subtype) ) - end - - print( (' UID : 0x%s'):format(uid) ) - print( (' CARDID : 0x%s %s [%s]'):format( - cardidMsw,cardidLsw, - --Num2Card(cardidMsw, cardidLsw)) - '') - ) - print( string.rep('--',20) ) + -- Arguments for the script + for o, a in getopt.getopt(args, 'hmi:o:') do + if o == "h" then return help() end + if o == "m" then maxed = true end + if o == "o" then outputTemplate = a end + if o == "i" then inputTemplate = a end + end + + -- Turn off Debug + local cmdSetDbgOff = "hf mf dbg 0" + core.console( cmdSetDbgOff) + + -- Load dump.bin file + print( (' Load data from %s'):format(inputTemplate)) + hex, err = utils.ReadDumpFile(inputTemplate) + if not hex then return oops(err) end + + local blocks = {} + local blockindex = 0 + for i = 1, #hex, 32 do + blocks[blockindex] = hex:sub(i,i+31) + blockindex = blockindex + 1 + end + + if DEBUG then ValidateCheckSums(blocks) end + + -- + print( string.rep('--',20) ) + print(' Gathering info') + local uid = blocks[0]:sub(1,8) + local toytype = blocks[1]:sub(1,4) + local cardidLsw = blocks[1]:sub(9,16) + local cardidMsw = blocks[1]:sub(17,24) + local subtype = blocks[1]:sub(25,28) + + -- Show info + print( string.rep('--',20) ) + + local item = toys.Find( toytype, subtype) + if item then + local itemStr = ('%s - %s (%s)'):format(item[6],item[5], item[4]) + print(' ITEM TYPE : '..itemStr ) + else + print( (' ITEM TYPE : 0x%s 0x%s'):format(toytype, subtype) ) + end + + print( (' UID : 0x%s'):format(uid) ) + print( (' CARDID : 0x%s %s [%s]'):format( + cardidMsw,cardidLsw, + --Num2Card(cardidMsw, cardidLsw)) + '') + ) + print( string.rep('--',20) ) - -- Experience should be: - local experience = blocks[8]:sub(1,6) - print(('Experience : %d'):format(utils.SwapEndianness(experience,16))) - - local money = blocks[8]:sub(7,10) - print(('Money : %d'):format(utils.SwapEndianness(money,16))) + -- Experience should be: + local experience = blocks[8]:sub(1,6) + print(('Experience : %d'):format(utils.SwapEndianness(experience,16))) - -- - - -- Sequence number - local seqnum = blocks[8]:sub(18,19) - print(('Sequence number : %d'):format( tonumber(seqnum,16))) - - local fairy = blocks[9]:sub(1,8) - --FD0F = Left, FF0F = Right - local path = 'not choosen' - if fairy:sub(2,2) == 'D' then - path = 'Left' - elseif fairy:sub(2,2) == 'F' then - path = 'Right' - end - print(('Fairy : %d [Path: %s] '):format(utils.SwapEndianness(fairy,24),path)) - - local hat = blocks[9]:sub(8,11) - print(('Hat : %d'):format(utils.SwapEndianness(hat,16))) + local money = blocks[8]:sub(7,10) + print(('Money : %d'):format(utils.SwapEndianness(money,16))) - local level = blocks[13]:sub(27,28) - print(('LEVEL : %d'):format( tonumber(level,16))) + -- - --local health = blocks[]:sub(); - --print(('Health : %d'):format( tonumber(health,16)) - - --0x0D 0x29 0x0A 0x02 16-bit hero points value. Maximum 100. - local heropoints = blocks[13]:sub(20,23) - print(('Hero points : %d'):format(utils.SwapEndianness(heropoints,16))) + -- Sequence number + local seqnum = blocks[8]:sub(18,19) + print(('Sequence number : %d'):format( tonumber(seqnum,16))) - --0x10 0x2C 0x0C 0x04 32 bit flag value indicating heroic challenges completed. - local challenges = blocks[16]:sub(25,32) - print(('Finished hero challenges : %d'):format(utils.SwapEndianness(challenges,32))) - - -- Character Name - local name1 = blocks[10]:sub(1,32) - local name2 = blocks[12]:sub(1,32) - print('Custom name : '..utils.ConvertHexToAscii(name1..name2)) - - if maxed then - print('Lets try to max out some values') - -- max out money, experience - --print (blocks[8]) - blocks[8] = 'FFFFFF'..'FFFF'..blocks[8]:sub(11,32) - blocks[36] = 'FFFFFF'..'FFFF'..blocks[36]:sub(11,32) - --print (blocks[8]) - - -- max out hero challenges - --print (blocks[16]) - blocks[16] = blocks[16]:sub(1,24)..'FFFFFFFF' - blocks[44] = blocks[44]:sub(1,24)..'FFFFFFFF' - --print (blocks[16]) - - -- max out heropoints - --print (blocks[13]) - blocks[13] = blocks[13]:sub(1,19)..'0064'..blocks[13]:sub(24,32) - blocks[41] = blocks[41]:sub(1,19)..'0064'..blocks[41]:sub(24,32) - --print (blocks[13]) - - -- Update Checksums - SetAllCheckSum(blocks) + local fairy = blocks[9]:sub(1,8) + --FD0F = Left, FF0F = Right + local path = 'not choosen' + if fairy:sub(2,2) == 'D' then + path = 'Left' + elseif fairy:sub(2,2) == 'F' then + path = 'Right' + end + print(('Fairy : %d [Path: %s] '):format(utils.SwapEndianness(fairy,24),path)) - -- Validate Checksums - ValidateCheckSums(blocks) - end + local hat = blocks[9]:sub(8,11) + print(('Hat : %d'):format(utils.SwapEndianness(hat,16))) - --Load dumpdata to emulator memory - if DEBUG then - err = LoadEmulator(uid, blocks) - if err then return oops(err) end - core.clearCommandBuffer() - print('The simulation is now prepared.\n --> run \"hf mf sim u '..uid..'\" <--') - end + local level = blocks[13]:sub(27,28) + print(('LEVEL : %d'):format( tonumber(level,16))) + + --local health = blocks[]:sub(); + --print(('Health : %d'):format( tonumber(health,16)) + + --0x0D 0x29 0x0A 0x02 16-bit hero points value. Maximum 100. + local heropoints = blocks[13]:sub(20,23) + print(('Hero points : %d'):format(utils.SwapEndianness(heropoints,16))) + + --0x10 0x2C 0x0C 0x04 32 bit flag value indicating heroic challenges completed. + local challenges = blocks[16]:sub(25,32) + print(('Finished hero challenges : %d'):format(utils.SwapEndianness(challenges,32))) + + -- Character Name + local name1 = blocks[10]:sub(1,32) + local name2 = blocks[12]:sub(1,32) + print('Custom name : '..utils.ConvertHexToAscii(name1..name2)) + + if maxed then + print('Lets try to max out some values') + -- max out money, experience + --print (blocks[8]) + blocks[8] = 'FFFFFF'..'FFFF'..blocks[8]:sub(11,32) + blocks[36] = 'FFFFFF'..'FFFF'..blocks[36]:sub(11,32) + --print (blocks[8]) + + -- max out hero challenges + --print (blocks[16]) + blocks[16] = blocks[16]:sub(1,24)..'FFFFFFFF' + blocks[44] = blocks[44]:sub(1,24)..'FFFFFFFF' + --print (blocks[16]) + + -- max out heropoints + --print (blocks[13]) + blocks[13] = blocks[13]:sub(1,19)..'0064'..blocks[13]:sub(24,32) + blocks[41] = blocks[41]:sub(1,19)..'0064'..blocks[41]:sub(24,32) + --print (blocks[13]) + + -- Update Checksums + SetAllCheckSum(blocks) + + -- Validate Checksums + ValidateCheckSums(blocks) + end + + --Load dumpdata to emulator memory + if DEBUG then + err = LoadEmulator(uid, blocks) + if err then return oops(err) end + core.clearCommandBuffer() + print('The simulation is now prepared.\n --> run \"hf mf sim u '..uid..'\" <--') + end end main(args) \ No newline at end of file diff --git a/client/scripts/tracetest.lua b/client/scripts/tracetest.lua index ae4055aed..96d1f79c6 100644 --- a/client/scripts/tracetest.lua +++ b/client/scripts/tracetest.lua @@ -5,122 +5,122 @@ local utils = require('utils') local dumplib = require('html_dumplib') example =[[ - 1. script run tracetest + 1. script run tracetest ]] author = "Iceman" usage = "script run tracetest" desc =[[ -This script will load several traces files in ../traces/ folder and do +This script will load several traces files in ../traces/ folder and do "data load" -"lf search 1 u" +"lf search 1 u" -The following tracefiles will be loaded: +The following tracefiles will be loaded: em*.pm3 m*.pm3 Arguments: - -h : this help + -h : this help ]] local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds local DEBUG = true -- the debug flag ---- +--- -- A debug printout-function function dbg(args) - if not DEBUG then - return - end - + if not DEBUG then + return + end + if type(args) == "table" then - local i = 1 - while result[i] do - dbg(result[i]) - i = i+1 - end - else - print("###", args) - end -end ---- + local i = 1 + while result[i] do + dbg(result[i]) + i = i+1 + end + else + print("###", args) + end +end +--- -- This is only meant to be used when errors occur function oops(err) - print("ERROR: ",err) + print("ERROR: ",err) end ---- +--- -- Usage help function help() - print(desc) - print("Example usage") - print(example) + print(desc) + print("Example usage") + print(example) end -- -- Exit message function ExitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() end local function main(args) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - - local cmdDataLoad = 'data load %s'; - local tracesEM = "find '../traces/' -iname 'em*.pm3' -type f" - local tracesMOD = "find '../traces/' -iname 'm*.pm3' -type f" + print( string.rep('--',20) ) + print( string.rep('--',20) ) - local write2File = false - local outputTemplate = os.date("testtest_%Y-%m-%d_%H%M%S") + local cmdDataLoad = 'data load %s'; + local tracesEM = "find '../traces/' -iname 'em*.pm3' -type f" + local tracesMOD = "find '../traces/' -iname 'm*.pm3' -type f" - -- Arguments for the script - for o, arg in getopt.getopt(args, 'h') do - if o == "h" then return help() end - end - - core.clearCommandBuffer() - - local files = {} - - -- Find a set of traces staring with EM - local p = assert( io.popen(tracesEM)) - for file in p:lines() do - table.insert(files, file) - end - p.close(); - - -- Find a set of traces staring with MOD - p = assert( io.popen(tracesMOD) ) - for file in p:lines() do - table.insert(files, file) - end - p.close(); - - local cmdLFSEARCH = "lf search 1 u" - - -- main loop - io.write('Starting to test traces > ') - for _,file in pairs(files) do + local write2File = false + local outputTemplate = os.date("testtest_%Y-%m-%d_%H%M%S") - local x = "data load "..file - dbg(x) - core.console(x) - - dbg(cmdLFSEARCH) - core.console(cmdLFSEARCH) - - core.clearCommandBuffer() - - if core.ukbhit() then - print("aborted by user") - break - end - end - io.write('\n') + -- Arguments for the script + for o, arg in getopt.getopt(args, 'h') do + if o == "h" then return help() end + end - print( string.rep('--',20) ) + core.clearCommandBuffer() + + local files = {} + + -- Find a set of traces staring with EM + local p = assert( io.popen(tracesEM)) + for file in p:lines() do + table.insert(files, file) + end + p.close(); + + -- Find a set of traces staring with MOD + p = assert( io.popen(tracesMOD) ) + for file in p:lines() do + table.insert(files, file) + end + p.close(); + + local cmdLFSEARCH = "lf search 1 u" + + -- main loop + io.write('Starting to test traces > ') + for _,file in pairs(files) do + + local x = "data load "..file + dbg(x) + core.console(x) + + dbg(cmdLFSEARCH) + core.console(cmdLFSEARCH) + + core.clearCommandBuffer() + + if core.ukbhit() then + print("aborted by user") + break + end + end + io.write('\n') + + print( string.rep('--',20) ) end main(args) \ No newline at end of file diff --git a/client/scripts/ufodump.lua b/client/scripts/ufodump.lua index a77bb6c92..67949fd94 100644 --- a/client/scripts/ufodump.lua +++ b/client/scripts/ufodump.lua @@ -3,8 +3,8 @@ local getopt = require('getopt') local lib14a = require('read14a') local utils = require('utils') example = [[ - script run ufodump - script run ufodump -b 10 + script run ufodump + script run ufodump -b 10 ]] author = "Iceman" desc = @@ -22,155 +22,155 @@ Arguments: -- Some globals local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds local DEBUG = false -- the debug flag ---- +--- -- A debug printout-function local function dbg(args) - if DEBUG then - print("###", args) - end -end ---- + if DEBUG then + print("###", args) + end +end +--- -- This is only meant to be used when errors occur local function oops(err) - print("ERROR: ",err) - core.clearCommandBuffer() + print("ERROR: ",err) + core.clearCommandBuffer() end ---- +--- -- Usage help local function help() - print(desc) - print("Example usage") - print(example) + print(desc) + print("Example usage") + print(example) end -- -- writes data to ascii textfile. function writeDumpFile(uid, blockData) - local destination = string.format("%s.eml", uid) - local file = io.open(destination, "w") - if file == nil then - return nil, string.format("Could not write to file %s", destination) - end - local rowlen = string.len(blockData[1]) + local destination = string.format("%s.eml", uid) + local file = io.open(destination, "w") + if file == nil then + return nil, string.format("Could not write to file %s", destination) + end + local rowlen = string.len(blockData[1]) - for i,block in ipairs(blockData) do - if rowlen ~= string.len(block) then - print(string.format("WARNING: Dumpdata seems corrupted, line %d was not the same length as line 1",i)) - end - file:write(block.."\n") - end - file:close() - return destination + for i,block in ipairs(blockData) do + if rowlen ~= string.len(block) then + print(string.format("WARNING: Dumpdata seems corrupted, line %d was not the same length as line 1",i)) + end + file:write(block.."\n") + end + file:close() + return destination end -- --- Picks out and displays the data read from a tag -- Specifically, takes a usb packet, converts to a Command --- (as in commands.lua), takes the data-array and +-- (as in commands.lua), takes the data-array and -- reads the number of bytes specified in arg1 (arg0 in c-struct) -- and displays the data -- @blockno just to print which block the data belong to -- @param usbpacket the data received from the device function showdata(blockno, data) - local xorkey = '55AA55AA55AA55AA6262' - local s = data.." | " - local dex = '' - local rs - for i = 1, 20-4, 4 do - local item = string.sub(data, i, i+3) - local xor = string.sub(xorkey, i, i+3) + local xorkey = '55AA55AA55AA55AA6262' + local s = data.." | " + local dex = '' + local rs + for i = 1, 20-4, 4 do + local item = string.sub(data, i, i+3) + local xor = string.sub(xorkey, i, i+3) - if blockno > 2 then - rs = bit32.bxor(tonumber(item,16) , tonumber(xor,16)) - else - rs = tonumber(item, 16) - end - dex = (dex..'%04X'):format(rs) - end - s = s..dex.." | " - print( (" %02d | %s"):format(blockno,s)) + if blockno > 2 then + rs = bit32.bxor(tonumber(item,16) , tonumber(xor,16)) + else + rs = tonumber(item, 16) + end + dex = (dex..'%04X'):format(rs) + end + s = s..dex.." | " + print( (" %02d | %s"):format(blockno,s)) end -- -- Send a "raw" iso14443a package, ie "hf 14a raw" command function sendRaw(rawdata, options) - --print(">> ", rawdata) - local flags = lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT + lib14a.ISO14A_COMMAND.ISO14A_RAW + lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC + lib14a.ISO14A_COMMAND.ISO14A_NO_RATS - local command = Command:new{cmd = cmds.CMD_READER_ISO_14443a, - arg1 = flags, -- Send raw - -- arg2 contains the length, which is half the length - -- of the ASCII-string rawdata - arg2 = string.len(rawdata)/2, - data = rawdata} - return lib14a.sendToDevice(command, options.ignore_response) + --print(">> ", rawdata) + local flags = lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT + lib14a.ISO14A_COMMAND.ISO14A_RAW + lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC + lib14a.ISO14A_COMMAND.ISO14A_NO_RATS + local command = Command:new{cmd = cmds.CMD_READER_ISO_14443a, + arg1 = flags, -- Send raw + -- arg2 contains the length, which is half the length + -- of the ASCII-string rawdata + arg2 = string.len(rawdata)/2, + data = rawdata} + return lib14a.sendToDevice(command, options.ignore_response) end -- -- Sends an instruction to do nothing, only disconnect function disconnect() - local command = Command:new{cmd = cmds.CMD_READER_ISO_14443a, arg1 = 0, } - -- We can ignore the response here, no ACK is returned for this command - -- Check /armsrc/iso14443a.c, ReaderIso14443a() for details - return lib14a.sendToDevice(command, true) - --core.console("hf 14a raw -r") -end ---- + local command = Command:new{cmd = cmds.CMD_READER_ISO_14443a, arg1 = 0,} + -- We can ignore the response here, no ACK is returned for this command + -- Check /armsrc/iso14443a.c, ReaderIso14443a() for details + return lib14a.sendToDevice(command, true) + --core.console("hf 14a raw -r") +end +--- -- The main entry point function main(args) - local ignore_response = false - local endblock = 20 - - -- Read the parameters - for o, a in getopt.getopt(args, 'hb:') do - if o == "h" then return help() end - if o == "b" then endblock = a end - end - endblock = endblock or 20 - - -- First of all, connect - info, err = lib14a.read(true, true) - if err then disconnect() return oops(err) end - core.clearCommandBuffer() - - local blockData = {} - - -- Show tag info - print(("\nFound Card UID [%s]\n"):format(info.uid)) + local ignore_response = false + local endblock = 20 - print("blk | data | xored") - print("----+------------------+-------------------") - for block = 00, endblock do - local cmd = string.format("10%02x00", block) - res, err = sendRaw(cmd , {ignore_response = ignore_response}) - if err then disconnect() return oops(err) end - - local cmd_response = Command.parse(res) - local len = tonumber(cmd_response.arg1) * 2 - local data = string.sub(tostring(cmd_response.data), 0, len-4) + -- Read the parameters + for o, a in getopt.getopt(args, 'hb:') do + if o == "h" then return help() end + if o == "b" then endblock = a end + end + endblock = endblock or 20 - showdata(block, data) - table.insert(blockData, data) - end - print("----+------------------+-------------------") - disconnect() - - local filename, err = writeDumpFile(info.uid, blockData) - if err then return oops(err) end + -- First of all, connect + info, err = lib14a.read(true, true) + if err then disconnect() return oops(err) end + core.clearCommandBuffer() - print(string.format("\nDumped data into %s", filename)) + local blockData = {} + + -- Show tag info + print(("\nFound Card UID [%s]\n"):format(info.uid)) + + print("blk | data | xored") + print("----+------------------+-------------------") + for block = 00, endblock do + local cmd = string.format("10%02x00", block) + res, err = sendRaw(cmd , {ignore_response = ignore_response}) + if err then disconnect() return oops(err) end + + local cmd_response = Command.parse(res) + local len = tonumber(cmd_response.arg1) * 2 + local data = string.sub(tostring(cmd_response.data), 0, len-4) + + showdata(block, data) + table.insert(blockData, data) + end + print("----+------------------+-------------------") + disconnect() + + local filename, err = writeDumpFile(info.uid, blockData) + if err then return oops(err) end + + print(string.format("\nDumped data into %s", filename)) end - + ------------------------- --- Testing +-- Testing ------------------------- function selftest() - DEBUG = true - dbg("Performing test") - main() - dbg("Tests done") + DEBUG = true + dbg("Performing test") + main() + dbg("Tests done") end --- Flip the switch here to perform a sanity check. +-- Flip the switch here to perform a sanity check. -- It read a nonce in two different ways, as specified in the usage-section -if "--test"==args then - selftest() -else - -- Call the main - main(args) +if "--test"==args then + selftest() +else + -- Call the main + main(args) end \ No newline at end of file diff --git a/client/scripts/ul_uid.lua b/client/scripts/ul_uid.lua index d87939c4a..7dbb51b49 100644 --- a/client/scripts/ul_uid.lua +++ b/client/scripts/ul_uid.lua @@ -6,139 +6,139 @@ author = "Iceman" version = 'v1.0.0' desc = [[ This script tries to set UID on a mifare Ultralight magic card which either - - answers to chinese backdoor commands + - answers to chinese backdoor commands - brickable magic tag (must write in one session) ]] example = [[ - -- backdoor magic tag - script run ul_uid -u 11223344556677 - - -- brickable magic tag - script run ul_uid -b -u 11223344556677 + -- backdoor magic tag + script run ul_uid -u 11223344556677 + + -- brickable magic tag + script run ul_uid -b -u 11223344556677 ]] usage = [[ script run ul_uid -h -b -u Arguments: - -h : this help - -u : UID (14 hexsymbols) - -b : write to brickable magic tag + -h : this help + -u : UID (14 hexsymbols) + -b : write to brickable magic tag ]] local DEBUG = true local bxor = bit32.bxor ---- +--- -- 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 ---- + 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) - return nil, err + print("ERROR: ",err) + return nil, err end ---- +--- -- Usage help local function help() - print(copyright) - print(author) - print(version) - print(desc) - print('Example usage') - print(example) + print(copyright) + print(author) + print(version) + print(desc) + print('Example usage') + print(example) end -- --- Set UID on magic command enabled function magicUID(b0, b1, b2) - print('Using backdoor Magic tag function') + print('Using backdoor Magic tag function') - -- write block 0 - core.console("hf 14a raw -p -a -b 7 40") - core.console("hf 14a raw -p -a 43") - core.console("hf 14a raw -c -a A200"..b0) + -- write block 0 + core.console("hf 14a raw -p -a -b 7 40") + core.console("hf 14a raw -p -a 43") + core.console("hf 14a raw -c -a A200"..b0) - -- write block 1 - core.console("hf 14a raw -p -a -b 7 40") - core.console("hf 14a raw -p -a 43") - core.console("hf 14a raw -c -a A201"..b1) + -- write block 1 + core.console("hf 14a raw -p -a -b 7 40") + core.console("hf 14a raw -p -a 43") + core.console("hf 14a raw -c -a A201"..b1) - -- write block 2 - core.console("hf 14a raw -p -a -b 7 40") - core.console("hf 14a raw -p -a 43") - core.console("hf 14a raw -c -a A202"..b2) + -- write block 2 + core.console("hf 14a raw -p -a -b 7 40") + core.console("hf 14a raw -p -a 43") + core.console("hf 14a raw -c -a A202"..b2) end -- ---- Set UID on magic but brickable +--- Set UID on magic but brickable function brickableUID(b0, b1, b2) - - print('Using BRICKABLE Magic tag function') - - core.console("hf 14a raw -p -s -3") - - -- write block 0 - core.console("hf 14a raw -p -c A200"..b0) - -- write block 1 - core.console("hf 14a raw -p -c A201"..b1) + print('Using BRICKABLE Magic tag function') - -- write block 2 - core.console("hf 14a raw -p -c A202"..b2) + core.console("hf 14a raw -p -s -3") + + -- write block 0 + core.console("hf 14a raw -p -c A200"..b0) + + -- write block 1 + core.console("hf 14a raw -p -c A201"..b1) + + -- write block 2 + core.console("hf 14a raw -p -c A202"..b2) end ---- +--- -- The main entry point function main(args) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print() + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() - local uid = '04112233445566' - local tagtype = 1 - - -- Read the parameters - for o, a in getopt.getopt(args, 'hu:b') do - if o == "h" then return help() end - if o == "u" then uid = a end - if o == "b" then tagtype = 2 end - end - - -- uid string checks - if uid == nil then return oops('empty uid string') end - if #uid == 0 then return oops('empty uid string') end - if #uid ~= 14 then return oops('uid wrong length. Should be 7 hex bytes') end + local uid = '04112233445566' + local tagtype = 1 - local uidbytes = utils.ConvertHexToBytes(uid) - - local bcc1 = bxor(0x88, uidbytes[1], uidbytes[2], uidbytes[3]) - local bcc2 = bxor(uidbytes[4], uidbytes[5], uidbytes[6], uidbytes[7]) - - local block0 = string.format('%02X%02X%02X%02X', uidbytes[1], uidbytes[2], uidbytes[3], bcc1) - local block1 = string.format('%02X%02X%02X%02X', uidbytes[4], uidbytes[5], uidbytes[6], uidbytes[7]) - local block2 = string.format('%02X%02X%02X%02X', bcc2, 0x48, 0x00, 0x00) - - print('new UID | '..uid) - - core.clearCommandBuffer() - - if tagtype == 2 then - brickableUID(block0, block1, block2) - else - magicUID(block0, block1, block2) - end - - --halt - core.console("hf 14a raw -c -a 5000") + -- Read the parameters + for o, a in getopt.getopt(args, 'hu:b') do + if o == "h" then return help() end + if o == "u" then uid = a end + if o == "b" then tagtype = 2 end + end + + -- uid string checks + if uid == nil then return oops('empty uid string') end + if #uid == 0 then return oops('empty uid string') end + if #uid ~= 14 then return oops('uid wrong length. Should be 7 hex bytes') end + + local uidbytes = utils.ConvertHexToBytes(uid) + + local bcc1 = bxor(0x88, uidbytes[1], uidbytes[2], uidbytes[3]) + local bcc2 = bxor(uidbytes[4], uidbytes[5], uidbytes[6], uidbytes[7]) + + local block0 = string.format('%02X%02X%02X%02X', uidbytes[1], uidbytes[2], uidbytes[3], bcc1) + local block1 = string.format('%02X%02X%02X%02X', uidbytes[4], uidbytes[5], uidbytes[6], uidbytes[7]) + local block2 = string.format('%02X%02X%02X%02X', bcc2, 0x48, 0x00, 0x00) + + print('new UID | '..uid) + + core.clearCommandBuffer() + + if tagtype == 2 then + brickableUID(block0, block1, block2) + else + magicUID(block0, block1, block2) + end + + --halt + core.console("hf 14a raw -c -a 5000") end main(args)