//----------------------------------------------------------------------------- // Christian Herrmann, 2020 // // This code is licensed to you under the terms of the GNU GPL, version 2 or, // at your option, any later version. See the LICENSE.txt file for the text of // the license. //----------------------------------------------------------------------------- // main code for HID collector aka IceHID by Iceman //----------------------------------------------------------------------------- #include #include "standalone.h" // standalone definitions #include "proxmark3_arm.h" #include "appmain.h" #include "lfops.h" #include "lfsampling.h" #include "BigBuf.h" #include "fpgaloader.h" #include "util.h" #include "dbprint.h" #include "printf.h" #include "spiffs.h" #include "ticks.h" #include "lfdemod.h" /* * `lf_hidcollect` sniffs after LF HID credentials, and stores them in internal * flash. It requires RDV4 hardware (for flash and battery). * * On entering stand-alone mode, this module will start reading/record HID credentials. * Every found / collected credential will be written/appended to the logfile in flash * as a text string. * * LEDs: * - LED A: reading / record * - LED B: writing to flash * - LED C: unmounting/sync'ing flash (normally < 100ms) * * To retrieve log file from flash: * * 1. mem spiffs dump o lf_hidcollect.log f lf_hidcollect.log * Copies log file from flash to your client. * * 2. exit the Proxmark3 client * * 3. more lf_hidcollect.log * * This module emits debug strings during normal operation -- so try it out in * the lab connected to PM3 client before taking it into the field. * * To delete the log file from flash: * * 1. mem spiffs remove lf_hidcollect.log */ #define LF_HIDCOLLECT_LOGFILE "lf_hidcollect.log" static void DownloadLogInstructions(void) { Dbprintf(""); Dbprintf("[=] To get the logfile from flash and display it:"); Dbprintf("[=] " _YELLOW_("1.") " mem spiffs dump o "LF_HIDCOLLECT_LOGFILE" f "LF_HIDCOLLECT_LOGFILE); Dbprintf("[=] " _YELLOW_("2.") " exit proxmark3 client"); Dbprintf("[=] " _YELLOW_("3.") " cat "LF_HIDCOLLECT_LOGFILE); } bool log_exists; static void append(uint8_t *entry, size_t entry_len) { LED_B_ON(); if (log_exists == false) { rdv40_spiffs_write(LF_HIDCOLLECT_LOGFILE, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); log_exists = true; } else { rdv40_spiffs_append(LF_HIDCOLLECT_LOGFILE, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); } LED_B_OFF(); } static uint32_t IceEM410xdemod(void) { uint8_t *dest = BigBuf_get_addr(); size_t idx = 0; int clk = 0, invert = 0, maxErr = 20; uint32_t hi = 0; uint64_t lo = 0; size_t size = MIN(16385, BigBuf_max_traceLen()); //askdemod and manchester decode int errCnt = askdemod(dest, &size, &clk, &invert, maxErr, 0, 1); WDT_HIT(); if (errCnt > 50) { BigBuf_free(); return PM3_ESOFT; } errCnt = Em410xDecode(dest, &size, &idx, &hi, &lo); if (errCnt != 1) { BigBuf_free(); return PM3_ESOFT; } uint8_t entry[81]; memset(entry, 0, sizeof(entry)); if (size == 128) { sprintf((char *)entry, "EM XL TAG ID: %06"PRIx32"%08"PRIx32"%08"PRIx32" - (%05"PRIu32"_%03"PRIu32"_%08"PRIu32")\n", hi, (uint32_t)(lo >> 32), (uint32_t)lo, (uint32_t)(lo & 0xFFFF), (uint32_t)((lo >> 16LL) & 0xFF), (uint32_t)(lo & 0xFFFFFF)); } else { sprintf((char *)entry, "EM TAG ID: %02"PRIx32"%08"PRIx32" - (%05"PRIu32"_%03"PRIu32"_%08"PRIu32")\n", (uint32_t)(lo >> 32), (uint32_t)lo, (uint32_t)(lo & 0xFFFF), (uint32_t)((lo >> 16LL) & 0xFF), (uint32_t)(lo & 0xFFFFFF)); } append(entry, strlen((char *)entry)); Dbprintf("%s", entry); BigBuf_free(); return PM3_SUCCESS; } static uint32_t IceAWIDdemod(void) { uint8_t *dest = BigBuf_get_addr(); size_t size = MIN(12800, BigBuf_max_traceLen()); int dummyIdx = 0; //askdemod and manchester decode int idx = detectAWID(dest, &size, &dummyIdx); if (idx <= 0 || size != 96) { BigBuf_free(); return PM3_ESOFT; } //get raw ID before removing parities uint32_t rawLo = bytebits_to_byte(dest + idx + 64, 32); uint32_t rawHi = bytebits_to_byte(dest + idx + 32, 32); uint32_t rawHi2 = bytebits_to_byte(dest + idx, 32); size = removeParity(dest, idx + 8, 4, 1, 88); if (size != 66) { BigBuf_free(); return PM3_ESOFT; } uint8_t entry[110]; memset(entry, 0, sizeof(entry)); uint8_t fmtLen = bytebits_to_byte(dest, 8); if (fmtLen == 26) { uint8_t fac = bytebits_to_byte(dest + 9, 8); uint32_t cardnum = bytebits_to_byte(dest + 17, 16); uint32_t code1 = bytebits_to_byte(dest + 8, fmtLen); sprintf((char *)entry, "AWID bit len: %d, FC: %d, Card: %"PRIu32" - Wiegand: %"PRIx32", Raw: %08"PRIx32"%08"PRIx32"%08"PRIx32"\n", fmtLen, fac, cardnum, code1, rawHi2, rawHi, rawLo); } else { uint32_t cardnum = bytebits_to_byte(dest + 8 + (fmtLen - 17), 16); if (fmtLen > 32) { uint32_t code1 = bytebits_to_byte(dest + 8, fmtLen - 32); uint32_t code2 = bytebits_to_byte(dest + 8 + (fmtLen - 32), 32); sprintf((char *)entry, "AWID bit len: %d -unk bit len - Card: %"PRIu32" - Wiegand: %"PRIx32"%08"PRIx32", Raw: %08"PRIx32"%08"PRIx32"%08"PRIx32"\n", fmtLen, cardnum, code1, code2, rawHi2, rawHi, rawLo); } else { uint32_t code1 = bytebits_to_byte(dest + 8, fmtLen); sprintf((char *)entry, "AWID bit len: %d -unk bit len - Card: %"PRIu32" - Wiegand: %"PRIx32", Raw: %08"PRIx32"%08"PRIx32"%08"PRIx32"\n", fmtLen, cardnum, code1, rawHi2, rawHi, rawLo); } } append(entry, strlen((char *)entry)); Dbprintf("%s", entry); BigBuf_free(); return PM3_SUCCESS; } static uint32_t IceIOdemod(void) { int dummyIdx = 0; uint8_t version = 0, facilitycode = 0; uint16_t number = 0; uint32_t hi = 0, lo = 0; size_t size = MIN(12000, BigBuf_max_traceLen()); // uint8_t *dest = BigBuf_malloc(size); uint8_t *dest = BigBuf_get_addr(); //fskdemod and get start index int idx = detectIOProx(dest, &size, &dummyIdx); if (idx < 0) { BigBuf_free(); return PM3_ESOFT; } hi = bytebits_to_byte(dest + idx, 32); lo = bytebits_to_byte(dest + idx + 32, 32); version = bytebits_to_byte(dest + idx + 27, 8); //14,4 facilitycode = bytebits_to_byte(dest + idx + 18, 8); number = (bytebits_to_byte(dest + idx + 36, 8) << 8) | (bytebits_to_byte(dest + idx + 45, 8)); //36,9 uint8_t entry[64]; memset(entry, 0, sizeof(entry)); sprintf((char *)entry, "IO Prox XSF(%02u)%02x:%05u (%08"PRIx32"%08"PRIx32")\n" , version , facilitycode , number , hi , lo ); append(entry, strlen((char *)entry)); Dbprintf("%s", entry); BigBuf_free(); return PM3_SUCCESS; } static uint32_t IceHIDDemod(void) { int dummyIdx = 0; uint32_t hi2 = 0, hi = 0, lo = 0; // large enough to catch 2 sequences of largest format // size_t size = 50 * 128 * 2; // 12800 bytes size_t size = MIN(12800, BigBuf_max_traceLen()); //uint8_t *dest = BigBuf_malloc(size); uint8_t *dest = BigBuf_get_addr(); // FSK demodulator int idx = HIDdemodFSK(dest, &size, &hi2, &hi, &lo, &dummyIdx); if (idx < 0) { BigBuf_free(); return PM3_ESOFT; } if ((size == 96 || size == 192)) { uint8_t entry[80]; memset(entry, 0, sizeof(entry)); // go over previously decoded manchester data and decode into usable tag ID if (hi2 != 0) { //extra large HID tags 88/192 bits sprintf((char *)entry, "HID large: %"PRIx32"%08"PRIx32"%08"PRIx32" (%"PRIu32")\n", hi2, hi, lo, (lo >> 1) & 0xFFFF ); append(entry, strlen((char *)entry)); } else { //standard HID tags 44/96 bits uint8_t bitlen = 0; uint32_t fac = 0; uint32_t cardnum = 0; if (((hi >> 5) & 1) == 1) { //if bit 38 is set then < 37 bit format is used uint32_t lo2 = 0; lo2 = (((hi & 31) << 12) | (lo >> 20)); //get bits 21-37 to check for format len bit uint8_t idx3 = 1; while (lo2 > 1) { //find last bit set to 1 (format len bit) lo2 >>= 1; idx3++; } bitlen = idx3 + 19; fac = 0; cardnum = 0; if (bitlen == 26) { cardnum = (lo >> 1) & 0xFFFF; fac = (lo >> 17) & 0xFF; } if (bitlen == 37) { cardnum = (lo >> 1) & 0x7FFFF; fac = ((hi & 0xF) << 12) | (lo >> 20); } if (bitlen == 34) { cardnum = (lo >> 1) & 0xFFFF; fac = ((hi & 1) << 15) | (lo >> 17); } if (bitlen == 35) { cardnum = (lo >> 1) & 0xFFFFF; fac = ((hi & 1) << 11) | (lo >> 21); } } else { //if bit 38 is not set then 37 bit format is used bitlen = 37; cardnum = (lo >> 1) & 0x7FFFF; fac = ((hi & 0xF) << 12) | (lo >> 20); } sprintf((char *)entry, "HID: %"PRIx32"%08"PRIx32" (%"PRIu32") Format: %d bit FC: %"PRIu32" Card: %"PRIu32"\n", hi, lo, (lo >> 1) & 0xFFFF, bitlen, fac, cardnum ); append(entry, strlen((char *)entry)); } Dbprintf("%s", entry); } BigBuf_free(); return PM3_SUCCESS; } void ModInfo(void) { DbpString(_YELLOW_(" LF HID / IOprox / AWID / EM4100 collector mode") " - a.k.a IceHID (Iceman)"); } void RunMod(void) { FpgaDownloadAndGo(FPGA_BITSTREAM_LF); LFSetupFPGAForADC(LF_DIVISOR_125, true); BigBuf_Clear(); StandAloneMode(); Dbprintf(_YELLOW_("[=] Standalone mode IceHID started")); rdv40_spiffs_lazy_mount(); log_exists = exists_in_spiffs(LF_HIDCOLLECT_LOGFILE); // the main loop for your standalone mode for (;;) { WDT_HIT(); // exit from IceHID, send a usbcommand. if (data_available()) break; // Was our button held down or pressed? int button_pressed = BUTTON_HELD(280); if (button_pressed == BUTTON_HOLD) break; LED_A_ON(); uint32_t res; // since we steal 12800 from bigbuffer, no need to sample it. size_t size = MIN(28000, BigBuf_max_traceLen()); DoAcquisition_config(false, size); res = IceHIDDemod(); if (res == PM3_SUCCESS) { LED_A_OFF(); continue; } DoAcquisition_config(false, size); res = IceAWIDdemod(); if (res == PM3_SUCCESS) { LED_A_OFF(); continue; } DoAcquisition_config(false, size); res = IceIOdemod(); if (res == PM3_SUCCESS) { LED_A_OFF(); continue; } size = MIN(20000, BigBuf_max_traceLen()); DoAcquisition_config(false, size); res = IceEM410xdemod(); if (res == PM3_SUCCESS) { LED_A_OFF(); continue; } } LED_C_ON(); rdv40_spiffs_lazy_unmount(); LED_C_OFF(); LEDsoff(); DownloadLogInstructions(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); }