From ead825720d9d3928ad4183a8be9a47078794f48c Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sun, 17 Nov 2019 11:45:20 +0100 Subject: [PATCH 1/4] covsubmit: avoid aborting when previous data are not present --- covsubmit.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/covsubmit.sh b/covsubmit.sh index dcfda0999..e39240954 100755 --- a/covsubmit.sh +++ b/covsubmit.sh @@ -6,7 +6,7 @@ set -e pre_submit_hook ## delete all previous tarballs -rm proxmark3.all.*.tgz proxmark3.all.*.log +rm -f proxmark3.all.*.tgz proxmark3.all.*.log TODAY="$(date --date now +%Y%m%d.%H%M)" VERSION="0.1.$TODAY" From 5dc2c7c3929c42ae0749c85e8d806938a6ac8c9b Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sun, 17 Nov 2019 11:47:08 +0100 Subject: [PATCH 2/4] pm3 serial detection on Linux more robust. Fixes #475 Official firmwares < 2018.02 had a different USB Model string (PM3<>proxmark3). Better to detect based on the vendor string (proxmark.org) which is more stable, to ease reflashing devices with old firmwares to the RDV4 firmware. Thanks @fishilico for having pointed it out. --- pm3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pm3 b/pm3 index c3bed278e..a03b3351e 100755 --- a/pm3 +++ b/pm3 @@ -21,7 +21,7 @@ PM3LIST=() function get_pm3_list_Linux { PM3LIST=() for DEV in $(find /dev/ttyACM* 2>/dev/null); do - if udevadm info -q property -n "$DEV" |grep -q "ID_MODEL=proxmark3"; then + if udevadm info -q property -n "$DEV" |grep -q "ID_VENDOR=proxmark.org"; then PM3LIST+=("$DEV") fi done From dec0b0202a5cd0fa3aaba53e34f4dacf8f5fb5ab Mon Sep 17 00:00:00 2001 From: Denis Bodor Date: Sun, 17 Nov 2019 12:58:30 +0100 Subject: [PATCH 3/4] Add Luxeo dump script --- client/luascripts/luxeodump.lua | 309 ++++++++++++++++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 client/luascripts/luxeodump.lua diff --git a/client/luascripts/luxeodump.lua b/client/luascripts/luxeodump.lua new file mode 100644 index 000000000..182af67d4 --- /dev/null +++ b/client/luascripts/luxeodump.lua @@ -0,0 +1,309 @@ +--- +-- This Lua script is designed to run with Iceman/RRG Proxmark3 fork +-- Just copy luxeodump.lua to client/luascripts/ +-- and run "script run luxeodump" + +-- requirements +local cmds = require('commands') +local getopt = require('getopt') +local utils = require('utils') +local lib14a = require('read14a') +local ansicolors = require('ansicolors') + +copyright = '' +author = '0xdrrb' +version = 'v0.1.0' +desc = [[ +This is a script to dump and decrypt the data of a specific type of Mifare laundromat token. +]] +example = [[ + script run luxeodump +]] +usage = [[ +script run luxeodump +]] + +local PM3_SUCCESS = 0 + +-- Some shortcuts +local band = bit32.band +local bor = bit32.bor +local bnot = bit32.bnot +local bxor = bit32.bxor +local lsh = bit32.lshift +local rsh = bit32.rshift + +local acgreen = ansicolors.bright..ansicolors.green +local accyan = ansicolors.bright..ansicolors.cyan +local acred = ansicolors.red +local acyellow = ansicolors.bright..ansicolors.yellow +local acblue = ansicolors.bright..ansicolors.blue +local acmagenta = ansicolors.bright..ansicolors.magenta +local acoff = ansicolors.reset + + +-- This is only meant to be used when errors occur +local function oops(err) + print('ERROR: ', err) + core.clearCommandBuffer() + return nil, err +end + +local function setdevicedebug( status ) + local c = 'hw dbg ' + if status then + c = c..'1' + else + c = c..'0' + end + core.console(c) +end + +local function xteaCrypt(num_rounds, v, key) + local v0 = v[0] + local v1 = v[1] + local delta = 0x9E3779B9 + local sum = 0 + + for i = 0, num_rounds-1 do + -- v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]); + v0 = band(bxor(bxor(lsh(v1,4), rsh(v1,5)) + v1, sum + key[band(sum,3)]) + v0, 0xFFFFFFFF) + sum = band(sum + delta, 0xFFFFFFFF) + -- v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]); + v1 = band(bxor(bxor(lsh(v0,4), rsh(v0,5)) + v0, sum + key[band(rsh(sum,11),3)]) + v1, 0xFFFFFFFF) + end + v[0]=v0 + v[1]=v1 +end + +local function xteaDecrypt(num_rounds, v, key) + local v0 = v[0] + local v1 = v[1] + local delta = 0x9E3779B9 + local sum = band(delta * num_rounds, 0xFFFFFFFF) + + for i = 0, num_rounds-1 do + -- v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]); + v1 = band(v1 - bxor(bxor(lsh(v0,4), rsh(v0,5)) + v0, sum + key[band(rsh(sum,11),3)]), 0xFFFFFFFF) + sum = band(sum - delta, 0xFFFFFFFF) + -- v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]); + v0 = band(v0 - bxor(bxor(lsh(v1,4), rsh(v1,5)) + v1, sum + key[band(sum,3)]), 0xFFFFFFFF) + end + v[0]=v0 + v[1]=v1 +end + +local function createxteakey(mfuid) + local xteakey = {} + local buid = {} + local tmpkey = {} + local uid = {} + + -- Warning ! "it is customary in Lua to START ARRAYS WITH ONE" + buid = utils.ConvertHexToBytes(mfuid) + uid[0] = bor(buid[1], lsh(buid[2], 8)) + uid[1] = bor(buid[3], lsh(buid[4], 8)) + + tmpkey[0] = 0x198B + tmpkey[1] = uid[0] + tmpkey[2] = 0x46D8 + tmpkey[3] = uid[1] + tmpkey[4] = 0x5310 + tmpkey[5] = bxor(uid[0], 0xA312) + tmpkey[6] = 0xFFCB + tmpkey[7] = bxor(uid[1], 0x55AA) + + xteakey[0] = bor(lsh(tmpkey[1], 16), tmpkey[0]) + xteakey[1] = bor(lsh(tmpkey[3], 16), tmpkey[2]) + xteakey[2] = bor(lsh(tmpkey[5], 16), tmpkey[4]) + xteakey[3] = bor(lsh(tmpkey[7], 16), tmpkey[6]) + + return xteakey +end + +-- CRC16/ARC from core.reveng_runmodel() does not seem to return the right values. +-- So here is an implementation in Lua. +local function bitreflect(data, nbits) + local output = 0 + for i = 0, nbits-1 do + if bit.band(data,1) ~= 0 then + output = bit32.bor(output, bit32.lshift(1,((nbits - 1) - i))) + else + end + data = bit32.rshift(data,1) + end + return output +end + +local function crc16arc(s) + assert(type(s) == 'string') + local crc = 0x0000 + for i = 1, #s do + local c = s:byte(i) + dbyte = bitreflect(c, 8) + crc = bit32.bxor(crc, bit32.lshift(dbyte,8)) + for j = 0, 7 do + local mix = bit32.band(crc, 0x8000) + crc = bit32.lshift(crc,1) + if mix ~= 0 then + crc = bit32.bxor(crc, 0x8005) + end + end + end + return bitreflect(crc, 16) +end + +local function getblockdata(response) + if not response then + return nil, 'No response from device' + end + if response.Status == PM3_SUCCESS then + return response.Data + else + return nil, "Couldn't read block.. ["..response.Status.."]" + end +end + +local function readblock(blockno, key) + -- Read block N + local keytype = '01' -- key B + local data = ('%02x%s%s'):format(blockno, keytype, key) + local c = Command:newNG{cmd = cmds.CMD_HF_MIFARE_READBL, data = data} + local b, err = getblockdata(c:sendNG(false)) + if not b then return oops(err) end + return b +end + +local function readtag(mfkey,xteakey) + local tagdata = {} + local cleardata = {} + local v = {} + local vv = {} + + -- Read 4 sectors and build table + for sect = 8, 11 do + for blockn = sect*4, (sect*4)+2 do + local blockdata = readblock(blockn, mfkey) + if not blockdata then return oops('[!] failed reading block') end + table.insert(tagdata, blockdata) + end + end + + -- Decrypt data and build clear table + for key,value in ipairs(tagdata) do + local clearblockdata + v[0]=utils.SwapEndianness(value:sub(1,8),32) + v[1]=utils.SwapEndianness(value:sub(9,16),32) + xteaDecrypt(16, v, xteakey) + vv[0]=utils.SwapEndianness(value:sub(17,24),32) + vv[1]=utils.SwapEndianness(value:sub(25,32),32) + xteaDecrypt(16, vv, xteakey) + clearblockdata=string.format("%08X%08X%08X%08X", + utils.SwapEndianness(string.format("%08X", v[0]),32), + utils.SwapEndianness(string.format("%08X", v[1]),32), + utils.SwapEndianness(string.format("%08X", vv[0]),32), + utils.SwapEndianness(string.format("%08X", vv[1]),32)) + table.insert(cleardata, clearblockdata) + end + + return tagdata,cleardata + +end + + +local function main(args) + local xteakey = {} + -- local v = {} + local edata = {} + local cdata = {} + + -- Turn off Debug + setdevicedebug(false) + + -- GET TAG UID + tag, err = lib14a.read(false, true) + if err then + lib14a.disconnect() + return oops(err) + end + core.clearCommandBuffer() + + -- simple tag check + if 0x08 ~= tag.sak then + if 0x0400 ~= tag.atqa then + return oops(('[fail] found tag %s :: looking for Mifare S50 1k'):format(tag.name)) + end + end + + xteakey = createxteakey(tag.uid) + print(acblue.."UID: "..tag.uid..acoff) + print(acblue..string.format("XTEA key: %08X %08X %08X %08X", xteakey[0], xteakey[1], xteakey[2], xteakey[3])..acoff) + + edata, cdata = readtag("415A54454B4D",xteakey) + + if edata == nil or cdata == nil then + print("ERROR Reading tag!") + return nil + end + + print("Ciphered data:") + for key,value in ipairs(edata) do + print(value) + if key % 3 == 0 then print("") end + end + + -- compute CRC for each segment + crcH = crc16arc(utils.ConvertHexToAscii(cdata[1]..cdata[2]..cdata[3]:sub(1,28))) + crcA = crc16arc(utils.ConvertHexToAscii(cdata[4]..cdata[5]..cdata[6]..cdata[7]:sub(1,28))) + crcB = crc16arc(utils.ConvertHexToAscii(cdata[8]..cdata[9]..cdata[10]..cdata[11]:sub(1,28))) + + print("\nHeader:") + for key,value in ipairs(cdata) do + if key == 3 then + print(value:sub(1,28)..acmagenta..value:sub(29,32)..acoff) + if utils.SwapEndianness(value:sub(29,32),16) == crcH then strcrc = " OK" else strcrc = acred.." CRCERROR !!" end + print(acmagenta.."CRC16/ARC = "..string.format("0x%04X", crcH)..strcrc..acoff) + print("\nDataA:") + elseif key == 4 then + print(acgreen..value:sub(1,4)..acoff..value:sub(5,16)..accyan..value:sub(17,24)..acoff..value:sub(25,26)..accyan..value:sub(27,28)..acoff..value:sub(29,32)) + versionA = utils.SwapEndianness(value:sub(1,4),16) + dateA = string.format("%d/%02d/%02d %02d:%02d", tonumber(value:sub(17,18),10)+2000, tonumber(value:sub(19,20),10), + tonumber(string.format("%02X", band(tonumber(value:sub(21,22),16),0x3f)),10), + tonumber(value:sub(23,24),10), tonumber(value:sub(27,28),10)) + elseif key == 8 then + print(acgreen..value:sub(1,4)..acoff..value:sub(5,16)..accyan..value:sub(17,24)..acoff..value:sub(25,26)..accyan..value:sub(27,28)..acoff..value:sub(29,32)) + versionB = utils.SwapEndianness(value:sub(1,4),16) + dateB = string.format("%d/%02d/%02d %02d:%02d", tonumber(value:sub(17,18),10)+2000, tonumber(value:sub(19,20),10), + tonumber(string.format("%02X", band(tonumber(value:sub(21,22),16),0x3f)),10), + tonumber(value:sub(23,24),10), tonumber(value:sub(27,28),10)) + elseif key == 5 then + print(acyellow..value:sub(1,4)..acoff..value:sub(5,32)) + creditA = utils.SwapEndianness(value:sub(1,4),16)/100 + elseif key == 9 then + print(acyellow..value:sub(1,4)..acoff..value:sub(5,32)) + creditB = utils.SwapEndianness(value:sub(1,4),16)/100 + elseif key == 7 then + print(value:sub(1,28)..acmagenta..value:sub(29,32)..acoff) + print(acgreen.."Version "..string.format("0x%04X", versionA)..acoff) + print(acyellow.."Credit : "..creditA..acoff) + if utils.SwapEndianness(value:sub(29,32),16) == crcA then strcrc = " OK" else strcrc = acred.." CRCERROR !!" end + print(acmagenta.."CRC16/ARC = "..string.format("0x%04X", crcA)..strcrc..acoff) + print(accyan.."Date: "..dateA..acoff) + print("\nDataB:") + elseif key == 11 then + print(value:sub(1,28)..acmagenta..value:sub(29,32)..acoff) + print(acgreen.."Version "..string.format("0x%04X", versionB)..acoff) + print(acyellow.."Credit : "..creditB..acoff) + if utils.SwapEndianness(value:sub(29,32),16) == crcB then strcrc = " OK" else strcrc = acred.." CRCERROR !!" end + print(acmagenta.."CRC16/ARC = "..string.format("0x%04X", crcB)..strcrc..acoff) + print(accyan.."Date: "..dateB..acoff) + print("\nFooter:") + else + print(value) + end + end + + return +end + +main(args) From 5e85d53c3e272f280f689d7f38dc2ce48e9aecbb Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Mon, 18 Nov 2019 13:11:28 +0100 Subject: [PATCH 4/4] pm3 serial detection on OS X more robust Official firmwares < 2018.02 had a different USB Model string (PM3<>proxmark3). Better to detect based on the vendor string (proxmark.org) which is more stable, to ease reflashing devices with old firmwares to the RDV4 firmware. --- pm3 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pm3 b/pm3 index a03b3351e..d40fb0a91 100755 --- a/pm3 +++ b/pm3 @@ -29,7 +29,9 @@ function get_pm3_list_Linux { function get_pm3_list_macOS { PM3LIST=() - for DEV in $(ioreg -r -n proxmark3 -l|awk -F '"' '/IODialinDevice/{print $4}'); do + for DEV in $(ioreg -r -c "IOUSBHostDevice" -l|awk -F '"' ' + $2=="USB Vendor Name"{b=($4=="proxmark.org")} + b==1 && $2=="IODialinDevice"{print $4}'); do PM3LIST+=("$DEV") done }