Skip to content

Commit 2f394ef

Browse files
authored
Merge pull request #3067 from xianglin1998/master
staticnested faild to find a KeyB
2 parents 8302d46 + 621af43 commit 2f394ef

File tree

7 files changed

+75
-33
lines changed

7 files changed

+75
-33
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
3131
- Added `Verkada 40-bit` format (@aaronmaxlevy)
3232
- Added `hf seos write` command (@aaronjamt)
3333
- Added `hf seos sim` command (@aaronjamt)
34+
- Fix `hf mf staticnested` faild to find a KeyB (@xianglin1998)
3435

3536
## [Phrack.4.20728][2025-09-11]
3637
- Added `unofficial desfire bible` document (@mistial-dev)

armsrc/appmain.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1945,10 +1945,11 @@ static void PacketReceived(PacketCommandNG *packet) {
19451945
uint8_t keytype;
19461946
uint8_t target_block;
19471947
uint8_t target_keytype;
1948+
uint8_t force_detect_dist;
19481949
uint8_t key[6];
19491950
} PACKED;
19501951
struct p *payload = (struct p *) packet->data.asBytes;
1951-
MifareStaticNested(payload->block, payload->keytype, payload->target_block, payload->target_keytype, payload->key);
1952+
MifareStaticNested(payload->block, payload->keytype, payload->target_block, payload->target_keytype, payload->key, payload->force_detect_dist);
19521953
break;
19531954
}
19541955
case CMD_HF_MIFARE_CHKKEYS: {

armsrc/mifarecmd.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,7 +1586,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
15861586
set_tracing(false);
15871587
}
15881588

1589-
void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t *key) {
1589+
void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t *key, uint8_t forceDetectDist) {
15901590

15911591
LEDsoff();
15921592

@@ -1653,8 +1653,24 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo,
16531653
continue;
16541654
};
16551655

1656-
// pre-generate nonces
1657-
if (targetKeyType == 1 && nt1 == 0x009080A2) {
1656+
// ST types:
1657+
// ---
1658+
// NT1 is 0x01200145:
1659+
// NT2 case:
1660+
// A type dist is 160, B type dist is 160, Can double NT2 to fast decrypt.
1661+
// A type dist is 160, B type dist is 160, No double NT2 to fast decrypt.
1662+
// ---
1663+
// NT1 is 0x009080A2:
1664+
// NT2 case:
1665+
// A type dist is 160, B type dist is 160, Can double NT2 to fast decrypt.
1666+
// A type dist is 160, B type dist is 161, Can double NT2 to fast decrypt.
1667+
// ---
1668+
// NT1 is any:
1669+
// NT2 case: random, but is static(static encrypted nested).
1670+
1671+
// pre-generate nonces: the distance value is related to the key type, so if the key type is the same,
1672+
// we can directly use the measured distance value. (Experience)
1673+
if (targetKeyType == 1 && nt1 == 0x009080A2 && forceDetectDist == 0) {
16581674
target_nt[0] = prng_successor(nt1, 161);
16591675
target_nt[1] = prng_successor(nt1, 321);
16601676
} else {

armsrc/mifarecmd.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ void MifareUWriteBlockCompat(mful_writeblock_t *packet);
3535
void MifareUWriteBlock(mful_writeblock_t *packet);
3636

3737
void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, bool calibrate, uint8_t *key);
38-
void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t *key);
38+
void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t *key, uint8_t forceDetectDist);
3939

4040
void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain);
4141
int MifareAcquireStaticEncryptedNonces(uint32_t flags, const uint8_t *key, bool reply, uint8_t first_block_no, uint8_t first_key_type);

