[๐Ÿฅ‰ Bronze 2] 6523๊ฐœ CAN ํ”„๋ ˆ์ž„ ์ค‘ ํŠ€๋Š” ํ•˜๋‚˜ โ€” DreamHack Read My Car ํ’€์ด

2026-07-24ยท1๋ถ„ ์ฝ๊ธฐยท

[๐Ÿฅ‰ Bronze 2] 6523๊ฐœ CAN ํ”„๋ ˆ์ž„ ์ค‘ ํŠ€๋Š” ํ•˜๋‚˜ โ€” DreamHack Read My Car ํ’€์ด

์ •๋น„์†Œ์—์„œ ๋ฐ›์•„์˜จ ์ฐจ๋Ÿ‰ ์ฃผํ–‰ ๋กœ๊ทธ๋ผ๋ฉฐ candump ํŒŒ์ผ ํ•˜๋‚˜๋งŒ ์ค€๋‹ค. ์—ด์–ด ๋ณด๋ฉด 1953๊ฐ€์ง€ CAN ID๊ฐ€ ๋’ค์„ž์ธ ๋‚œ์ˆ˜ ๋ฉ์–ด๋ฆฌ์ธ๋ฐ, ๋“ฑ์žฅ ํšŸ์ˆ˜๋ฅผ ์„ธ๋ฉด ๋”ฑ ํ•˜๋‚˜๋งŒ ๋‹ค๋ฅธ ID๋“ค๋ณด๋‹ค 4๋ฐฐ ๋„˜๊ฒŒ ํŠ„๋‹ค. ๊ทธ ID์˜ ํŽ˜์ด๋กœ๋“œ๋ฅผ ASCII๋กœ ์ฝ์œผ๋ฉด flag๊ฐ€ ๋‚˜์˜จ๋‹ค.

๋ฌธ์ œ: 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

file๊ณผ head๋กœ ํ™•์ธํ•œ candump ๋กœ๊ทธ โ€” 6523์ค„, ํƒ€์ž„์Šคํƒฌํ”„+์ธํ„ฐํŽ˜์ด์Šค+ID#ํŽ˜์ด๋กœ๋“œ ํ˜•์‹
file๊ณผ head๋กœ ํ™•์ธํ•œ candump ๋กœ๊ทธ โ€” 6523์ค„, ํƒ€์ž„์Šคํƒฌํ”„+์ธํ„ฐํŽ˜์ด์Šค+ID#ํŽ˜์ด๋กœ๋“œ ํ˜•์‹

ํ•œ ์ค„์ด 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๊ฐ€ "์ด ๋ฉ”์‹œ์ง€๊ฐ€ ๋ฌด์Šจ ๋‚ด์šฉ์ธ์ง€"๋ฅผ ๋œปํ•œ๋‹ค.

CAN ํ‘œ์ค€(base) ํ”„๋ ˆ์ž„ ๊ตฌ์กฐ โ€” 11๋น„ํŠธ Arbitration ID, 4๋น„ํŠธ DLC, ์ตœ๋Œ€ 8๋ฐ”์ดํŠธ Data
CAN ํ‘œ์ค€(base) ํ”„๋ ˆ์ž„ ๊ตฌ์กฐ โ€” 11๋น„ํŠธ Arbitration ID, 4๋น„ํŠธ DLC, ์ตœ๋Œ€ 8๋ฐ”์ดํŠธ Data

์ถœ์ฒ˜: 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  # FDB3655488F4

vcan0์€ ๋ฆฌ๋ˆ…์Šค ์ปค๋„์˜ ๊ฐ€์ƒ 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} ๊ฐœ")

recon.py ์‹คํ–‰ โ€” 6523ํ”„๋ ˆ์ž„ / 1953 unique ID / ๋“ฑ์žฅ ํšŸ์ˆ˜ ํžˆ์Šคํ† ๊ทธ๋žจ
recon.py ์‹คํ–‰ โ€” 6523ํ”„๋ ˆ์ž„ / 1953 unique ID / ๋“ฑ์žฅ ํšŸ์ˆ˜ ํžˆ์Šคํ† ๊ทธ๋žจ

