๋ฌธ์ : DreamHack โ Read My Car ๋ถ๋ฅ: Misc ๋์ด๋: ๐ฅ Bronze 2 FLAG:
DH{my_car_is_br0ken!!!!}
๋ฌธ์ ์ค๋ช ์ ์งง๋ค. ์ฐจ์ ๋ฌธ์ ๊ฐ ์๊ฒจ ์ ๋น์์ ๊ฐ๋๋ ์ ๋น์ฌ๊ฐ ์ฃผํ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋กํด ๋ก๊ทธ ํ์ผ๋ก ์คฌ๋๋ฐ, ์์๋ณผ ์๊ฐ ์๋ค๋ ๊ฒ.
๋ฐ์ ๊ฑด candump-2024-04-19_143417.log ํ๋. ํ์ฅ์์ ํ์ผ๋ช
์์ ์ด๋ฏธ ์ ์ฒด๊ฐ ๋๋ฌ๋๋ค. candump๋ ๋ฆฌ๋
์ค SocketCAN ํด์
(can-utils)์ ๋ค์ด ์๋ CAN ๋ฒ์ค ์ค๋ํผ๊ณ , ์ด ์ด๋ฆ ๊ท์น์ ๊ทธ ํด์ด -l ์ต์
์ผ๋ก ๋จ๊ธฐ๋ ๋ก๊ทธ ํ์ผ ๊ทธ๋๋ก๋ค.
์ด ๊ธ์ ๋ช ๋ น์ ๋ชจ๋
extracted/์์ ์คํํ๋ค.
file candump-2024-04-19_143417.log && wc -l candump-2024-04-19_143417.log && head -6 candump-2024-04-19_143417.log
ํ ์ค์ด CAN ํ๋ ์ ํ๋๋ค. (1713504859.236545) vcan0 747#FDB3655488F4 โ ๊ดํธ ์์ด epoch ํ์์คํฌํ, vcan0์ด ์ธํฐํ์ด์ค, # ์์ด ํ๋ ์ ID, ๋ค๊ฐ ํ์ด๋ก๋ hex.
์ฐธ๊ณ ๋ก ์ฒซ ํ์์คํฌํ 1713504859๋ฅผ KST๋ก ํ์ฐํ๋ฉด 2024-04-19 14:34:19๋ค. ํ์ผ๋ช
์ 143417๊ณผ ๋ง๋๋ค. ๋ก๊ทธ๋ ๊ทธ๋ด๋ฏํ๊ฒ ๋ง๋ค์ด์ก๋ค.
๋ฌธ์ ๊ฐ์
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ๋ฌธ์ ๋ช | Read My Car |
| ๋์ด๋ | ๐ฅ Bronze 2 |
| ๋ถ๋ฅ | Misc (์ฐจ๋ ํฌ๋ ์) |
| ์ ๊ณต ํ์ผ | candump-2024-04-19_143417.log (6523์ค, 271KB) |
| ์๋ฒ | ์์ โ ํ์ผ๋ง์ผ๋ก ์๊ฒฐ |
| ํต์ฌ ๊ธฐ๋ฒ | CAN ID ๋น๋ ์ด์์น ํ์ง โ ํ์ด๋ก๋ ASCII ๋ณต์ |
ํ์ด ํ๋ฆ์ ์ธ ๋จ๊ณ๋ค. ๋ก๊ทธ๋ฅผ ํ์ฑํด ID๋ณ ๋ฑ์ฅ ํ์๋ฅผ ์ธ๊ณ , ํต๊ณ์ ์ผ๋ก ํ๋ ID ํ๋๋ฅผ ๊ณจ๋ผ๋ด๊ณ , ๊ทธ ID์ ํ์ด๋ก๋๋ง ์ด์ด ๋ถ์ฌ ASCII๋ก ์ฝ๋๋ค.
๐ ๋ฐฐ๊ฒฝ โ CAN ๋ฒ์ค์ candump ๋ก๊ทธ ํฌ๋งท
CAN(Controller Area Network)์ ์ฐจ๋ ๋ด๋ถ ECU๋ค์ด ์๋ก ๋ ๋๋ 2์ ์ ๋ธ๋ก๋์บ์คํธ ๋ฒ์ค๋ค. ์์ง ECU, ABS, ๊ณ๊ธฐํ, ๋์ด ๋ชจ๋์ด ์ ๋ถ ๊ฐ์ ์ ์ ๋ฌผ๋ ค ์๊ณ , ๊ฐ์ ์๊ธฐ ๋ฉ์์ง๋ฅผ ์ฃผ๊ธฐ์ ์ผ๋ก ๋ฟ๋ฆฐ๋ค. ์์ ์ ์ฃผ์ ๊ฐ์ ๊ฑด ์๋ค. ํ๋ ์์ ๋ถ๋ ๊ฑด ID ํ๋๋ฟ์ด๊ณ , ๊ทธ ID๊ฐ "์ด ๋ฉ์์ง๊ฐ ๋ฌด์จ ๋ด์ฉ์ธ์ง"๋ฅผ ๋ปํ๋ค.

