From 43b5ee5918473ef6c131912f78135cf823e88738 Mon Sep 17 00:00:00 2001 From: Uli Heilmeier Date: Wed, 8 Apr 2020 22:47:13 +0200 Subject: [PATCH 1/5] legic.lua: updated to work again Fixed/changed things: * added info that virtual tag is always MIM1024 * changed reading files to read binary files (as written by 'hf legic dump') * changed extension for writing files (*.bin and *.eml) to be on par with 'hf legic dump' * CRC was calculated wrong when data was not padded with 0 for one char hex strings * readTag (rt) can now be called multiple times without using the wrong filename * tag length was calculated wrong as segment header length field includes the header itself * bytes are XORed before writing them to a tag * default name for file contains now the tag id --- CHANGELOG.md | 1 + client/luascripts/legic.lua | 161 +++++++++++++++++++----------------- 2 files changed, 87 insertions(+), 75 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eff29cc79..0f15617c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Updated 'legic.lua' and 'legic_clone.lua' script - works with current command set (@Pizza_4u) - Rewrote `hf mfdes` functions and added apdu debugging (@bkerler) - Add Mifare Desfire GetDFNames and improve HF MFDES Enum output (@bkerler) - Fix Mifare Desfire select appid handling (@bkerler) diff --git a/client/luascripts/legic.lua b/client/luascripts/legic.lua index 7e0f8d3be..393cc9e52 100644 --- a/client/luascripts/legic.lua +++ b/client/luascripts/legic.lua @@ -91,14 +91,20 @@ CRC1 = crc8 over addr 0x00..0x03+0x07..0x0E (special 'gantner crc8') CRC2 = MCD + MSB0..2+ addr 0x06 + addr 0x05 + addr 0x07 + Stamp (regular Master-Token-CRC) --]] +--[[ +Known issues; needs to be fixed: +* last byte in last segment is handled incorrectly when it is the last bytes on the card itself (MIM256: => byte 256) +--]] + example = "script run legic" -author = "Mosci" -version = "1.0.3" +author = "Mosci, uhei" +version = "1.0.4" desc = [[ This script helps you to read, create and modify Legic Prime Tags (MIM22, MIM256, MIM1024) +The virtual tag (and therefore the file to be saved) is always a MIM1024 tag. it's kinda interactive with following commands in three categories: Data I/O Segment Manipulation Token-Data @@ -108,8 +114,8 @@ it's kinda interactive with following commands in three categories: ed => edit Segment Data tk => toggle KGH-Flag File I/O rs => remove Segment ----------------- cc => check Segment-CRC - lf => load File ck => check KGH - sf => save File ds => dump Segments + lf => load bin File ck => check KGH + sf => save eml/bin File ds => dump Segments xf => xor to File @@ -128,8 +134,8 @@ it's kinda interactive with following commands in three categories: without the need of changing anything - MCD,MSN,MCC will be read from the tag before and applied to the output. - lf: 'load file' - load a (xored) file from the local Filesystem into the 'virtual inTag' - sf: 'save file' - saves the 'virtual inTag' to the local Filesystem (xored with Tag-MCC) + lf: 'load file' - load a (xored) binary file (*.bin) from the local Filesystem into the 'virtual inTag' + sf: 'save file' - saves the 'virtual inTag' to the local Filesystem as eml and bin (xored with Tag-MCC) xf: 'xor file' - saves the 'virtual inTag' to the local Filesystem (xored with choosen MCC - use '00' for plain values) ct: 'copy tag' - copy the 'virtual Tag' to a second 'virtual TAG' - not usefull yet, but inernally needed @@ -242,6 +248,16 @@ function istable(t) return type(t) == 'table' end +--- +-- To have two char string for a byte +local function padString(str) + if (#str == 1) then + return '0'..str + end + + return str +end + --- -- creates a 'deep copy' of a table (a=b only references) function deepCopy(object) @@ -387,15 +403,15 @@ end function bytesToTag(bytes, tag) if istable(tag) == false then return oops("tag is no table in: bytesToTag ("..type(tag)..")") end - tag.MCD =bytes[1]; - tag.MSN0=bytes[2]; - tag.MSN1=bytes[3]; - tag.MSN2=bytes[4]; - tag.MCC =bytes[5]; - tag.DCFl=bytes[6]; - tag.DCFh=bytes[7]; - tag.raw =bytes[8]; - tag.SSC =bytes[9]; + tag.MCD =padString(bytes[1]); + tag.MSN0=padString(bytes[2]); + tag.MSN1=padString(bytes[3]); + tag.MSN2=padString(bytes[4]); + tag.MCC =padString(bytes[5]); + tag.DCFl=padString(bytes[6]); + tag.DCFh=padString(bytes[7]); + tag.raw =padString(bytes[8]); + tag.SSC =padString(bytes[9]); tag.Type=getTokenType(tag.DCFl); tag.OLE=bbit("0x"..tag.DCFl,7,1) tag.WRP=("%d"):format(bbit("0x"..bytes[8],0,4)) @@ -500,42 +516,26 @@ function tagToBytes(tag) return bytes end + +--- --- PM3 I/O --- ---- --- read from pm3 into virtual-tag -function readFromPM3() - local tag, bytes, infile - infile="legic.temp" - -- core.console("hf legic reader") - -- core.console("hf legic esave "..infile) - core.console("hf legic dump o "..infile) - tag=readFile(infile..".bin") - return tag -end - -local function padString(str) - if (#str == 1) then - return '0'..str - end - - return str -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 + local writeDCF = false + if(utils.confirm(acred.."\nPlace the (empty) Tag onto the PM3\nand confirm writing to this Tag: "..acoff) == false) then return end + if(utils.confirm(acred.."\nShould the decremental field (DCF) be written?: "..acoff) == true) then + writeDCF = true + 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 + taglen = taglen + tag.SEG[i] . len end end local uid_old = tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2 @@ -571,37 +571,32 @@ function writeToTag(tag) bytes[22] = calcMtCrc(bytes) end if (bytes) then - print("write temp-file '"..filename.."'") - print(accyan) - writeFile(bytes, filename..".bin") - print(acoff) + bytes = xorBytes(bytes,tag.MCC) end end + -- write data to file if (taglen > 0) then WriteBytes = 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])) + for i=1, WriteBytes do + if (i > 7) then + cmd = ("hf legic wrbl o %02x d %s "):format(i-1, padString(bytes[i])) print(acgreen..cmd..acoff) core.console(cmd) core.clearCommandBuffer() + elseif (i == 7) then + if (writeDCF) then + -- write DCF in reverse order (requires 'mosci-patch') + cmd = ('hf legic wrbl o 05 d %s%s'):format(padString(bytes[i-1]), padString(bytes[i])) + print(acgreen..cmd..acoff) + core.console(cmd) + core.clearCommandBuffer() + else + print(acgreen.."skip byte 0x05-0x06 - DCF"..acoff) + end 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) @@ -641,12 +636,12 @@ end local function save_BIN(data, filename) local outfile local counter = 1 - local ext = filename:match("^.+(%..+)$") or '' - local fn = filename + local ext = ".bin" + local fn = filename..ext -- Make sure we don't overwrite a file while file_check(fn) do - fn = filename:gsub(ext, tostring(counter)..ext) + fn = filename..ext:gsub(ext, "-"..tostring(counter)..ext) counter = counter + 1 end @@ -664,26 +659,27 @@ 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?") + local emlext = ".eml" + if (filename ~= 'MyLegicClone') then + if (file_check(filename..emlext)) then + local answer = confirm("\nthe output-file "..filename..emlext.." 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") + local fho, err = io.open(filename..emlext, "w") if err then - return oops("OOps ... failed to open output-file ".. filename) + return oops("OOps ... failed to open output-file ".. filename..emlext) end bytes = xorBytes(bytes, bytes[5]) for i = 1, #bytes do if (bcnt == 0) then - line = bytes[i] + line = padString(bytes[i]) elseif (bcnt <= 7) then - line = line.." "..bytes[i] + line = line.." "..padString(bytes[i]) end if (bcnt == 7) then -- write line to new file @@ -699,7 +695,7 @@ function writeFile(bytes, filename) -- save binary local fn_bin, fn_bin_num = save_BIN(bytes, filename) - print("\nwrote "..acyellow..(#bytes * 3)..acoff.." bytes to " ..acyellow..filename..acoff) + print("\nwrote "..acyellow..(#bytes * 3)..acoff.." bytes to " ..acyellow..filename..emlext..acoff) if fn_bin and fn_bin_num then print("\nwrote "..acyellow..fn_bin_num..acoff.." bytes to BINARY file "..acyellow..fn_bin..acoff) @@ -708,6 +704,21 @@ function writeFile(bytes, filename) return true end +--- +-- read from pm3 into virtual-tag +function readFromPM3() + local tag, bytes, infile + --infile="legic.temp" + infile=os.tmpname() + core.console("hf legic dump f "..infile) + tag=readFile(infile..".bin") + os.remove(infile) + os.remove(infile..".bin") + os.remove(infile..".eml") + os.remove(infile..".json") + return tag +end + --- Map related --- --- -- make tagMap @@ -2265,8 +2276,8 @@ function modifyHelp() ed => edit Segment Data tk => toggle KGH-Flag File I/O rs => remove Segment ----------------- cc => check Segment-CRC - lf => load File ck => check KGH - sf => save File ds => dump Segments + lf => load bin File ck => check KGH + sf => save eml/bin File ds => dump Segments xf => xor to File @@ -2352,10 +2363,10 @@ function modifyMode() -- save values of mainTAG to a file (xored with MCC of mainTAG) ["sf"] = function(x) if istable(inTAG) then - outfile = input("enter filename:", "legic.temp") + outfile = input("enter filename:", "hf-legic-"..inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2) bytes = tagToBytes(inTAG) --bytes=xorBytes(bytes, inTAG.MCC) - if bytes then + if (bytes) then writeFile(bytes, outfile) end end @@ -2364,7 +2375,7 @@ function modifyMode() -- save values of mainTAG to a file (xored with 'specific' MCC) ["xf"] = function(x) if istable(inTAG) then - outfile = input("enter filename:", "legic.temp") + outfile = input("enter filename:", "hf-legic-"..inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2) crc = input("enter new crc: ('00' for a plain dump)", inTAG.MCC) print("obfuscate with: "..crc) bytes=tagToBytes(inTAG) From 0904cce336c8bb428613a0e63043a29aafdfd312 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 9 Apr 2020 13:23:36 +0200 Subject: [PATCH 2/5] fix: null --- client/cmdhfmfdes.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/client/cmdhfmfdes.c b/client/cmdhfmfdes.c index 22e401b07..3d805631d 100644 --- a/client/cmdhfmfdes.c +++ b/client/cmdhfmfdes.c @@ -62,6 +62,7 @@ static int CmdHelp(const char *Cmd); */ int DESFIRESendApdu(bool activate_field, bool leavefield_on, sAPDU apdu, uint8_t *result, int max_result_len, int *result_len, uint16_t *sw) { + *result_len = 0; if (sw) *sw = 0; @@ -180,7 +181,7 @@ static int test_desfire_authenticate() { sAPDU apdu = {0x90, MFDES_AUTHENTICATE, 0x00, 0x00, 0x01, &c}; // 0x0A, KEY 0 int recv_len = 0; uint16_t sw = 0; - return send_desfire_cmd(&apdu, false, NONE, &recv_len, &sw, 0); + return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0); } // none @@ -189,7 +190,7 @@ static int test_desfire_authenticate_iso() { sAPDU apdu = {0x90, MFDES_AUTHENTICATE_ISO, 0x00, 0x00, 0x01, &c}; // 0x1A, KEY 0 int recv_len = 0; uint16_t sw = 0; - return send_desfire_cmd(&apdu, false, NONE, &recv_len, &sw, 0); + return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0); } //none @@ -198,7 +199,7 @@ static int test_desfire_authenticate_aes() { sAPDU apdu = {0x90, MFDES_AUTHENTICATE_AES, 0x00, 0x00, 0x01, &c}; // 0xAA, KEY 0 int recv_len = 0; uint16_t sw = 0; - return send_desfire_cmd(&apdu, false, NONE, &recv_len, &sw, 0); + return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0); } // --- FREE MEM @@ -405,7 +406,7 @@ static int get_desfire_select_application(uint8_t *aid) { int recv_len = 0; uint16_t sw = 0; if (aid == NULL) return PM3_ESOFT; - return send_desfire_cmd(&apdu, true, NONE, &recv_len, &sw, sizeof(dfname_t)); + return send_desfire_cmd(&apdu, true, NULL, &recv_len, &sw, sizeof(dfname_t)); } // none From dcede2f8e39a724879c5083f450b31722c91a8c7 Mon Sep 17 00:00:00 2001 From: Uli Heilmeier Date: Thu, 9 Apr 2020 13:24:27 +0200 Subject: [PATCH 3/5] cmdhfmfdes: fix clang warnings Make clang happy and fix several error: expression which evaluates to zero treated as a null pointer constant of type 'uint8_t *' (aka 'unsigned char *') [-Werror,-Wnon-literal-null-conversion] and cmdhfmfdes.c:732:31: error: suggest braces around initialization of subobject [-Werror,-Wmissing-braces] Fixes RfidResearchGroup/proxmark3#659 --- client/cmdhfmfdes.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/client/cmdhfmfdes.c b/client/cmdhfmfdes.c index 22e401b07..d52242823 100644 --- a/client/cmdhfmfdes.c +++ b/client/cmdhfmfdes.c @@ -180,7 +180,7 @@ static int test_desfire_authenticate() { sAPDU apdu = {0x90, MFDES_AUTHENTICATE, 0x00, 0x00, 0x01, &c}; // 0x0A, KEY 0 int recv_len = 0; uint16_t sw = 0; - return send_desfire_cmd(&apdu, false, NONE, &recv_len, &sw, 0); + return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0); } // none @@ -189,7 +189,7 @@ static int test_desfire_authenticate_iso() { sAPDU apdu = {0x90, MFDES_AUTHENTICATE_ISO, 0x00, 0x00, 0x01, &c}; // 0x1A, KEY 0 int recv_len = 0; uint16_t sw = 0; - return send_desfire_cmd(&apdu, false, NONE, &recv_len, &sw, 0); + return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0); } //none @@ -198,7 +198,7 @@ static int test_desfire_authenticate_aes() { sAPDU apdu = {0x90, MFDES_AUTHENTICATE_AES, 0x00, 0x00, 0x01, &c}; // 0xAA, KEY 0 int recv_len = 0; uint16_t sw = 0; - return send_desfire_cmd(&apdu, false, NONE, &recv_len, &sw, 0); + return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0); } // --- FREE MEM @@ -209,7 +209,7 @@ static int desfire_print_freemem(uint32_t free_mem) { // init / disconnect static int get_desfire_freemem(uint32_t *free_mem) { - sAPDU apdu = {0x90, MFDES_GET_FREE_MEMORY, 0x00, 0x00, 0x00, NONE}; // 0x6E + sAPDU apdu = {0x90, MFDES_GET_FREE_MEMORY, 0x00, 0x00, 0x00, NULL}; // 0x6E int recv_len = 0; uint16_t sw = 0; uint8_t fmem[4] = {0}; @@ -334,7 +334,7 @@ static int desfire_print_keysetting(uint8_t key_settings, uint8_t num_keys) { // none static int get_desfire_keysettings(uint8_t *key_settings, uint8_t *num_keys) { - sAPDU apdu = {0x90, MFDES_GET_KEY_SETTINGS, 0x00, 0x00, 0x00, NONE}; //0x45 + sAPDU apdu = {0x90, MFDES_GET_KEY_SETTINGS, 0x00, 0x00, 0x00, NULL}; //0x45 int recv_len = 0; uint16_t sw = 0; uint8_t data[2] = {0}; @@ -405,7 +405,7 @@ static int get_desfire_select_application(uint8_t *aid) { int recv_len = 0; uint16_t sw = 0; if (aid == NULL) return PM3_ESOFT; - return send_desfire_cmd(&apdu, true, NONE, &recv_len, &sw, sizeof(dfname_t)); + return send_desfire_cmd(&apdu, true, NULL, &recv_len, &sw, sizeof(dfname_t)); } // none @@ -729,7 +729,7 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) { uint8_t file_ids[33] = {0}; uint8_t file_ids_len = 0; - dfname_t dfnames[255] = {0}; + dfname_t dfnames[255]; uint8_t dfname_count = 0; if (get_desfire_appids(app_ids, &app_ids_len) != PM3_SUCCESS) { From 8f07ac80d11e9d9009511661154294bc528cb1f2 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 9 Apr 2020 13:28:43 +0200 Subject: [PATCH 4/5] fix: null --- client/cmdhfmfdes.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/client/cmdhfmfdes.c b/client/cmdhfmfdes.c index 3d805631d..add158e0e 100644 --- a/client/cmdhfmfdes.c +++ b/client/cmdhfmfdes.c @@ -177,8 +177,8 @@ static desfire_cardtype_t getCardType(uint8_t major, uint8_t minor) { //none static int test_desfire_authenticate() { - uint8_t c = 0x00; - sAPDU apdu = {0x90, MFDES_AUTHENTICATE, 0x00, 0x00, 0x01, &c}; // 0x0A, KEY 0 + uint8_t data[] = {0x00}; + sAPDU apdu = {0x90, MFDES_AUTHENTICATE, 0x00, 0x00, 0x01, data}; // 0x0A, KEY 0 int recv_len = 0; uint16_t sw = 0; return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0); @@ -186,8 +186,8 @@ static int test_desfire_authenticate() { // none static int test_desfire_authenticate_iso() { - uint8_t c = 0x00; - sAPDU apdu = {0x90, MFDES_AUTHENTICATE_ISO, 0x00, 0x00, 0x01, &c}; // 0x1A, KEY 0 + uint8_t data[] = {0x00}; + sAPDU apdu = {0x90, MFDES_AUTHENTICATE_ISO, 0x00, 0x00, 0x01, data}; // 0x1A, KEY 0 int recv_len = 0; uint16_t sw = 0; return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0); @@ -195,8 +195,8 @@ static int test_desfire_authenticate_iso() { //none static int test_desfire_authenticate_aes() { - uint8_t c = 0x00; - sAPDU apdu = {0x90, MFDES_AUTHENTICATE_AES, 0x00, 0x00, 0x01, &c}; // 0xAA, KEY 0 + uint8_t data[] = {0x00}; + sAPDU apdu = {0x90, MFDES_AUTHENTICATE_AES, 0x00, 0x00, 0x01, data}; // 0xAA, KEY 0 int recv_len = 0; uint16_t sw = 0; return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0); @@ -210,7 +210,7 @@ static int desfire_print_freemem(uint32_t free_mem) { // init / disconnect static int get_desfire_freemem(uint32_t *free_mem) { - sAPDU apdu = {0x90, MFDES_GET_FREE_MEMORY, 0x00, 0x00, 0x00, NONE}; // 0x6E + sAPDU apdu = {0x90, MFDES_GET_FREE_MEMORY, 0x00, 0x00, 0x00, NULL}; // 0x6E int recv_len = 0; uint16_t sw = 0; uint8_t fmem[4] = {0}; @@ -335,7 +335,7 @@ static int desfire_print_keysetting(uint8_t key_settings, uint8_t num_keys) { // none static int get_desfire_keysettings(uint8_t *key_settings, uint8_t *num_keys) { - sAPDU apdu = {0x90, MFDES_GET_KEY_SETTINGS, 0x00, 0x00, 0x00, NONE}; //0x45 + sAPDU apdu = {0x90, MFDES_GET_KEY_SETTINGS, 0x00, 0x00, 0x00, NULL}; //0x45 int recv_len = 0; uint16_t sw = 0; uint8_t data[2] = {0}; From aba7c88565536597434a94cd7350e17294badb9e Mon Sep 17 00:00:00 2001 From: Iceman Date: Thu, 9 Apr 2020 18:43:26 +0200 Subject: [PATCH 5/5] Update Troubleshooting.md --- doc/md/Installation_Instructions/Troubleshooting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/md/Installation_Instructions/Troubleshooting.md b/doc/md/Installation_Instructions/Troubleshooting.md index e727180bf..3fba71e1c 100644 --- a/doc/md/Installation_Instructions/Troubleshooting.md +++ b/doc/md/Installation_Instructions/Troubleshooting.md @@ -18,7 +18,7 @@ Always use the latest repository commits from *master* branch. There are always * [File not found](#file-not-found) * [Pixmap / pixbuf warnings](#pixmap--pixbuf-warnings) * [Usb cable](#usb-cable) - * [WSL 2 explorer.exe . doesnt work](WSL-2) + * [WSL 2 explorer.exe . doesnt work](#WSL-2) ## `pm3` or `pm3-flash*` doesn't see my Proxmark