--- title: "[社課共筆]20251016-這是替身攻擊!悠遊卡背後的 RFID 攻防" description: tags: - 社課 - 共筆 --- :::success # 這是替身攻擊!悠遊卡背後的 RFID 攻防 **時間:** 2025/10/16(星期四)18:30 ~ 21:00 **地點:** 挺生大樓 A3-200 教室 **簡報:** **[DC上有](https://discord.gg/tTkb4FAx)** **Slido:** [連結]() **回饋表單:**[連結](https://forms.gle/UV9WQ1w6B8CfyAh89) ![qr.ioi.tw](https://hackmd.io/_uploads/B1PDj-CTxl.png =100x) ::: - [Arduino IDE](https://www.arduino.cc/en/software/) > 請從這裡開始 **小試身手** ```cpp void setup() { // put your setup code here, to run once: Serial.begin(9600); Serial.println("Initialize Arduino program."); } int count = 0; // 全域變數 void loop() { // put your main code here, to run repeatedly: Serial.print("program is running for "); Serial.print(count); Serial.println(" second."); delay(1000); // 暫停一秒 單位:毫秒(ms) count = count + 1; // 每次 count 數值加1 } ``` **Arduino 程式基本架構** ```cpp void setup() { // put your setup code here, to run once: } void loop() { // put your main code here, to run repeatedly: } ``` ![螢幕擷取畫面 2025-10-16 201441](https://hackmd.io/_uploads/ByQaWDR6gx.png) **MFRC-522 程式基本架構** ```cpp /* * Typical pin layout used: * ----------------------------------------------------------------------------- * MFRC522 Arduino Arduino Arduino Arduino * Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro * Signal Pin Pin Pin Pin Pin * ----------------------------------------------------------------------------- * RST/Reset RST 9 5 D9 RESET/ICSP-5 * SPI SS SDA(SS) 10 53 D10 10 * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 */ #include <SPI.h> #include <MFRC522.h> #define RST_PIN 9 // Configurable, see typical pin layout above #define SS_PIN 10 // Configurable, see typical pin layout above MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance void setup() { Serial.begin(9600); // Initialize serial communications with the PC while (!Serial); // Do nothing if no serial port is opened SPI.begin(); // Init SPI bus mfrc522.PCD_Init(); // Init MFRC522 } void loop() { // Reset the loop if no new card present on the sensor/reader. // This saves the entire process when idle. if ( ! mfrc522.PICC_IsNewCardPresent()) { return; } // Select one of the cards if ( ! mfrc522.PICC_ReadCardSerial()) { return; } // TODO ... } ``` **練習範例程式碼** ```cpp /* * Typical pin layout used: * ----------------------------------------------------------------------------- * MFRC522 Arduino Arduino Arduino Arduino * Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro * Signal Pin Pin Pin Pin Pin * ----------------------------------------------------------------------------- * RST/Reset RST 9 5 D9 RESET/ICSP-5 * SPI SS SDA(SS) 10 53 D10 10 * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 */ #include <MFRC522.h> #include <SPI.h> // Definition /////////////////////////////////////////////////////////// #define RST_PIN 9 // Configurable, see typical pin layout above #define SS_PIN 10 // Configurable, see typical pin layout above // Global Variables /////////////////////////////////////////////////////////// MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance MFRC522::MIFARE_Key key; MFRC522::StatusCode status; // Setup /////////////////////////////////////////////////////////// void setup() { Serial.begin(9600); // Initialize serial communications with the PC while (!Serial) ; // Do nothing if no serial port is opened SPI.begin(); // Init SPI bus mfrc522.PCD_Init(); // Init MFRC522 for (byte i = 0; i < 6; i++) { key.keyByte[i] = 0xFF; } // 印出讀卡機韌體資訊 // mfrc522.PCD_DumpVersionToSerial(); } // Loop /////////////////////////////////////////////////////////// void loop() { // Reset the loop if no new card present on the sensor/reader. // This saves the entire process when idle. if (!mfrc522.PICC_IsNewCardPresent()) { return; } // Select one of the cards if (!mfrc522.PICC_ReadCardSerial()) { return; } // TODO ... // 印出卡片資訊 // mfrc522.PICC_DumpDetailsToSerial(&mfrc522.uid); // 印出卡片所有資料 // mfrc522.PICC_DumpToSerial(&mfrc522.uid); // 印出 UID // Serial.print("uid:"); // dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); // Serial.println(); // 用 key A 驗證 sector 0 // auth_keyA(0, &key); // 讀取 block 1 // unsigned char block[32] = { 0 }; // read_block(1, block, 32); // dump_block(1, block); // 寫入 block 1 // strncpy(block, "Yuto Forever", 16); // write_block(1, block, 16); // read_block(1, block, 32); // hexdump(block, 16); // 寫入 uid // byte uid[] = { 0xDE, 0xAD, 0xBE, 0xEF }; // memcpy(block, uid, 4); // uid // block[4] = bcc0(uid, 4); // bcc0 // block[5] = 0x08; // SAK // block[6] = 0x04; block[7] = 0x00; // ATQA // mock factory data // for(char i = 0, c = 'b'; i < 8; i++, c++) // block[i + 8] = c; // 印出欲寫入的資料 // hexdump(block, 16); // 寫入並印出寫入結果 // write_block(0, block, 16); // read_block(1, block, 32); // hexdump(block, 16); } // Helper Functions /////////////////////////////////////////////////////////// /* * @brief 將 array 的內容以 16 進位印出 * * @param[out] buffer 要印出的資料 * @param[in] size buffer 的大小 */ void dump_byte_array(byte* buffer, byte size) { for (byte i = 0; i < size; i++) { Serial.print(buffer[i] < 0x10 ? " 0" : " "); Serial.print(buffer[i], HEX); } } /* * @brief 將 buffer 的內容 16 進位 + ASCII 印出 * * @param[out] buffer 要印出的資料 * @param[in] size buffer 的大小 */ void hexdump(const byte* buffer, size_t size) { const byte bytes_per_line = 16; for (size_t offset = 0; offset < size; offset += bytes_per_line) { if (offset < 0x10) Serial.print("0"); Serial.print(offset, HEX); Serial.print(F(": ")); for (byte i = 0; i < bytes_per_line; i++) { size_t idx = offset + i; if (i == 8) Serial.print(" "); if (idx < size) { if (buffer[idx] < 0x10) Serial.print("0"); Serial.print(buffer[idx], HEX); Serial.print(" "); } else { Serial.print(" "); } } Serial.print("| "); for (byte i = 0; i < bytes_per_line; i++) { size_t idx = offset + i; if (idx < size) { byte c = buffer[idx]; Serial.print(isPrintable(c) ? (char)c : '.'); } else { Serial.print(" "); } } Serial.println(); } } /* * @brief 讀取卡片中的 block * * @param[in] addr 讀取的 block 地址 * @param[out] buffer 讀出來存放的空間 * @param[in] size buffer 的大小 */ bool read_block(byte addr, byte* buffer, byte size) { MFRC522::StatusCode status = mfrc522.MIFARE_Read(addr, buffer, &size); if (status == MFRC522::STATUS_OK) return true; Serial.print(F("[-] MIFARE_Read() failed: ")); Serial.println(mfrc522.GetStatusCodeName(status)); return false; } /* * @brief 寫入卡片中的 block * * @param[in] addr 讀取的 block 地址 * @param[in] buffer 要寫入的資料 * @param[in] size buffer 的大小 */ bool write_block(byte addr, byte* buffer, byte size) { MFRC522::StatusCode status = mfrc522.MIFARE_Write(addr, buffer, size); if (status == MFRC522::STATUS_OK) return true; Serial.print(F("[-] MIFARE_Write() failed: ")); Serial.println(mfrc522.GetStatusCodeName(status)); return false; } /* * @brief 驗證 sector 的 key A * * @param[in] sector 要驗證的的 block * @param[in] key 用來驗證的金鑰 */ bool auth_keyA(byte sector, MFRC522::MIFARE_Key* key_a) { Serial.println(F("[i] 驗證 key A...")); byte trailer = sector * 4 + 3; status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailer, key_a, &(mfrc522.uid)); if (status != MFRC522::STATUS_OK) { Serial.print(F("[-] PCD_Authenticate() failed: ")); Serial.println(mfrc522.GetStatusCodeName(status)); return false; } return true; } /* * @brief 驗證 sector 的 key B * * @param[in] sector 要驗證的的 block * @param[in] key 用來驗證的金鑰 */ bool auth_keyB(byte sector, MFRC522::MIFARE_Key* key_b) { Serial.println(F("[i] 驗證 key A...")); byte trailer = sector * 4 + 3; status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailer, key_b, &(mfrc522.uid)); if (status != MFRC522::STATUS_OK) { Serial.print(F("[-] PCD_Authenticate() failed: ")); Serial.println(mfrc522.GetStatusCodeName(status)); return false; } return true; } /* * @brief 傾印 block 的資料 * * @param[in] addr block 的 地址 * @param[in] buffer block 的資料 */ void dump_block(byte addr, byte* buffer) { if (addr < 0x10) Serial.print("0"); Serial.print(addr); Serial.print(F(":")); for (byte i = 0; i < 16; i++) { if (i == 8) Serial.print(" "); Serial.print(buffer[i] < 0x10 ? " 0" : " "); Serial.print(buffer[i], HEX); } Serial.println(); } /* * @brief 計算 uid 的校驗碼 * * @param[in] uid uid 的陣列 * @param[in] size uid 的長度 */ byte bcc0(byte* uid, byte size) { byte result = 0; for (byte i = 0; i < size; i++) { result ^= uid[i]; } return result; } ``` --- # [儲備幹部申請表單](https://forms.gle/FQrHCi4QG4kg6wL28) ![250916135334](https://hackmd.io/_uploads/S1pDkwRpee.jpg =1000%x) --- ### 2025 Vibe coding 青年放輕鬆 ![(EDM) 2025 Vibe Coding青年放輕松](https://hackmd.io/_uploads/B1irxPR6lx.jpg) - **競賽官網:** https://scedux.com/AwX2 - **報名表單:** https://scedux.com/RO3l ## 寒期教育優先區營隊 ![寒期教育優先區](https://hackmd.io/_uploads/HkB-mhMnll.png)