This commit is contained in:
iceman1001 2024-07-21 16:19:21 +02:00
commit 4de7b7d6b9
10 changed files with 103 additions and 66 deletions

View file

@ -119,7 +119,7 @@ void RunMod(void) {
LEDsoff();
Dbprintf("[=] >> LF EM4100 simulator stopped due to button hold <<");
return; // RunMod end
}
}
selected = (selected + 1) % em4100emul_slots_count;
}
}

View file

@ -2242,17 +2242,17 @@ void iClass_Recover(iclass_recover_req_t *msg) {
//Viewing the weak macs table card 24 bits (3x8) in the form of a 24 bit decimal number
static uint32_t iclass_mac_table_bit_values[8] = {0, 2396745, 4793490, 7190235, 9586980, 11983725, 14380470, 16777215};
/* iclass_mac_table is a series of weak macs, those weak macs correspond to the different combinations of the last 3 bits of each key byte.
If we concatenate the last three bits of each key byte, we have a 24 bits long binary string.
If we convert that string to decimal we obtain the decimal numbers in iclass_mac_table_bit_values
Xorring the index of iterations against those decimal numbers allows us to retrieve the what was the corresponding sequence of bits of the original key in decimal format. */
/* iclass_mac_table is a series of weak macs, those weak macs correspond to the different combinations of the last 3 bits of each key byte.
If we concatenate the last three bits of each key byte, we have a 24 bits long binary string.
If we convert that string to decimal we obtain the decimal numbers in iclass_mac_table_bit_values
Xorring the index of iterations against those decimal numbers allows us to retrieve the what was the corresponding sequence of bits of the original key in decimal format. */
uint8_t zero_key[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint32_t index = 1;
int bits_found = -1;
//START LOOP
while (bits_found == -1){
while (bits_found == -1) {
//Step3 Calculate New Key
uint8_t genkeyblock[PICOPASS_BLOCK_SIZE];
@ -2262,12 +2262,12 @@ Xorring the index of iterations against those decimal numbers allows us to retri
//NOTE BEFORE UPDATING THE KEY WE NEED TO KEEP IN MIND KEYS ARE XORRED
//xor the new key against the previously generated key so that we only update the difference
if(index != 0){
if (index != 0) {
generate_single_key_block_inverted(zero_key, index - 1, genkeyblock_old);
for (int i = 0; i < 8 ; i++) {
xorkeyblock[i] = genkeyblock[i] ^ genkeyblock_old[i];
}
}else{
} else {
memcpy(xorkeyblock, genkeyblock, PICOPASS_BLOCK_SIZE);
}
@ -2289,7 +2289,7 @@ Xorring the index of iterations against those decimal numbers allows us to retri
Dbprintf("Write block [%3d/0x%02X] " _GREEN_("successful"), blockno, blockno);
} else {
Dbprintf("Write block [%3d/0x%02X] " _RED_("failed"), blockno, blockno);
if (index > 1){
if (index > 1) {
Dbprintf(_RED_("Card is likely to be unusable!"));
}
goto out;
@ -2349,4 +2349,4 @@ out:
switch_off();
reply_ng(CMD_HF_ICLASS_RECOVER, PM3_ESOFT, NULL, 0);
}
}

View file

@ -414,4 +414,4 @@ void convertToHexArray(uint8_t num, uint8_t *partialkey) {
group[3] = '\0'; // Null-terminate the group string
partialkey[i] = (uint8_t)strtoul(group, NULL, 2);
}
}
}

View file

@ -8,33 +8,33 @@ mod = " ELECTRA or EM410x fob cloning SCRIPT "
version = " v1.1.17 02/09/2023 made by jareckib "
desc = [[
Cloning new ELECTRA tags or EM410x to T5577 tag. This script changes
block 0. Additional data is written to block 3 and 4. The last
ELECTRA ID can be accessed through the option ---> "-c". For copy
directly from the original ELECTRA tag, ---> option "-e". For copy
from input, EM410X ID ---> option "-s". Next option for cloning simple
EM4102 ---> option "-m". If press <Enter> it, which writes an ID.
Cloning new ELECTRA tags or EM410x to T5577 tag. This script changes
block 0. Additional data is written to block 3 and 4. The last
ELECTRA ID can be accessed through the option ---> "-c". For copy
directly from the original ELECTRA tag, ---> option "-e". For copy
from input, EM410X ID ---> option "-s". Next option for cloning simple
EM4102 ---> option "-m". If press <Enter> it, which writes an ID.
If press <n> ---> exit the script.
]]
example = [[
-------------------------------------------------------------------------------
--------------- cloning ELECTRA tag from input ID to T5577 tag ----------------
script run lf_electra -s 11AA22BB55
----------------- continue cloning from last cloned ELECTRA -------------------
----------------- continue cloning from last cloned ELECTRA -------------------
script run lf_electra -c
---------------------- ELECTRA cloning from the original TAG -----------------
script run lf_electra -e
----------------------------- simple EM4102 cloning ---------------------------
----------------------------- simple EM4102 cloning ---------------------------
script run lf_electra -m
-------------------------------------------------------------------------------
]]
usage = [[
@ -212,7 +212,7 @@ local function main(args)
if o == 'c' then saved_id = true end
end
--------------------check -id
if not saved_id and not id_original and not emarine then
if not saved_id and not id_original and not emarine then
if input_id == nil then return oops(' empty EM410x ID string') end
if #input_id == 0 then return oops(' empty EM410x ID string') end
if #input_id < 10 then return oops(' EM410x ID too short. Must be 5 hex bytes') end

View file

@ -89,7 +89,7 @@ def Describe_Usage_1(Usage, ContractMediumEndDate, Certificate):
EventTimeStamp = Usage.nom(11)
unk = Usage.nom_bits(65)
EventValidityTimeFirstStamp = Usage.nom(11)
print(' EventDateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d')));
print(' EventTimeStamp : {} ({:02d}:{:02d})'. format(EventTimeStamp, EventTimeStamp // 60, EventTimeStamp % 60))
print(' unk1... :', unk);
@ -109,7 +109,7 @@ def Describe_Usage_1_1(Usage, ContractMediumEndDate, Certificate):
EventGeoRoute_Direction = Usage.nom(2)
EventCountPassengers_mb = Usage.nom(4)
EventValidityTimeFirstStamp = Usage.nom(11)
print(' DateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d')));
print(' TimeStamp : {} ({:02d}:{:02d})'. format(EventTimeStamp, EventTimeStamp // 60, EventTimeStamp % 60))
print(' unk0... :', unk0);
@ -137,12 +137,12 @@ def Describe_Usage_1_2(Usage, ContractMediumEndDate, Certificate):
EventGeoRoute_Direction = Usage.nom(2)
EventCountPassengers_mb = Usage.nom(4)
EventValidityTimeFirstStamp = Usage.nom(11)
TYPE_EventCode_Nature_Reims = { # usually it's the opposite, but ... ?
0x4: 'urban bus',
0x1: 'tramway',
}
print(' DateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d')));
print(' TimeStamp : {} ({:02d}:{:02d})'. format(EventTimeStamp, EventTimeStamp // 60, EventTimeStamp % 60))
print(' Count(?) : {}'. format(EventCount_mb))
@ -170,7 +170,7 @@ def Describe_Usage_2(Usage, ContractMediumEndDate, Certificate):
EventGeoRoute_Direction = Usage.nom(2)
EventCountPassengers_mb = Usage.nom(4)
EventValidityTimeFirstStamp = Usage.nom(11)
print(' DateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d')));
print(' TimeStamp : {} ({:02d}:{:02d})'. format(EventTimeStamp, EventTimeStamp // 60, EventTimeStamp % 60))
print(' unk0... :', unk0);
@ -183,26 +183,26 @@ def Describe_Usage_2(Usage, ContractMediumEndDate, Certificate):
print(' ValidityTimeFirstStamp: {} ({:02d}:{:02d})'. format(EventValidityTimeFirstStamp, EventValidityTimeFirstStamp // 60, EventValidityTimeFirstStamp % 60))
print(' left... :', Usage.nom_bits_left());
print(' [CER] Usage : {:04x}'.format(Certificate.nom(16)))
def Describe_Usage_3(Usage, ContractMediumEndDate, Certificate):
EventDateStamp = Usage.nom(10)
EventTimeStamp = Usage.nom(11)
unk = Usage.nom_bits(27)
EventValidityTimeFirstStamp = Usage.nom(11)
print(' EventDateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d')));
print(' EventTimeStamp : {} ({:02d}:{:02d})'. format(EventTimeStamp, EventTimeStamp // 60, EventTimeStamp % 60))
print(' unk1... :', unk);
print(' EventValidityTimeFirstStamp: {} ({:02d}:{:02d})'. format(EventValidityTimeFirstStamp, EventValidityTimeFirstStamp // 60, EventValidityTimeFirstStamp % 60))
print(' left... :', Usage.nom_bits_left());
print(' [CER] Usage : {:04x}'.format(Certificate.nom(16)))
def Describe_Usage_4(Usage, ContractMediumEndDate, Certificate):
EventDateStamp = Usage.nom(10)
EventTimeStamp = Usage.nom(11)
unk = Usage.nom_bits(63)
EventValidityTimeFirstStamp = Usage.nom(11)
print(' EventDateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d')));
print(' EventTimeStamp : {} ({:02d}:{:02d})'. format(EventTimeStamp, EventTimeStamp // 60, EventTimeStamp % 60))
print(' unk1... :', unk);
@ -311,7 +311,7 @@ def main():
if not chunk:
break
data.addBytes(chunk[::-1])
file.close()
Distribution_Data = BitMe()
@ -336,7 +336,7 @@ def main():
PID = data.nom(5)
match PID:
case 0x10:
Distribution_Data.addBits(data.nom_bits(2 * 32))
Distribution_Data.addBits(Block0Left.nom_bits_left())
@ -365,7 +365,7 @@ def main():
Usage_B_DAT.addBits(data.nom_bits(16))
Usage_B_CER.addBits(data.nom_bits(16))
Distribution_Cer.addBits(data.nom_bits(32))
case _:
print('PID not (yet?) supported: 0x{:02x}'.format(PID))
return 3
@ -413,7 +413,7 @@ def main():
if(Describe_Usage is None):
Describe_Usage = Describe_Usage_Generic
if COUNTER1 is not None:
print('[1] Counter: 0x{:06x} - Reloading available: 0x{:02x}'.format(COUNTER1, RELOADING1))
# if COUNTER2 is not None:
@ -433,7 +433,7 @@ def main():
print()
print('USAGE_A')
Describe_Usage(Usage_A_DAT, ContractMediumEndDate, Usage_A_CER)
if not Usage_B_DAT.isEmpty():
print()
print('USAGE_B')

View file

@ -3601,9 +3601,9 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
bool use_vb6kdf = arg_get_lit(ctx, 6);
bool use_elite = arg_get_lit(ctx, 3);
bool use_raw = arg_get_lit(ctx, 4);
if(use_vb6kdf){
if (use_vb6kdf) {
use_elite = true;
}else{
} else {
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
}
@ -3827,14 +3827,14 @@ uint8_t picopass_elite_nextByte(void) {
return (picopass_elite_rng() >> 16) & 0xFF;
}
void picopass_elite_nextKey(uint8_t* key) {
if(prepared) {
for(size_t i = 0; i < 7; i++) {
void picopass_elite_nextKey(uint8_t *key) {
if (prepared) {
for (size_t i = 0; i < 7; i++) {
key_state[i] = key_state[i + 1];
}
key_state[7] = picopass_elite_nextByte();
} else {
for(size_t i = 0; i < 8; i++) {
for (size_t i = 0; i < 8; i++) {
key_state[i] = picopass_elite_nextByte();
}
prepared = true;
@ -4086,14 +4086,14 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf iclass legrec",
"Attempts to recover the diversified key of a specific iClass card. This may take a long time. The Card must remain be on the PM3 antenna during the whole process! This process may brick the card!",
"hf iclass legrec --macs 0000000089cb984b"
);
"Attempts to recover the diversified key of a specific iClass card. This may take a long time. The Card must remain be on the PM3 antenna during the whole process! This process may brick the card!",
"hf iclass legrec --macs 0000000089cb984b"
);
void *argtable[] = {
arg_param_begin,
arg_str1(NULL, "macs", "<hex>", "MACs"),
arg_param_end
arg_param_begin,
arg_str1(NULL, "macs", "<hex>", "MACs"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -4148,9 +4148,9 @@ static int CmdHFiClassLookUp(const char *Cmd) {
bool use_elite = arg_get_lit(ctx, 5);
bool use_raw = arg_get_lit(ctx, 6);
if(use_vb6kdf){
if (use_vb6kdf) {
use_elite = true;
}else{
} else {
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
}

View file

@ -37,7 +37,7 @@ void PrintPreCalc(iclass_prekey_t *list, uint32_t itemcnt);
uint8_t get_pagemap(const picopass_hdr_t *hdr);
bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t *rmac, uint8_t *tmac, uint8_t *key);
void picopass_elite_nextKey(uint8_t* key);
void picopass_elite_nextKey(uint8_t *key);
void picopass_elite_reset(void);
uint32_t picopass_elite_rng(void);
uint32_t picopass_elite_lcg(void);

View file

@ -279,6 +279,8 @@ const static vocabulary_t vocabulary[] = {
{ 0, "hf iclass chk" },
{ 1, "hf iclass loclass" },
{ 1, "hf iclass lookup" },
{ 0, "hf iclass legrec" },
{ 1, "hf iclass legbrute" },
{ 0, "hf iclass sim" },
{ 0, "hf iclass eload" },
{ 0, "hf iclass esave" },

View file

@ -189,9 +189,9 @@
"options": [
"-h, --help This help",
"-d <hex> ASN1 encoded byte array",
"-t, --test perform self test"
"--test perform self tests"
],
"usage": "data asn1 [-ht] [-d <hex>]"
"usage": "data asn1 [-h] [-d <hex>] [--test]"
},
"data atr": {
"command": "data atr",
@ -3163,7 +3163,8 @@
"description": "Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag",
"notes": [
"hf iclass chk -f iclass_default_keys.dic",
"hf iclass chk -f iclass_elite_keys.dic --elite"
"hf iclass chk -f iclass_elite_keys.dic --elite",
"hf iclass chk --vb6kdf"
],
"offline": false,
"options": [
@ -3172,9 +3173,10 @@
"--credit key is assumed to be the credit key",
"--elite elite computations applied to key",
"--raw no computations applied to key (raw)",
"--shallow use shallow (ASK) reader modulation instead of OOK"
"--shallow use shallow (ASK) reader modulation instead of OOK",
"--vb6kdf use the VB6 elite KDF instead of a file"
],
"usage": "hf iclass chk [-h] -f <fn> [--credit] [--elite] [--raw] [--shallow]"
"usage": "hf iclass chk [-h] [-f <fn>] [--credit] [--elite] [--raw] [--shallow] [--vb6kdf]"
},
"hf iclass configcard": {
"command": "hf iclass configcard",
@ -3370,7 +3372,7 @@
},
"hf iclass help": {
"command": "hf iclass help",
"description": "help This help list List iclass history view Display content from tag dump file ----------- --------------------- Recovery -------------------- loclass Use loclass to perform bruteforce reader attack lookup Uses authentication trace to check for key in dictionary file ----------- ---------------------- Utils ---------------------- calcnewkey Calc diversified keys (blocks 3 & 4) to write new keys encode Encode binary wiegand to block 7 encrypt Encrypt given block data decrypt Decrypt given block data or tag dump file managekeys Manage keys to use with iclass commands permutekey Permute function from 'heart of darkness' paper --------------------------------------------------------------------------------------- hf iclass list available offline: yes Alias of `trace list -t iclass -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol",
"description": "help This help list List iclass history view Display content from tag dump file ----------- --------------------- Recovery -------------------- loclass Use loclass to perform bruteforce reader attack lookup Uses authentication trace to check for key in dictionary file legbrute Bruteforces 40 bits of a partial raw key ----------- ---------------------- Utils ---------------------- calcnewkey Calc diversified keys (blocks 3 & 4) to write new keys encode Encode binary wiegand to block 7 encrypt Encrypt given block data decrypt Decrypt given block data or tag dump file managekeys Manage keys to use with iclass commands permutekey Permute function from 'heart of darkness' paper --------------------------------------------------------------------------------------- hf iclass list available offline: yes Alias of `trace list -t iclass -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol",
"notes": [
"hf iclass list --frame -> show frame delay times",
"hf iclass list -1 -> use trace buffer"
@ -3402,6 +3404,35 @@
],
"usage": "hf iclass info [-h] [--shallow]"
},
"hf iclass legbrute": {
"command": "hf iclass legbrute",
"description": "This command take sniffed trace data and partial raw key and bruteforces the remaining 40 bits of the raw key.",
"notes": [
"hf iclass legbrute --csn 8D7BD711FEFF12E0 --epurse feffffffffffffff --macs 00000000BD478F76 --pk B4F12AADC5301225"
],
"offline": true,
"options": [
"-h, --help This help",
"--csn <hex> Specify CSN as 8 hex bytes",
"--epurse <hex> Specify ePurse as 8 hex bytes",
"--macs <hex> MACs",
"--pk <hex> Partial Key"
],
"usage": "hf iclass legbrute [-h] --csn <hex> --epurse <hex> --macs <hex> --pk <hex>"
},
"hf iclass legrec": {
"command": "hf iclass legrec",
"description": "Attempts to recover the diversified key of a specific iClass card. This may take a long time. The Card must remain be on the PM3 antenna during the whole process! This process may brick the card!",
"notes": [
"hf iclass legrec --macs 0000000089cb984b"
],
"offline": false,
"options": [
"-h, --help This help",
"--macs <hex> MACs"
],
"usage": "hf iclass legrec [-h] --macs <hex>"
},
"hf iclass loclass": {
"command": "hf iclass loclass",
"description": "Execute the offline part of loclass attack An iclass dumpfile is assumed to consist of an arbitrary number of malicious CSNs, and their protocol responses The binary format of the file is expected to be as follows: <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC> <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC> <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC> ... totalling N*24 bytes",
@ -3423,7 +3454,8 @@
"description": "This command take sniffed trace data and try to recovery a iCLASS Standard or iCLASS Elite key.",
"notes": [
"hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f iclass_default_keys.dic",
"hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f iclass_default_keys.dic --elite"
"hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f iclass_default_keys.dic --elite",
"hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b --vb6rng"
],
"offline": true,
"options": [
@ -3433,9 +3465,10 @@
"--epurse <hex> Specify ePurse as 8 hex bytes",
"--macs <hex> MACs",
"--elite Elite computations applied to key",
"--raw no computations applied to key"
"--raw no computations applied to key",
"--vb6rng use the VB6 rng for elite keys instead of a dictionary file"
],
"usage": "hf iclass lookup [-h] -f <fn> --csn <hex> --epurse <hex> --macs <hex> [--elite] [--raw]"
"usage": "hf iclass lookup [-h] [-f <fn>] --csn <hex> --epurse <hex> --macs <hex> [--elite] [--raw] [--vb6rng]"
},
"hf iclass managekeys": {
"command": "hf iclass managekeys",
@ -12732,8 +12765,8 @@
}
},
"metadata": {
"commands_extracted": 737,
"commands_extracted": 739,
"extracted_by": "PM3Help2JSON v1.00",
"extracted_on": "2024-05-27T13:38:05"
"extracted_on": "2024-07-21T14:16:40"
}
}

View file

@ -402,6 +402,8 @@ Check column "offline" for their availability.
|`hf iclass chk `|N |`Check keys`
|`hf iclass loclass `|Y |`Use loclass to perform bruteforce reader attack`
|`hf iclass lookup `|Y |`Uses authentication trace to check for key in dictionary file`
|`hf iclass legrec `|N |`Attempts to recover the standard key of a legacy card`
|`hf iclass legbrute `|Y |`Bruteforces 40 bits of a partial raw key`
|`hf iclass sim `|N |`Simulate iCLASS tag`
|`hf iclass eload `|N |`Upload file into emulator memory`
|`hf iclass esave `|N |`Save emulator memory to file`