์ˆซ์ž๋ฅผ ๋ณด๋ฉด ๋‹ต์ด ๊ฑฐ์˜ ๋‚˜์˜จ๋‹ค.

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])

try_ascii_all.py ์‹คํ–‰ โ€” ๋…ธ์ด์ฆˆ์— ์„ž์—ฌ flag ์กฐ๊ฐ์ด ๋ฐ˜๋ณต๋˜์ง€๋งŒ ์“ฐ๋ ˆ๊ธฐ ๋ฌธ์ž๊ฐ€ ํ•จ๊ป˜ ๋”ธ๋ ค์˜จ๋‹ค
try_ascii_all.py ์‹คํ–‰ โ€” ๋…ธ์ด์ฆˆ์— ์„ž์—ฌ flag ์กฐ๊ฐ์ด ๋ฐ˜๋ณต๋˜์ง€๋งŒ ์“ฐ๋ ˆ๊ธฐ ๋ฌธ์ž๊ฐ€ ํ•จ๊ป˜ ๋”ธ๋ ค์˜จ๋‹ค

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)}")

try_obd.py ์‹คํ–‰ โ€” OBD-II ID๋Š” ์žˆ์ง€๋งŒ ํŽ˜์ด๋กœ๋“œ๊ฐ€ ๊ทœ๊ฒฉ์— ์•ˆ ๋งž๊ณ , ์ฃผ๊ธฐ์„ฑ๋„ ์—†๊ณ , ๋ฐ”์ดํŠธ ๋ถ„ํฌ๋Š” ์™„์ „ ๊ท ๋“ฑ
try_obd.py ์‹คํ–‰ โ€” OBD-II ID๋Š” ์žˆ์ง€๋งŒ ํŽ˜์ด๋กœ๋“œ๊ฐ€ ๊ทœ๊ฒฉ์— ์•ˆ ๋งž๊ณ , ์ฃผ๊ธฐ์„ฑ๋„ ์—†๊ณ , ๋ฐ”์ดํŠธ ๋ถ„ํฌ๋Š” ์™„์ „ ๊ท ๋“ฑ

์„ธ ๊ฐ€์ง€๊ฐ€ ์ „๋ถ€ ์•„๋‹ˆ๋ผ๊ณ  ๋งํ•œ๋‹ค.

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}ํšŒ๋Š” ๊ท ๋“ฑ ๋žœ๋ค์œผ๋กœ๋Š” ์„ค๋ช…์ด ์•ˆ ๋œ๋‹ค. ๋ˆ„๊ฐ€ ์ผ๋ถ€๋Ÿฌ ๋„ฃ์€ ๊ฒƒ.")

stats_check.py ์‹คํ–‰ โ€” ๊ธฐ๋Œ€ ID ์ข…๋ฅ˜ 1963๊ฐœ vs ์‹ค์ œ 1953๊ฐœ, k=43 ๊ธฐ๋Œ€๊ฐ’ 2.3e-13๊ฐœ
stats_check.py ์‹คํ–‰ โ€” ๊ธฐ๋Œ€ ID ์ข…๋ฅ˜ 1963๊ฐœ vs ์‹ค์ œ 1953๊ฐœ, k=43 ๊ธฐ๋Œ€๊ฐ’ 2.3e-13๊ฐœ

๊ท ๋“ฑ ๋žœ๋ค ๊ฐ€์ •์ด ๋‚˜๋จธ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ์ •ํ™•ํžˆ ์„ค๋ช…ํ•œ๋‹ค. ๊ธฐ๋Œ€ 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

