[๐Ÿฅ‰ Bronze 4] ๋ณต์‚ฌ ๊ธˆ์ง€๋Š” ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ๋งŒ ํ•˜๋Š” ๋ถ€ํƒ์ด๋‹ค โ€” DreamHack Ctrl-C ํ’€์ด

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

[๐Ÿฅ‰ Bronze 4] ๋ณต์‚ฌ ๊ธˆ์ง€๋Š” ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ๋งŒ ํ•˜๋Š” ๋ถ€ํƒ์ด๋‹ค โ€” DreamHack Ctrl-C ํ’€์ด

์šฐํด๋ฆญยท๋“œ๋ž˜๊ทธยทF12๋ฅผ ์ „๋ถ€ ๋ง‰์•„ ๋‘” ํŽ˜์ด์ง€๊ฐ€ 2000์ž์งœ๋ฆฌ ๋ฌธ์ž์—ด์„ ๋ณด์—ฌ์ฃผ๊ณ  "๋ณต์‚ฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉด ํ•ด๋ด๋ผ"๋ผ๊ณ  ํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ๋ฐฉ์–ด๋Š” ์ „๋ถ€ ๋ธŒ๋ผ์šฐ์ € ์•ˆ์—์„œ ๋„๋Š” JS๋ผ, HTTP ์‘๋‹ต ์ž์ฒด์—๋Š” ์•„๋ฌด ํž˜๋„ ์—†๋‹ค. curl ํ•œ ๋ฒˆ์ด๋ฉด ๋ณธ๋ฌธ์ด ๊ทธ๋Œ€๋กœ ๋‚˜์˜จ๋‹ค. ๋ฝ‘์€ ๋ฌธ์ž์—ด์„ ๋ฐฐํฌ๋œ ์Šคํฌ๋ฆฝํŠธ์— ๋„ฃ์œผ๋ฉด sha256์˜ base64 ์กฐ๊ฐ๊ณผ 25๋ฐ”์ดํŠธ ์ƒ์ˆ˜๋ฅผ XORํ•ด ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋–จ์–ด์ง„๋‹ค. ์ƒ์ˆ˜๊ฐ€ 25๋ฐ”์ดํŠธ, XOR ๋Œ€์ƒ์ด 23๋ฐ”์ดํŠธ๋ผ ์ถœ๋ ฅ์€ ์ž…๋ ฅ๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ๋Š˜ ๋‘ ๊ธ€์ž๊ฐ€ ๊ณ ์ •๋œ๋‹ค.

๋ฌธ์ œ: DreamHack โ€” Ctrl-C ๋ถ„๋ฅ˜: web ๋‚œ์ด๋„: ๐Ÿฅ‰ Bronze 4 FLAG: WaRP{1_w4n7_5h0r7cu7_k3y}

๋ฌธ์ œ ์„ค๋ช…์€ ๋”ฑ ํ•œ ์ค„์ด๋‹ค. "Copy it if you can!"

๋“ค์–ด๊ฐ€ ๋ณด๋ฉด ์ •๋ง๋กœ ๊ทธ ๋ง๋Œ€๋กœ๋‹ค. ํ™”๋ฉด ๊ฐ€๋“ ๋žœ๋คํ•ด ๋ณด์ด๋Š” ๋ฌธ์ž์—ด์ด ๊น”๋ ค ์žˆ๊ณ , ๋“œ๋ž˜๊ทธ๋„ ์•ˆ ๋˜๊ณ  ์šฐํด๋ฆญ๋„ ์•ˆ ๋จน๋Š”๋‹ค.

DreamHack Ctrl-C ๋ฉ”์ธ ํŽ˜์ด์ง€. ์•ˆ๋‚ด ๋ฌธ๊ตฌ ์•„๋ž˜๋กœ 2000์ž์งœ๋ฆฌ ๋ฌธ์ž์—ด์ด ๊น”๋ ค ์žˆ๊ณ  ์ฃผ์†Œ์ฐฝ์— ๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค ์ฃผ์†Œ๊ฐ€ ๋ณด์ธ๋‹ค.
DreamHack Ctrl-C ๋ฉ”์ธ ํŽ˜์ด์ง€. ์•ˆ๋‚ด ๋ฌธ๊ตฌ ์•„๋ž˜๋กœ 2000์ž์งœ๋ฆฌ ๋ฌธ์ž์—ด์ด ๊น”๋ ค ์žˆ๊ณ  ์ฃผ์†Œ์ฐฝ์— ๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค ์ฃผ์†Œ๊ฐ€ ๋ณด์ธ๋‹ค.


๋ฌธ์ œ ๊ฐœ์š”

ํ•ญ๋ชฉ๋‚ด์šฉ
๋ฌธ์ œ๋ช…Ctrl-C
๋‚œ์ด๋„๐Ÿฅ‰ Bronze 4
๋ถ„๋ฅ˜web
์ŠคํƒPython 3.13 ยท Flask ยท Werkzeug 3.1.3
์ œ๊ณต ํŒŒ์ผCtrl_C.py, Dockerfile
์„œ๋ฒ„์—๋งŒ ์žˆ๋Š” ๊ฒƒapp.py, text.txt, templates/index.html
ํ•ต์‹ฌ ์ทจ์•ฝ์ ํด๋ผ์ด์–ธํŠธ ์ธก JS๋กœ๋งŒ ๊ตฌํ˜„๋œ ๋ณต์‚ฌ ๋ฐฉ์ง€ โ€” HTTP ์‘๋‹ต์—๋Š” ์•„๋ฌด ํšจ๋ ฅ์ด ์—†๋‹ค

ํ’€์ด ํ๋ฆ„์€ ์„ธ ์ค„๋กœ ๋๋‚œ๋‹ค.

curl ๋กœ ํŽ˜์ด์ง€๋ฅผ ๋ฐ›์•„ <p> ์•ˆ์˜ 2000์ž๋ฅผ ๊บผ๋‚ธ๋‹ค. ๊ทธ ๋ฌธ์ž์—ด์„ ๋ฐฐํฌ๋œ Ctrl_C.py ์˜ ํ‘œ์ค€์ž…๋ ฅ์— ๋„ฃ๋Š”๋‹ค. sha256 โ†’ base64 โ†’ ์Šฌ๋ผ์ด์Šค โ†’ ์ƒ์ˆ˜์™€ XOR ์„ ๊ฑฐ์ณ ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋‚˜์˜จ๋‹ค.

๋ฌธ์ œ ์ž์ฒด๋Š” ๋ธŒ๋ก ์ฆˆ๋‹ต๊ฒŒ ์งง๋‹ค. ๋Œ€์‹  "์™œ ์ด ๋ฐฉ์–ด๊ฐ€ ์•„๋ฌด๊ฒƒ๋„ ๋ชป ๋ง‰๋Š”๊ฐ€"๋ฅผ ๋ˆˆ์— ๋ณด์ด๊ฒŒ ์‹ค์ฆํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์„ ์ผ๋‹ค.



๐Ÿงฉ ๋ฐฐ๊ฒฝ โ€” ๋ณต์‚ฌ ๋ฐฉ์ง€๊ฐ€ ์‹ค์ œ๋กœ ๋ง‰๋Š” ๊ฒƒ

์›น์—์„œ ํ”ํžˆ ๋ณด๋Š” "์šฐํด๋ฆญ ๊ธˆ์ง€" ์Šคํฌ๋ฆฝํŠธ๋Š” ์„ธ ๊ฐ€์ง€ ์ด๋ฒคํŠธ๋ฅผ ์žก๋Š”๋‹ค.

contextmenu ๋Š” ์šฐํด๋ฆญํ–ˆ์„ ๋•Œ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ฉ”๋‰ด๋ฅผ ๋„์šฐ๊ธฐ ์ง์ „์— ๋ฐœ์ƒํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ false ๋ฅผ ๋Œ๋ ค์ฃผ๋ฉด ๋ฉ”๋‰ด๊ฐ€ ์•ˆ ๋œฌ๋‹ค.

selectstart ๋Š” ๋“œ๋ž˜๊ทธ๋กœ ํ…์ŠคํŠธ ์„ ํƒ์ด ์‹œ์ž‘๋  ๋•Œ ๋ฐœ์ƒํ•œ๋‹ค. ๋ง‰์œผ๋ฉด ์„ ํƒ ์ž์ฒด๊ฐ€ ์‹œ์ž‘๋˜์ง€ ์•Š๋Š”๋‹ค.

keydown ์€ F12 ๋‚˜ Ctrl+Shift+I ๊ฐ™์€ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ ๋‹จ์ถ•ํ‚ค๋ฅผ ๊ฐ€๋กœ์ฑŒ ๋•Œ ์“ด๋‹ค.

์„ธ ๊ฐœ ๋‹ค ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํŽ˜์ด์ง€์—๊ฒŒ ๋ฌผ์–ด๋ด ์ฃผ๋Š” ๊ฒƒ์ด๋‹ค. ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ Œ๋”๋ง ๊ณผ์ •์—์„œ "์ด ๋™์ž‘ ํ•ด๋„ ๋˜๋‚˜์š”?" ํ•˜๊ณ  ํŽ˜์ด์ง€ ์Šคํฌ๋ฆฝํŠธ์— ํ™•์ธํ•˜๊ณ , ํŽ˜์ด์ง€๊ฐ€ ์•ˆ ๋œ๋‹ค๊ณ  ํ•˜๋ฉด ๊ทธ ๋™์ž‘์„ ์ ‘๋Š”๋‹ค.

๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ์ด๊ฑด ๋ณดํ˜ธ๊ฐ€ ์•„๋‹ˆ๋ผ ๋ถ€ํƒ์ด๋‹ค. ๋ฌผ์–ด๋ด ์ฃผ๋Š” ์ฃผ์ฒด๊ฐ€ ์žˆ์–ด์•ผ ์„ฑ๋ฆฝํ•œ๋‹ค. ์„œ๋ฒ„๋Š” ๊ทธ๋ƒฅ HTML ์„ ๋ฐ”์ดํŠธ๋กœ ๋ฑ‰์„ ๋ฟ์ด๊ณ , ๊ทธ ๋ฐ”์ดํŠธ๋ฅผ ๋ˆ„๊ฐ€ ์–ด๋–ป๊ฒŒ ์ฝ๋Š”์ง€์—๋Š” ๊ด€์—ฌํ•˜์ง€ ์•Š๋Š”๋‹ค. curl ์€ ์• ์ดˆ์— ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š์œผ๋‹ˆ ๋ฌผ์–ด๋ณผ ์ผ๋„ ์—†๋‹ค.

์ด ๋ฌธ์ œ์˜ ์ „๋ถ€๊ฐ€ ์—ฌ๊ธฐ ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋จผ์ € ์„œ๋ฒ„๊ฐ€ ์‹ค์ œ๋กœ ๋ญ˜ ์ฃผ๋Š”์ง€๋ถ€ํ„ฐ ๋ดค๋‹ค.


๐Ÿ”ฌ ์ •์ฐฐ โ€” ์„œ๋ฒ„๊ฐ€ ์ฃผ๋Š” ๊ฒƒ๊ณผ ์•ˆ ์ฃผ๋Š” ๊ฒƒ

๋ฐฐํฌ ํŒŒ์ผ์€ ๋‘˜๋ฟ์ด๋‹ค. Ctrl_C.py ์™€ Dockerfile.

FROM python:3.13@sha256:385ccb8304f6330738a6d9e6fa0bd7608e006da7e15bc52b33b0398e1ba4a15b
 
ENV user ctrlc
 
RUN apt update
RUN pip install flask
 
RUN useradd -d /home/$user $user
 
ADD app.py /home/$user/app.py
ADD text.txt /home/$user/text.txt
ADD templates/index.html /home/$user/templates/index.html

Dockerfile ์ด ์„ธ ํŒŒ์ผ์„ ์ด๋ฏธ์ง€์— ๋„ฃ๋Š”๋ฐ, ๊ทธ ์…‹ ์ค‘ ์–ด๋А ๊ฒƒ๋„ ๋ฐฐํฌ๋ณธ์— ์—†๋‹ค. app.py ๋„ text.txt ๋„ index.html ๋„ ์„œ๋ฒ„์—๋งŒ ์žˆ๋‹ค.

์ด๊ฒŒ ์ค‘์š”ํ•˜๋‹ค. text.txt ๋Š” ์„œ๋ฒ„์—๋งŒ ์กด์žฌํ•˜๊ณ , ๊ทธ๊ฒŒ ๊ณง ํ•ด์‹œ ์ž…๋ ฅ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ํŒŒ์ผ๋งŒ ๋“ค๊ณ ๋Š” ์˜คํ”„๋ผ์ธ์œผ๋กœ ๋‹ต์„ ๋งŒ๋“ค ์ˆ˜ ์—†๋‹ค. ์„œ๋ฒ„์— ๋ถ™์–ด์•ผ ํ•œ๋‹ค.

๊ทธ๋Ÿผ ๋‚˜๋จธ์ง€ ํ•˜๋‚˜, Ctrl_C.py ๋Š” ์ด๋ ‡๊ฒŒ ์ƒ๊ฒผ๋‹ค.

import hashlib
import base64
 
def bytes_to_long(a):
    return int.from_bytes(a, byteorder='big')
