diff --git a/armsrc/appmain.c b/armsrc/appmain.c index eed443599..bf4bddef6 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1285,10 +1285,20 @@ void UsbPacketReceived(uint8_t *packet, int len) { if (!FlashInit()) { break; } - + Flash_CheckBusy(BUSY_TIMEOUT); Flash_WriteEnable(); + + if ( startidx == DEFAULT_T55XX_KEYS_OFFSET ) + Flash_Erase4k(3, 0xC); + else if (startidx == DEFAULT_MF_KEYS_OFFSET ) + Flash_Erase4k(3, 0xB); + else if (startidx == DEFAULT_ICLASS_KEYS_OFFSET) + Flash_Erase4k(3, 0xA); + Flash_CheckBusy(BUSY_TIMEOUT); + Flash_WriteEnable(); + // inside 256b page? if ( (tmp & 0xFF) != 0) { diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 0dac64bd1..e690714df 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -103,7 +103,7 @@ void setT55xxConfig(uint8_t arg0, t55xx_config *c) { Flash_CheckBusy(BUSY_TIMEOUT); Flash_WriteEnable(); - Flash_Erase4k(3, 0xD); + Flash_Erase4k(3, 0xD); res = Flash_Write(T55XX_CONFIG_OFFSET, buf, T55XX_CONFIG_LEN); if ( res == T55XX_CONFIG_LEN && MF_DBGLEVEL > 1) { diff --git a/client/cmdflashmem.c b/client/cmdflashmem.c index 2ff68bd3d..6361d48e3 100644 --- a/client/cmdflashmem.c +++ b/client/cmdflashmem.c @@ -50,13 +50,19 @@ int usage_flashmem_read(void){ } int usage_flashmem_load(void){ PrintAndLogEx(NORMAL, "Loads binary file into flash memory on device"); - PrintAndLogEx(NORMAL, "Usage: mem load o f "); + PrintAndLogEx(NORMAL, "Usage: mem load o f m t i"); PrintAndLogEx(NORMAL, " o : offset in memory"); PrintAndLogEx(NORMAL, " f : file name"); + PrintAndLogEx(NORMAL, " m : upload 6 bytes keys (mifare key dictionary)"); + PrintAndLogEx(NORMAL, " i : upload 8 bytes keys (iClass key dictionary)"); + PrintAndLogEx(NORMAL, " t : upload 4 bytes keys (pwd dictionary)"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " mem load f myfile"); // upload file myfile at default offset 0 PrintAndLogEx(NORMAL, " mem load f myfile o 1024"); // upload file myfile at offset 1024 + PrintAndLogEx(NORMAL, " mem load f default_keys m"); + PrintAndLogEx(NORMAL, " mem load f default_pwd t"); + PrintAndLogEx(NORMAL, " mem load f default_iclass_keys i"); return 0; } int usage_flashmem_save(void){ @@ -154,7 +160,8 @@ int CmdFlashMemLoad(const char *Cmd){ uint32_t start_index = 0; char filename[FILE_PATH_SIZE] = {0}; bool errors = false; - uint8_t cmdp = 0; + uint8_t cmdp = 0; + Dictionary_t d = DICTIONARY_NONE; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { @@ -171,7 +178,19 @@ int CmdFlashMemLoad(const char *Cmd){ case 'o': start_index = param_get32ex(Cmd, cmdp+1, 0, 10); cmdp += 2; - break; + break; + case 'm': + d = DICTIONARY_MIFARE; + cmdp++; + break; + case 't': + d = DICTIONARY_T55XX; + cmdp++; + break; + case 'i': + d = DICTIONARY_ICLASS; + cmdp++; + break; default: PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; @@ -181,20 +200,61 @@ int CmdFlashMemLoad(const char *Cmd){ //Validations if (errors || cmdp == 0 ) return usage_flashmem_load(); - - uint8_t *data = calloc(FLASH_MEM_MAX_SIZE, sizeof(uint8_t)); + size_t datalen = 0; - int res = loadFile(filename, "bin", data, &datalen); - //int res = loadFileEML( filename, "eml", data, &datalen); - if ( res ) { - free(data); - return 1; - } + uint16_t keycount = 0; + int res = 0; + uint8_t *data = calloc(FLASH_MEM_MAX_SIZE, sizeof(uint8_t)); - if (datalen > FLASH_MEM_MAX_SIZE) { - PrintAndLogDevice(WARNING, "error, filesize is larger than available memory"); - free(data); - return 1; + switch (d) { + case DICTIONARY_MIFARE: + start_index = DEFAULT_MF_KEYS_OFFSET; + res = loadFileDICTIONARY(filename, "dic", data+2, &datalen, 6, &keycount ); + if ( res || !keycount) { + free(data); + return 1; + } + data[0] = (keycount >> 0) & 0xFF; + data[1] = (keycount >> 8) & 0xFF; + datalen += 2; + break; + case DICTIONARY_T55XX: + start_index = DEFAULT_T55XX_KEYS_OFFSET; + res = loadFileDICTIONARY(filename, "dic", data+2, &datalen, 4, &keycount ); + if ( res || !keycount) { + free(data); + return 1; + } + data[0] = (keycount >> 0) & 0xFF; + data[1] = (keycount >> 8) & 0xFF; + datalen += 2; + break; + case DICTIONARY_ICLASS: + start_index = DEFAULT_ICLASS_KEYS_OFFSET; + res = loadFileDICTIONARY(filename, "dic", data+2, &datalen, 8, &keycount ); + if ( res || !keycount) { + free(data); + return 1; + } + data[0] = (keycount >> 0) & 0xFF; + data[1] = (keycount >> 8) & 0xFF; + datalen += 2; + break; + default: + + res = loadFile(filename, "bin", data, &datalen); + //int res = loadFileEML( filename, "eml", data, &datalen); + if ( res ) { + free(data); + return 1; + } + + if (datalen > FLASH_MEM_MAX_SIZE) { + PrintAndLogDevice(WARNING, "error, filesize is larger than available memory"); + free(data); + return 1; + } + break; } data = realloc(data, datalen); diff --git a/client/cmdflashmem.h b/client/cmdflashmem.h index 843c17d6f..9f71a4ce0 100644 --- a/client/cmdflashmem.h +++ b/client/cmdflashmem.h @@ -24,6 +24,13 @@ #include "loclass/fileutils.h" //saveFile #include "comms.h" //getfromdevice +typedef enum { + DICTIONARY_NONE = 0, + DICTIONARY_MIFARE, + DICTIONARY_T55XX, + DICTIONARY_ICLASS +} Dictionary_t; + extern int CmdFlashMem(const char *Cmd); extern int CmdFlashMemRead(const char* cmd); diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 6cc2aa191..0e62afaf6 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -2316,7 +2316,8 @@ int LoadDictionaryKeyFile( char* filename, uint8_t **keys, int *keycnt) { while (fgetc(f) != '\n' && !feof(f)) {}; //The line start with # is comment, skip - if( buf[0]=='#' ) continue; + if( buf[0]=='#' ) + continue; // doesn't this only test first char only? if (!isxdigit(buf[0])){ @@ -2329,7 +2330,7 @@ int LoadDictionaryKeyFile( char* filename, uint8_t **keys, int *keycnt) { p = realloc(*keys, 8 * (keyitems += 64)); if (!p) { - PrintAndLogEx(NORMAL, _RED_([!])" cannot allocate memory for default keys"); + PrintAndLogEx(ERR, "cannot allocate memory for default keys"); fclose(f); return 2; } @@ -2341,7 +2342,7 @@ int LoadDictionaryKeyFile( char* filename, uint8_t **keys, int *keycnt) { memset(buf, 0, sizeof(buf)); } fclose(f); - PrintAndLogEx(NORMAL, _BLUE_([+]) "Loaded " _GREEN_(%2d) " keys from %s", *keycnt, filename); + PrintAndLogEx(SUCCESS, "Loaded " _GREEN_(%2d) " keys from %s", *keycnt, filename); return 0; } diff --git a/client/loclass/fileutils.c b/client/loclass/fileutils.c index b099d6a35..5bac3d2cd 100644 --- a/client/loclass/fileutils.c +++ b/client/loclass/fileutils.c @@ -453,6 +453,72 @@ out: return retval; } +int loadFileDICTIONARY(const char *preferredName, const char *suffix, void* data, size_t* datalen, uint8_t keylen, uint16_t* keycnt ) { + + if ( preferredName == NULL ) return 1; + if ( suffix == NULL ) return 1; + + // t5577 == 4bytes + // mifare == 6 bytes + // iclass == 8 bytes + // default to 6 bytes. + if (keylen != 4 && keylen != 6 && keylen != 8) { + keylen = 6; + } + + // double up since its chars + keylen <<= 1; + + char line[255]; + + size_t counter = 0; + int retval = 0; + int size = sizeof(char) * (strlen(preferredName) + strlen(suffix) + 10); + char * fileName = calloc(size, sizeof(char)); + sprintf(fileName,"%s.%s", preferredName, suffix); + + FILE *f = fopen(fileName, "r"); + if ( !f ) { + PrintAndLogDevice(FAILED, "file: %s: not found or locked.", fileName); + retval = 1; + goto out; + } + + // read file + while ( fgets(line, sizeof(line), f) ) { + + // add null terminator + line[keylen] = 0; + + // smaller keys than expected is skipped + if (strlen(line) < keylen) + continue; + + + // The line start with # is comment, skip + if( line[0] == '#' ) + continue; + + if (!isxdigit(line[0])){ + PrintAndLogEx(FAILED, "file content error. '%s' must include " _BLUE_(%2d) "HEX symbols", line, keylen); + continue; + } + + uint64_t key = strtoull(line, NULL, 16); + + num_to_bytes(key, keylen >> 1, data + counter); + (*keycnt)++; + memset(line, 0, sizeof(line)); + counter += (keylen >> 1); + } + fclose(f); + PrintAndLogDevice(SUCCESS, "loaded " _GREEN_(%2d) "keys from dictionary file %s", *keycnt, fileName); + *datalen = counter; +out: + free(fileName); + return retval; +} + #else //if we're on ARM #endif diff --git a/client/loclass/fileutils.h b/client/loclass/fileutils.h index b73f5fc30..3fc781d2e 100644 --- a/client/loclass/fileutils.h +++ b/client/loclass/fileutils.h @@ -124,7 +124,7 @@ extern int loadFile(const char *preferredName, const char *suffix, void* data, s */ extern int loadFileEML(const char *preferredName, const char *suffix, void* data, size_t* datalen); -/** STUB +/** * @brief Utility function to load data from a JSON textfile. This method takes a preferred name. * E.g. dumpdata-15.json * @@ -137,6 +137,21 @@ extern int loadFileEML(const char *preferredName, const char *suffix, void* data */ extern int loadFileJSON(const char *preferredName, const char *suffix, void* data, size_t maxdatalen, size_t* datalen); + +/** + * @brief Utility function to load data from a DICTIONARY textfile. This method takes a preferred name. + * E.g. default_keys.dic + * + * @param preferredName + * @param suffix the file suffix. Leave out the ".". + * @param data The data array to store the loaded bytes from file + * @param maxdatalen maximum size of data array in bytes + * @param datalen the number of bytes loaded from file + * @param keylen the number of bytes a key per row is + * @return 0 for ok, 1 for failz +*/ +extern int loadFileDICTIONARY(const char *preferredName, const char *suffix, void* data, size_t* datalen, uint8_t keylen, uint16_t* keycnt ); + #define PrintAndLogDevice(level, format, args...) PrintAndLogEx(level, format , ## args) #else diff --git a/client/scripts/read_pwd_mem.lua b/client/scripts/read_pwd_mem.lua index fbe4d0459..772927c0c 100644 --- a/client/scripts/read_pwd_mem.lua +++ b/client/scripts/read_pwd_mem.lua @@ -1,23 +1,29 @@ local getopt = require('getopt') local bin = require('bin') +copyright = 'Copyright (c) 2018 Bogito. All rights reserved.' author = "Bogito" -version = 'v1.0.0' -desc =[[ +version = 'v1.0.1' +desc = +[[ This script will read the flash memory of RDV4 and print the stored passwords. It was meant to be used as a help tool after using the BogRun standalone mode. + +(Iceman) script adapted to read and print keys in the default dictionary flashmemory sections. ]] -usage = [[ +usage = +[[ Usage: - script run read_pwd_mem -h -o -l + 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. + -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 ]] -example =[[ -Examples: +example = +[[ -- This will scan the first 256 bytes of flash memory for stored passwords script run read_pwd_mem @@ -26,61 +32,103 @@ Examples: -- This will scan 32 bytes of flash memory at offset 64 for stored passwords script run read_pwd_mem -o 64 -l 32 + + -- This will print found + script run read_pwd_mem -o 241664 -k 6 ]] - +--- +-- This is only meant to be used when errors occur +local function oops(err) + print("ERROR: ", err) + return nil, err +end +--- -- Usage help local function help() + print(copyright) + print(version) print(desc) print(usage) + print('Example usage:') print(example) end - +--- +-- The main entry point local function main(args) - local data, err, quadlet, pwdcnt + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() + + local data, err, quadlet + local cnt = 0 local offset = 0 local length = 256 + local keylength = 4 + local usedkey = false - -- Read the parameters - for o, a in getopt.getopt(args, 'ho:l:') do + for o, a in getopt.getopt(args, 'ho:l:k:') 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 end if length < 0 or length > 256 then - return print('Error: Length is not valid. Must be less than 256') + return oops('Error: Length is not valid. Must be less than 256') end - if ((offset < 0) or (offset % 4 ~= 0)) then - return print('Error: Offset is not valid. Mod-4 values are only allowed.') + if (offset < 0) or (offset % 4 ~= 0) then + return oops('Error: Offset is not valid. Mod-4 values are only allowed.') end - print('Offset: ' .. offset) - print('Length: ' .. length) - print() + print('Memory offset', offset) + print('Length ', length) + print('Key length ', keylength) + print( string.rep('--',20) ) - data, err = core.GetFromFlashMem(offset, length) + if usedkey then length = 4096 end + + data, err = core.GetFromFlashMem(offset, length) + if err then return oops(err) end - if err then - print(err) - return + if usedkey then + + _, keys, s = bin.unpack('SH'..length-2, data) + if keys == 0xFFFF then return "No keys found in section" end + + local kl = keylength * 2 + for i = 1, keys do + + key = string.sub(s, (i - 1) * kl + 1, i * kl ) + print(string.format("[%02d] %s",i, key)) + end + print( string.rep('--',20) ) + print( ('[+] found %d passwords'):format(keys)) + else + + _, s = bin.unpack('H'..length, data) + + local cnt = 0, i + for i = 1, (length/keylength) do + + key = string.sub(s, (i-1)*8+1, i*8) + if key == "FFFFFFFF" then break end + print(string.format("[%02d] %s",i, key)) + cnt = cnt + 1 + end + print( string.rep('--',20) ) + print( ('[+] found %d passwords'):format(cnt)) end - - local count, s = bin.unpack('H'..length, data) - - pwdcnt = 0 - for i = 1,(length/4),1 - do - quadlet = string.sub(s, (i-1)*8+1, i*8) - if quadlet == "FFFFFFFF" then break end - print(string.format("[%02d]",i) .. ' ' .. quadlet) - pwdcnt = pwdcnt + 1 - - end - print() - print('Found passwords: ' .. pwdcnt) - + print( string.rep('--',20) ) end main(args) diff --git a/include/common.h b/include/common.h index 90394448c..d3da792aa 100644 --- a/include/common.h +++ b/include/common.h @@ -90,13 +90,17 @@ extern uint32_t FLASHMEM_SPIBAUDRATE; #ifndef T55XX_CONFIG_OFFSET # define T55XX_CONFIG_OFFSET (FLASH_MEM_MAX_4K_SECTOR - 0x2000) #endif - - #ifndef DEFAULT_MF_KEYS_OFFSET - # define DEFAULT_MF_KEYS_OFFSET (FLASH_MEM_MAX_4K_SECTOR - 0x3000) + + #ifndef DEFAULT_T55XX_KEYS_OFFSET + # define DEFAULT_T55XX_KEYS_OFFSET (FLASH_MEM_MAX_4K_SECTOR - 0x3000) #endif - #ifndef DEFAULT_LF_KEYS_OFFSET - # define DEFAULT_LF_KEYS_OFFSET (FLASH_MEM_MAX_4K_SECTOR - 0x4000) + #ifndef DEFAULT_MF_KEYS_OFFSET + # define DEFAULT_MF_KEYS_OFFSET (FLASH_MEM_MAX_4K_SECTOR - 0x4000) + #endif + + #ifndef DEFAULT_ICLASS_KEYS_OFFSET + # define DEFAULT_ICLASS_KEYS_OFFSET (FLASH_MEM_MAX_4K_SECTOR - 0x5000) #endif #endif