grep์œผ๋กœ ๋ฝ‘์€ 0x000 ํ”„๋ ˆ์ž„ ์›๋ณธ โ€” 4๊ฐœ ๋ฌถ์Œ์ด ์•ฝ 3์ดˆ ๊ฐ„๊ฒฉ์œผ๋กœ ๋ฐ˜๋ณต
grep์œผ๋กœ ๋ฝ‘์€ 0x000 ํ”„๋ ˆ์ž„ ์›๋ณธ โ€” 4๊ฐœ ๋ฌถ์Œ์ด ์•ฝ 3์ดˆ ๊ฐ„๊ฒฉ์œผ๋กœ ๋ฐ˜๋ณต

ํŒจํ„ด์ด ๋ฐ”๋กœ ๋ณด์ธ๋‹ค. 6D795F6361725F โ†’ 69735F โ†’ 6272306B656E โ†’ 21212121 ๋„ค ๊ฐœ๊ฐ€ 1ms ๊ฐ„๊ฒฉ์œผ๋กœ ๋ถ™์–ด ๋‚˜์˜ค๊ณ , ๊ทธ ๋ฌถ์Œ์ด ์•ฝ 3์ดˆ ๊ฐ„๊ฒฉ์œผ๋กœ ๋‹ค์‹œ ๋‚˜์˜จ๋‹ค. ์ค„ ๋ฒˆํ˜ธ๋„ 446ยท947ยท1449ยท1953์œผ๋กœ 500์ค„์ฏค์”ฉ ๋›ด๋‹ค.

hex๋ฅผ ASCII๋กœ ์˜ฎ๊ธฐ๋ฉด my_car_ / is_ / br0ken / !!!!. ์ˆœ์„œ๋Œ€๋กœ ์ด์œผ๋ฉด flag ๋ณธ๋ฌธ์ด๋‹ค.

๋…ธ์ด์ฆˆ ์† 0x000 ์‹ ํ˜ธ ์ถ”์ถœ ํ๋ฆ„ โ€” ID ํžˆ์Šคํ† ๊ทธ๋žจ์œผ๋กœ ๊ฑธ๋Ÿฌ 4์กฐ๊ฐ์„ ์ด์–ด ๋ถ™์ธ๋‹ค
๋…ธ์ด์ฆˆ ์† 0x000 ์‹ ํ˜ธ ์ถ”์ถœ ํ๋ฆ„ โ€” ID ํžˆ์Šคํ† ๊ทธ๋žจ์œผ๋กœ ๊ฑธ๋Ÿฌ 4์กฐ๊ฐ์„ ์ด์–ด ๋ถ™์ธ๋‹ค

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

ip link๋กœ ๋งŒ๋“  ๊ฐ€์ƒ CAN ์ธํ„ฐํŽ˜์ด์Šค vcan0 โ€” link/can, mtu 72
ip link๋กœ ๋งŒ๋“  ๊ฐ€์ƒ CAN ์ธํ„ฐํŽ˜์ด์Šค vcan0 โ€” link/can, mtu 72

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

can-utils candump -a ์‹คํ–‰ โ€” ํ•„ํ„ฐ ์—†์ด ๋ฐ›์œผ๋ฉด ๋žœ๋ค ID์™€ ๊นจ์ง„ ASCII๋งŒ ์Ÿ์•„์ง„๋‹ค
can-utils candump -a ์‹คํ–‰ โ€” ํ•„ํ„ฐ ์—†์ด ๋ฐ›์œผ๋ฉด ๋žœ๋ค ID์™€ ๊นจ์ง„ ASCII๋งŒ ์Ÿ์•„์ง„๋‹ค

ํ•„ํ„ฐ ์—†์ด ๋ฐ›์œผ๋ฉด ์ด ํ™”๋ฉด์ด๋‹ค. 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'

can-utils candump -a์— ID ํ•„ํ„ฐ ์ ์šฉ โ€” 0x000๋งŒ ๋‚จ๊ธฐ๋‹ˆ ASCII ์นธ์— flag ์กฐ๊ฐ์ด ๊ทธ๋Œ€๋กœ ๋ณด์ธ๋‹ค
can-utils candump -a์— ID ํ•„ํ„ฐ ์ ์šฉ โ€” 0x000๋งŒ ๋‚จ๊ธฐ๋‹ˆ ASCII ์นธ์— flag ์กฐ๊ฐ์ด ๊ทธ๋Œ€๋กœ ๋ณด์ธ๋‹ค