def long_to_bytes(a):
    return a.to_bytes((a.bit_length()+7)//8, byteorder='big')
 
print(long_to_bytes(548488142063681088110499188198346596132432266189304030893626^bytes_to_long(base64.b64encode(hashlib.sha256(input().rstrip().encode('utf-8')).digest())[13:36])))

ํ•œ ์ค„์งœ๋ฆฌ๋‹ค. ์•ˆ์ชฝ๋ถ€ํ„ฐ ํ’€๋ฉด ์ด๋ ‡๊ฒŒ ๋œ๋‹ค.

  1. ํ‘œ์ค€์ž…๋ ฅ์„ ๋ฐ›์•„ rstrip() โ€” ๋’ค์ชฝ ๊ณต๋ฐฑ๊ณผ ๊ฐœํ–‰๋งŒ ์ž˜๋ผ๋‚ธ๋‹ค.
  2. UTF-8 ๋กœ ์ธ์ฝ”๋”ฉํ•ด sha256 โ†’ 32๋ฐ”์ดํŠธ ๋‹ค์ด์ œ์ŠคํŠธ.
  3. base64 ์ธ์ฝ”๋”ฉ โ†’ 44๊ธ€์ž(ํŒจ๋”ฉ = ํฌํ•จ).
  4. [13:36] ์œผ๋กœ ์ž˜๋ผ 23๋ฐ”์ดํŠธ.
  5. ๊ทธ๊ฑธ ํฐ ์ •์ˆ˜๋กœ ๋ฐ”๊ฟ” ์ƒ์ˆ˜ ํ•˜๋‚˜์™€ XOR.
  6. ๋‹ค์‹œ ๋ฐ”์ดํŠธ๋กœ ๋Œ๋ ค ์ถœ๋ ฅ.

์„œ๋ฒ„ ์‘๋‹ต์„ ๋จผ์ € ๋ดค๋‹ค.

curl -s -D - -o /dev/null http://host3.dreamhack.games:21647/

curl๋กœ ๋ฐ›์€ ์‘๋‹ต ํ—ค๋”. Werkzeug 3.1.3๊ณผ Python 3.13์ด ์ฐํ˜€ ์žˆ๊ณ  ๋ณธ๋ฌธ ๊ธธ์ด๋Š” 4164๋ฐ”์ดํŠธ๋‹ค.
curl๋กœ ๋ฐ›์€ ์‘๋‹ต ํ—ค๋”. Werkzeug 3.1.3๊ณผ Python 3.13์ด ์ฐํ˜€ ์žˆ๊ณ  ๋ณธ๋ฌธ ๊ธธ์ด๋Š” 4164๋ฐ”์ดํŠธ๋‹ค.

Server: Werkzeug/3.1.3 Python/3.13.2 โ€” Dockerfile ๊ทธ๋Œ€๋กœ Flask ๊ฐœ๋ฐœ ์„œ๋ฒ„๋‹ค. ๋ณธ๋ฌธ์ด 4164๋ฐ”์ดํŠธ๋ฐ–์— ์•ˆ ๋œ๋‹ค. 2000์ž์งœ๋ฆฌ ๋ฌธ์ž์—ด์ด ๋“ค์–ด ์žˆ๋Š” ํŽ˜์ด์ง€์น˜๊ณ ๋Š” ์ž‘๋‹ค. ์ฟ ํ‚ค๋„ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋„ ์—†๋‹ค. ๊ทธ๋ƒฅ ์ •์ ์ธ HTML ํ•œ ์žฅ์ด๋‹ค.

๊ทธ๋Ÿฐ๋ฐ Dockerfile ์ด ์ด๋ฏธ์ง€์— ๋„ฃ๋Š” ์„ธ ํŒŒ์ผ ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์ •์ ์œผ๋กœ ์„œ๋น™๋˜๊ณ  ์žˆ๋‹ค๋ฉด, HTML ์„ ํŒŒ์‹ฑํ•  ๊ฒƒ๋„ ์—†์ด text.txt ๋ฅผ ๊ทธ๋ƒฅ ๋ฐ›์œผ๋ฉด ๋œ๋‹ค. Flask ์—์„œ static ํด๋” ์„ค์ •์„ ์ž˜๋ชป ์žก๊ฑฐ๋‚˜ ํŒŒ์ผ์„ ํ†ต์งธ๋กœ ์˜ฌ๋ ค ๋‘๋ฉด ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ๋œ๋‹ค. ํ™•์ธ๋ถ€ํ„ฐ ํ–ˆ๋‹ค.

#!/usr/bin/env bash
# Ctrl-C โ€” ์„œ๋ฒ„๊ฐ€ ๋…ธ์ถœํ•˜๋Š” ๊ฒฝ๋กœ๊ฐ€ ์ •๋ง '/' ํ•˜๋‚˜๋ฟ์ธ์ง€ ํ™•์ธํ•œ๋‹ค.
# Dockerfile ์ด ๋„ฃ๋Š” ์„ธ ํŒŒ์ผ(app.py / text.txt / templates/index.html)์ด
# ํ˜น์‹œ ์ •์ ์œผ๋กœ ์„œ๋น™๋˜์ง€ ์•Š๋Š”์ง€๋ถ€ํ„ฐ ๋ณธ๋‹ค. ๋˜๋ฉด ๊ตณ์ด ํŒŒ์‹ฑํ•  ๊ฒƒ๋„ ์—†๋‹ค.
U=${1:-http://host3.dreamhack.games:21647}
for p in /text.txt /app.py /static/text.txt /templates/index.html /flag /Ctrl_C.py /robots.txt; do
  printf "%-24s " "$p"
  curl -s -o /dev/null -w "%{http_code}  %{size_download}B\n" --max-time 12 "$U$p"
done
printf "%-24s " "/ (OPTIONS)"; curl -s -o /dev/null -w "%{http_code}\n" -X OPTIONS --max-time 12 "$U/"
printf "%-24s " "/ (POST)";    curl -s -o /dev/null -w "%{http_code}\n" -X POST    --max-time 12 "$U/"
printf "%-24s " "/ (GET)";     curl -s -o /dev/null -w "%{http_code}  %{size_download}B\n" --max-time 12 "$U/"
./probe_endpoints.sh

probe_endpoints.sh ๋กœ ๊ฒฝ๋กœ๋ฅผ ํ›‘์€ ๊ฒฐ๊ณผ. text.txt ์™€ app.py ๋ฅผ ๋น„๋กฏํ•œ ๋ถ€๊ฐ€ ๊ฒฝ๋กœ๋Š” ์ „๋ถ€ 404 ์ด๊ณ  ์‘๋‹ต ํฌ๊ธฐ๋„ 207๋ฐ”์ดํŠธ๋กœ ๊ฐ™์œผ๋ฉฐ, 200 ์ด ๋‚˜์˜ค๋Š” ๊ฑด ๋ฃจํŠธ ํ•˜๋‚˜๋ฟ์ด๋‹ค.
probe_endpoints.sh ๋กœ ๊ฒฝ๋กœ๋ฅผ ํ›‘์€ ๊ฒฐ๊ณผ. text.txt ์™€ app.py ๋ฅผ ๋น„๋กฏํ•œ ๋ถ€๊ฐ€ ๊ฒฝ๋กœ๋Š” ์ „๋ถ€ 404 ์ด๊ณ  ์‘๋‹ต ํฌ๊ธฐ๋„ 207๋ฐ”์ดํŠธ๋กœ ๊ฐ™์œผ๋ฉฐ, 200 ์ด ๋‚˜์˜ค๋Š” ๊ฑด ๋ฃจํŠธ ํ•˜๋‚˜๋ฟ์ด๋‹ค.

์ „๋ถ€ 404 ๋‹ค. ์‘๋‹ต ํฌ๊ธฐ๋„ 207๋ฐ”์ดํŠธ๋กœ ๋˜‘๊ฐ™์•„์„œ Flask ๊ธฐ๋ณธ 404 ํŽ˜์ด์ง€ ํ•˜๋‚˜๋ฅผ ๋Œ๋ ค์ฃผ๊ณ  ์žˆ๋‹ค. POST ๋Š” 405 ๋ผ ๋ผ์šฐํŠธ๊ฐ€ GET ์ „์šฉ์ด๊ณ , 200 ์ด ๋‚˜์˜ค๋Š” ๊ฑด / ํ•˜๋‚˜๋ฟ์ด๋‹ค.

์ฆ‰ ์„œ๋ฒ„๋Š” ๋”ฑ ํ•œ ์žฅ์˜ HTML ๋งŒ ์ค€๋‹ค. text.txt ๋Š” ๊ทธ HTML ์•ˆ์— ๋ Œ๋”๋œ ํ˜•ํƒœ๋กœ๋งŒ ๋‚˜์˜จ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๊ทธ HTML ์„ ๋ด์•ผ ํ•œ๋‹ค.

๊ทธ HTML ์•ˆ์—์„œ ๋ฐฉ์–ด๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ๋ถ€๋ถ„๋งŒ ์ž˜๋ผ ๋ดค๋‹ค.

curl -s http://host3.dreamhack.games:21647/ | sed -n "20,58p"

curl ์‘๋‹ต์—์„œ ์ž˜๋ผ๋‚ธ ๋ณต์‚ฌ ๋ฐฉ์ง€ ์Šคํฌ๋ฆฝํŠธ ์ „๋ฌธ. ์šฐํด๋ฆญ ๋ฐฉ์ง€, ๋“œ๋ž˜๊ทธ ๋ฐฉ์ง€, F12 ๋น„ํ™œ์„ฑํ™”๊ฐ€ ํ•œ๊ตญ์–ด ์ฃผ์„๊ณผ ํ•จ๊ป˜ ๊ทธ๋Œ€๋กœ ๋“ค์–ด ์žˆ๋‹ค.
curl ์‘๋‹ต์—์„œ ์ž˜๋ผ๋‚ธ ๋ณต์‚ฌ ๋ฐฉ์ง€ ์Šคํฌ๋ฆฝํŠธ ์ „๋ฌธ. ์šฐํด๋ฆญ ๋ฐฉ์ง€, ๋“œ๋ž˜๊ทธ ๋ฐฉ์ง€, F12 ๋น„ํ™œ์„ฑํ™”๊ฐ€ ํ•œ๊ตญ์–ด ์ฃผ์„๊ณผ ํ•จ๊ป˜ ๊ทธ๋Œ€๋กœ ๋“ค์–ด ์žˆ๋‹ค.

์„ธ ๊ฐ€์ง€ ๋ฐฉ์–ด๊ฐ€ ์ฃผ์„๊นŒ์ง€ ๋ถ™์–ด์„œ ๊ทธ๋Œ€๋กœ ์žˆ๋‹ค.

// ์˜ค๋ฅธ์ชฝ ํด๋ฆญ ๋ฐฉ์ง€
document.oncontextmenu = function() {
    return false;
}
 
// ๋“œ๋ž˜๊ทธ ๋ฐฉ์ง€
var omitformtags = ["input", "textarea", "select"];
omitformtags = omitformtags.join("|");
 
function disableselect(e) {
    if (omitformtags.indexOf(e.target.tagName.toLowerCase()) == -1)
        return false;
}
 
if (typeof document.onselectstart != "undefined")
    document.onselectstart = new Function("return false");
else {
    document.onmousedown = disableselect;
    document.onmouseup = reEnable;
}
 
// F12 ํ‚ค ๋น„ํ™œ์„ฑํ™”
document.addEventListener("keydown", function(e) {
    if (e.keyCode == 123) { // F12 ํ‚ค์˜ keyCode๋Š” 123
        e.preventDefault();
    }
});

์—ฌ๊ธฐ์„œ ์ด๋ฏธ ๋‹ต์ด ๋‚˜์™”๋‹ค. ์ด ์Šคํฌ๋ฆฝํŠธ๋ฅผ curl ๋กœ ์ฝ๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ ์ž์ฒด๊ฐ€, ์ด ์Šคํฌ๋ฆฝํŠธ๊ฐ€ curl ์—๊ฒŒ ์•„๋ฌด ์˜ํ–ฅ๋„ ๋ชป ์ค€๋‹ค๋Š” ์ฆ๊ฑฐ๋‹ค. ๊ฐ™์€ ์‘๋‹ต ์•ˆ์— ๋ณธ๋ฌธ 2000์ž๋„ ๊ฐ™์ด ๋“ค์–ด ์žˆ๋‹ค.

๊ทธ๋ž˜๋„ ๋ฐฉ์–ด๊ฐ€ ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” ์‹ค์ œ๋กœ ๋„๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์ •ํ™•ํžˆ ๋ฌด์—‡์„ ๋ง‰๋Š”์ง€๋Š” ์ง์ ‘ ๋ˆŒ๋Ÿฌ ๋ณด๊ณ  ์‹ถ์—ˆ๋‹ค.



๐Ÿ–ฑ๏ธ ๋ฐฉ์–ด๋ฅผ ํ•˜๋‚˜์”ฉ ๋ˆŒ๋Ÿฌ ๋ณด๊ธฐ

์—ฌ๊ธฐ์„œ ํ•œ ๋ฒˆ ๋ง‰ํ˜”๋‹ค. Playwright ์˜ page.click() ๊ฐ™์€ ํ•ฉ์„ฑ ์ด๋ฒคํŠธ๋กœ๋Š” ์ด ๋ฐฉ์–ด๊ฐ€ ์ œ๋Œ€๋กœ ๋ฐœํ™”ํ•˜๋Š”์ง€ ํ™•์ธ์ด ์•ˆ ๋œ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์‹ค์ œ ์ž…๋ ฅ ์žฅ์น˜์—์„œ ์˜ฌ๋ผ์˜จ ์ด๋ฒคํŠธ์™€ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋งŒ๋“  ์ด๋ฒคํŠธ๋ฅผ ๋‹ค๋ฅด๊ฒŒ ์ทจ๊ธ‰ํ•˜๋Š” ๊ตฌ๊ฐ„์ด ์žˆ์–ด์„œ, "๋ง‰ํ˜”๋‹ค"๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋ฐฉ์–ด ๋•Œ๋ฌธ์ธ์ง€ ์ž๋™ํ™” ๋•Œ๋ฌธ์ธ์ง€ ๊ตฌ๋ถ„์ด ์•ˆ ๋œ๋‹ค.

๊ทธ๋ž˜์„œ Xvfb ์œ„์— Chromium ์„ ๋„์šฐ๊ณ  xdotool ๋กœ ์ง„์งœ X11 ๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ๋ฅผ ๊ฝ‚์•˜๋‹ค. ์‚ฌ๋žŒ์ด ๋งˆ์šฐ์Šค๋ฅผ ์›€์ง์—ฌ ํด๋ฆญยท๋“œ๋ž˜๊ทธํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๊ฒฝ๋กœ๋‹ค.

# cap_browser.py โ€” ์‹ค์ œ ๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ๋กœ ๋ฐฉ์–ด๋ฅผ ๋ˆŒ๋Ÿฌ ๋ณธ๋‹ค (๋ฐœ์ทŒ)
def xdo(env, *args):
    subprocess.run(["xdotool", *args], env=env, check=False,
                   stderr=subprocess.DEVNULL, timeout=10)
 
# ๋ทฐํฌํŠธ ์ขŒ์ƒ๋‹จ์˜ ํ™”๋ฉด(์Šคํฌ๋ฆฐ) ์ขŒํ‘œ. ์ฐฝ ํ…Œ๋‘๋ฆฌยทํƒญ๋ฐ”ยท์ฃผ์†Œ์ฐฝ ๋‘๊ป˜๋ฅผ ์ง์ ‘
# ์žฌ์ง€ ์•Š๊ณ  ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ๋ฌผ์–ด๋ณธ๋‹ค -> ์ขŒํ‘œ๊ฐ€ ์ฐฝ ํฌ๊ธฐ์— ์•ˆ ํ”๋“ค๋ฆฐ๋‹ค.
ox = page.evaluate("window.screenX + (window.outerWidth - window.innerWidth) / 2")
oy = page.evaluate("window.screenY + (window.outerHeight - window.innerHeight)")
box = page.evaluate(
    "(() => { const r = document.querySelector('.content p')"
    ".getBoundingClientRect();"
    " return {x: r.x, y: r.y, w: r.width, h: r.height}; })()")
 
x1 = int(ox + box["x"] + 8)
y1 = int(oy + box["y"] + 10)
x2 = int(ox + box["x"] + box["w"] - 8)
y2 = int(oy + box["y"] + 58)
 
# ์‹ค์ œ ์šฐํด๋ฆญ
xdo(env, "mousemove", "--sync", str(x1 + 120), str(y1 + 20))
xdo(env, "click", "3")

๋จผ์ € ๋ณธ๋ฌธ ์œ„์—์„œ ์šฐํด๋ฆญ.

๋ณธ๋ฌธ ์œ„์—์„œ ์‹ค์ œ ์šฐํด๋ฆญ์„ ํ–ˆ์ง€๋งŒ ์ปจํ…์ŠคํŠธ ๋ฉ”๋‰ด๊ฐ€ ๋œจ์ง€ ์•Š๋Š”๋‹ค. oncontextmenu ํ•ธ๋“ค๋Ÿฌ๊ฐ€ false๋ฅผ ๋Œ๋ ค์ค€ ๊ฒฐ๊ณผ๋‹ค.
๋ณธ๋ฌธ ์œ„์—์„œ ์‹ค์ œ ์šฐํด๋ฆญ์„ ํ–ˆ์ง€๋งŒ ์ปจํ…์ŠคํŠธ ๋ฉ”๋‰ด๊ฐ€ ๋œจ์ง€ ์•Š๋Š”๋‹ค. oncontextmenu ํ•ธ๋“ค๋Ÿฌ๊ฐ€ false๋ฅผ ๋Œ๋ ค์ค€ ๊ฒฐ๊ณผ๋‹ค.

๋ฉ”๋‰ด๊ฐ€ ์•ˆ ๋œฌ๋‹ค. oncontextmenu ๊ฐ€ ์ผํ•˜๊ณ  ์žˆ๋‹ค.

๋‹ค์Œ์€ ๋“œ๋ž˜๊ทธ. ๋ฌธ๋‹จ ์ฒซ ์ค„ ์™ผ์ชฝ์—์„œ ๋ˆŒ๋Ÿฌ ์…‹์งธ ์ค„ ์˜ค๋ฅธ์ชฝ๊นŒ์ง€ ๋Œ์—ˆ๋‹ค.

# ๋งˆ์šฐ์Šค๋ฅผ ๋ˆ„๋ฅธ ์ฑ„๋กœ ๋„ค ๋ฒˆ์— ๊ฑธ์ณ ์ด๋™์‹œํ‚จ ๋’ค ๋—€๋‹ค โ€” ์‚ฌ๋žŒ ๋“œ๋ž˜๊ทธ์™€ ๊ฐ™์€ ๊ฒฝ๋กœ
xdo(env, "mousemove", "--sync", str(x1), str(y1))
xdo(env, "mousedown", "1")
for f in (0.25, 0.5, 0.75, 1.0):
    xdo(env, "mousemove", "--sync",
        str(int(x1 + (x2 - x1) * f)), str(int(y1 + (y2 - y1) * f)))
    time.sleep(0.12)
xdo(env, "mouseup", "1")
sel = page.evaluate("window.getSelection().toString().length")
print(f"[*] ๋ฐฉ์–ด ์ผœ์ง„ ์ƒํƒœ ์„ ํƒ ๊ธธ์ด = {sel}")

๋ธŒ๋ผ์šฐ์ €์—์„œ ๋ณธ๋ฌธ ์„ธ ์ค„์— ๊ฑธ์ณ ์‹ค์ œ๋กœ ๋“œ๋ž˜๊ทธํ•ด ๋ดค์ง€๋งŒ ํŒŒ๋ž€ ์„ ํƒ ํ•˜์ด๋ผ์ดํŠธ๊ฐ€ ํ•œ ๊ธ€์ž๋„ ๋œจ์ง€ ์•Š๋Š”๋‹ค. onselectstart ์™€ onmousedown ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์„ ํƒ์„ ๊ฐ€๋กœ์ฑ„๊ณ  ์žˆ๋‹ค.
๋ธŒ๋ผ์šฐ์ €์—์„œ ๋ณธ๋ฌธ ์„ธ ์ค„์— ๊ฑธ์ณ ์‹ค์ œ๋กœ ๋“œ๋ž˜๊ทธํ•ด ๋ดค์ง€๋งŒ ํŒŒ๋ž€ ์„ ํƒ ํ•˜์ด๋ผ์ดํŠธ๊ฐ€ ํ•œ ๊ธ€์ž๋„ ๋œจ์ง€ ์•Š๋Š”๋‹ค. onselectstart ์™€ onmousedown ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์„ ํƒ์„ ๊ฐ€๋กœ์ฑ„๊ณ  ์žˆ๋‹ค.

ํ•˜์ด๋ผ์ดํŠธ๊ฐ€ ํ•œ ๊ธ€์ž๋„ ์—†๋‹ค. ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ฐ์€ ๊ฐ’๋„ ์„ ํƒ ๊ธธ์ด = 0 ์ด์—ˆ๋‹ค.

์ด์ œ ํ•ธ๋“ค๋Ÿฌ๋งŒ ์ง€์šฐ๊ณ  ์™„์ „ํžˆ ๊ฐ™์€ ๋“œ๋ž˜๊ทธ๋ฅผ ๋‹ค์‹œ ํ–ˆ๋‹ค.

page.evaluate("document.onselectstart = null;"
              "document.onmousedown = null;"
              "document.oncontextmenu = null;")
# ... ์œ„์™€ ๋˜‘๊ฐ™์€ mousedown -> mousemove x4 -> mouseup ...
sel2 = page.evaluate("window.getSelection().toString().length")
print(f"[*] ํ•ธ๋“ค๋Ÿฌ ์ œ๊ฑฐ ํ›„ ์„ ํƒ ๊ธธ์ด = {sel2}")

๊ฐœ๋ฐœ์ž ๋„๊ตฌ ์ฝ˜์†”์—์„œ oncontextmenu ์™€ onselectstart, onmousedown ์„ธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ null ๋กœ ์ง€์šด ๋’ค ๊ฐ™์€ ์ž๋ฆฌ๋ฅผ ๋“œ๋ž˜๊ทธํ•˜๋‹ˆ ์„ธ ์ค„์ด ๊ทธ๋Œ€๋กœ ํŒŒ๋ž—๊ฒŒ ์„ ํƒ๋œ๋‹ค.
๊ฐœ๋ฐœ์ž ๋„๊ตฌ ์ฝ˜์†”์—์„œ oncontextmenu ์™€ onselectstart, onmousedown ์„ธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ null ๋กœ ์ง€์šด ๋’ค ๊ฐ™์€ ์ž๋ฆฌ๋ฅผ ๋“œ๋ž˜๊ทธํ•˜๋‹ˆ ์„ธ ์ค„์ด ๊ทธ๋Œ€๋กœ ํŒŒ๋ž—๊ฒŒ ์„ ํƒ๋œ๋‹ค.

์„ธ ์ค„์ด ํŒŒ๋ž—๊ฒŒ ์žกํ˜”๋‹ค. ์ฝ˜์†”๋กœ ์žฐ ๊ฐ’์€ ์„ ํƒ ๊ธธ์ด = 260. 0 ์—์„œ 260 ์œผ๋กœ ๋ฐ”๋€ ๊ฒƒ ๋ง๊ณ ๋Š” ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ๊ฑด๋“œ๋ ธ๋‹ค.

๊ฐ™์€ ์ƒํƒœ์—์„œ ์šฐํด๋ฆญ๋„ ๋‹ค์‹œ ํ•ด ๋ดค๋‹ค.

ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ง€์šด ๋’ค ์šฐํด๋ฆญํ•˜๋‹ˆ ์ปจํ…์ŠคํŠธ ๋ฉ”๋‰ด๊ฐ€ ๋œฌ๋‹ค. ๋งจ ์œ„ ํ•ญ๋ชฉ์ด ๋ณต์‚ฌ์ด๊ณ  ๋‹จ์ถ•ํ‚ค๊ฐ€ Ctrl+C๋กœ ํ‘œ์‹œ๋ผ ์žˆ๋‹ค.
ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ง€์šด ๋’ค ์šฐํด๋ฆญํ•˜๋‹ˆ ์ปจํ…์ŠคํŠธ ๋ฉ”๋‰ด๊ฐ€ ๋œฌ๋‹ค. ๋งจ ์œ„ ํ•ญ๋ชฉ์ด ๋ณต์‚ฌ์ด๊ณ  ๋‹จ์ถ•ํ‚ค๊ฐ€ Ctrl+C๋กœ ํ‘œ์‹œ๋ผ ์žˆ๋‹ค.

๋ฉ”๋‰ด ๋งจ ์œ„๊ฐ€ ๋ณต์‚ฌ Ctrl+C ๋‹ค. ๋ฌธ์ œ ์ œ๋ชฉ์ด ์™œ Ctrl-C ์ธ์ง€ ์—ฌ๊ธฐ์„œ ํ™•์ธ๋œ๋‹ค.

์ •๋ฆฌํ•˜๋ฉด ์ด๋ ‡๋‹ค. ๋ฐฉ์–ด๋Š” ์‹ค์ œ๋กœ ๋™์ž‘ํ•œ๋‹ค. ๋‹ค๋งŒ ๊ทธ ๋™์ž‘ ๋ฒ”์œ„๊ฐ€ "์ด ๋ธŒ๋ผ์šฐ์ € ํƒญ ์•ˆ์—์„œ, ์ด ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‚ด์•„ ์žˆ๋Š” ๋™์•ˆ"์œผ๋กœ ํ•œ์ •๋œ๋‹ค. ํ•œ ์ค„๋กœ ๊ป๋‹ค๋Š” ๊ฑด ๊ณง ์ด ๋ฐฉ์–ด๊ฐ€ ์‚ฌ์šฉ์ž ์ชฝ ์ƒํƒœ๋ผ๋Š” ๋œป์ด๋‹ค.

F12 ์ฐจ๋‹จ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋‹ค. ๋ธŒ๋ผ์šฐ์ €๋ฅผ --auto-open-devtools-for-tabs ๋กœ ๋„์šฐ๋ฉด ํŽ˜์ด์ง€๊ฐ€ ํ‚ค๋ฅผ ๊ฐ€๋กœ์ฑŒ ๊ธฐํšŒ ์ž์ฒด๊ฐ€ ์—†๋‹ค. ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๊ฐ€ ์ด๋ฏธ ์—ด๋ฆฐ ์ฑ„๋กœ ๋œฌ๋‹ค. ๊ทธ ์ฝ˜์†”์—์„œ ๋ณธ๋ฌธ์„ ๊ทธ๋ƒฅ ์ฝ์–ด ๋ดค๋‹ค.

t=document.querySelector('.content p').innerText; [t.length, t.slice(0,32), t.slice(-16)]

Chrome DevTools ์ฝ˜์†”์—์„œ ๋ณธ๋ฌธ์„ ์ฝ์€ ๊ฒฐ๊ณผ. ๊ธธ์ด 2000๊ณผ ์•ž 32์ž, ๋’ค 16์ž๊ฐ€ ๋ฐฐ์—ด๋กœ ์ถœ๋ ฅ๋๋‹ค.
Chrome DevTools ์ฝ˜์†”์—์„œ ๋ณธ๋ฌธ์„ ์ฝ์€ ๊ฒฐ๊ณผ. ๊ธธ์ด 2000๊ณผ ์•ž 32์ž, ๋’ค 16์ž๊ฐ€ ๋ฐฐ์—ด๋กœ ์ถœ๋ ฅ๋๋‹ค.

(3) [2000, 'XESBGo7MvS8ia39lltRaFeWj3ptSSC45', 'ZT47ctewsumXcMmT'].

๋ณธ๋ฌธ์€ ์ฒ˜์Œ๋ถ€ํ„ฐ DOM ์— ํ‰๋ฌธ์œผ๋กœ ์žˆ์—ˆ๋‹ค. ๊ฐ€๋ฆฐ ์ ์ด ์—†๋‹ค. ๋‚œ๋…ํ™”๋„, ์ด๋ฏธ์ง€๋กœ ๋ Œ๋”ํ•œ ๊ฒƒ๋„, ์กฐ๊ฐ๋‚ด์„œ ๋ถ™์ธ ๊ฒƒ๋„ ์•„๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ <p> ์•ˆ์— 2000์ž๊ฐ€ ํ†ต์งธ๋กœ ๋“ค์–ด ์žˆ๊ณ , ๊ทธ ์œ„์— "๋งŒ์ง€์ง€ ๋งˆ์„ธ์š”" ๋”ฑ์ง€๋งŒ ๋ถ™์–ด ์žˆ์—ˆ๋‹ค.



๐Ÿ› ์‚ฝ์งˆ

โ–ถ๐Ÿ•ณ๏ธ ์‚ฝ์งˆ 1 โ€” ์„œ๋ฒ„ ์—†์ด ์ƒ์ˆ˜๋งŒ์œผ๋กœ ํ’€์–ด ๋ณด๋ ค ํ–ˆ๋‹ค

text.txt ๊ฐ€ ์„œ๋ฒ„์—๋งŒ ์žˆ๋‹ค๋Š” ๊ฑธ ํ™•์ธํ•œ ๋’ค์—๋„, ํ˜น์‹œ ์ƒ์ˆ˜๋งŒ์œผ๋กœ ์–ด๋–ป๊ฒŒ ์•ˆ ๋˜๋‚˜ ํ•˜๊ณ  ํ•œ์ฐธ ๋ถ™๋“ค์—ˆ๋‹ค.

์ถœ๋ ฅ์€ CONST ^ b64์Šฌ๋ผ์ด์Šค ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ๋Š” ํ”Œ๋ž˜๊ทธ์˜ ํ˜•์‹์„ ์•ˆ๋‹ค. WaRP{ ๋กœ ์‹œ์ž‘ํ•˜๊ณ  } ๋กœ ๋๋‚œ๋‹ค. ์•Œ๋ ค์ง„ ์ž๋ฆฌ๊ฐ€ ๋„ค ๊ตฐ๋ฐ๋‚˜ ์žˆ๋Š” ์…ˆ์ด๋‹ค.

๊ฒŒ๋‹ค๊ฐ€ XOR ๋Œ€์ƒ์ธ b64 ์Šฌ๋ผ์ด์Šค๋Š” ์•„๋ฌด ๋ฐ”์ดํŠธ๋‚˜ ๋  ์ˆ˜ ์—†๋‹ค. base64 ์ถœ๋ ฅ์ด๋ผ ๋ฌธ์ž๊ฐ€ A-Z a-z 0-9 + / = 64์ข…์œผ๋กœ ์ œํ•œ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ๊ฐ ์ž๋ฆฌ์˜ ํ”Œ๋ž˜๊ทธ ๋ฐ”์ดํŠธ๋„ CONST[i] ^ (b64 ๋ฌธ์ž) ํ˜•ํƒœ๋กœ๋งŒ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋‹ค. ํ›„๋ณด๊ฐ€ ํ™• ์ค„์–ด๋“ ๋‹ค๋Š” ๋œป์ด๋‹ค. ์—ฌ๊ธฐ๊นŒ์ง€ ์˜ค๋‹ˆ ๋  ๊ฒƒ ๊ฐ™์•˜๋‹ค.

๊ณ„์‚ฐํ•ด ๋ณด๋ ค๊ณ  ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์งฐ๋‹ค.

#!/usr/bin/env python3
"""Ctrl-C โ€” ๋ฐฐํฌ ํŒŒ์ผ๋งŒ์œผ๋กœ ํ™•์ธ ๊ฐ€๋Šฅํ•œ ๊ฒƒ: ์ƒ์ˆ˜์˜ ๊ตฌ์กฐ."""
import string
 
CONST = 548488142063681088110499188198346596132432266189304030893626
B64 = set((string.ascii_letters + string.digits + "+/=").encode())
 
c = CONST.to_bytes((CONST.bit_length() + 7) // 8, "big")
print(f"CONST bit_length = {CONST.bit_length()}  ->  {len(c)} bytes")
print(f"CONST bytes      = {c!r}")
print(f"๊ณ ์ • ์ ‘๋‘(XOR ๋ฏธ์ ์šฉ ์ƒ์œ„ 2๋ฐ”์ดํŠธ) = {c[:2]!r}")
print()
 
# ํ”Œ๋ž˜๊ทธ๋ฅผ 25๋ฐ”์ดํŠธ๋กœ ๊ฐ€์ •ํ–ˆ์„ ๋•Œ ์•Œ๋ ค์ง„ ์œ„์น˜์—์„œ ์—ญ์‚ฐ๋˜๋Š” b64 ์Šฌ๋ผ์ด์Šค ๋ฌธ์ž
known = {2: "R", 3: "P", 4: "{", 24: "}"}
print("์œ„์น˜  CONST  ํ”Œ๋ž˜๊ทธ  ->  b64์Šฌ๋ผ์ด์Šค ๋ฌธ์ž  b64 ์œ ํšจ?")
for i, ch in known.items():
    s = c[i] ^ ord(ch)
    print(f"  {i:2d}   0x{c[i]:02x}    {ch!r}    ->  {chr(s)!r}"
          f"            {'OK' if s in B64 else 'NO'}")
print()
 
# ๋‚จ์€ 19์ž๋ฆฌ๋Š” ๊ฐ ์œ„์น˜๋งˆ๋‹ค 'CONST[i] ^ (b64 ๋ฌธ์ž)' ๋งŒ ๊ฐ€๋Šฅ -> ํ›„๋ณด ์ˆ˜ ๊ณ„์‚ฐ
total = 1
for i in range(5, 24):
    cand = [c[i] ^ b for b in B64]
    printable = [x for x in cand if 0x20 <= x < 0x7f]
    total *= len(printable)
    print(f"  flag[{i:2d}] ๊ฐ€๋Šฅ ํ›„๋ณด {len(printable):2d}๊ฐœ: "
          f"{''.join(sorted(chr(x) for x in printable))}")
print(f"\n์กฐํ•ฉ ์ˆ˜ = {total:.3e}  -> ์˜คํ”„๋ผ์ธ ์™„์ „ํƒ์ƒ‰ ๋ถˆ๊ฐ€. text.txt(์„œ๋ฒ„ ์ „์šฉ) ํ•„์š”.")
python3 analyze_const.py

์ƒ์ˆ˜ ๋ถ„์„ ์Šคํฌ๋ฆฝํŠธ ์ถœ๋ ฅ. ์ƒ์ˆ˜๊ฐ€ 25๋ฐ”์ดํŠธ์ด๊ณ  ์•Œ๋ ค์ง„ ๋„ค ์ž๋ฆฌ๊ฐ€ ์ „๋ถ€ ์œ ํšจํ•œ base64 ๋ฌธ์ž๋กœ ์—ญ์‚ฐ๋˜๋ฉฐ ๋‚จ์€ ์กฐํ•ฉ์ด 5.988e32๋กœ ๊ณ„์‚ฐ๋๋‹ค.
์ƒ์ˆ˜ ๋ถ„์„ ์Šคํฌ๋ฆฝํŠธ ์ถœ๋ ฅ. ์ƒ์ˆ˜๊ฐ€ 25๋ฐ”์ดํŠธ์ด๊ณ  ์•Œ๋ ค์ง„ ๋„ค ์ž๋ฆฌ๊ฐ€ ์ „๋ถ€ ์œ ํšจํ•œ base64 ๋ฌธ์ž๋กœ ์—ญ์‚ฐ๋˜๋ฉฐ ๋‚จ์€ ์กฐํ•ฉ์ด 5.988e32๋กœ ๊ณ„์‚ฐ๋๋‹ค.

๊ฒฐ๊ณผ๋Š” ๋ฐ˜์€ ์„ฑ๊ณต, ๋ฐ˜์€ ์‹คํŒจ์˜€๋‹ค.

์„ฑ๊ณตํ•œ ์ชฝ. ์•Œ๋ ค์ง„ ๋„ค ์ž๋ฆฌ๊ฐ€ ์ „๋ถ€ ์œ ํšจํ•œ base64 ๋ฌธ์ž๋กœ ์—ญ์‚ฐ๋๋‹ค. R ์ž๋ฆฌ๋Š” A, P ์ž๋ฆฌ๋Š” 6, { ์ž๋ฆฌ๋Š” x, } ์ž๋ฆฌ๋Š” G. ๋„ท ๋‹ค base64 ์•ŒํŒŒ๋ฒณ ์•ˆ์ด๋‹ค. ์šฐ์—ฐํžˆ ์ด๋Ÿด ํ™•๋ฅ ์€ ๋‚ฎ์œผ๋‹ˆ, "ํ”Œ๋ž˜๊ทธ๋Š” 25๋ฐ”์ดํŠธ์ด๊ณ  WaRP{ ๋กœ ์‹œ์ž‘ํ•ด } ๋กœ ๋๋‚œ๋‹ค"๋Š” ๊ฐ€์ •์ด ๋งž๋‹ค๊ณ  ๋ด๋„ ๋œ๋‹ค.

์‹คํŒจํ•œ ์ชฝ. ๋‚จ์€ 19์ž๋ฆฌ์˜ ํ›„๋ณด๋ฅผ ๊ณฑํ•˜๋‹ˆ 5.988e32 ๊ฐ€ ๋‚˜์™”๋‹ค. ์ž๋ฆฌ๋‹น 38~65๊ฐœ์”ฉ ๋‚จ๋Š”๋‹ค. ์ œ์•ฝ์ด ๊ฑธ๋ฆฌ๊ธด ๊ฑธ๋ฆฌ๋Š”๋ฐ, ์ „ํ˜€ ๋ถ€์กฑํ•˜๋‹ค. ํ”Œ๋ž˜๊ทธ ๋ณธ๋ฌธ์ด leetspeak ๋ผ ์˜์–ด ์‚ฌ์ „์œผ๋กœ ๊ฑธ๋Ÿฌ๋‚ผ ์ˆ˜๋„ ์—†๋‹ค.

์—ฌ๊ธฐ์„œ ์ ‘์—ˆ๋‹ค. ์ด ๋ฌธ์ œ๋Š” ๊ตฌ์กฐ์ ์œผ๋กœ text.txt ์—†์ด๋Š” ์•ˆ ๋œ๋‹ค.

โ–ถ๐Ÿ•ณ๏ธ ์‚ฝ์งˆ 2 โ€” VM ํฌ๋ ˆ๋”ง์ด 0์ด๋ผ ๋ฉฐ์น  ๋ฌตํ˜”๋‹ค

๋ฌธ์ œ๋ฅผ ์ฒ˜์Œ ์—ด์–ด ๋ณธ ๊ฒŒ 7์›” 23์ผ์ด์—ˆ๋‹ค. ๋ฐฐํฌ ํŒŒ์ผ์„ ๋‹ค ๋œฏ๊ณ  "์ด๊ฑด ์„œ๋ฒ„ ์—†์œผ๋ฉด ์•ˆ ๋œ๋‹ค"๊นŒ์ง€ ๊ฒฐ๋ก ์„ ๋ƒˆ๋Š”๋ฐ, ํ•˜ํ•„ ๊ทธ ์ฃผ VM ํฌ๋ ˆ๋”ง์„ ๋‹ค ์“ด ์ƒํƒœ์˜€๋‹ค.

๋“œ๋ฆผํ•ต ์›Œ๊ฒŒ์ž„ VM ์€ ์ƒ์„ฑํ•  ๋•Œ ํฌ๋ ˆ๋”ง์„ ํ•˜๋‚˜ ๋จน๊ณ , ๊ทธ ๋ฌธ์ œ๋ฅผ ํ’€์–ด์„œ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ œ์ถœํ•˜๋ฉด ๋Œ๋ ค๋ฐ›๋Š”๋‹ค. ๋งค์ฃผ ์›”์š”์ผ์— ์ „์ฒด ์ถฉ์ „๋œ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ํฌ๋ ˆ๋”ง 0 ์ด๋ฉด ์„œ๋ฒ„๋ฅผ ๋ชป ์ผœ๊ณ , ์„œ๋ฒ„๋ฅผ ๋ชป ์ผœ๋ฉด ์ด ๋ฌธ์ œ๋Š” ํ•œ ๊ธ€์ž๋„ ์ง„์ „์ด ์•ˆ ๋œ๋‹ค.

๊ทธ ๋’ค๋กœ ๋ฉฐ์น ์€ ์—ด์–ด ๋ณผ ๋•Œ๋งˆ๋‹ค ํฌ๋ ˆ๋”ง์ด 0 ์ด์—ˆ๋‹ค. ๊ทธ๋•Œ๋งˆ๋‹ค "์˜คํ”„๋ผ์ธ์œผ๋กœ ์–ด๋–ป๊ฒŒ ์•ˆ ๋˜๋‚˜"๋ฅผ ๋‹ค์‹œ ๋“ค์—ฌ๋‹ค๋ดค๋Š”๋ฐ, ์œ„ ์‚ฝ์งˆ 1 ์˜ ๊ฒฐ๋ก ์€ ๋งค๋ฒˆ ๊ฐ™์•˜๋‹ค. 5.988e32.

๋ฐฐ์šด ๊ฑด ์ด๊ฑฐ๋‹ค. ๋ง‰ํžŒ ์ด์œ ๊ฐ€ ์‹ค๋ ฅ ๋ฌธ์ œ์ธ์ง€ ์ž์› ๋ฌธ์ œ์ธ์ง€ ๊ตฌ๋ถ„ํ•ด์„œ ๊ธฐ๋กํ•ด ๋‘ฌ์•ผ ํ•œ๋‹ค. "์•„์ง ๋ชป ํ’€์—ˆ์Œ"์œผ๋กœ๋งŒ ์ ์–ด ๋‘๋ฉด ๋‹ค์Œ์— ์—ด์—ˆ์„ ๋•Œ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ๋œฏ๊ฒŒ ๋œ๋‹ค. "์˜คํ”„๋ผ์ธ ๋ถ„์„์€ ๋๋‚ฌ๊ณ  ์„œ๋ฒ„๋งŒ ์žˆ์œผ๋ฉด ๋จ"์ด๋ผ๊ณ  ์ ์–ด ๋‘๋ฉด ํฌ๋ ˆ๋”ง์ด ์ฐจ๋Š” ์ˆœ๊ฐ„ ๋ฐ”๋กœ ์ด์–ด์„œ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์‹ค์ œ๋กœ ์ด๋ฒˆ์—” ํฌ๋ ˆ๋”ง์„ ํ™•์ธํ•˜๊ณ  ์„œ๋ฒ„๋ฅผ ์ผœ๊ธฐ๊นŒ์ง€๊ฐ€ ๋ช‡ ๋ถ„์ด์—ˆ๋‹ค.

โ–ถ๐Ÿ•ณ๏ธ ์‚ฝ์งˆ 3 โ€” ๋ณธ๋ฌธ์„ ์–ด๋–ป๊ฒŒ ๊ธ๋А๋ƒ๋กœ ๋‹ต์ด ๊ฐˆ๋ฆฐ๋‹ค

๋ณธ๋ฌธ์ด 2000์ž๋‹ค. ์†์œผ๋กœ ์˜ฎ๊ธธ ๋ฌผ๊ฑด์ด ์•„๋‹ˆ๊ณ , ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ธ์–ด ์˜ค๋“  curl ๋กœ ๋ฐ›๋“  ํ•œ ๊ธ€์ž๋ผ๋„ ์–ด๊ธ‹๋‚˜๋ฉด sha256 ์ด ํ†ต์งธ๋กœ ๋‹ฌ๋ผ์ง„๋‹ค.

Ctrl_C.py ๋Š” input().rstrip() ์ด๋‹ค. ๋’ค์ชฝ ๊ณต๋ฐฑ๋งŒ ์ž˜๋ผ ์ค€๋‹ค. ์•ž์ชฝ์€ ์•ˆ ์ž˜๋ผ ์ค€๋‹ค. ๊ทธ๋Ÿผ ์–ด๋–ค ์‹ค์ˆ˜๊ฐ€ ์น˜๋ช…์ ์ด๊ณ  ์–ด๋–ค ๊ฑด ๊ดœ์ฐฎ์€์ง€ ์ง์ ‘ ์žฌ ๋ดค๋‹ค.

#!/usr/bin/env python3
"""์ž…๋ ฅ์„ ์กฐ๊ธˆ์”ฉ ํ”๋“ค์–ด ๋ณด๊ณ  ๊ฒฐ๊ณผ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋‹ฌ๋ผ์ง€๋Š”์ง€ ์‹ค์ธกํ•œ๋‹ค."""
import base64
import hashlib
import pathlib
 
CONST = 548488142063681088110499188198346596132432266189304030893626
TEXT = pathlib.Path("text.txt").read_text()
 
 
def run(s):
    d = hashlib.sha256(s.rstrip().encode()).digest()
    v = CONST ^ int.from_bytes(base64.b64encode(d)[13:36], "big")
    b = v.to_bytes((v.bit_length() + 7) // 8, "big")
    try:
        return b.decode()
    except UnicodeDecodeError:
        return b.hex() + "  (๋””์ฝ”๋”ฉ ๋ถˆ๊ฐ€)"
 
 
cases = [
    ("์›๋ฌธ ๊ทธ๋Œ€๋กœ", TEXT),
    ("๋’ค์— ๊ฐœํ–‰ ํ•˜๋‚˜", TEXT + "\n"),
    ("๋’ค์— ๊ณต๋ฐฑ ์…‹", TEXT + "   "),
    ("์•ž์— ๊ณต๋ฐฑ ํ•˜๋‚˜", " " + TEXT),
    ("๊ฐ€์šด๋ฐ ๊ฐœํ–‰ ํ•˜๋‚˜(์ค„๋ฐ”๊ฟˆ์งธ๋กœ ๋ณต์‚ฌ)", TEXT[:1000] + "\n" + TEXT[1000:]),
    ("๋งˆ์ง€๋ง‰ ํ•œ ๊ธ€์ž ๋ˆ„๋ฝ", TEXT[:-1]),
]
w = max(len(n) for n, _ in cases)
for name, s in cases:
    print(f"{name:<{w}}  len={len(s):>4}  -> {run(s)}")
python3 variants.py

์ž…๋ ฅ์„ ํ”๋“ค์–ด ๋ณธ ๊ฒฐ๊ณผํ‘œ. ๋’ค์ชฝ ๊ณต๋ฐฑ๊ณผ ๊ฐœํ–‰์€ rstrip ๋•์— ๋ฌดํ•ดํ•˜์ง€๋งŒ ์•ž์ชฝ ๊ณต๋ฐฑ์ด๋‚˜ ์ค‘๊ฐ„ ๊ฐœํ–‰์€ ์ „ํ˜€ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๊ธฐ ๋ฌธ์ž์—ด์„ ๋งŒ๋“ ๋‹ค.
์ž…๋ ฅ์„ ํ”๋“ค์–ด ๋ณธ ๊ฒฐ๊ณผํ‘œ. ๋’ค์ชฝ ๊ณต๋ฐฑ๊ณผ ๊ฐœํ–‰์€ rstrip ๋•์— ๋ฌดํ•ดํ•˜์ง€๋งŒ ์•ž์ชฝ ๊ณต๋ฐฑ์ด๋‚˜ ์ค‘๊ฐ„ ๊ฐœํ–‰์€ ์ „ํ˜€ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๊ธฐ ๋ฌธ์ž์—ด์„ ๋งŒ๋“ ๋‹ค.

์ž…๋ ฅ ๋ณ€ํ˜•๊ฒฐ๊ณผ
์›๋ฌธ ๊ทธ๋Œ€๋กœWaRP{1_w4n7_5h0r7cu7_k3y}
๋’ค์— ๊ฐœํ–‰ ํ•˜๋‚˜๋™์ผ โ€” rstrip() ์ด ๋จน๋Š”๋‹ค
๋’ค์— ๊ณต๋ฐฑ ์…‹๋™์ผ
์•ž์— ๊ณต๋ฐฑ ํ•˜๋‚˜๊นจ์ง„ ๋ฐ”์ดํŠธ์—ด
๊ฐ€์šด๋ฐ ๊ฐœํ–‰ ํ•˜๋‚˜๊นจ์ง„ ๋ฐ”์ดํŠธ์—ด
๋งˆ์ง€๋ง‰ ํ•œ ๊ธ€์ž ๋ˆ„๋ฝ๊นจ์ง„ ๋ฐ”์ดํŠธ์—ด

๋’ค์ชฝ์€ ๊ด€๋Œ€ํ•˜๊ณ  ์•žยท์ค‘๊ฐ„์€ ๋ฌด๊ด€์šฉ์ด๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์ด ํ‘œ์—์„œ ์ง„์งœ ์กฐ์‹ฌํ•  ๊ฑด ๋”ฐ๋กœ ์žˆ๋‹ค. ํ‹€๋ฆฐ ์ž…๋ ฅ์˜ ์ถœ๋ ฅ๋„ ์ „๋ถ€ Wa ๋กœ ์‹œ์ž‘ํ•œ๋‹ค. ์„ธ ๊ฐœ์˜ ์‹คํŒจ ์ผ€์ด์Šค๊ฐ€ ๋‹ค ๊ทธ๋ ‡๋‹ค.

์ด์œ ๋Š” ๋‹ค์Œ ์„น์…˜์˜ ์ž๋ฆฌ์ˆ˜ ๊ณ„์‚ฐ์— ์žˆ๋Š”๋ฐ, ์š”์ ์€ ์•ž ๋‘ ๋ฐ”์ดํŠธ๊ฐ€ XOR ์„ ์•„์˜ˆ ์•ˆ ํƒ„๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋ž˜์„œ Wa ๋กœ ์‹œ์ž‘ํ•œ๋‹ค๋Š” ๊ฑด ์•„๋ฌด ์ฆ๊ฑฐ๋„ ์•„๋‹ˆ๋‹ค. WaRP{ ๊นŒ์ง€ ๋‚˜์˜ค๊ณ  } ๋กœ ๋‹ซํ˜€์•ผ ๋งž์€ ๊ฒƒ์ด๋‹ค. ์—ฌ๊ธฐ์„œ ํ•œ ๋ฒˆ ํ—ท๊ฐˆ๋ฆด ๋ป”ํ–ˆ๋‹ค.



๐Ÿ’ฃ ํ•ต์‹ฌ โ€” 25๋ฐ”์ดํŠธ์™€ 23๋ฐ”์ดํŠธ

์ด์ œ Ctrl_C.py ์˜ ๊ณ„์‚ฐ์„ ์ •ํ™•ํžˆ ์งš์–ด ๋ณด์ž. ์—ฌ๊ธฐ๊ฐ€ ์ด ๋ฌธ์ œ์—์„œ ์œ ์ผํ•˜๊ฒŒ ์ƒ๊ฐํ•  ๊ฑฐ๋ฆฌ๋‹ค.

sha256 ๋‹ค์ด์ œ์ŠคํŠธ๋Š” 32๋ฐ”์ดํŠธ๋‹ค. base64 ๋กœ ์ธ์ฝ”๋”ฉํ•˜๋ฉด 44๊ธ€์ž๊ฐ€ ๋œ๋‹ค. 32๋ฐ”์ดํŠธ๋Š” 3์˜ ๋ฐฐ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ์„œ ๋งˆ์ง€๋ง‰์— ํŒจ๋”ฉ = ์ด ํ•˜๋‚˜ ๋ถ™๋Š”๋‹ค. ๊ฑฐ๊ธฐ์„œ [13:36] ์„ ์ž˜๋ผ ์˜ค๋‹ˆ ์ •ํ™•ํžˆ 23๋ฐ”์ดํŠธ๋‹ค.

์ด ์Šฌ๋ผ์ด์Šค๊ฐ€ ์‹ค์ œ๋กœ ๋‹ค์ด์ œ์ŠคํŠธ์˜ ์–ด๋””๋ฅผ ๋ณด๋Š” ๊ฑด์ง€ ๊ณ„์‚ฐํ•ด ๋ดค๋‹ค. base64 ๋Š” 6๋น„ํŠธ๋ฅผ ํ•œ ๊ธ€์ž๋กœ ๋งŒ๋“œ๋‹ˆ, ๊ธ€์ž ๋ฒˆํ˜ธ์— 6์„ ๊ณฑํ•˜๋ฉด ๊ณง ๋น„ํŠธ ์œ„์น˜๊ฐ€ ๋œ๋‹ค.

#!/usr/bin/env python3
"""[13:36] ์ด ์ •ํ™•ํžˆ ๋ฌด์—‡์„ ์ž˜๋ผ ์˜ค๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
 
base64 ๋Š” 6๋น„ํŠธ์”ฉ ํ•œ ๊ธ€์ž๋กœ ๋งŒ๋“ ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ์Šฌ๋ผ์ด์Šค๋Š” '๋‹ค์ด์ œ์ŠคํŠธ์˜ ์–ด๋А ๋น„ํŠธ ๊ตฌ๊ฐ„'
์ด๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ ๊ตฌ๊ฐ„์ด ์–ผ๋งˆ๋‚˜ ๋˜๋Š”์ง€๊ฐ€ ๊ณง '๋˜๋Œ๋ฆด ์ˆ˜ ์žˆ๋А๋ƒ'์˜ ๋‹ต์ด๋‹ค.
"""
import base64
import hashlib
import pathlib
 
TEXT = pathlib.Path("text.txt").read_text()
d = hashlib.sha256(TEXT.rstrip().encode()).digest()
b64 = base64.b64encode(d).decode()
 
print(f"sha256 ๋‹ค์ด์ œ์ŠคํŠธ   : {len(d)}๋ฐ”์ดํŠธ = {len(d) * 8}๋น„ํŠธ")
print(f"base64 ์ „์ฒด         : {b64}")
print(f"                      ({len(b64)}๊ธ€์ž, ๋์— ํŒจ๋”ฉ '{b64[-1]}')")
print(f"[13:36] ์Šฌ๋ผ์ด์Šค    : {' ' * 13}{b64[13:36]}")
print(f"                      ({len(b64[13:36])}๊ธ€์ž = 23๋ฐ”์ดํŠธ)")
 
lo, hi = 13 * 6, 36 * 6                     # base64 ๊ธ€์ž i = ๋‹ค์ด์ œ์ŠคํŠธ ๋น„ํŠธ [6i, 6i+6)
print()
print(f"๋ฎ๋Š” ๋น„ํŠธ ๊ตฌ๊ฐ„      : {lo} ~ {hi - 1}  ({hi - lo}๋น„ํŠธ)")
print(f"์ „์ฒด ๋Œ€๋น„           : {(hi - lo) / (len(d) * 8):.1%}")
print(f"ํ•ด๋‹น ๋ฐ”์ดํŠธ         : {lo // 8} ~ {(hi - 1) // 8}  (์ด {(hi - 1) // 8 - lo // 8 + 1}๋ฐ”์ดํŠธ)")
print(f"ํŒจ๋”ฉ '=' ํฌํ•จ?      : {'์˜ˆ' if 36 > len(b64) - 1 else '์•„๋‹ˆ์˜ค (43๋ฒˆ์งธ ํŒจ๋”ฉ์€ ์•ˆ ๊ฑธ๋ฆฐ๋‹ค)'}")
print()
print(f"-> ๋‹ค์ด์ œ์ŠคํŠธ์˜ {(hi - lo)}๋น„ํŠธ๋งŒ ๋ณธ๋‹ค. ๋‚˜๋จธ์ง€ {len(d) * 8 - (hi - lo)}๋น„ํŠธ๋Š” ๋ฒ„๋ ค์ง„๋‹ค.")
print("   ๊ทธ๋ž˜๋„ ์›๋ฌธ์„ ๋˜๋Œ๋ฆด ์ˆ˜๋Š” ์—†๋‹ค. sha256 ์ž์ฒด๊ฐ€ ๋‹จ๋ฐฉํ–ฅ์ด๋ผ ๋ช‡ ๋น„ํŠธ๋ฅผ ๋ณด๋“  ๋งˆ์ฐฌ๊ฐ€์ง€๋‹ค.")
python3 slice_math.py

base64 ์Šฌ๋ผ์ด์Šค ๋ถ„์„ ์ถœ๋ ฅ. ์ „์ฒด 44๊ธ€์ž ์•„๋ž˜ 13๋ฒˆ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š” 23๊ธ€์ž๊ฐ€ ์ž๋ฆฌ๋ฅผ ๋งž์ถฐ ์ฐํ˜”๊ณ  ๋‹ค์ด์ œ์ŠคํŠธ ๋น„ํŠธ 78๋ถ€ํ„ฐ 215๊นŒ์ง€๋ฅผ ๋ฎ๋Š”๋‹ค.
base64 ์Šฌ๋ผ์ด์Šค ๋ถ„์„ ์ถœ๋ ฅ. ์ „์ฒด 44๊ธ€์ž ์•„๋ž˜ 13๋ฒˆ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š” 23๊ธ€์ž๊ฐ€ ์ž๋ฆฌ๋ฅผ ๋งž์ถฐ ์ฐํ˜”๊ณ  ๋‹ค์ด์ œ์ŠคํŠธ ๋น„ํŠธ 78๋ถ€ํ„ฐ 215๊นŒ์ง€๋ฅผ ๋ฎ๋Š”๋‹ค.

์Šฌ๋ผ์ด์Šค๋Š” ๋‹ค์ด์ œ์ŠคํŠธ์˜ ๋น„ํŠธ 78~215, ๊ณง 138๋น„ํŠธ๋ฅผ ๋ฎ๋Š”๋‹ค. ์ „์ฒด์˜ 53.9% ๋‹ค. ๋ฐ”์ดํŠธ๋กœ ๋ณด๋ฉด 9๋ฒˆ๋ถ€ํ„ฐ 26๋ฒˆ๊นŒ์ง€ 18๋ฐ”์ดํŠธ์— ๊ฑธ์นœ๋‹ค. ๊ทธ๋ฆฌ๊ณ  43๋ฒˆ ์ž๋ฆฌ์˜ ํŒจ๋”ฉ = ์€ 36 ๋ฏธ๋งŒ์ด ์•„๋‹ˆ๋ผ ์•ˆ ๊ฑธ๋ฆฐ๋‹ค โ€” ๊ทธ๋ž˜์„œ ์ž˜๋ฆฐ 23๊ธ€์ž๊ฐ€ ์ „๋ถ€ ์ง„์งœ base64 ๋ฌธ์ž๋‹ค. ์‚ฝ์งˆ 1 ์—์„œ ํ›„๋ณด๋ฅผ 64์ข…์œผ๋กœ ์žก์„ ์ˆ˜ ์žˆ์—ˆ๋˜ ๊ทผ๊ฑฐ๋‹ค.

์ ˆ๋ฐ˜์ด ๋„˜๊ฒŒ ๋ณด์ธ๋‹ค๊ณ  ํ•ด๋„ ์›๋ฌธ์„ ๋˜๋Œ๋ฆด ๋ฐฉ๋ฒ•์€ ์—†๋‹ค. sha256 ์ด ๋‹จ๋ฐฉํ–ฅ์ด๋ผ ๋ช‡ ๋น„ํŠธ๋ฅผ ๋ณด๋“  ๊ฐ™๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ์šฐ๋ฆฌ๊ฐ€ ํ•  ์ผ์€ ๊ณ„์‚ฐ์„ ๋’ค์ง‘๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ์ž…๋ ฅ์„ ์†์— ๋„ฃ๋Š” ๊ฒƒ์ด๋‹ค. ๋ฌธ์ œ๊ฐ€ ์›น ์นดํ…Œ๊ณ ๋ฆฌ์— ์žˆ๋Š” ์ด์œ ๋‹ค.

ํ•œํŽธ ์ƒ์ˆ˜๋Š” ์ด๋ ‡๋‹ค.

548488142063681088110499188198346596132432266189304030893626
  -> bit_length = 199
  -> (199 + 7) // 8 = 25 ๋ฐ”์ดํŠธ
  -> 5761136603080d246d3a012761434911032a381c362505163a

25๋ฐ”์ดํŠธ์งœ๋ฆฌ์™€ 23๋ฐ”์ดํŠธ์งœ๋ฆฌ๋ฅผ XOR ํ•œ๋‹ค. ์ž๋ฆฌ์ˆ˜๊ฐ€ ๋‘ ๋ฐ”์ดํŠธ ์–ด๊ธ‹๋‚œ๋‹ค.

์ •์ˆ˜ XOR ์ด๋‹ˆ ์˜ค๋ฅธ์ชฝ ๋์„ ๊ธฐ์ค€์œผ๋กœ ๋งž์ถฐ์ง„๋‹ค. 23๋ฐ”์ดํŠธ์งœ๋ฆฌ๋Š” ์ƒ์œ„ ๋‘ ๋ฐ”์ดํŠธ ์ž๋ฆฌ์— ์•„๋ฌด ๊ฐ’๋„ ์—†๋‹ค โ€” 0 ์ด๋‹ค. ๊ทธ๋ž˜์„œ ๊ฒฐ๊ณผ์˜ ์ƒ์œ„ ๋‘ ๋ฐ”์ดํŠธ๋Š” ์ƒ์ˆ˜์˜ ์ƒ์œ„ ๋‘ ๋ฐ”์ดํŠธ๊ฐ€ ๊ทธ๋Œ€๋กœ ์‚ด์•„๋‚จ๋Š”๋‹ค.

๊ทธ ๋‘ ๋ฐ”์ดํŠธ๊ฐ€ 0x57 0x61, ๊ณง Wa ๋‹ค.

์ƒ์ˆ˜ 25๋ฐ”์ดํŠธ์™€ base64 ์Šฌ๋ผ์ด์Šค 23๋ฐ”์ดํŠธ๋ฅผ ์ž๋ฆฌ ๋งž์ถฐ XORํ•œ ๋ฐฐ์น˜๋„. ์•ž ๋‘ ์นธ์€ XOR ๋Œ€์ƒ์ด ์—†์–ด ์ƒ์ˆ˜ ๊ฐ’์ด ๊ทธ๋Œ€๋กœ ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋œ๋‹ค.
์ƒ์ˆ˜ 25๋ฐ”์ดํŠธ์™€ base64 ์Šฌ๋ผ์ด์Šค 23๋ฐ”์ดํŠธ๋ฅผ ์ž๋ฆฌ ๋งž์ถฐ XORํ•œ ๋ฐฐ์น˜๋„. ์•ž ๋‘ ์นธ์€ XOR ๋Œ€์ƒ์ด ์—†์–ด ์ƒ์ˆ˜ ๊ฐ’์ด ๊ทธ๋Œ€๋กœ ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋œ๋‹ค.

๋ฐฐ์น˜๋„๋กœ ๋ณด๋ฉด ํ•œ๋ˆˆ์— ๋“ค์–ด์˜จ๋‹ค. ์ฃผํ™ฉ์ƒ‰ ๋‘ ์นธ์ด XOR ์ƒ๋Œ€๊ฐ€ ์—†๋Š” ์ž๋ฆฌ๋‹ค. ๊ทธ ์•„๋ž˜ b64[13:36] ํ–‰์˜ ์ฒซ ๋‘ ์นธ์ด ๋น„์–ด ์žˆ๋Š” ๊ฒŒ ๊ทธ ๋œป์ด๋‹ค.

์—ฌ๊ธฐ์„œ ๋‘ ๊ฐ€์ง€๊ฐ€ ๋”ฐ๋ผ ๋‚˜์˜จ๋‹ค.

ํ•˜๋‚˜. ์ถœ์ œ์ž๊ฐ€ ์ƒ์ˆ˜๋ฅผ ๊ทธ๋ƒฅ ๊ณ ๋ฅธ ๊ฒŒ ์•„๋‹ˆ๋‹ค. ํ”Œ๋ž˜๊ทธ๊ฐ€ WaRP{...} ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฑธ ์•Œ๊ณ , ์•ž ๋‘ ๊ธ€์ž Wa ๋ฅผ ์ƒ์ˆ˜ ์ตœ์ƒ์œ„์— ์‹ฌ์–ด ๋’€๋‹ค. 25์™€ 23์ด๋ผ๋Š” ๊ธธ์ด ์ฐจ์ด๋„ ๊ทธ๋ž˜์„œ ๋‚˜์˜จ ๊ฒƒ์ด๋‹ค. ์šฐ์—ฐ์ด ์•„๋‹ˆ๋‹ค.

๋‘˜. ๊ทธ๋ž˜์„œ Wa ๋Š” ๊ฒ€์ฆ์— ์“ธ ์ˆ˜ ์—†๋‹ค. ์ž…๋ ฅ์ด ๋ญ๊ฐ€ ๋๋“  ์ถœ๋ ฅ์€ Wa ๋กœ ์‹œ์ž‘ํ•œ๋‹ค. ์‚ฝ์งˆ 3 ์˜ ์‹คํŒจ ์ผ€์ด์Šค๋“ค์ด ์‹ค์ œ๋กœ ๊ทธ๋žฌ๋‹ค.

ํ•œ ๊ฐ€์ง€ ๋”. long_to_bytes ๊ฐ€ bit_length() ๋กœ ๊ธธ์ด๋ฅผ ์žก๊ธฐ ๋•Œ๋ฌธ์—, XOR ๊ฒฐ๊ณผ์˜ ์ตœ์ƒ์œ„ ๋ฐ”์ดํŠธ๊ฐ€ 0 ์ด ๋˜๋ฉด ์ถœ๋ ฅ์ด ๊ทธ๋งŒํผ ์งง์•„์ง„๋‹ค. ์ด ๋ฌธ์ œ์—์„œ๋Š” ๊ทธ ์ž๋ฆฌ๊ฐ€ ์ƒ์ˆ˜์˜ 0x57 ๋กœ ๊ณ ์ •์ด๋ผ ํ•ญ์ƒ 25๋ฐ”์ดํŠธ๊ฐ€ ๋‚˜์˜ค์ง€๋งŒ, ์•„๋ž˜ ์ž๋ฆฌ์—์„œ 0 ์ด ๋‚˜์˜ค๋Š” ๊ฑด ์–ผ๋งˆ๋“ ์ง€ ๊ฐ€๋Šฅํ•˜๋‹ค. ์‚ฝ์งˆ 3 ์˜ "๋งˆ์ง€๋ง‰ ํ•œ ๊ธ€์ž ๋ˆ„๋ฝ" ์ผ€์ด์Šค๊ฐ€ ๊ทธ๋ž˜์„œ ๊ธธ์ด๊ฐ€ ๋“ค์ญ‰๋‚ ์ญ‰ํ–ˆ๋‹ค.

ํ”Œ๋ž˜๊ทธ ์ž๋ฆฌ์— ์‹ค์ œ๋กœ ๋“ค์–ด๊ฐ„ ๊ฐ’์„ ์—ญ์œผ๋กœ ํ™•์ธํ•ด ๋ณด๋ฉด ์ด๋ ‡๋‹ค.

์œ„์น˜์ƒ์ˆ˜ ๋ฐ”์ดํŠธb64 ์Šฌ๋ผ์ด์ŠคXOR ๊ฒฐ๊ณผ
00x57(์—†์Œ)W
10x61(์—†์Œ)a
20x13A (0x41)R
30x666 (0x36)P
40x03x (0x78){
240x3aG (0x47)}

๋ฐฐํฌ ํŒŒ์ผ๋งŒ ์žˆ์„ ๋•Œ ์ด ํ‘œ์—์„œ ์ฑ„์šธ ์ˆ˜ ์žˆ๋Š” ๊ฑด ์™ผ์ชฝ ๋‘ ์—ด๋ฟ์ด์—ˆ๋‹ค. text.txt ๊ฐ€ ๋“ค์–ด์˜ค๋ฉด ๊ฐ€์šด๋ฐ ์—ด์ด ์ฑ„์›Œ์ง€๊ณ , ๊ทธ๋Ÿฌ๋ฉด ์˜ค๋ฅธ์ชฝ์ด ์ž๋™์œผ๋กœ ๋‚˜์˜จ๋‹ค.



๐ŸŽฏ ์ต์Šคํ”Œ๋กœ์ž‡

ํ•  ์ผ์€ ํ•˜๋‚˜๋‹ค. <p> ์•ˆ์˜ 2000์ž๋ฅผ ๊ทธ๋Œ€๋กœ ๊บผ๋‚ด ํ‘œ์ค€์ž…๋ ฅ์— ๋ฐ€์–ด ๋„ฃ๋Š”๋‹ค.

with urllib.request.urlopen(url, timeout=30) as r:
    html = r.read().decode("utf-8")
m = re.search(r"<p>(.*?)</p>", html, re.S)
text = m.group(1)

re.S ๋ฅผ ์ค€ ๊ฑด ํ˜น์‹œ ๋ณธ๋ฌธ์— ๊ฐœํ–‰์ด ์„ž์—ฌ ์žˆ์„ ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•œ ๊ฒƒ์ด๋‹ค. ์‹ค์ œ๋กœ๋Š” ํ•œ ์ค„์ด์—ˆ๋‹ค. ๋ฝ‘์•„ ๋ณด๋‹ˆ ์ •ํ™•ํžˆ 2000์ž.

์—ฌ๊ธฐ์„œ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ™”๋ฉด์— ๋ณด์—ฌ ์ค€ ๊ฒƒ๊ณผ HTTP ์‘๋‹ต์˜ ์›๋ฌธ์ด ๊ฐ™์€์ง€ ํ™•์ธํ•ด ๋‘˜ ํ•„์š”๊ฐ€ ์žˆ์—ˆ๋‹ค. ํŽ˜์ด์ง€ CSS ์— white-space: pre-wrap ๊ณผ word-wrap: break-word ๊ฐ€ ๊ฑธ๋ ค ์žˆ์–ด์„œ, ํ™”๋ฉด์—์„œ๋Š” ์—ด๋ช‡ ์ค„๋กœ ์ ‘ํ˜€ ๋ณด์ธ๋‹ค. ์ ‘ํžŒ ๊ฒŒ ์‹ค์ œ ๊ฐœํ–‰์ด๋ฉด ํ•ด์‹œ๊ฐ€ ๋‹ฌ๋ผ์ง„๋‹ค.

์•ž์—์„œ DevTools ๋กœ ์ฝ์€ innerText ๊ฐ€ 2000์ž์˜€๊ณ , ์•ž 32์žยท๋’ค 16์ž๊ฐ€ curl ๋กœ ๋ฐ›์€ ๊ฒƒ๊ณผ ํ•œ ๊ธ€์ž๋„ ๋‹ค๋ฅด์ง€ ์•Š์•˜๋‹ค. ํ™”๋ฉด์˜ ์ค„๋ฐ”๊ฟˆ์€ CSS ๊ฐ€ ๋งŒ๋“  ์‹œ๊ฐ์  ์ ‘ํž˜์ผ ๋ฟ ๋ฌธ์ž์—ด์—๋Š” ์—†๋‹ค.

์ด์ œ ๋ฐฐํฌ๋œ ์Šคํฌ๋ฆฝํŠธ์— ๊ทธ๋Œ€๋กœ ๋จน์ด๋ฉด ๋œ๋‹ค.

import subprocess, pathlib
t = pathlib.Path('text.txt').read_text()
r = subprocess.run(['python3','extracted/Ctrl_C.py'], input=t+'\n', capture_output=True, text=True)
print('stdout:', r.stdout.strip())
stdout: b'WaRP{1_w4n7_5h0r7cu7_k3y}'

1_w4n7_5h0r7cu7_k3y โ€” "I want shortcut key". ๋ฌธ์ œ ์ œ๋ชฉ๊ณผ ๋งž์•„๋–จ์–ด์ง„๋‹ค.


๐Ÿš€ Full Exploit

๋ฐฐํฌ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š๊ณ  ํ•œ ํŒŒ์ผ๋กœ ๋๋‚˜๊ฒŒ ์ •๋ฆฌํ–ˆ๋‹ค. ์„œ๋ฒ„์—์„œ ๋ฐ›์•„ ์˜ค๋Š” ๊ฒฝ๋กœ์™€, ์ด๋ฏธ ๋ฐ›์•„ ๋‘” ๋ณธ๋ฌธ์œผ๋กœ ์˜คํ”„๋ผ์ธ ์žฌํ˜„ํ•˜๋Š” ๊ฒฝ๋กœ๋ฅผ ๋‘˜ ๋‹ค ๋„ฃ์—ˆ๋‹ค.

#!/usr/bin/env python3
"""Ctrl-C (DreamHack, Bronze 4 / web) โ€” ์ž์ฒด ์™„๊ฒฐ solve.
 
๋™์ž‘:
  1) ๋ฌธ์ œ ์„œ๋ฒ„์˜ ๋ฉ”์ธ ํŽ˜์ด์ง€๋ฅผ ๋ฐ›๋Š”๋‹ค. ๋ณต์‚ฌ๋ฐฉ์ง€(์šฐํด๋ฆญยท๋“œ๋ž˜๊ทธยทF12 ์ฐจ๋‹จ)๋Š”
     ์ „๋ถ€ ๋ธŒ๋ผ์šฐ์ €์—์„œ๋งŒ ๋„๋Š” JS๋ผ HTTP ์‘๋‹ต ์ž์ฒด์—๋Š” ์•„๋ฌด ์˜ํ–ฅ์ด ์—†๋‹ค.
  2) <p> ์•ˆ์˜ 2000์ž๋ฅผ ๊ทธ๋Œ€๋กœ ๊บผ๋‚ธ๋‹ค.
  3) ๋ฐฐํฌ๋œ Ctrl_C.py ์™€ ๋™์ผํ•œ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
       long_to_bytes( CONST ^ bytes_to_long( b64(sha256(text))[13:36] ) )
     CONST ๋Š” 25๋ฐ”์ดํŠธ, b64 ์Šฌ๋ผ์ด์Šค๋Š” 23๋ฐ”์ดํŠธ๋ผ ์ƒ์œ„ 2๋ฐ”์ดํŠธ๋Š” XOR ๋ฅผ ์•ˆ ํƒ„๋‹ค
     -> ์ถœ๋ ฅ์€ ์ž…๋ ฅ๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ํ•ญ์ƒ b'Wa' ๋กœ ์‹œ์ž‘ํ•˜๊ณ , ๊ทธ ๋’ค 23๋ฐ”์ดํŠธ๊ฐ€ ํ”Œ๋ž˜๊ทธ ๋ณธ๋ฌธ.
 
์‚ฌ์šฉ:
  python3 solve.py http://hostN.dreamhack.games:PORT/
  python3 solve.py --text-file text.txt      # ์ด๋ฏธ ๋ฐ›์•„๋‘” ๋ณธ๋ฌธ์œผ๋กœ ์˜คํ”„๋ผ์ธ ์žฌํ˜„
 
์ธ์ž๋ฅผ ์ƒ๋žตํ•˜๋ฉด ๊ธฐ๋ณธ URL ๋กœ ๋ถ™์ง€๋งŒ, ๋“œ๋ฆผํ•ต ์ธ์Šคํ„ด์Šค๋Š” ์‹œ๊ฐ„์ œํ•œ์ด ์žˆ์–ด
๋งŒ๋ฃŒ๋œ ๋’ค์—๋Š” ์‹คํŒจํ•œ๋‹ค. ๊ทธ๋•Œ๋Š” --text-file ๋กœ ์ €์žฅ๋ณธ์„ ์“ฐ๊ฑฐ๋‚˜ ์ƒˆ URL ์„ ๋„˜๊ธธ ๊ฒƒ.
"""
import argparse
import base64
import hashlib
import re
import sys
import urllib.request
 
DEFAULT_URL = "http://host3.dreamhack.games:21647/"
CONST = 548488142063681088110499188198346596132432266189304030893626
 
 
def bytes_to_long(a):
    return int.from_bytes(a, byteorder="big")
 
 
def long_to_bytes(a):
    return a.to_bytes((a.bit_length() + 7) // 8, byteorder="big")
 
 
def fetch_text(url):
    """๋ฉ”์ธ ํŽ˜์ด์ง€์—์„œ <p> ์•ˆ ๋ณธ๋ฌธ์„ ๊บผ๋‚ธ๋‹ค. JS ๋ณต์‚ฌ๋ฐฉ์ง€๋Š” ์—ฌ๊ธฐ ๊ด€์—ฌํ•˜์ง€ ๋ชปํ•œ๋‹ค."""
    with urllib.request.urlopen(url, timeout=30) as r:
        html = r.read().decode("utf-8")
    m = re.search(r"<p>(.*?)</p>", html, re.S)
    if not m:
        raise SystemExit("[-] <p> ๋ณธ๋ฌธ์„ ์ฐพ์ง€ ๋ชปํ–ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ๋งŒ๋ฃŒ๋๋Š”์ง€ ํ™•์ธํ•  ๊ฒƒ.")
    return m.group(1)
 
 
def solve(text):
    """๋ฐฐํฌ๋œ Ctrl_C.py ์™€ ๊ฐ™์€ ์—ฐ์‚ฐ. input().rstrip() ์„ ๊ทธ๋Œ€๋กœ ์žฌํ˜„ํ•œ๋‹ค."""
    digest = hashlib.sha256(text.rstrip().encode("utf-8")).digest()
    sliced = base64.b64encode(digest)[13:36]
    return long_to_bytes(CONST ^ bytes_to_long(sliced)), sliced
 
 
def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("url", nargs="?", default=DEFAULT_URL)
    ap.add_argument("--text-file", help="์ €์žฅํ•ด ๋‘” ๋ณธ๋ฌธ์œผ๋กœ ์˜คํ”„๋ผ์ธ ์žฌํ˜„")
    a = ap.parse_args()
 
    if a.text_file:
        text = open(a.text_file, encoding="utf-8").read()
        print(f"[*] ๋ณธ๋ฌธ ์ถœ์ฒ˜: {a.text_file}")
    else:
        text = fetch_text(a.url)
        print(f"[*] ๋ณธ๋ฌธ ์ถœ์ฒ˜: {a.url}")
 
    print(f"[*] ๋ณธ๋ฌธ ๊ธธ์ด: {len(text)}์ž")
    print(f"[*] ๋ณธ๋ฌธ ์•ž 48์ž: {text[:48]}")
 
    flag, sliced = solve(text)
    print(f"[*] sha256 b64 ์Šฌ๋ผ์ด์Šค[13:36]: {sliced.decode()}")
    print(f"[*] ๊ณ ์ • ์ ‘๋‘(XOR ๋ฏธ์ ์šฉ 2๋ฐ”์ดํŠธ): {flag[:2].decode()}")
    print(f"[+] FLAG: {flag.decode()}")
    return 0
 
 
if __name__ == "__main__":
    sys.exit(main())

๋ผ์ด๋ธŒ ์„œ๋ฒ„๋ฅผ ์ƒ๋Œ€๋กœ ๋Œ๋ฆฐ ๊ฒฐ๊ณผ๋‹ค.

python3 solve.py http://host3.dreamhack.games:21647/

๋ผ์ด๋ธŒ ์„œ๋ฒ„๋ฅผ ์ƒ๋Œ€๋กœ solve.py๋ฅผ ์‹คํ–‰ํ•œ ๊ฒฐ๊ณผ. ๋ณธ๋ฌธ 2000์ž๋ฅผ ๋ฐ›์•„ base64 ์Šฌ๋ผ์ด์Šค๋ฅผ ๊ฑฐ์ณ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ถœ๋ ฅํ–ˆ๋‹ค.
๋ผ์ด๋ธŒ ์„œ๋ฒ„๋ฅผ ์ƒ๋Œ€๋กœ solve.py๋ฅผ ์‹คํ–‰ํ•œ ๊ฒฐ๊ณผ. ๋ณธ๋ฌธ 2000์ž๋ฅผ ๋ฐ›์•„ base64 ์Šฌ๋ผ์ด์Šค๋ฅผ ๊ฑฐ์ณ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ถœ๋ ฅํ–ˆ๋‹ค.

์Šฌ๋ผ์ด์Šค๊ฐ€ A6x9RSYT6xT+yc4IM+iN6oG ๋กœ ๋‚˜์™”๋‹ค. ์•ž ์„ธ ๊ธ€์ž A6x ์™€ ๋งˆ์ง€๋ง‰ G ๋ฅผ ๋ณด๋ผ. ์‚ฝ์งˆ 1 ์—์„œ ํ”Œ๋ž˜๊ทธ ํ˜•์‹๋งŒ ๊ฐ€์ง€๊ณ  ์—ญ์‚ฐํ•ด ๋’€๋˜ ๋„ค ๊ธ€์ž์™€ ์ •ํ™•ํžˆ ๊ฐ™๋‹ค. ๊ทธ๋•Œ ์„ธ์šด "25๋ฐ”์ดํŠธ ํ”Œ๋ž˜๊ทธ" ๊ฐ€์ •์ด ๋งž์•˜๋‹ค๋Š” ๋’ทํ™•์ธ์ด ๋œ๋‹ค.



โœ… ์žฌํ˜„

๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค๋Š” ์‹œ๊ฐ„์ œํ•œ์ด ์žˆ์–ด์„œ ์–ธ์  ๊ฐ€ ๋‹ซํžŒ๋‹ค. ๋ฐ›์•„ ๋‘” ๋ณธ๋ฌธ์œผ๋กœ๋„ ๋˜‘๊ฐ™์ด ๋Œ์•„๊ฐ€๊ฒŒ ์Šคํฌ๋ฆฝํŠธ ํ•˜๋‚˜๋กœ ๋ฌถ์—ˆ๋‹ค.

#!/usr/bin/env bash
# Ctrl-C (DreamHack Bronze 4 / web) โ€” ํ•œ ๋ฐฉ ์žฌํ˜„. ๋ณธ๋ฌธ ํ™•๋ณด โ†’ ์—ฐ์‚ฐ โ†’ flag ๋Œ€์กฐ.
#
#   ./reproduce.sh                                   # ์ €์žฅ๋œ text.txt ๋กœ ์˜คํ”„๋ผ์ธ ์žฌํ˜„ (ํ•ญ์ƒ ๋™์ž‘)
#   ./reproduce.sh http://hostN.dreamhack.games:PORT/  # ๋ผ์ด๋ธŒ ์„œ๋ฒ„์—์„œ ๋ณธ๋ฌธ์„ ์ƒˆ๋กœ ๋ฐ›์•„ ์žฌํ˜„
#
# โ˜… ์ธ์ž ์—†์ด ๋Œ๋ฆฌ๋ฉด ์˜คํ”„๋ผ์ธ ๋ชจ๋“œ๋‹ค. ๋ผ์ด๋ธŒ๋กœ ํ™•์ธํ•˜๋ ค๋ฉด URL ์„ ๋ฐ˜๋“œ์‹œ ๋„˜๊ธธ ๊ฒƒ โ€”
#   ๋“œ๋ฆผํ•ต ์ธ์Šคํ„ด์Šค๋Š” ์‹œ๊ฐ„์ œํ•œ์ด ์žˆ์–ด ์˜ˆ์ „ URL ์€ ์ด๋ฏธ ๋งŒ๋ฃŒ๋๋‹ค.
set -eu
cd "$(dirname "$(readlink -f "$0")")"
EXPECT=$(python3 -c "import json;print(json.load(open('๋ฌธ์ œ.json'))['flag'])" 2>/dev/null || echo '')
 
if [ $# -ge 1 ]; then
  OUT=$(timeout 120 python3 solve.py "$1" 2>&1) || true
else
  OUT=$(timeout 120 python3 solve.py --text-file text.txt 2>&1) || true
fi
 
echo "$OUT" | tail -8
FLAG=$(printf '%s' "$OUT" | grep -aoE 'WaRP\{[^}]+\}' | head -1)
if [ -n "$FLAG" ] && { [ -z "$EXPECT" ] || [ "$FLAG" = "$EXPECT" ]; }; then
  echo; echo "โœ… PASS  $FLAG"; exit 0
fi
echo; echo "โŒ FAIL (์–ป์€ ๊ฐ’: '${FLAG:-์—†์Œ}' / ๊ธฐ๋Œ€: '$EXPECT')"; exit 1
./reproduce.sh

reproduce.sh ๋ฅผ ์ธ์ž ์—†์ด ์‹คํ–‰ํ•ด ์ €์žฅํ•ด ๋‘” text.txt ๋กœ ์˜คํ”„๋ผ์ธ ์žฌํ˜„ํ•œ ๊ฒฐ๊ณผ. ๋ณธ๋ฌธ ๊ธธ์ด 2000์ž์™€ ๊ณ ์ • ์ ‘๋‘ Wa ๋ฅผ ๊ฑฐ์ณ ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋‚˜์™”๊ณ  ๊ธฐ๋Œ€๊ฐ’๊ณผ ์ผ์น˜ํ•ด PASS ๊ฐ€ ๋–ด๋‹ค.
reproduce.sh ๋ฅผ ์ธ์ž ์—†์ด ์‹คํ–‰ํ•ด ์ €์žฅํ•ด ๋‘” text.txt ๋กœ ์˜คํ”„๋ผ์ธ ์žฌํ˜„ํ•œ ๊ฒฐ๊ณผ. ๋ณธ๋ฌธ ๊ธธ์ด 2000์ž์™€ ๊ณ ์ • ์ ‘๋‘ Wa ๋ฅผ ๊ฑฐ์ณ ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋‚˜์™”๊ณ  ๊ธฐ๋Œ€๊ฐ’๊ณผ ์ผ์น˜ํ•ด PASS ๊ฐ€ ๋–ด๋‹ค.

ํŒ์ • ๋งˆ์ปค๋Š” ์ด๋ ‡๊ฒŒ ์ฝ์œผ๋ฉด ๋œ๋‹ค.

ํ™”๋ฉด์— ๋œจ๋Š” ๊ฒƒ๋œป
๋ณธ๋ฌธ ๊ธธ์ด: 2000์ž๋ณธ๋ฌธ์„ ์˜จ์ „ํžˆ ํ™•๋ณดํ–ˆ๋‹ค
๊ณ ์ • ์ ‘๋‘: Wa์ด๊ฑด ํ•ญ์ƒ ๋œฌ๋‹ค. ์„ฑ๊ณต ์‹ ํ˜ธ๊ฐ€ ์•„๋‹ˆ๋‹ค
FLAG: WaRP{...} ๋กœ ๋‹ซํž˜์—ฌ๊ธฐ๊นŒ์ง€ ์™€์•ผ ๋งž์€ ๊ฒƒ
<p> ๋ณธ๋ฌธ์„ ์ฐพ์ง€ ๋ชปํ–ˆ๋‹ค์ธ์Šคํ„ด์Šค๊ฐ€ ๋งŒ๋ฃŒ๋๋‹ค. ์ƒˆ๋กœ ๋ฐœ๊ธ‰๋ฐ›์„ ๊ฒƒ
์•Œ์•„๋ณผ ์ˆ˜ ์—†๋Š” ๋ฐ”์ดํŠธ์—ด๋ณธ๋ฌธ์— ์•ž์ชฝ ๊ณต๋ฐฑ์ด๋‚˜ ๊ฐœํ–‰์ด ์„ž์˜€๋‹ค

๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค ์—†์ด ๋”ฐ๋ผ ํ•ด ๋ณด๋ ค๋ฉด

์ด ๊ธ€์„ ์ฝ๋‹ค๊ฐ€ ์ง์ ‘ ๋ˆŒ๋Ÿฌ ๋ณด๊ณ  ์‹ถ์€๋ฐ ์ธ์Šคํ„ด์Šค๊ฐ€ ์—†์„ ์ˆ˜ ์žˆ๋‹ค. ๋“œ๋ฆผํ•ต VM ์€ ํฌ๋ ˆ๋”ง์„ ๋จน๊ณ  ์‹œ๊ฐ„์ œํ•œ๋„ ์žˆ์œผ๋‹ˆ๊นŒ.

app.py ์™€ index.html ์€ ๋ฐฐํฌ๋ณธ์— ์—†์ง€๋งŒ, Dockerfile ์˜ ํŒŒ์ผ ๊ตฌ์„ฑ๊ณผ ์‹ค์ œ ์‘๋‹ต ๋ชจ์–‘์„ ๋ณด๋ฉด ์žฌ๊ตฌ์„ฑ์ด ์–ด๋ ต์ง€ ์•Š๋‹ค. ์ตœ์†Œํ•œ์œผ๋กœ ๋‹ค์‹œ ์ผ๋‹ค.

#!/usr/bin/env python3
"""Ctrl-C ๋กœ์ปฌ ๋ณต์ œ๋ณธ.
 
app.py ๋Š” ๋ฐฐํฌ๋˜์ง€ ์•Š์•˜๋‹ค. ๊ทธ๋ž˜์„œ Dockerfile ์ด ๋„ฃ๋Š” ํŒŒ์ผ ๊ตฌ์„ฑ
(app.py / text.txt / templates/index.html)๊ณผ ์‹ค์ œ ์‘๋‹ต ๋ชจ์–‘์— ๋งž์ถฐ ์ตœ์†Œํ•œ์œผ๋กœ ๋‹ค์‹œ ์ผ๋‹ค.
text.txt ๋Š” ๋ผ์ด๋ธŒ์—์„œ ๋ฐ›์•„ ๋‘” ๋ณธ๋ฌธ ๊ทธ๋Œ€๋กœ๋ผ, ์ด ์„œ๋ฒ„๋กœ ํ’€์–ด๋„ ๊ฐ™์€ ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋‚˜์˜จ๋‹ค.
"""
from flask import Flask, render_template
 
app = Flask(__name__)
 
 
@app.route("/")
def index():
    with open("text.txt", encoding="utf-8") as f:
        text = f.read()
    return render_template("index.html", text=text)
 
 
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

ํ…œํ”Œ๋ฆฟ์€ ๋ผ์ด๋ธŒ์—์„œ ๋ฐ›์€ HTML ์„ ๊ทธ๋Œ€๋กœ ์“ฐ๋˜ ๋ณธ๋ฌธ๋งŒ ๋ณ€์ˆ˜๋กœ ๋ฐ”๊ฟจ๋‹ค. div.content ์™€ <p> ๊ตฌ์กฐ, ๊ทธ๋ฆฌ๊ณ  ๋ฐฉ์–ด ์Šคํฌ๋ฆฝํŠธ ์„ธ ๊ฐœ๋ฅผ ์œ ์ง€ํ•ด์•ผ ๋ธŒ๋ผ์šฐ์ € ์ชฝ ์‹คํ—˜๋„ ๋˜‘๊ฐ™์ด ์žฌํ˜„๋œ๋‹ค.

    <div class="content">
        <h1>์ด ๋ฌธ์ž๋“ค์„ ์ œ๊ณต๋œ ์ฝ”๋“œ์— ๋„ฃ์–ด flag๋ฅผ ํš๋“ํ•˜์„ธ์š”!!!</h1>
        <p>{{ text }}</p>
    </div>

๋„์šฐ๊ณ  ํ‘ธ๋Š” ๊ฒƒ๊นŒ์ง€ ํ•œ ๋ฒˆ์— ํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ๋‹ค. pip install flask ๋งŒ ๋ฏธ๋ฆฌ ํ•ด ๋‘๋ฉด ๋œ๋‹ค.

#!/usr/bin/env bash
# ๋กœ์ปฌ ๋ณต์ œ๋ณธ์„ 5000๋ฒˆ ํฌํŠธ๋กœ ๋„์šฐ๊ณ , solve.py ๋ฅผ ๊ทธ ์„œ๋ฒ„์— ๋ถ™์—ฌ flag ๊นŒ์ง€ ํ™•์ธํ•œ ๋’ค ๋‚ด๋ฆฐ๋‹ค.
#   pip install flask   (ํ•œ ๋ฒˆ๋งŒ)
set -eu
cd "$(dirname "$(readlink -f "$0")")"
python3 app.py > /tmp/ctrlc_local.log 2>&1 &
PID=$!
trap 'kill $PID 2>/dev/null || true' EXIT
for _ in $(seq 1 40); do
  curl -s -o /dev/null http://127.0.0.1:5000/ && break || sleep 0.25
done
python3 ../solve.py http://127.0.0.1:5000/
./local/run_local.sh

๋กœ์ปฌ ๋ณต์ œ ์„œ๋ฒ„๋กœ ์žฌํ˜„ํ•œ ๊ฒฐ๊ณผ. 127.0.0.1:5000์—์„œ ๋ณธ๋ฌธ์„ ๋ฐ›์•„ ๋ผ์ด๋ธŒ์™€ ๋™์ผํ•œ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ถœ๋ ฅํ–ˆ๋‹ค.
๋กœ์ปฌ ๋ณต์ œ ์„œ๋ฒ„๋กœ ์žฌํ˜„ํ•œ ๊ฒฐ๊ณผ. 127.0.0.1:5000์—์„œ ๋ณธ๋ฌธ์„ ๋ฐ›์•„ ๋ผ์ด๋ธŒ์™€ ๋™์ผํ•œ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ถœ๋ ฅํ–ˆ๋‹ค.

๋ณธ๋ฌธ ์ถœ์ฒ˜๋งŒ 127.0.0.1:5000 ์œผ๋กœ ๋ฐ”๋€Œ์—ˆ๊ณ  ์Šฌ๋ผ์ด์Šค๋„ ํ”Œ๋ž˜๊ทธ๋„ ๋ผ์ด๋ธŒ์™€ ๊ฐ™๋‹ค. text.txt ๊ฐ€ ๊ฐ™์€ ํŒŒ์ผ์ด๋‹ˆ ๋‹น์—ฐํ•˜์ง€๋งŒ, ์ด๊ฑธ ํ™•์ธํ•ด ๋‘๋ฉด "์„œ๋ฒ„๊ฐ€ ํ•˜๋Š” ์ผ์€ ์ด ํŒŒ์ผ์„ ๋ Œ๋”ํ•ด์„œ ๋‚ด๋ ค๋ณด๋‚ด๋Š” ๊ฒƒ๋ฟ"์ด๋ผ๋Š” ๊ฒŒ ์‹ค๋ฌผ๋กœ ์ฆ๋ช…๋œ๋‹ค.



๐Ÿ”“ ์šฐํšŒ ๊ฒฝ๋กœ๊ฐ€ ํ•˜๋‚˜๊ฐ€ ์•„๋‹Œ ์ด์œ 

curl ์„ ์ผ์ง€๋งŒ, ์ด ๋ฌธ์ œ๋ฅผ ํ‘ธ๋Š” ๊ธธ์€ ์—ฌ๋Ÿฟ์ด๋‹ค. ์–ด๋–ค ๊ฒŒ ๋˜๊ณ  ์–ด๋–ค ๊ฒŒ ์•ˆ ๋˜๋Š”์ง€๋ฅผ ์ •๋ฆฌํ•ด ๋‘๋ฉด ๋ฐฉ์–ด๊ฐ€ ์™œ ์‹คํŒจํ–ˆ๋Š”์ง€๊ฐ€ ๋” ๋ถ„๋ช…ํ•ด์ง„๋‹ค.

๊ธฐ์ค€์€ ํ•˜๋‚˜๋‹ค. ๊ทธ ๊ฒฝ๋กœ์—์„œ ํŽ˜์ด์ง€ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹คํ–‰๋  ๊ธฐํšŒ๊ฐ€ ์žˆ๋А๋ƒ.

๊ฒฝ๋กœ๋˜๋‚˜์ด์œ 
curl ยท wgetโ—‹JS ๋ฅผ ์•„์˜ˆ ์‹คํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋ฐฉ์–ด ์ฝ”๋“œ๋Š” ๊ทธ๋ƒฅ ํ…์ŠคํŠธ๋กœ ์ง€๋‚˜๊ฐ„๋‹ค
view-source:โ—‹์†Œ์Šค ๋ณด๊ธฐ๋Š” ๋ Œ๋” ํŠธ๋ฆฌ๊ฐ€ ์•„๋‹ˆ๋ผ ์‘๋‹ต ์›๋ฌธ์„ ๋ณด์—ฌ ์ค€๋‹ค
๊ฐœ๋ฐœ์ž ๋„๊ตฌ ์ฝ˜์†”โ—‹๋ธŒ๋ผ์šฐ์ € UI ๋ผ ํŽ˜์ด์ง€๊ฐ€ ๋ชป ๊ฑด๋“œ๋ฆฐ๋‹ค. ์•ž์—์„œ ์‹ค์ œ๋กœ ์ฝ์–ด ๋ƒˆ๋‹ค
๋ธŒ๋ผ์šฐ์ € JS ๋„๊ธฐโ—‹์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š์œผ๋‹ˆ ํ•ธ๋“ค๋Ÿฌ๋„ ์•ˆ ๊ฑธ๋ฆฐ๋‹ค. ๋ณธ๋ฌธ์€ ๊ทธ๋Œ€๋กœ ๋ณด์ธ๋‹ค
ํŽ˜์ด์ง€ ์ €์žฅ(Ctrl+S)โ—‹์ €์žฅ์€ ๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋Šฅ์ด๋ผ ํŽ˜์ด์ง€๊ฐ€ ๊ฐœ์ž…ํ•  ์ง€์ ์ด ์—†๋‹ค
ํ•ธ๋“ค๋Ÿฌ null ๋Œ€์ž…โ—‹์•ž์—์„œ ํ•œ ๊ฒƒ. ์‚ฌ์šฉ์ž ์ชฝ ์ƒํƒœ๋ผ ๋ฎ์–ด์“ธ ์ˆ˜ ์žˆ๋‹ค
๊ทธ๋ƒฅ ๋“œ๋ž˜๊ทธยท์šฐํด๋ฆญโœ—์ด๊ฑด ์‹ค์ œ๋กœ ๋ง‰ํžŒ๋‹ค. ์ด ๋ฐฉ์–ด๊ฐ€ ์œ ์ผํ•˜๊ฒŒ ์„ฑ๊ณตํ•˜๋Š” ๊ตฌ๊ฐ„์ด๋‹ค

ํ‘œ์—์„œ โœ— ๊ฐ€ ํ•œ ์ค„๋ฟ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ ํ•œ ์ค„์ด ์ด ๋ฐฉ์–ด๊ฐ€ ์ƒ์ •ํ•œ ์œ ์ผํ•œ ๊ณต๊ฒฉ์ž๋‹ค. "๋งˆ์šฐ์Šค๋กœ ๊ธ์–ด์„œ Ctrl+C ๋ฅผ ๋ˆ„๋ฅด๋Š” ์‚ฌ๋žŒ" ๋ง์ด๋‹ค.

์ด๊ฑด ๋ฐฉ์–ด๊ฐ€ ํ—ˆ์ˆ ํ•ด์„œ ์ƒ๊ธด ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋‹ค. ์„ธ ํ•ธ๋“ค๋Ÿฌ๋Š” ์ œ ํ•  ์ผ์„ ์ •ํ™•ํžˆ ํ–ˆ๋‹ค. ๋ฌธ์ œ๋Š” ๋ง‰์œผ๋ ค๋Š” ๋Œ€์ƒ๊ณผ ์‹ค์ œ๋กœ ๋ง‰์„ ์ˆ˜ ์žˆ๋Š” ๋Œ€์ƒ์ด ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ฌ๋ž๋‹ค๋Š” ๋ฐ ์žˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ HTML ๋กœ ๋‚ด๋ ค๋ณด๋‚ธ ์‹œ์ ์— ์ด๋ฏธ ์ƒ๋Œ€์—๊ฒŒ ์ค€ ๊ฒƒ์ด๊ณ , ๊ทธ ๋’ค์— ๋ถ™์ด๋Š” ๊ฑด ๋ฌด์—‡์ด๋“  "๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฃฐ์ง€"์— ๋Œ€ํ•œ ๊ถŒ๊ณ ๊ฐ€ ๋œ๋‹ค.

๊ฐ™์€ ์ด์œ ๋กœ, ํ”ํžˆ ๊ฐ™์ด ์“ฐ์ด๋Š” ๋‹ค๋ฅธ ์žฅ์น˜๋“ค๋„ ์ด ๋ฌธ์ œ์—์„œ๋Š” ๋ฌด์˜๋ฏธํ•˜๋‹ค. user-select: none CSS ๋Š” ๋“œ๋ž˜๊ทธ๋งŒ ๋ง‰์ง€ ์‘๋‹ต ๋ฐ”์ดํŠธ๋ฅผ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค. ํ…์ŠคํŠธ๋ฅผ ์ด๋ฏธ์ง€๋กœ ๋ Œ๋”ํ•˜๋ฉด curl ๋กœ๋Š” ๋ชป ์ฝ์ง€๋งŒ ๊ทธ๊ฑด ๋ฐ์ดํ„ฐ๋ฅผ ์‹ค์ œ๋กœ ์•ˆ ๋‚ด๋ ค๋ณด๋‚ธ ๊ฒƒ์— ๊ฐ€๊น๋‹ค. ๋ฌธ์ž๋ฅผ ์กฐ๊ฐ๋‚ด CSS ๋กœ ์žฌ๋ฐฐ์—ดํ•˜๋Š” ๋ฐฉ์‹๋„ ๊ฒฐ๊ตญ ์กฐ๊ฐ์ด ๋‹ค ์‘๋‹ต ์•ˆ์— ์žˆ๋‹ค.


๐Ÿ“ ๊ฒฐ๋ก 

ํด๋ผ์ด์–ธํŠธ ์ธก ์ œ์–ด๋Š” UI ์ •์ฑ…์ด์ง€ ์ ‘๊ทผ ํ†ต์ œ๊ฐ€ ์•„๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ์˜ ๋ฐฉ์–ด๋Š” ์…‹ ๋‹ค ์ •์ƒ ๋™์ž‘ํ–ˆ๋‹ค. ์šฐํด๋ฆญ์€ ์•ˆ ๋๊ณ  ๋“œ๋ž˜๊ทธ๋„ ์•ˆ ๋๋‹ค. ์‹คํŒจํ•œ ๊ฑด ๊ตฌํ˜„์ด ์•„๋‹ˆ๋ผ ๋ฐฐ์น˜๋‹ค. ์ง€ํ‚ค๋ ค๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์ด๋ฏธ ํด๋ผ์ด์–ธํŠธ์— ๋‚ด๋ ค๊ฐ€ ์žˆ์—ˆ์œผ๋‹ˆ, ๊ทธ ์œ„์— ๋ฌด์—‡์„ ๋ง๋Œ€๋“  ์‚ฌ์šฉ์ž ์ชฝ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ถ€ํƒํ•˜๋Š” ๊ผด์ด ๋œ๋‹ค. ์ฝ˜์†” ํ•œ ์ค„๋กœ null ์„ ๋Œ€์ž…ํ•˜๋ฉด ๋์ด๊ณ , ์• ์ดˆ์— curl ์€ ๊ทธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ฝ์ง€๋„ ์•Š๋Š”๋‹ค.

"๋ดค์ง€๋งŒ ๊ฐ€์ ธ๊ฐ€์ง„ ๋ชปํ•˜๊ฒŒ"๋Š” ์›น์—์„œ ์„ฑ๋ฆฝํ•˜์ง€ ์•Š๋Š”๋‹ค.

๋ Œ๋”ํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ค€ ๊ฒƒ์€ ์ด๋ฏธ ์ค€ ๊ฒƒ์ด๋‹ค. ์ •๋ง ๋ชป ๊ฐ€์ ธ๊ฐ€๊ฒŒ ํ•ด์•ผ ํ•œ๋‹ค๋ฉด ์•ˆ ๋‚ด๋ ค๋ณด๋‚ด๋Š” ์ˆ˜๋ฐ–์— ์—†๋‹ค. ์„œ๋ฒ„์—์„œ ์ž๋ฅด๊ฑฐ๋‚˜, ์ธ์ฆยท์ธ๊ฐ€๋ฅผ ๊ฑธ๊ฑฐ๋‚˜, ์›Œํ„ฐ๋งˆํฌ์ฒ˜๋Ÿผ ์œ ์ถœ ํ›„ ์ถ”์ ์œผ๋กœ ๋ชฉํ‘œ๋ฅผ ๋ฐ”๊พธ๊ฑฐ๋‚˜. DRM ์ด ๋ถ™์€ ์ŠคํŠธ๋ฆฌ๋ฐ์ด ํ™”๋ฉด ๋ฐ– ๋ณตํ˜ธ๋ฅผ ๊ทธ๋ ‡๊ฒŒ ์–ด๋ ต๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ๋„ ๊ฐ™์€ ์ด์œ ๋‹ค.

๊ทธ๋Ÿผ ์ด ํŽ˜์ด์ง€๋ฅผ ์‹ค์ œ๋กœ ์ง€ํ‚ค๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ–ˆ์„๊นŒ. ๋ชฉํ‘œ๋ฅผ ๋ญ˜๋กœ ์žก๋А๋ƒ์— ๋”ฐ๋ผ ๋‹ต์ด ๊ฐˆ๋ฆฐ๋‹ค.

๋Œ€๋Ÿ‰ ์ˆ˜์ง‘์„ ๋Šฆ์ถ”๋Š” ๊ฒŒ ๋ชฉํ‘œ๋ผ๋ฉด โ€” ์„œ๋ฒ„์—์„œ ํ†ต์ œํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๋“ค๋กœ ์˜ฎ๊ธด๋‹ค. ์„ธ์…˜ยท์ธ์ฆ์„ ๊ฑธ์–ด ๋ˆ„๊ฐ€ ๋ฐ›์•„ ๊ฐ”๋Š”์ง€ ๋‚จ๊ธฐ๊ณ , IPยท๊ณ„์ • ๋‹จ์œ„๋กœ ์š”์ฒญ ๋นˆ๋„๋ฅผ ์ œํ•œํ•˜๊ณ , ํ•œ ๋ฒˆ์— ์ฃผ๋Š” ์–‘์„ ์ชผ๊ฐœ ํŽ˜์ด์ง€๋„ค์ด์…˜ํ•œ๋‹ค. ์ „๋ถ€ ์‘๋‹ต์„ ๋‚ด๋ณด๋‚ด๋Š” ์ชฝ์—์„œ ๊ฒฐ์ •๋˜๋Š” ๊ฒƒ์ด๋ผ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ญ˜ ํ•˜๋“  ์šฐํšŒํ•  ์ˆ˜ ์—†๋‹ค. ๋ง‰์ง€๋Š” ๋ชปํ•ด๋„ ๋น„์šฉ์€ ํ™•์‹คํžˆ ์˜ฌ๋ผ๊ฐ„๋‹ค.

์œ ์ถœ์ž๋ฅผ ํŠน์ •ํ•˜๋Š” ๊ฒŒ ๋ชฉํ‘œ๋ผ๋ฉด โ€” ์‚ฌ์šฉ์ž๋งˆ๋‹ค ๋ฏธ์„ธํ•˜๊ฒŒ ๋‹ค๋ฅธ ์‚ฌ๋ณธ์„ ์ค€๋‹ค. ๊ณต๋ฐฑ ๋ฌธ์ž๋ฅผ ๋ฐ”๊พธ๊ฑฐ๋‚˜ ๋ˆˆ์— ์•ˆ ๋„๋Š” ๊ตฌ๊ฐ„์— ์‹๋ณ„์ž๋ฅผ ์‹ฌ๋Š” ์‹์ด๋‹ค. ๋ณต์‚ฌ๋Š” ์—ฌ์ „ํžˆ ๋˜์ง€๋งŒ, ์œ ์ถœ๋œ ์‚ฌ๋ณธ์„ ๋ณด๋ฉด ๋ˆ„๊ฐ€ ๋ฐ›์•„ ๊ฐ„ ๊ฒƒ์ธ์ง€ ์—ญ์ถ”์ ์ด ๋œ๋‹ค. ๋ฌธ์„œยท๊ณ„์•ฝ์„œ ์ชฝ์—์„œ ์‹ค์ œ๋กœ ์“ฐ๋Š” ๋ฐฉ์‹์ด๋‹ค.

์ •๋ง๋กœ ์›๋ฌธ์„ ์•ˆ ์ฃผ๋Š” ๊ฒŒ ๋ชฉํ‘œ๋ผ๋ฉด โ€” ์• ์ดˆ์— ์›๋ฌธ์„ ์•ˆ ๋ณด๋‚ธ๋‹ค. ์„œ๋ฒ„์—์„œ ์ด๋ฏธ์ง€๋กœ ๋ Œ๋”ํ•ด ๋‚ด๋ ค๋ณด๋‚ด๊ฑฐ๋‚˜, ํ•„์š”ํ•œ ๊ณ„์‚ฐ์„ ์„œ๋ฒ„์—์„œ ๋๋‚ด๊ณ  ๊ฒฐ๊ณผ๋งŒ ์ค€๋‹ค. ์ด ๋ฌธ์ œ๋กœ ์น˜๋ฉด text.txt ๋ฅผ ์•„์˜ˆ ์•ˆ ๋ณด๋‚ด๊ณ , ํ•ด์‹œ ๊ณ„์‚ฐ๊นŒ์ง€ ์„œ๋ฒ„๊ฐ€ ํ•œ ๋’ค ์‚ฌ์šฉ์ž์—๊ฒŒ๋Š” ๊ฒฐ๊ณผ๋งŒ ๋Œ๋ ค์ฃผ๋ฉด ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์• ์ดˆ์— ๊ฐ€์ ธ๊ฐˆ ์›๋ฌธ์ด ํด๋ผ์ด์–ธํŠธ์— ์—†๋‹ค.

์…‹ ๋‹ค ๊ณตํ†ต์ ์ด ์žˆ๋‹ค. ๊ฒฐ์ •์ด ์„œ๋ฒ„์—์„œ ๋‚ด๋ ค์ง„๋‹ค. ๋ฐ˜๋Œ€๋กœ ์ด ๋ฌธ์ œ์˜ ๋ฐฉ์–ด๋Š” ๊ฒฐ์ •์„ ์ „๋ถ€ ํด๋ผ์ด์–ธํŠธ์— ๋งก๊ฒผ๋‹ค. ๊ทธ๋ž˜์„œ ํด๋ผ์ด์–ธํŠธ๋ฅผ ๋ฐ”๊พธ๊ฑฐ๋‚˜ ์•„์˜ˆ ์•ˆ ์“ฐ๋Š” ์ˆœ๊ฐ„ ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ๋‚จ๋Š”๋‹ค.

๊ฐœ๋ฐœ์ž ๋„๊ตฌ ์ฐจ๋‹จ์€ ํŠนํžˆ ๋ฌด๋ ฅํ•˜๋‹ค.

์ด ํŽ˜์ด์ง€๋Š” F12 ์™€ Ctrl+Shift+IยทJ ๋ฅผ keydown ์—์„œ preventDefault ํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๊ฐ€ ์—ด๋ฆฐ ์ƒํƒœ๋กœ ์‹œ์ž‘ํ•ด ๋ฒ„๋ฆฌ๋ฉด ํŽ˜์ด์ง€๊ฐ€ ๊ฐœ์ž…ํ•  ์ง€์ ์ด ์—†๋‹ค. ๋ฉ”๋‰ด๋กœ ์—ด์–ด๋„ ๋˜๊ณ , ์•„์˜ˆ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์•ˆ ์จ๋„ ๋œ๋‹ค. ๋ง‰์„ ์ˆ˜ ์žˆ๋Š” ๊ฑด "๊ทธ ํ‚ค๋ฅผ ๊ทธ ํƒญ์—์„œ ๋ˆŒ๋ €์„ ๋•Œ"๋ฟ์ด๋‹ค.

ํ˜•์‹์ด ๋งž๋Š” ๊ฒƒ๊ณผ ๊ฐ’์ด ๋งž๋Š” ๊ฒƒ์€ ๋‹ค๋ฅด๋‹ค.

์ด ๋ฌธ์ œ์—์„œ ์ œ์ผ ์žฌ๋ฏธ์žˆ์—ˆ๋˜ ๋ถ€๋ถ„์ด๋‹ค. 25๋ฐ”์ดํŠธ ์ƒ์ˆ˜์™€ 23๋ฐ”์ดํŠธ XOR ์ด๋ผ๋Š” ์ž๋ฆฌ์ˆ˜ ์ฐจ์ด ๋•Œ๋ฌธ์— ์–ด๋–ค ์ž…๋ ฅ์„ ๋„ฃ์–ด๋„ ์ถœ๋ ฅ์ด WaRP{ ์˜ ์•ž ๋‘ ๊ธ€์ž๋กœ ์‹œ์ž‘ํ•œ๋‹ค. ์ ‘๋‘๋งŒ ๋ณด๊ณ  ๋งž์•˜๋‹ค๊ณ  ํŒ๋‹จํ•˜๋ฉด ํ‹€๋ฆฐ ๋‹ต์„ ๋ถ™๋“ค๊ฒŒ ๋œ๋‹ค. ๊ฒ€์ฆ์— ์“ธ ์ง€ํ‘œ๋Š” XOR ์„ ์‹ค์ œ๋กœ ํ†ต๊ณผํ•œ ์ž๋ฆฌ์—์„œ ๊ณจ๋ผ์•ผ ํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ๋‹ซ๋Š” } ์˜€๋‹ค.

๋ง‰ํžŒ ์ด์œ ๋ฅผ ๊ตฌ๋ถ„ํ•ด์„œ ์ ์–ด ๋‘๋ฉด ๋‹ค์Œ์ด ๋นจ๋ผ์ง„๋‹ค.

์ด ๋ฌธ์ œ๋Š” ๋ฉฐ์น  ๋ฌตํ˜€ ๋’€๋Š”๋ฐ, ์‹ค๋ ฅ์ด ๋ชจ์ž๋ผ์„œ๊ฐ€ ์•„๋‹ˆ๋ผ VM ํฌ๋ ˆ๋”ง์ด ์—†์–ด์„œ์˜€๋‹ค. "์˜คํ”„๋ผ์ธ ๋ถ„์„ ๋, ์„œ๋ฒ„๋งŒ ์žˆ์œผ๋ฉด ๋จ"์ด๋ผ๊ณ  ๋‚จ๊ฒจ ๋’€๋”๋‹ˆ ํฌ๋ ˆ๋”ง์ด ์ฐจ์ž๋งˆ์ž ์„œ๋ฒ„ ์ผœ๊ณ  ํ”Œ๋ž˜๊ทธ๊นŒ์ง€ ๋ช‡ ๋ถ„์ด ๊ฑธ๋ ธ๋‹ค. ๋ง‰ํžŒ ์ง€์ ์„ "๋ชป ํ’€์—ˆ์Œ"์œผ๋กœ ๋ญ‰๋šฑ๊ทธ๋ฆฌ๋ฉด ๋‹ค์Œ์— ์—ด์—ˆ์„ ๋•Œ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ๋œฏ๊ฒŒ ๋œ๋‹ค.

์ด ๊ธ€์ด ๋„์›€์ด ๋๋‚˜์š”?

Comments

๋Œ“๊ธ€

0๊ฐœ

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

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

Related

๊ด€๋ จ ๊ธ€

3๊ฐœ
[๐Ÿฅ‰ Bronze 1] ๊ฒ€์ฆ์‹์„ ๋ธŒ๋ผ์šฐ์ € ๋Œ€์‹  ๋‚ด๊ฐ€ ๊ณ„์‚ฐํ•˜๊ธฐ โ€” DreamHack funjs ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 1] ๊ฒ€์ฆ์‹์„ ๋ธŒ๋ผ์šฐ์ € ๋Œ€์‹  ๋‚ด๊ฐ€ ๊ณ„์‚ฐํ•˜๊ธฐ โ€” DreamHack funjs ํ’€์ด

input ๊ฐ’์„ ๊ฒ€์‚ฌํ•˜๋Š” JS๊ฐ€ ๋‚œ๋…ํ™”๋ผ ์žˆ์ง€๋งŒ, ์‹ค์ œ๋กœ ๊ฐ€๋ ค์ง„ ๊ฑด charCodeAtยทlength ๊ฐ™์€ ๋ฉ”์„œ๋“œ ์ด๋ฆ„๋ฟ์ด๋‹ค. ์ •๋‹ต์„ ๋งŒ๋“œ๋Š” ๋‘ ์ˆซ์ž ๋ฐฐ์—ด๊ณผ ์‚ฌ์น™์—ฐ์‚ฐ ์‚ฌ์ดํด์€ ํ‰๋ฌธ ๊ทธ๋Œ€๋กœ ๋ฐฐ๋‹ฌ๋˜๋ฏ€๋กœ, ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ•  ๊ณ„์‚ฐ์„ ํŒŒ์ด์ฌ์œผ๋กœ ๊ทธ๋Œ€๋กœ ์˜ฎ๊ฒจ ์‹คํ–‰ํ•˜๋ฉด ๊ทธ๊ฒŒ ๊ณง ํ”Œ๋ž˜๊ทธ๋‹ค.
#dreamhack#ctf#web+5
2026-07-06#dreamhack +4
[๐ŸŒฑ ์ƒˆ์‹น] ํ˜ธ๋ฐ•์„ ๋งŒ ๋ฒˆ ๊นŽ์œผ๋ฉด ๋–จ์–ด์ง€๋Š” ํ”Œ๋ž˜๊ทธ โ€” DreamHack Carve Party ํ’€์ด
blog

[๐ŸŒฑ ์ƒˆ์‹น] ํ˜ธ๋ฐ•์„ ๋งŒ ๋ฒˆ ๊นŽ์œผ๋ฉด ๋–จ์–ด์ง€๋Š” ํ”Œ๋ž˜๊ทธ โ€” DreamHack Carve Party ํ’€์ด

์„œ๋ฒ„๋„ ๋ฐฑ์—”๋“œ๋„ ์—†๋Š” HTML ํ•œ ์žฅ์งœ๋ฆฌ ๋ฌธ์ œ. ํ˜ธ๋ฐ•์„ 10000๋ฒˆ ํด๋ฆญํ•˜๋ฉด canvas์— ํ”Œ๋ž˜๊ทธ๊ฐ€ ๊ทธ๋ ค์ง€๋Š”๋ฐ, ๊ทธ ํ”Œ๋ž˜๊ทธ ๋ฐ”์ดํŠธ๋Š” ํด๋ฆญ 100๋ฒˆ๋งˆ๋‹ค ํ•œ ๋ฒˆ์”ฉ XOR ๋ณ€ํ™˜์„ ๊ฑฐ์นœ๋‹ค. ํ‚ค๋กœ ์“ฐ์ด๋Š” pie ๋ณ€์ˆ˜๊ฐ€ ํ•จ์ˆ˜ ๋ฐ– ์ „์—ญ์ด๋ผ ๋ฐฐ์น˜ ์‚ฌ์ด์— ๊ฐ’์ด ์ด์–ด์ง„๋‹ค๋Š” ์ ๋งŒ ์žก์œผ๋ฉด, ์†์œผ๋กœ ๋งŒ ๋ฒˆ ๋ˆ„๋ฅด๋Š” ๋Œ€์‹  100๋ฐฐ์น˜๋ฅผ ๊ทธ๋Œ€๋กœ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•ด์„œ ํ”Œ๋ž˜๊ทธ๋ฅผ ๊บผ๋‚ผ ์ˆ˜ ์žˆ๋‹ค.
#dreamhack#ctf#web+4
2026-06-22#dreamhack +4
[๐Ÿฅ‰ Bronze 2] ์•”ํ˜ธ๋„ ํ”Œ๋ž˜๊ทธ๋„ .data ์— ๋ˆ„์›Œ ์žˆ๋‹ค โ€” DreamHack Gyul Brix Calculator ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 2] ์•”ํ˜ธ๋„ ํ”Œ๋ž˜๊ทธ๋„ .data ์— ๋ˆ„์›Œ ์žˆ๋‹ค โ€” DreamHack Gyul Brix Calculator ํ’€์ด

๋‹น๋„๋ฅผ ์ž…๋ ฅ๋ฐ›๋Š” ์ฒ™ํ•˜๋Š” 32๋น„ํŠธ PE ์•ˆ์—, ๊ด€๋ฆฌ์ž ์•”ํ˜ธ์™€ ํ”Œ๋ž˜๊ทธ๊ฐ€ ๊ฐ๊ฐ ๋‹จ์ผ๋ฐ”์ดํŠธ XOR ํ•œ ๊ฒน๋งŒ ์“ด ์ฑ„ .data ์— ๋‚˜๋ž€ํžˆ ๋ˆ„์›Œ ์žˆ๋‹ค. ํ‚ค๊ฐ€ ์ฝ”๋“œ ์•ˆ ์ฆ‰์น˜๊ฐ’์ด๋ผ strings ๋กœ๋Š” ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ์žกํžˆ๊ณ , ๋‘ ๋ธ”๋กญ์„ ํ‚คยท์•”ํ˜ธ๋ฌธ ์Œ์œผ๋กœ ๋„˜๊ฒจ์งš์œผ๋ฉด ๋” ํ—ค๋งจ๋‹ค. ๋””์Šค์–ด์…ˆ๋ธ”๋ฆฌ์—์„œ 0x55 ์™€ 0x77 ์„ ์ฝ์–ด๋‚ด๋ฉด ๋๋‚œ๋‹ค.
#dreamhack#ctf#reversing+6
2026-08-17#dreamhack +3