Merge pull request #3067 from xianglin1998/master

staticnested faild to find a KeyB
This commit is contained in:
Iceman
2025-12-24 13:37:54 +01:00
committed by GitHub
7 changed files with 75 additions and 33 deletions
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
}
}
}
+3 -1
View File
@@ -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;
+1 -1
View File
@@ -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,