ํ•„ํ„ฐ ํ•œ ์ค„๋กœ ๋๋‚œ๋‹ค. 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)๋กœ ํ•œ ์ฃผ๊ธฐ๋ฅผ ๋ฝ‘๋Š”๋‹ค.

solve.py ์‹คํ–‰ โ€” ์ตœ๋นˆ ID 0x000 ์ž๋™ ๊ฒ€์ถœ, 4์กฐ๊ฐ ๋ณต์›, FLAG ์ถœ๋ ฅ
solve.py ์‹คํ–‰ โ€” ์ตœ๋นˆ ID 0x000 ์ž๋™ ๊ฒ€์ถœ, 4์กฐ๊ฐ ๋ณต์›, FLAG ์ถœ๋ ฅ

[*] ์ตœ๋‹ค ์ถœํ˜„ 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

๋Œ“๊ธ€

0๊ฐœ

๋Œ“๊ธ€์„ ๋‚จ๊ธฐ๋ ค๋ฉด ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ด์š”. (๋„ค์ด๋ฒ„ ยท ๊ตฌ๊ธ€ ๊ณ„์ •)

๋Œ“๊ธ€ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘โ€ฆ

Related

๊ด€๋ จ ๊ธ€

3๊ฐœ
[๐Ÿฅ‰ ๋ธŒ๋ก ์ฆˆ 1] CAN ๋ฒ„์Šค ๋กœ๊ทธ์—์„œ ํ›”์นœ ์ฐจ์˜ ์ •์ฒด โ€” DreamHack Grand Theft Auto ํ’€์ด
blog

[๐Ÿฅ‰ ๋ธŒ๋ก ์ฆˆ 1] CAN ๋ฒ„์Šค ๋กœ๊ทธ์—์„œ ํ›”์นœ ์ฐจ์˜ ์ •์ฒด โ€” DreamHack Grand Theft Auto ํ’€์ด

์ž๋™์ฐจ CAN ๋ฒ„์Šค ์บก์ณ candump.txt ํ•œ ๊ฐœ๊ฐ€ ์ฃผ์–ด์ง„๋‹ค. ๋กœ๊ทธ๋Š” UDS ์ง„๋‹จ ์„ธ์…˜์œผ๋กœ, ์ง„๋‹จ๊ธฐ๊ฐ€ ReadDataByIdentifier(0x22)๋กœ DID 0xF190(VIN)์„ ์š”์ฒญํ•˜๊ณ  ECU๊ฐ€ ISO-TP ๋ฉ€ํ‹ฐํ”„๋ ˆ์ž„์œผ๋กœ ์‘๋‹ตํ•œ๋‹ค. ํ”„๋ ˆ์ž„์„ ์žฌ์กฐ๋ฆฝํ•ด VIN์„ ์–ป๊ณ , ๊ทธ VIN์„ ์—ฐ๋„ยท์ œ์กฐ์‚ฌยท๋ชจ๋ธ๋กœ ๋””์ฝ”๋“œํ•ด ํ”Œ๋ž˜๊ทธ๋ฅผ ์™„์„ฑํ–ˆ๋‹ค.
#dreamhack#ctf#forensics+4
2026-07-13#dreamhack +5
[๐Ÿฅ‰ Bronze 4] ๋ฐ˜ํˆฌ๋ช… ๋ง์น ์€ ์ง€์šฐ๊ฐœ๊ฐ€ ์•„๋‹ˆ๋‹ค โ€” DreamHack QR Code ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 4] ๋ฐ˜ํˆฌ๋ช… ๋ง์น ์€ ์ง€์šฐ๊ฐœ๊ฐ€ ์•„๋‹ˆ๋‹ค โ€” DreamHack QR Code ํ’€์ด