์ถ์ฒ: Wikimedia Commons, CC BY-SA 3.0
์ด ๋ฌธ์ ์ ํ์ํ ํ๋๋ ์ ์ด๋ค.
-
Arbitration ID (11๋นํธ) โ ํ์ค ํ๋ ์์ด๋ฉด
0x000~0x7FF, ์ด 2048๊ฐ์ง. ๋ฉ์์ง ์ข ๋ฅ๋ฅผ ๋ปํ๋ ๋์์ ๋ฒ์ค ์ค์ฌ ์ฐ์ ์์๋ก๋ ์ฐ์ธ๋ค. ๋ ๋ ธ๋๊ฐ ๋์์ ์ก์ ํ๋ฉด ID๋ฅผ ๋นํธ ๋จ์๋ก ๋น๊ตํด ์ซ์๊ฐ ์์ ์ชฝ์ด ์ด๊ธด๋ค. ์ฆ0x000์ด ๋ฒ์ค์์ ๊ฐ์ฅ ์ผ ID๋ค. -
DLC (4๋นํธ) โ ๋ฐ์ดํฐ ๊ธธ์ด. 0~8๋ฐ์ดํธ.
-
Data (0~8๋ฐ์ดํธ) โ ์ค์ ๋ด์ฉ. ๋ฌด์จ ๋ฐ์ดํธ๊ฐ ๋ฌด์จ ๋ป์ธ์ง๋ ์ ์กฐ์ฌ DBC ํ์ผ์ ์์์ผ ํด์๋๊ณ , ๊ทธ ๋งคํ์ ๊ณต๊ฐ๋ผ ์์ง ์๋ค.
candump ๋ก๊ทธ๋ ์ด๊ฑธ ํ ์คํธ ํ ์ค๋ก ๋ํ ๊ฒ์ด๋ค.
(<epoch.microsec>) <interface> <ID(hex)>#<DATA(hex)>
(1713504859.236545) vcan0 747 # FDB3655488F4vcan0์ ๋ฆฌ๋
์ค ์ปค๋์ ๊ฐ์ CAN ์ธํฐํ์ด์ค๋ค. ์ค์ฐจ ํ๋ค์ค์ ๋ฌผ๋ฆฌ์ง ์๊ณ ๋ CAN ํ๋ ์์ ์ฃผ๊ณ ๋ฐ๊ฒ ํด์ฃผ๋ ๋ฃจํ๋ฐฑ ์ฅ์น๋ผ, ์ด๋ฐ ๋ก๊ทธ๋ฅผ ๋์ค์ ๊ทธ๋๋ก ์ฌ์ํด๋ณผ ์ ์๋ค. ๋ค์์ ์ค์ ๋ก ์จ๋จน๋๋ค.
๐ฌ ์ ์ฐฐ โ ๋ก๊ทธ๊ฐ ๋ฌด์จ ๋ชจ์์ธ๊ฐ
๋จผ์ ๋ก๊ทธ ์ ์ฒด๋ฅผ ํ์ฑํด ํํ๋ฅผ ๋ณธ๋ค. ํ๋ ์ ์, ID ์ข ๋ฅ, DLC ๋ถํฌ, ๊ทธ๋ฆฌ๊ณ ID๋ณ ๋ฑ์ฅ ํ์๊น์ง.
#!/usr/bin/env python3
"""candump ๋ก๊ทธ 1์ฐจ ์ ์ฐฐ โ ํ๋ ์ ์ / ID ์ข
๋ฅ / DLC ๋ถํฌ / ์๊ฐ ๋ฒ์."""
import re
from collections import Counter
LOG = "candump-2024-04-19_143417.log"
FRAME = re.compile(r"\((\d+\.\d+)\)\s+(\S+)\s+([0-9A-F]{3})#([0-9A-F]*)$")
ts, ids, dlc, iface = [], Counter(), Counter(), Counter()
bad = 0
for line in open(LOG):
m = FRAME.match(line.strip())
if not m:
bad += 1
continue
t, ifn, cid, payload = m.groups()
ts.append(float(t))
ids[cid] += 1
dlc[len(payload) // 2] += 1
iface[ifn] += 1
print(f"parsed frames : {len(ts)} (unparsed {bad})")
print(f"interface : {dict(iface)}")
print(f"unique CAN ID : {len(ids)}")
print(f"duration : {ts[-1] - ts[0]:.2f} s ({len(ts) / (ts[-1] - ts[0]):.0f} frame/s)")
print(f"DLC ๋ถํฌ : {dict(sorted(dlc.items()))}")
print()
print("--- ID ๋ฑ์ฅ ํ์ ์์ 8๊ฐ ---")
for cid, n in ids.most_common(8):
print(f" 0x{cid} : {n:3d} ํ")
print()
print("--- ๋ฑ์ฅ ํ์๋ณ ID ๊ฐ์ ---")
hist = Counter(ids.values())
for n, k in sorted(hist.items()):
print(f" {n:2d}ํ ๋ฑ์ฅํ ID : {k:4d} ๊ฐ")
์ซ์๋ฅผ ๋ณด๋ฉด ๋ต์ด ๊ฑฐ์ ๋์จ๋ค.
38.81์ด ๋์ 6523ํ๋ ์, ์ด๋น 168ํ๋ ์. ๊ทธ๋ฐ๋ฐ ID ์ข ๋ฅ๊ฐ 1953๊ฐ์ง๋ค. 11๋นํธ ํ์ค ID ๊ณต๊ฐ์ด 2048์นธ์ธ๋ฐ ๊ทธ์ค 95%๊ฐ ์ต์ ํ ๋ฒ์ฉ ์ฐ์๋ค๋ ๋ป์ด๋ค.
์ค์ฐจ CAN์ ์ด๋ ๊ฒ ์ ์๊ฒผ๋ค. ์ค์ ์ฐจ๋์ ID๋ฅผ ์์ญ ๊ฐ ์ ๋๋ง ์ฐ๊ณ , ๊ฐ ID๊ฐ 10msยท50msยท100ms ๊ฐ์ ๊ณ ์ ์ฃผ๊ธฐ๋ก ๊ณ์ ๋ฐ๋ณต๋๋ค. ID ์ข ๋ฅ๊ฐ 2048์นธ์ ๊ฑฐ์ ์ฑ์ด๋ค๋ ๊ฑด ID๋ฅผ ๋์๋ก ๋ฝ์๋ค๋ ์๊ธฐ๋ค.
๊ทธ๋ฆฌ๊ณ ๋ง์ง๋ง ํ์คํ ๊ทธ๋จ. ๋๋ถ๋ถ ID๊ฐ 1~10ํ ๋ฑ์ฅํ๋๋ฐ 43ํ์ง๋ฆฌ๊ฐ ๋ฑ ํ๋ ์๋ค. 2์(10ํ)์ 4.3๋ฐฐ๋ค.
๐ ์ฝ์ง
์ ์ฐฐ ์คํฌ๋ฆฝํธ๋ฅผ ์ง๊ธฐ ์ ์ ๋จผ์ ํด๋ณธ ๊ฒ๋ค. ๋ ๋ค ํ๋ค๋ฆฌ์์ง๋ง ๋ฌธ์ ๊ตฌ์กฐ๋ฅผ ํ์ ํ๋ ๋ฐ๋ ๋์์ด ๋๋ค.
โถ๐ ์ฝ์ง 1 โ ๋ฌด์์ ์ ํ๋ ์์ ASCII๋ก ์ฐ์ด๋ณด๊ธฐ
flag๊ฐ ์ด๋๊ฐ ๋ฌธ์์ด๋ก ๋ฐํ ์์ ์ ์์ผ๋ grep "DH{"๋ถํฐ ํด๋ดค๋ค. 0์ค. ๋ก๊ทธ๋ ์์ hex ํ
์คํธ๋ผ ๋น์ฐํ๋ค.
๊ทธ๋์ ํ์ด๋ก๋๋ฅผ ์ ๋ถ ๋์ฝ๋ฉํด์ ์ถ๋ ฅ ๊ฐ๋ฅํ ASCII๋ง ๋ฝ์ ์ด์ด ๋ถ์ฌ๋ดค๋ค.
#!/usr/bin/env python3
"""์ฝ์ง 1 โ ๋ฌด์์ ์ ํ๋ ์์ ASCII ๋ก ์ฐ์ด๋ณด๊ธฐ. ์ฐ์ฐํ ์ถ๋ ฅ๊ฐ๋ฅํ ์กฐ๊ฐ์ด ์์์ง๋ค."""
import re
LOG = "candump-2024-04-19_143417.log"
FRAME = re.compile(r"\((\d+\.\d+)\)\s+\S+\s+([0-9A-F]{3})#([0-9A-F]*)$")
hits = []
for line in open(LOG):
m = FRAME.match(line.strip())
if not m:
continue
_, cid, payload = m.groups()
b = bytes.fromhex(payload)
if len(b) >= 2 and all(0x20 <= c < 0x7F for c in b):
hits.append((cid, b.decode()))
print(f"์ถ๋ ฅ๊ฐ๋ฅ ASCII ํ๋ ์ : {len(hits)} ๊ฐ <- ๋
ธ์ด์ฆ๊น์ง ์ ๋ถ ๊ฑธ๋ฆฐ๋ค")
print("์ด์ด๋ถ์ด๋ฉด:")
print("".join(s for _, s in hits[:60])[:260])
my_car_is_br0ken!!!!๊ฐ ๋ณด์ด๊ธด ํ๋ค. ํ์ง๋ง ๊ทธ ์ฌ์ด์ฌ์ด์ tJoEhA>/G(EgHAG;;%f{A:3j0 ๊ฐ์ ์ฐ๋ ๊ธฐ๊ฐ ์๋ฉ ๋๋ค. 28๋ฐ์ดํธ์ง๋ฆฌ ๋์๊ฐ ์ฐ์ฐํ ์ ๋ถ 0x200x7E ๋ฒ์์ ๋ค์ด๊ฐ ํ๋ฅ ์ด ๊ฝค ๋๊ธฐ ๋๋ฌธ์ด๋ค(2๋ฐ์ดํธ๋ฉด ์ฝ 37%).
140๊ฐ๊ฐ ๊ฑธ๋ ธ๋๋ฐ ์ง์ง๋ 40๊ฐ๋ฟ. ์ด๋ค ์กฐ๊ฐ์ด ์ง์ง์ธ์ง ๊ตฌ๋ถํ ๊ธฐ์ค์ด ์์ผ๋ฉด ์ด ๋ฐฉ๋ฒ์ ๋ชป ์ด๋ค. ๊ทธ ๊ธฐ์ค์ด ๊ฒฐ๊ตญ "์ด๋ ID์์ ์๋"์๋ค.
โถ๐ ์ฝ์ง 2 โ ์ง์ง ์ฃผํ ๋ฐ์ดํฐ๋ก ๋ณด๊ณ OBD-II ํด์ ์๋
๋ฌธ์ ์ค๋ช
์ด "์ ๋น์ฌ๊ฐ ์ฃผํ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋กํด ์คฌ๋ค"๊ณ ํ๋, ์ง์ง ์ฐจ๋ ์ ํธ๋ก ๋ณด๊ณ ์๋ยทRPM์ ๋ฝ์๋ด์ผ ํ๋ ์ถ์๋ค. ์ ๋น์์์ ์ฐ๋ ๊ฑด ๋ณดํต OBD-II ์ง๋จ ํต์ ์ด๊ณ , ๊ทธ๊ฑด ์์ฒญ 0x7DF / ์๋ต 0x7E8~0x7EF๋ผ๋ ๊ณ ์ ID๋ฅผ ์ด๋ค.
#!/usr/bin/env python3
"""์ฝ์ง 2 โ ์ด๊ฒ ์ ๋ง '์ฃผํ ๋ฐ์ดํฐ'์ธ๊ฐ? OBD-II ํ์ค ID / ํ์ด๋ก๋ ๊ท์น์ฑ ํ์ธ."""
import re
from collections import Counter
LOG = "candump-2024-04-19_143417.log"
FRAME = re.compile(r"\((\d+\.\d+)\)\s+\S+\s+([0-9A-F]{3})#([0-9A-F]*)$")
rows = []
for line in open(LOG):
m = FRAME.match(line.strip())
if m:
t, cid, p = m.groups()
rows.append((float(t), cid, p))
# (1) OBD-II ์ง๋จ ํต์ ์ ์์ฒญ 0x7DF, ์๋ต 0x7E8~0x7EF ๋ฅผ ์ด๋ค.
obd = {"7DF"} | {f"7E{c:X}" for c in range(0x0, 0x10)}
hit = [r for r in rows if r[1] in obd]
print(f"[1] OBD-II ํ์ค ID(7DF / 7E0~7EF) ํ๋ ์ : {len(hit)} ๊ฐ")
for r in hit[:5]:
print(f" {r[1]}#{r[2]}")
# (2) ์ค์ฐจ CAN ์ ๊ฐ์ ID ๊ฐ 10~100ms ์ฃผ๊ธฐ๋ก ๊ท์น์ ์ผ๋ก ๋ฐ๋ณต๋๋ค.
per = {}
for t, cid, p in rows:
per.setdefault(cid, []).append(t)
multi = {c: v for c, v in per.items() if len(v) >= 5}
print(f"\n[2] 5ํ ์ด์ ๋ฑ์ฅํ ID : {len(multi)} ๊ฐ / ์ ์ฒด {len(per)} ๊ฐ")
jit = []
for cid, v in multi.items():
gaps = [b - a for a, b in zip(v, v[1:])]
avg = sum(gaps) / len(gaps)
spread = (max(gaps) - min(gaps)) / avg
jit.append((spread, cid, avg))
jit.sort()
print(" ์ฃผ๊ธฐ ํ๋ค๋ฆผ(=(max-min)/avg)์ด ์์ ์ ์์ 5๊ฐ:")
for spread, cid, avg in jit[:5]:
print(f" 0x{cid} ํ๊ท ์ฃผ๊ธฐ {avg*1000:7.1f} ms ํ๋ค๋ฆผ {spread:6.2f}")
# (3) ํ์ด๋ก๋ ๋ฐ์ดํธ ๋ถํฌ โ ์ค์ฐจ ์ ํธ๋ฉด ํน์ ๋ฐ์ดํธ๊ฐ ๊ณ ์ /์์ํ ๋ณํ๋ค.
allb = Counter()
for _, _, p in rows:
allb.update(bytes.fromhex(p))
print(f"\n[3] ํ์ด๋ก๋ ๋ฐ์ดํธ ์ข
๋ฅ : {len(allb)}/256, ์ต๋น 5๊ฐ {allb.most_common(5)}")
์ธ ๊ฐ์ง๊ฐ ์ ๋ถ ์๋๋ผ๊ณ ๋งํ๋ค.
0x7E8๋ ํ๋ ์์ด 45๊ฐ ๊ฑธ๋ฆฌ๊ธด ํ๋ค. ๊ทธ๋ฐ๋ฐ ํ์ด๋ก๋๊ฐ 7EB#D551A329C25A0268์ด๋ค. ์ง์ง OBD-II ์๋ต์ด๋ฉด ์ฒซ ๋ฐ์ดํธ๊ฐ ๊ธธ์ด(๋ณดํต 0x03~0x06), ๋์งธ๊ฐ ์๋ต ๋ชจ๋(0x41)์ฌ์ผ ํ๋๋ฐ D5 51์ ๊ท๊ฒฉ ๋ฐ์ด๋ค. ๊ทธ๋ฅ ๋์๊ฐ ์ฐ์ฐํ ๊ทธ ID๋ก ๋จ์ด์ง ๊ฒ.
์ฃผ๊ธฐ์ฑ๋ ์๋ค. ํ๋ค๋ฆผ์ด ๊ฐ์ฅ ์์ ID์กฐ์ฐจ (max-min)/avg๊ฐ 0.28์ด๋ค. ์ค์ฐจ ์ ํธ๋ผ๋ฉด ์ด ๊ฐ์ด 0์ ๊ฐ๊น์์ผ ํ๋ค. ๊ฒ๋ค๊ฐ "ํ๊ท ์ฃผ๊ธฐ 3.9์ด"๋ ์ฐจ๋ ์ ํธ๋ก๋ ๋ง์ด ์ ๋๋ ๊ฐ๊ฒฉ์ด๋ค.
ํ์ด๋ก๋ ๋ฐ์ดํธ๋ 0~255๊ฐ ์ ๋ถ ๋์ค๊ณ ์ต๋น๊ฐ์กฐ์ฐจ 211ํ๋ก ํํํ๋ค. ๋์๋ค.
๊ฒฐ๋ก : ์ด๊ฑด ์ฃผํ ๋ฐ์ดํฐ๊ฐ ์๋๋ผ ๋์ ์์ ๋ฉ์์ง ํ๋๋ฅผ ์จ๊ธด ๋ก๊ทธ๋ค. "์ฃผํ ๋ฐ์ดํฐ"๋ ๋ฌธ์ ์ค๋ช ์ ์ฐ์ถ์ด์๋ค.
๐ฃ ํต์ฌ โ 0x000๋ง ํต๊ณ์์ ๋ฒ์ด๋๋ค
"43ํ๋ ํ๋ ๊ฐ์ด๋ค"๋ฅผ ๋๋์ค์ด ์๋๋ผ ์์น๋ก ๋ชป ๋ฐ์ ๋์. ID๊ฐ ๊ท ๋ฑ ๋๋ค์ด๋ผ๋ฉด 6523๊ฐ๋ฅผ 2048์นธ์ ๋ฟ๋ฆฌ๋ ๋ฌธ์ ์ด๊ณ , ์ด๊ฑด ํฌ์์ก ๋ถํฌ๋ก ๊ทผ์ฌ๋๋ค.
#!/usr/bin/env python3
"""ID ๋ถํฌ๊ฐ '๊ท ๋ฑ ๋๋ค'์ธ์ง, 0x000 ์ด ์ ๋ง ์ด์์น์ธ์ง ์์น๋ก ํ์ธ."""
import math
import re
from collections import Counter
LOG = "candump-2024-04-19_143417.log"
FRAME = re.compile(r"\((\d+\.\d+)\)\s+\S+\s+([0-9A-F]{3})#([0-9A-F]*)$")
ids = Counter()
for line in open(LOG):
m = FRAME.match(line.strip())
if m:
ids[m.group(2)] += 1
N, BINS = sum(ids.values()), 0x800 # 11๋นํธ ํ์ค ID = 2048๊ฐ
lam = N / BINS
exp_distinct = BINS * (1 - (1 - 1 / BINS) ** N)
print(f"ํ๋ ์ {N}๊ฐ๋ฅผ ํ์ค ID {BINS}์นธ์ ๊ท ๋ฑ ๋๋ค์ผ๋ก ๋ฟ๋ ธ๋ค๋ฉด")
print(f" ๊ธฐ๋ ID ์ข
๋ฅ : {exp_distinct:.0f} ๊ฐ / ์ค์ : {len(ids)} ๊ฐ")
print(f" ์นธ๋น ํ๊ท : {lam:.2f} ํ")
# ๊ท ๋ฑ ๋๋ค ๊ฐ์ ์์ 'ํ ์นธ์ด kํ ์ด์' ๋์ฌ ๊ธฐ๋ ์นธ ์ (ํฌ์์ก ๊ทผ์ฌ)
def pois_ge(k, lam):
cdf = sum(math.exp(-lam) * lam ** i / math.factorial(i) for i in range(k))
return max(0.0, 1 - cdf)
print("\n kํ ์ด์ ๋ฑ์ฅํ๋ ID์ ๊ธฐ๋ ๊ฐ์(2048์นธ ์ค)")
for k in (10, 11, 12, 15, 20, 43):
e = BINS * pois_ge(k, lam)
real = sum(1 for v in ids.values() if v >= k)
print(f" k={k:2d} : ๊ธฐ๋ {e:11.3e} ๊ฐ ์ค์ {real} ๊ฐ")
top, n = ids.most_common(1)[0]
print(f"\nโ 0x{top} ์ {n}ํ๋ ๊ท ๋ฑ ๋๋ค์ผ๋ก๋ ์ค๋ช
์ด ์ ๋๋ค. ๋๊ฐ ์ผ๋ถ๋ฌ ๋ฃ์ ๊ฒ.")
๊ท ๋ฑ ๋๋ค ๊ฐ์ ์ด ๋๋จธ์ง ๋ฐ์ดํฐ๋ฅผ ์ ํํ ์ค๋ช ํ๋ค. ๊ธฐ๋ ID ์ข ๋ฅ 1963๊ฐ์ ์ค์ 1953๊ฐ, 10ํ ์ด์ ๋์ฌ ID ๊ธฐ๋์น 3.49๊ฐ์ ์ค์ 3๊ฐ, 11ํ ์ด์ ๊ธฐ๋์น 0.98๊ฐ์ ์ค์ 1๊ฐ.
๊ทธ๋ฐ๋ฐ 43ํ๋ ๊ธฐ๋์น๊ฐ 2.3e-13๊ฐ๋ค. ์ฐ์ฐํ ๋์ฌ ๋ฌผ๊ฑด์ด ์๋๋ค. ๋
ธ์ด์ฆ๋ ์ง์ง ๋์๊ณ , 0x000 ํ๋๋ง ์์ผ๋ก ์ฌ์ด์ก๋ค.
ํํ 0x000์ธ ๊ฒ๋ ์ฐ์ฐ์ด ์๋๋ค. ์์ ๋ณธ ๋๋ก CAN ์ค์ฌ์์ ID ์ซ์๊ฐ ์์์๋ก ์ฐ์ ์์๊ฐ ๋์ผ๋, 0x000์ ๋ฒ์ค์์ ๊ฐ์ฅ ๊ฐํ ID๋ค. ์ค์ฐจ๋ผ๋ฉด ์ด ID๋ก ์๋ฌด ๋ฐ์ดํฐ๋ ๊ณ์ ์๋ ๊ฒ ์์ฒด๊ฐ ๋ค๋ฅธ ECU๋ฅผ ๋ฐ์ด๋ด๋ ๊ณต๊ฒฉ์ด ๋๋ค.
๊ทธ 43๊ฐ ํ๋ ์์ ์ง์ ๋ณธ๋ค.
grep -n -m 14 ' 000#' candump-2024-04-19_143417.log
ํจํด์ด ๋ฐ๋ก ๋ณด์ธ๋ค. 6D795F6361725F โ 69735F โ 6272306B656E โ 21212121 ๋ค ๊ฐ๊ฐ 1ms ๊ฐ๊ฒฉ์ผ๋ก ๋ถ์ด ๋์ค๊ณ , ๊ทธ ๋ฌถ์์ด ์ฝ 3์ด ๊ฐ๊ฒฉ์ผ๋ก ๋ค์ ๋์จ๋ค. ์ค ๋ฒํธ๋ 446ยท947ยท1449ยท1953์ผ๋ก 500์ค์ฏค์ฉ ๋ด๋ค.
hex๋ฅผ ASCII๋ก ์ฎ๊ธฐ๋ฉด my_car_ / is_ / br0ken / !!!!. ์์๋๋ก ์ด์ผ๋ฉด flag ๋ณธ๋ฌธ์ด๋ค.

43๊ฐ ์ค 40๊ฐ๋ง ASCII๊ณ 3๊ฐ(9FD2, EE4CF127E1485E, E2C06F40B3B1A4)๋ ์ฐ๋ ๊ธฐ๋ค. ๋์ ์์ฑ๊ธฐ๊ฐ ์ฐ์ฐํ 0x000์ ๋ฝ์ ๊ฒ๋ค์ด๋ผ ๊ฑธ๋ฌ๋ด์ผ ํ๋ค. ์ถ๋ ฅ ๊ฐ๋ฅ ASCII๋ง ๋จ๊ธฐ๋ฉด ์์ฐ์ค๋ฝ๊ฒ ๋น ์ง๋ค.
๐ ๏ธ can-utils๋ก ์ค๊ธฐ ์ฌํ
ํ์ฑ๋ง์ผ๋ก ๋ต์ ๋์์ง๋ง, ์ด ๋ก๊ทธ๋ ์๋ ์ฌ์ํ๋ผ๊ณ ๋ง๋ ํฌ๋งท์ด๋ค. ์ปค๋ ๊ฐ์ CAN ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ค๊ณ ๋ก๊ทธ๋ฅผ ๊ทธ๋๋ก ๋ฒ์ค์ ํ๋ ค์ ์ค์ ์ค๋ํผ๋ก ๋ฐ์๋ณด๋ฉด ๋ฌธ์ ์ํฉ์ด ๊ทธ๋๋ก ์ฌํ๋๋ค.
๋จผ์ vcan ๋ชจ๋์ ์ฌ๋ฆฌ๊ณ ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ ๋ค.
sudo apt-get install -y can-utils
sudo modprobe vcan && sudo ip link add dev vcan0 type vcan && sudo ip link set up vcan0 && ip -details link show vcan0
mtu 72๊ฐ CAN ์์ผ ํน์ ์ ๊ฐ์ด๋ค(struct canfd_frame ํฌ๊ธฐ). ์ด์ canplayer๋ก ๋ก๊ทธ๋ฅผ ํ์์คํฌํ๊น์ง ์ด๋ ค ์ฌ์ํ๊ณ , candump๋ก ๋ฐ๋๋ค. -a ์ต์
์ ์ฃผ๋ฉด ํ์ด๋ก๋๋ฅผ hex์ ASCII ์์ชฝ์ผ๋ก ๋ณด์ฌ์ค๋ค.
canplayer -I candump-2024-04-19_143417.log vcan0=vcan0 & candump -n 16 -a vcan0
ํํฐ ์์ด ๋ฐ์ผ๋ฉด ์ด ํ๋ฉด์ด๋ค. ASCII ์นธ์ด '..eT..', '.w...J.k' ๊ฐ์ ์ ํฌ์ฑ์ด๋ผ ๋์ผ๋ก๋ ์๋ฌด๊ฒ๋ ๋ชป ๊ฑด์ง๋ค. ์ด๋น 168ํ๋ ์์ด ํ๋ฅด๋ ์ค์๊ฐ์ผ๋ก ๋ณด๋ฉด ๋ ์ ๋ณด์ธ๋ค.
์ฌ๊ธฐ์ ID ํํฐ๋ฅผ ๊ฑด๋ค. candump์ ํํฐ ๋ฌธ๋ฒ์ ์ธํฐํ์ด์ค,ID:๋ง์คํฌ๋ค. vcan0,000:7FF๋ 11๋นํธ ์ ์ฒด๋ฅผ ๋ง์คํฌ๋ก ๊ฑธ์ด ID๊ฐ ์ ํํ 0x000์ธ ํ๋ ์๋ง ํต๊ณผ์ํจ๋ค.
canplayer -I candump-2024-04-19_143417.log vcan0=vcan0 & candump -n 12 -a 'vcan0,000:7FF'
ํํฐ ํ ์ค๋ก ๋๋๋ค. ASCII ์นธ์ 'my_car_' 'is_' 'br0ken' '!!!!'๊ฐ 3์ด ์ฃผ๊ธฐ๋ก ๋ฐ๋ณตํด์ ์ฐํ๋ค. DLC๋ ๊ฐ๊ฐ 7/3/6/4๋ก ์๋ณธ ๊ทธ๋๋ก๋ค.
ํ์ด์ฌ์ผ๋ก ํ์ฑํ ๊ฒฐ๊ณผ์ ์ค์ CAN ์์ผ์ผ๋ก ๋ฐ์ ๊ฒฐ๊ณผ๊ฐ ๊ฐ์ผ๋, ๋ก๊ทธ ํด์์ด ํ๋ฆฌ์ง ์์๋ค๋ ๊ฒ๊น์ง ํ์ธ๋ ์ ์ด๋ค.
๐ Full Exploit
์ ์ฒด ๊ณผ์ ์ ํ๋๋ก ๋ฌถ๋๋ค. ๋ก๊ทธ๋ง ์์ผ๋ฉด ์ด๋์๋ ๋์๊ฐ๋ค.
#!/usr/bin/env python3
"""Read My Car โ candump ๋ก๊ทธ์์ ์ด์์น CAN ID ๋ฅผ ์ฐพ์ ํ์ด๋ก๋๋ฅผ ASCII ๋ก ๋ณต์."""
import re
from collections import Counter, OrderedDict
LOG = "candump-2024-04-19_143417.log"
FRAME = re.compile(r"\((\d+\.\d+)\)\s+\S+\s+([0-9A-F]{3})#([0-9A-F]*)$")
frames = []
for line in open(LOG):
m = FRAME.match(line.strip())
if m:
t, cid, payload = m.groups()
frames.append((float(t), cid, bytes.fromhex(payload)))
# 1) ๋ฑ์ฅ ํ์ ์ด์์น = ๋
ธ์ด์ฆ ์์ ์นํ ์ง์ง ๋ฉ์์ง
count = Counter(cid for _, cid, _ in frames)
top_id, top_n = count.most_common(1)[0]
second_n = count.most_common(2)[1][1]
print(f"[*] ์ต๋ค ์ถํ ID : 0x{top_id} ({top_n}ํ) / 2์ {second_n}ํ โ {top_n/second_n:.1f}๋ฐฐ ์ด์์น")
# 2) ๊ทธ ID ์ ํ์ด๋ก๋ ์ค ์ ๋ถ ์ถ๋ ฅ๊ฐ๋ฅ ASCII ์ธ ๊ฒ๋ง ์ถ๋ฆฐ๋ค (๋
ธ์ด์ฆ ํ๋ ์ ๋ฐฐ์ )
target = [(t, p) for t, cid, p in frames if cid == top_id]
ascii_only = [(t, p) for t, p in target if p and all(0x20 <= b < 0x7F for b in p)]
print(f"[*] 0x{top_id} ํ๋ ์ {len(target)}๊ฐ ์ค ์ถ๋ ฅ๊ฐ๋ฅ ASCII {len(ascii_only)}๊ฐ, ๋
ธ์ด์ฆ {len(target)-len(ascii_only)}๊ฐ")
# 3) ํ ์ฃผ๊ธฐ(๋ฐ๋ณต ๋จ์)๋ฅผ ์ถ์ถ โ ๋ฑ์ฅ ์์๋ฅผ ์ ์งํ ์ค๋ณต ์ ๊ฑฐ
cycle = list(OrderedDict.fromkeys(p for _, p in ascii_only))
print(f"[*] ๋ฐ๋ณต ์ฃผ๊ธฐ {len(cycle)}์กฐ๊ฐ ร {len(ascii_only)//len(cycle)}ํ")
for i, chunk in enumerate(cycle, 1):
print(f" {i}. {chunk.hex().upper():<16} -> {chunk.decode()!r}")
body = b"".join(cycle).decode()
print(f"\n[+] FLAG: DH{{{body}}}")ID๋ฅผ 0x000์ผ๋ก ํ๋์ฝ๋ฉํ์ง ์์ ๊ฒ ์์ ์ด๋ค. ์ต๋น ID๋ฅผ ์๋์ผ๋ก ์ฐพ๊ณ , ๊ทธ์ค ASCII ํ๋ ์๋ง ๋จ๊ธฐ๊ณ , ์์๋ฅผ ์ ์งํ ์ค๋ณต ์ ๊ฑฐ(OrderedDict.fromkeys)๋ก ํ ์ฃผ๊ธฐ๋ฅผ ๋ฝ๋๋ค.

[*] ์ต๋ค ์ถํ ID : 0x000 (43ํ) / 2์ 10ํ โ 4.3๋ฐฐ ์ด์์น
[*] 0x000 ํ๋ ์ 43๊ฐ ์ค ์ถ๋ ฅ๊ฐ๋ฅ ASCII 40๊ฐ, ๋
ธ์ด์ฆ 3๊ฐ
[*] ๋ฐ๋ณต ์ฃผ๊ธฐ 4์กฐ๊ฐ ร 10ํ
1. 6D795F6361725F -> 'my_car_'
2. 69735F -> 'is_'
3. 6272306B656E -> 'br0ken'
4. 21212121 -> '!!!!'
[+] FLAG: DH{my_car_is_br0ken!!!!}DH{my_car_is_br0ken!!!!} ์ ์ถํด์ ์ ๋ต.
๐ ๊ฒฐ๋ก
๋ ธ์ด์ฆ๋ฅผ ๋ซ๋ ๊ธฐ์ค์ "๋ด์ฉ"์ด ์๋๋ผ "๊ตฌ์กฐ"์๋ค.
์ฒ์์ ํ์ด๋ก๋๋ฅผ ASCII๋ก ์ฝ๋ ์ชฝ๋ถํฐ ์๋๋๋ฐ, ๋์ 2๋ฐ์ดํธ๊ฐ ์ฐ์ฐํ ์ถ๋ ฅ ๊ฐ๋ฅ ๋ฒ์์ ๋ค์ด๊ฐ ํ๋ฅ ์ด 37%๋ ๋ผ์ ์ง์ง์ ๊ฐ์ง๊ฐ ๋ค์์๋ค. ๋ด์ฉ์ ๋ณด๋ ๋์ ID๋ณ ๋ฑ์ฅ ํ์๋ผ๋ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ธ๋ ํ ๋ฐฉ์ ๊ฐ๋ ธ๋ค. ๋ฐ์ดํฐ๊ฐ ์๋๋ฌ์ธ ๋๋ ๊ฐ์ ํด์ํ๊ธฐ ์ ์ ๋ถํฌ๋ถํฐ ๋ณด๋ ๊ฒ ๋น ๋ฅด๋ค.
"์ด์์น๋ค"๋ ๋๋์ค ๋์ ์์น๋ก ํ์ธํ ์ ์๋ค.
43ํ๊ฐ ํ๋ค๋ ๊ฑด ํ์คํ ๊ทธ๋จ๋ง ๋ด๋ ์์ง๋ง, ๊ท ๋ฑ ๋๋ค์ ๊ฐ์ ํ๊ณ ํฌ์์ก์ผ๋ก ๊ธฐ๋์น๋ฅผ ๊ณ์ฐํ๋ฉด ๋๋จธ์ง ID๋ค์ด ๊ทธ ๊ฐ์ ์ ์ ํํ ๋ค์ด๋ง๋ ๊ฒ๊น์ง ๊ฐ์ด ๋ณด์ธ๋ค. ๋๋จธ์ง๊ฐ ์ ๋ถ ์ค๋ช ๋๋๋ฐ ํ๋๋ง ์ ๋๋ฉด, ๊ทธ ํ๋๊ฐ ์ฌ๋์ด ๋ฃ์ ๊ฒ์ด๋ค.
CAN์๋ ์ธ์ฆ๋ ์ํธํ๋ ์๋ค.
์ด ๋ฌธ์ ๊ฐ flag๋ฅผ 0x000์ผ๋ก ๋ธ๋ก๋์บ์คํธํ ๊ฑด ์ฐ์ถ์ด์ง๋ง, ๊ตฌ์กฐ ์์ฒด๋ ์ค์ ๊ทธ๋๋ก๋ค. CAN ํ๋ ์์๋ ์ก์ ์๋ฅผ ํ์ธํ ์๋จ์ด ์๊ณ ํ์ด๋ก๋๋ ํ๋ฌธ์ด๋ค. OBD-II ํฌํธ๋ ์ธํฌํ
์ธ๋จผํธ๋ฅผ ํตํด ๋ฒ์ค์ ํ ๋ฐ๋ง ๊ฑธ์น๋ฉด ์์ ID๋ก ํ๋ ์์ ๋ฟ๋ฆด ์ ์๊ณ , 0x000์ฒ๋ผ ์ฐ์ ์์๊ฐ ๋์ ID๋ฅผ ๊ณ์ ์ ์ ํ๋ฉด ์ ์ ECU ๋ฉ์์ง๋ฅผ ๋ฐ์ด๋ด๋ ๊ฒ๋ ๋๋ค.
๋ฐฉ์ด๋ ๋ฒ์ค ๋ฐ์์ ์จ๋ค. ๊ฒ์ดํธ์จ์ด๋ก ๋๋ฉ์ธ์ ๋ถ๋ฆฌํด ์ง๋จ ํฌํธ์์ ํ์ํธ๋ ์ธ ๋ฒ์ค๋ก ์์ ํ๋ ์์ด ๋์ด๊ฐ์ง ๋ชปํ๊ฒ ๋ง๊ณ , ์์ ๊ด๋ จ ๋ฉ์์ง์๋ CAN-FD ๊ธฐ๋ฐ MAC(SecOC ๊ฐ์)์ ๋ถ์ด๊ณ , IDS๋ก "์ด ID๋ ์๋ 10ms ์ฃผ๊ธฐ์ธ๋ฐ ์ ๊ฐ์๊ธฐ ๋ค๋ฅธ ์ฃผ๊ธฐ๋ก ์ค๋", "์กด์ฌํ์ง ์์์ผ ํ ID๊ฐ ์ ๋ณด์ด๋"๋ฅผ ๊ฐ์ํ๋ค. ๊ฒฐ๊ตญ ์ด๋ฒ ํ์ด์์ ์ด ๊ฒ๊ณผ ๊ฐ์ ํต๊ณ์ ์ด์์น ํ์ง๋ค. ๊ณต๊ฒฉ์๊ฐ ๋ก๊ทธ์์ ์ ํธ๋ฅผ ์ฐพ์๋ด๋ ๋ฐฉ๋ฒ์ด ๊ทธ๋๋ก ๋ฐฉ์ด์์ ํ์ง ๊ท์น์ด ๋๋ค.
Comments
๋๊ธ
๋๊ธ์ ๋จ๊ธฐ๋ ค๋ฉด ๋ก๊ทธ์ธ์ด ํ์ํด์. (๋ค์ด๋ฒ ยท ๊ตฌ๊ธ ๊ณ์ )
๋๊ธ ๋ถ๋ฌ์ค๋ ์คโฆ