mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-06-06 17:41:48 +00:00
Merge pull request #3067 from xianglin1998/master
staticnested faild to find a KeyB
This commit is contained in:
@@ -31,6 +31,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||
- Added `Verkada 40-bit` format (@aaronmaxlevy)
|
||||
- Added `hf seos write` command (@aaronjamt)
|
||||
- Added `hf seos sim` command (@aaronjamt)
|
||||
- Fix `hf mf staticnested` faild to find a KeyB (@xianglin1998)
|
||||
|
||||
## [Phrack.4.20728][2025-09-11]
|
||||
- Added `unofficial desfire bible` document (@mistial-dev)
|
||||
|
||||
+2
-1
@@ -1945,10 +1945,11 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
uint8_t keytype;
|
||||
uint8_t target_block;
|
||||
uint8_t target_keytype;
|
||||
uint8_t force_detect_dist;
|
||||
uint8_t key[6];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
MifareStaticNested(payload->block, payload->keytype, payload->target_block, payload->target_keytype, payload->key);
|
||||
MifareStaticNested(payload->block, payload->keytype, payload->target_block, payload->target_keytype, payload->key, payload->force_detect_dist);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_CHKKEYS: {
|
||||
|
||||
+19
-3
@@ -1586,7 +1586,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
|
||||
set_tracing(false);
|
||||
}
|
||||
|
||||
void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t *key) {
|
||||
void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t *key, uint8_t forceDetectDist) {
|
||||
|
||||
LEDsoff();
|
||||
|
||||
@@ -1653,8 +1653,24 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo,
|
||||
continue;
|
||||
};
|
||||
|
||||
// pre-generate nonces
|
||||
if (targetKeyType == 1 && nt1 == 0x009080A2) {
|
||||
// ST types:
|
||||
// ---
|
||||
// NT1 is 0x01200145:
|
||||
// NT2 case:
|
||||
// A type dist is 160, B type dist is 160, Can double NT2 to fast decrypt.
|
||||
// A type dist is 160, B type dist is 160, No double NT2 to fast decrypt.
|
||||
// ---
|
||||
// NT1 is 0x009080A2:
|
||||
// NT2 case:
|
||||
// A type dist is 160, B type dist is 160, Can double NT2 to fast decrypt.
|
||||
// A type dist is 160, B type dist is 161, Can double NT2 to fast decrypt.
|
||||
// ---
|
||||
// NT1 is any:
|
||||
// NT2 case: random, but is static(static encrypted nested).
|
||||
|
||||
// pre-generate nonces: the distance value is related to the key type, so if the key type is the same,
|
||||
// we can directly use the measured distance value. (Experience)
|
||||
if (targetKeyType == 1 && nt1 == 0x009080A2 && forceDetectDist == 0) {
|
||||
target_nt[0] = prng_successor(nt1, 161);
|
||||
target_nt[1] = prng_successor(nt1, 321);
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ void MifareUWriteBlockCompat(mful_writeblock_t *packet);
|
||||
void MifareUWriteBlock(mful_writeblock_t *packet);
|
||||
|
||||
void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, bool calibrate, uint8_t *key);
|
||||
void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t *key);
|
||||
void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t *key, uint8_t forceDetectDist);
|
||||
|
||||
void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain);
|
||||
int MifareAcquireStaticEncryptedNonces(uint32_t flags, const uint8_t *key, bool reply, uint8_t first_block_no, uint8_t first_key_type);
|
||||
|
||||
+48
-26
@@ -2495,15 +2495,20 @@ static int CmdHF14AMfNestedStatic(const char *Cmd) {
|
||||
PrintAndLogEx(SUCCESS, "Time in check keys " _YELLOW_("%.0f") " seconds\n", (float)t2 / 1000.0);
|
||||
PrintAndLogEx(SUCCESS, "--- " _CYAN_("Enter static nested key recovery") " --------------");
|
||||
|
||||
// Decryption backup logic for special card 0x009080A2(keyB NT1 dist is 160 & 320, not 161 & 321).
|
||||
bool forceDetectDist;
|
||||
|
||||
// nested sectors
|
||||
for (trgKeyType = MF_KEY_A; trgKeyType <= MF_KEY_B; ++trgKeyType) {
|
||||
for (uint8_t sectorNo = 0; sectorNo < SectorsCnt; ++sectorNo) {
|
||||
|
||||
for (int i = 0; i < 1; i++) {
|
||||
forceDetectDist = 0; // Fist decrypt, auto detect dist for NT2_1 & NT2_2.
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
|
||||
if (e_sector[sectorNo].foundKey[trgKeyType]) continue;
|
||||
|
||||
int16_t isOK = mf_static_nested(blockNo, keyType, key, mfFirstBlockOfSector(sectorNo), trgKeyType, keyBlock);
|
||||
|
||||
int16_t isOK = mf_static_nested(blockNo, keyType, key, mfFirstBlockOfSector(sectorNo), trgKeyType, keyBlock, forceDetectDist);
|
||||
switch (isOK) {
|
||||
case PM3_ETIMEOUT :
|
||||
PrintAndLogEx(ERR, "command execution time out");
|
||||
@@ -2512,11 +2517,15 @@ static int CmdHF14AMfNestedStatic(const char *Cmd) {
|
||||
PrintAndLogEx(WARNING, "aborted via keyboard.");
|
||||
break;
|
||||
case PM3_ESOFT :
|
||||
// No any key found?
|
||||
// Try to force decryption using measured nonce instead of automatic detection (some card types may misjudge)
|
||||
forceDetectDist = 1;
|
||||
PrintAndLogEx(WARNING, "No key found, next try...");
|
||||
continue;
|
||||
case PM3_SUCCESS :
|
||||
e_sector[sectorNo].foundKey[trgKeyType] = 1;
|
||||
e_sector[sectorNo].Key[trgKeyType] = bytes_to_num(keyBlock, 6);
|
||||
|
||||
i = 2; // Key found, no next retry.
|
||||
// mf_check_keys_fast(SectorsCnt, true, true, 2, 1, keyBlock, e_sector, false, false);
|
||||
continue;
|
||||
default :
|
||||
@@ -3018,6 +3027,10 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
||||
uint64_t key64 = 0;
|
||||
bool calibrate = true;
|
||||
|
||||
// staticNested parameter
|
||||
bool force_detect_dist;
|
||||
int static_nested_retry_i = 0;
|
||||
|
||||
// Attack key storage variables
|
||||
uint8_t *keyBlock = NULL;
|
||||
uint32_t key_cnt = 0;
|
||||
@@ -3694,28 +3707,37 @@ tryStaticnested:
|
||||
(current_key_type_i == MF_KEY_B) ? 'B' : 'A');
|
||||
}
|
||||
|
||||
isOK = mf_static_nested(mfFirstBlockOfSector(sectorno), keytype, key, mfFirstBlockOfSector(current_sector_i), current_key_type_i, tmp_key);
|
||||
DropField();
|
||||
switch (isOK) {
|
||||
case PM3_ETIMEOUT: {
|
||||
PrintAndLogEx(ERR, "\nError: No response from Proxmark3");
|
||||
free(e_sector);
|
||||
free(fptr);
|
||||
return isOK;
|
||||
}
|
||||
case PM3_EOPABORTED: {
|
||||
PrintAndLogEx(WARNING, "\nButton pressed, user aborted");
|
||||
free(e_sector);
|
||||
free(fptr);
|
||||
return isOK;
|
||||
}
|
||||
case PM3_SUCCESS: {
|
||||
e_sector[current_sector_i].Key[current_key_type_i] = bytes_to_num(tmp_key, MIFARE_KEY_SIZE);
|
||||
e_sector[current_sector_i].foundKey[current_key_type_i] = 'C';
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
force_detect_dist = 0; // First time to decrypt staticnested tag, we can auto detect dist by tag type.
|
||||
for (static_nested_retry_i = 0; static_nested_retry_i < 2; static_nested_retry_i++) {
|
||||
isOK = mf_static_nested(mfFirstBlockOfSector(sectorno), keytype, key, mfFirstBlockOfSector(current_sector_i), current_key_type_i, tmp_key, force_detect_dist);
|
||||
DropField();
|
||||
switch (isOK) {
|
||||
case PM3_ETIMEOUT: {
|
||||
PrintAndLogEx(ERR, "\nError: No response from Proxmark3");
|
||||
free(e_sector);
|
||||
free(fptr);
|
||||
return isOK;
|
||||
}
|
||||
case PM3_EOPABORTED: {
|
||||
PrintAndLogEx(WARNING, "\nButton pressed, user aborted");
|
||||
free(e_sector);
|
||||
free(fptr);
|
||||
return isOK;
|
||||
}
|
||||
case PM3_ESOFT: {
|
||||
PrintAndLogEx(WARNING, "No key found, next try...");
|
||||
force_detect_dist = 1;
|
||||
continue;
|
||||
}
|
||||
case PM3_SUCCESS: {
|
||||
e_sector[current_sector_i].Key[current_key_type_i] = bytes_to_num(tmp_key, MIFARE_KEY_SIZE);
|
||||
e_sector[current_sector_i].foundKey[current_key_type_i] = 'C';
|
||||
static_nested_retry_i = 2; // Key found, no next retry.
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -725,7 +725,7 @@ out:
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
int mf_static_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey) {
|
||||
int mf_static_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey, bool forceDetectDist) {
|
||||
|
||||
uint32_t uid = 0;
|
||||
StateList_t statelists[2];
|
||||
@@ -736,12 +736,14 @@ int mf_static_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trg
|
||||
uint8_t keytype;
|
||||
uint8_t target_block;
|
||||
uint8_t target_keytype;
|
||||
uint8_t force_detect_dist;
|
||||
uint8_t key[6];
|
||||
} PACKED payload;
|
||||
payload.block = blockNo;
|
||||
payload.keytype = keyType;
|
||||
payload.target_block = trgBlockNo;
|
||||
payload.target_keytype = trgKeyType;
|
||||
payload.force_detect_dist = forceDetectDist;
|
||||
memcpy(payload.key, key, sizeof(payload.key));
|
||||
|
||||
PacketResponseNG resp;
|
||||
|
||||
@@ -72,7 +72,7 @@ typedef struct {
|
||||
|
||||
int mf_dark_side(uint8_t blockno, uint8_t key_type, uint64_t *key);
|
||||
int mf_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey, bool calibrate);
|
||||
int mf_static_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey);
|
||||
int mf_static_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey, bool forceDetectDist);
|
||||
int mf_check_keys(uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t *keyBlock, uint64_t *key);
|
||||
int mf_check_keys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk,
|
||||
uint8_t strategy, uint32_t size, uint8_t *keyBlock, sector_t *e_sector,
|
||||
|
||||
Reference in New Issue
Block a user