QR ์ฝ”๋“œ ์œ„์— ๊ฒ€์€ ๋‚™์„œ๊ฐ€ ๋ฎ์—ฌ ์žˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ํ”ฝ์…€๊ฐ’์ด ์—ด ์ข…๋ฅ˜๋ฐ–์— ์—†๊ณ  255, 63, 16, 4, 1 ์ด๋ผ๋Š” ๋“ฑ๋น„ ์‚ฌ์Šฌ์„ ์ด๋ฃฌ๋‹ค. ์•ŒํŒŒ 75% ๊ฒ€์ •์„ ๊ฒน์น  ๋•Œ๋งˆ๋‹ค ๋ฐ‘์˜ ๋ฐ๊ธฐ๊ฐ€ 1/4 ์”ฉ๋งŒ ๋‚จ์€ ํ”์ ์ด๋‹ค. "ํ”ฝ์…€๊ฐ’์ด 0๋ณด๋‹ค ํฌ๋ฉด ํฐ ๋ชจ๋“ˆ" ํ•œ ์ค„๋กœ 29x29 ๊ฒฉ์ž๋ฅผ ๋˜์‚ด๋ฆฌ๊ณ , ์žฌ์ธ์ฝ”๋”ฉ๋ณธ๊ณผ 841์นธ ์ „์ˆ˜ ๋Œ€์กฐ๊นŒ์ง€ ํ–ˆ๋‹ค.
#dreamhack#ctf#misc+5
2026-08-22#dreamhack +4
[๐Ÿฅˆ Silver 3] ํ”„๋ฆฌ์  ํ„ฐ๋ฅผ 70๋ฒˆ ๋ˆ„๋ฅด๋ฉด ๋ชจ์Šค๋ถ€ํ˜ธ๊ฐ€ ๋œ๋‹ค โ€” DreamHack My Nervous PPT ํ’€์ด
blog

[๐Ÿฅˆ Silver 3] ํ”„๋ฆฌ์  ํ„ฐ๋ฅผ 70๋ฒˆ ๋ˆ„๋ฅด๋ฉด ๋ชจ์Šค๋ถ€ํ˜ธ๊ฐ€ ๋œ๋‹ค โ€” DreamHack My Nervous PPT ํ’€์ด

๋ฐœํ‘œ ์ „ ๊ธด์žฅํ•ด์„œ ํ”„๋ฆฌ์  ํ„ฐ๋ฅผ ๋ˆŒ๋Ÿฌ๋Œ”๋‹ค๋Š” ์ด์•ผ๊ธฐ์™€ ํ•จ๊ป˜ USBPcap ์บก์ณ ํ•˜๋‚˜๋งŒ ์ฃผ์–ด์ง„๋‹ค. 310๊ฐœ ํŒจํ‚ท ์ค‘ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋Š” ๋ฌด์„  ํ”„๋ฆฌ์  ํ„ฐ๊ฐ€ ์˜ฌ๋ฆฐ 8๋ฐ”์ดํŠธ HID ํ‚ค๋ณด๋“œ ๋ฆฌํฌํŠธ 140๊ฐœ๋ฟ์ด๊ณ , ๊ฑฐ๊ธฐ ๋“ฑ์žฅํ•˜๋Š” ํ‚ค๋Š” UpArrow์™€ DownArrow ๋‘˜๋ฟ์ด๋‹ค. ๋‘ ์ข…๋ฅ˜ ์‹ ํ˜ธ์— ๋ˆŒ๋ฆผ ๊ฐ„๊ฒฉ์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ๊ธ€์ž ๊ฒฝ๊ณ„๊นŒ์ง€ ์žˆ์œผ๋‹ˆ ๋ชจ์Šค๋ถ€ํ˜ธ๋‹ค. ๊ฐ„๊ฒฉ ํžˆ์Šคํ† ๊ทธ๋žจ์œผ๋กœ 19๋ฉ์–ด๋ฆฌ๋ฅผ ์ž๋ฅด๊ณ  ๋ณตํ˜ธํ•˜๋ฉด ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋‚˜์˜จ๋‹ค.
#dreamhack#ctf#misc+6
2026-08-17#dreamhack +4