client/src/cmdhfmf.c

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2495,15 +2495,20 @@ static int CmdHF14AMfNestedStatic(const char *Cmd) {
24952495
PrintAndLogEx(SUCCESS, "Time in check keys " _YELLOW_("%.0f") " seconds\n", (float)t2 / 1000.0);
24962496
PrintAndLogEx(SUCCESS, "--- " _CYAN_("Enter static nested key recovery") " --------------");
24972497

2498+
// Decryption backup logic for special card 0x009080A2(keyB NT1 dist is 160 & 320, not 161 & 321).
2499+
bool forceDetectDist;
2500+
24982501
// nested sectors
24992502
for (trgKeyType = MF_KEY_A; trgKeyType <= MF_KEY_B; ++trgKeyType) {
25002503
for (uint8_t sectorNo = 0; sectorNo < SectorsCnt; ++sectorNo) {
25012504

2502-
for (int i = 0; i < 1; i++) {
2505+
forceDetectDist = 0; // Fist decrypt, auto detect dist for NT2_1 & NT2_2.
25032506

2504-
if (e_sector[sectorNo].foundKey[trgKeyType]) continue;
2507+
for (int i = 0; i < 2; i++) {
25052508

2506-
int16_t isOK = mf_static_nested(blockNo, keyType, key, mfFirstBlockOfSector(sectorNo), trgKeyType, keyBlock);
2509+
if (e_sector[sectorNo].foundKey[trgKeyType]) continue;
2510+
2511+
int16_t isOK = mf_static_nested(blockNo, keyType, key, mfFirstBlockOfSector(sectorNo), trgKeyType, keyBlock, forceDetectDist);
25072512
switch (isOK) {
25082513
case PM3_ETIMEOUT :
25092514
PrintAndLogEx(ERR, "command execution time out");
@@ -2512,11 +2517,15 @@ static int CmdHF14AMfNestedStatic(const char *Cmd) {
25122517
PrintAndLogEx(WARNING, "aborted via keyboard.");
25132518
break;
25142519
case PM3_ESOFT :
2520+
// No any key found?
2521+
// Try to force decryption using measured nonce instead of automatic detection (some card types may misjudge)
2522+
forceDetectDist = 1;
2523+
PrintAndLogEx(WARNING, "No key found, next try...");
25152524
continue;
25162525
case PM3_SUCCESS :
25172526
e_sector[sectorNo].foundKey[trgKeyType] = 1;
25182527
e_sector[sectorNo].Key[trgKeyType] = bytes_to_num(keyBlock, 6);
2519-
2528+
i = 2; // Key found, no next retry.
25202529
// mf_check_keys_fast(SectorsCnt, true, true, 2, 1, keyBlock, e_sector, false, false);
25212530
continue;
25222531
default :
@@ -3018,6 +3027,10 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
30183027
uint64_t key64 = 0;
30193028
bool calibrate = true;
30203029

3030+
// staticNested parameter
3031+
bool force_detect_dist;
3032+
int static_nested_retry_i = 0;
3033+
30213034
// Attack key storage variables
30223035
uint8_t *keyBlock = NULL;
30233036
uint32_t key_cnt = 0;
@@ -3694,28 +3707,37 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
36943707
(current_key_type_i == MF_KEY_B) ? 'B' : 'A');
36953708
}
36963709

3697-
isOK = mf_static_nested(mfFirstBlockOfSector(sectorno), keytype, key, mfFirstBlockOfSector(current_sector_i), current_key_type_i, tmp_key);
3698-
DropField();
3699-
switch (isOK) {
3700-
case PM3_ETIMEOUT: {
3701-
PrintAndLogEx(ERR, "\nError: No response from Proxmark3");
3702-
free(e_sector);
3703-
free(fptr);
3704-
return isOK;
3705-
}
3706-
case PM3_EOPABORTED: {
3707-
PrintAndLogEx(WARNING, "\nButton pressed, user aborted");
3708-
free(e_sector);
3709-
free(fptr);
3710-
return isOK;
3711-
}
3712-
case PM3_SUCCESS: {
3713-
e_sector[current_sector_i].Key[current_key_type_i] = bytes_to_num(tmp_key, MIFARE_KEY_SIZE);
3714-
e_sector[current_sector_i].foundKey[current_key_type_i] = 'C';
3715-
break;
3716-
}
3717-
default: {
3718-
break;
3710+
force_detect_dist = 0; // First time to decrypt staticnested tag, we can auto detect dist by tag type.
3711+
for (static_nested_retry_i = 0; static_nested_retry_i < 2; static_nested_retry_i++) {
3712+
isOK = mf_static_nested(mfFirstBlockOfSector(sectorno), keytype, key, mfFirstBlockOfSector(current_sector_i), current_key_type_i, tmp_key, force_detect_dist);
3713+
DropField();
3714+
switch (isOK) {
3715+
case PM3_ETIMEOUT: {
3716+
PrintAndLogEx(ERR, "\nError: No response from Proxmark3");
3717+
free(e_sector);
3718+
free(fptr);
3719+
return isOK;
3720+
}
3721+
case PM3_EOPABORTED: {
3722+
PrintAndLogEx(WARNING, "\nButton pressed, user aborted");
3723+
free(e_sector);
3724+
free(fptr);
3725+
return isOK;
3726+
}
3727+
case PM3_ESOFT: {
3728+
PrintAndLogEx(WARNING, "No key found, next try...");
3729+
force_detect_dist = 1;
3730+
continue;
3731+
}
3732+
case PM3_SUCCESS: {
3733+
e_sector[current_sector_i].Key[current_key_type_i] = bytes_to_num(tmp_key, MIFARE_KEY_SIZE);
3734+
e_sector[current_sector_i].foundKey[current_key_type_i] = 'C';
3735+
static_nested_retry_i = 2; // Key found, no next retry.
3736+
break;
3737+
}
3738+
default: {
3739+
break;
3740+
}
37193741
}
37203742
}
37213743
}

client/src/mifare/mifarehost.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,7 @@ int mf_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo
725725
return PM3_ESOFT;
726726
}
727727

728-
int mf_static_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey) {
728+
int mf_static_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey, bool forceDetectDist) {
729729

730730
uint32_t uid = 0;
731731
StateList_t statelists[2];
@@ -736,12 +736,14 @@ int mf_static_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trg
736736
uint8_t keytype;
737737
uint8_t target_block;
738738
uint8_t target_keytype;
739+
uint8_t force_detect_dist;
739740
uint8_t key[6];
740741
} PACKED payload;
741742
payload.block = blockNo;
742743
payload.keytype = keyType;
743744
payload.target_block = trgBlockNo;
744745
payload.target_keytype = trgKeyType;
746+
payload.force_detect_dist = forceDetectDist;
745747
memcpy(payload.key, key, sizeof(payload.key));
746748

747749
PacketResponseNG resp;

client/src/mifare/mifarehost.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ typedef struct {
7272

7373
int mf_dark_side(uint8_t blockno, uint8_t key_type, uint64_t *key);
7474
int mf_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey, bool calibrate);
75-
int mf_static_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey);
75+
int mf_static_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey, bool forceDetectDist);
7676
int mf_check_keys(uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t *keyBlock, uint64_t *key);
7777
int mf_check_keys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk,
7878
uint8_t strategy, uint32_t size, uint8_t *keyBlock, sector_t *e_sector,

0 commit comments

Comments
 (0)