๋ฌธ์ : DreamHack โ Ctrl-C ๋ถ๋ฅ: web ๋์ด๋: ๐ฅ Bronze 4 FLAG:
WaRP{1_w4n7_5h0r7cu7_k3y}
๋ฌธ์ ์ค๋ช ์ ๋ฑ ํ ์ค์ด๋ค. "Copy it if you can!"
๋ค์ด๊ฐ ๋ณด๋ฉด ์ ๋ง๋ก ๊ทธ ๋ง๋๋ก๋ค. ํ๋ฉด ๊ฐ๋ ๋๋คํด ๋ณด์ด๋ ๋ฌธ์์ด์ด ๊น๋ ค ์๊ณ , ๋๋๊ทธ๋ ์ ๋๊ณ ์ฐํด๋ฆญ๋ ์ ๋จน๋๋ค.

๋ฌธ์ ๊ฐ์
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ๋ฌธ์ ๋ช | 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.htmlDockerfile ์ด ์ธ ํ์ผ์ ์ด๋ฏธ์ง์ ๋ฃ๋๋ฐ, ๊ทธ ์
์ค ์ด๋ ๊ฒ๋ ๋ฐฐํฌ๋ณธ์ ์๋ค.
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])))ํ ์ค์ง๋ฆฌ๋ค. ์์ชฝ๋ถํฐ ํ๋ฉด ์ด๋ ๊ฒ ๋๋ค.
- ํ์ค์
๋ ฅ์ ๋ฐ์
rstrip()โ ๋ค์ชฝ ๊ณต๋ฐฑ๊ณผ ๊ฐํ๋ง ์๋ผ๋ธ๋ค. - UTF-8 ๋ก ์ธ์ฝ๋ฉํด sha256 โ 32๋ฐ์ดํธ ๋ค์ด์ ์คํธ.
- base64 ์ธ์ฝ๋ฉ โ 44๊ธ์(ํจ๋ฉ
=ํฌํจ). [13:36]์ผ๋ก ์๋ผ 23๋ฐ์ดํธ.- ๊ทธ๊ฑธ ํฐ ์ ์๋ก ๋ฐ๊ฟ ์์ ํ๋์ XOR.
- ๋ค์ ๋ฐ์ดํธ๋ก ๋๋ ค ์ถ๋ ฅ.
์๋ฒ ์๋ต์ ๋จผ์ ๋ดค๋ค.
curl -s -D - -o /dev/null http://host3.dreamhack.games:21647/
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
์ ๋ถ 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"
์ธ ๊ฐ์ง ๋ฐฉ์ด๊ฐ ์ฃผ์๊น์ง ๋ถ์ด์ ๊ทธ๋๋ก ์๋ค.
// ์ค๋ฅธ์ชฝ ํด๋ฆญ ๋ฐฉ์ง
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 ๊ฐ ์ผํ๊ณ ์๋ค.
๋ค์์ ๋๋๊ทธ. ๋ฌธ๋จ ์ฒซ ์ค ์ผ์ชฝ์์ ๋๋ฌ ์ ์งธ ์ค ์ค๋ฅธ์ชฝ๊น์ง ๋์๋ค.
# ๋ง์ฐ์ค๋ฅผ ๋๋ฅธ ์ฑ๋ก ๋ค ๋ฒ์ ๊ฑธ์ณ ์ด๋์ํจ ๋ค ๋๋ค โ ์ฌ๋ ๋๋๊ทธ์ ๊ฐ์ ๊ฒฝ๋ก
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}")
ํ์ด๋ผ์ดํธ๊ฐ ํ ๊ธ์๋ ์๋ค. ์คํฌ๋ฆฝํธ๊ฐ ์ฐ์ ๊ฐ๋ ์ ํ ๊ธธ์ด = 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}")
์ธ ์ค์ด ํ๋๊ฒ ์กํ๋ค. ์ฝ์๋ก ์ฐ ๊ฐ์ ์ ํ ๊ธธ์ด = 260.
0 ์์ 260 ์ผ๋ก ๋ฐ๋ ๊ฒ ๋ง๊ณ ๋ ์๋ฌด๊ฒ๋ ์ ๊ฑด๋๋ ธ๋ค.
๊ฐ์ ์ํ์์ ์ฐํด๋ฆญ๋ ๋ค์ ํด ๋ดค๋ค.

๋ฉ๋ด ๋งจ ์๊ฐ ๋ณต์ฌ 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)]
(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
๊ฒฐ๊ณผ๋ ๋ฐ์ ์ฑ๊ณต, ๋ฐ์ ์คํจ์๋ค.
์ฑ๊ณตํ ์ชฝ. ์๋ ค์ง ๋ค ์๋ฆฌ๊ฐ ์ ๋ถ ์ ํจํ 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
| ์ ๋ ฅ ๋ณํ | ๊ฒฐ๊ณผ |
|---|---|
| ์๋ฌธ ๊ทธ๋๋ก | 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
์ฌ๋ผ์ด์ค๋ ๋ค์ด์ ์คํธ์ ๋นํธ 78~215, ๊ณง 138๋นํธ๋ฅผ ๋ฎ๋๋ค. ์ ์ฒด์ 53.9% ๋ค.
๋ฐ์ดํธ๋ก ๋ณด๋ฉด 9๋ฒ๋ถํฐ 26๋ฒ๊น์ง 18๋ฐ์ดํธ์ ๊ฑธ์น๋ค.
๊ทธ๋ฆฌ๊ณ 43๋ฒ ์๋ฆฌ์ ํจ๋ฉ = ์ 36 ๋ฏธ๋ง์ด ์๋๋ผ ์ ๊ฑธ๋ฆฐ๋ค โ ๊ทธ๋์ ์๋ฆฐ 23๊ธ์๊ฐ
์ ๋ถ ์ง์ง base64 ๋ฌธ์๋ค. ์ฝ์ง 1 ์์ ํ๋ณด๋ฅผ 64์ข
์ผ๋ก ์ก์ ์ ์์๋ ๊ทผ๊ฑฐ๋ค.
์ ๋ฐ์ด ๋๊ฒ ๋ณด์ธ๋ค๊ณ ํด๋ ์๋ฌธ์ ๋๋๋ฆด ๋ฐฉ๋ฒ์ ์๋ค. sha256 ์ด ๋จ๋ฐฉํฅ์ด๋ผ ๋ช ๋นํธ๋ฅผ ๋ณด๋ ๊ฐ๋ค. ๊ทธ๋ฌ๋ ์ฐ๋ฆฌ๊ฐ ํ ์ผ์ ๊ณ์ฐ์ ๋ค์ง๋ ๊ฒ ์๋๋ผ ์ ๋ ฅ์ ์์ ๋ฃ๋ ๊ฒ์ด๋ค. ๋ฌธ์ ๊ฐ ์น ์นดํ ๊ณ ๋ฆฌ์ ์๋ ์ด์ ๋ค.
ํํธ ์์๋ ์ด๋ ๋ค.
548488142063681088110499188198346596132432266189304030893626
-> bit_length = 199
-> (199 + 7) // 8 = 25 ๋ฐ์ดํธ
-> 5761136603080d246d3a012761434911032a381c362505163a25๋ฐ์ดํธ์ง๋ฆฌ์ 23๋ฐ์ดํธ์ง๋ฆฌ๋ฅผ XOR ํ๋ค. ์๋ฆฌ์๊ฐ ๋ ๋ฐ์ดํธ ์ด๊ธ๋๋ค.
์ ์ XOR ์ด๋ ์ค๋ฅธ์ชฝ ๋์ ๊ธฐ์ค์ผ๋ก ๋ง์ถฐ์ง๋ค. 23๋ฐ์ดํธ์ง๋ฆฌ๋ ์์ ๋ ๋ฐ์ดํธ ์๋ฆฌ์ ์๋ฌด ๊ฐ๋ ์๋ค โ 0 ์ด๋ค. ๊ทธ๋์ ๊ฒฐ๊ณผ์ ์์ ๋ ๋ฐ์ดํธ๋ ์์์ ์์ ๋ ๋ฐ์ดํธ๊ฐ ๊ทธ๋๋ก ์ด์๋จ๋๋ค.
๊ทธ ๋ ๋ฐ์ดํธ๊ฐ 0x57 0x61, ๊ณง Wa ๋ค.

๋ฐฐ์น๋๋ก ๋ณด๋ฉด ํ๋์ ๋ค์ด์จ๋ค.
์ฃผํฉ์ ๋ ์นธ์ด XOR ์๋๊ฐ ์๋ ์๋ฆฌ๋ค.
๊ทธ ์๋ b64[13:36] ํ์ ์ฒซ ๋ ์นธ์ด ๋น์ด ์๋ ๊ฒ ๊ทธ ๋ป์ด๋ค.
์ฌ๊ธฐ์ ๋ ๊ฐ์ง๊ฐ ๋ฐ๋ผ ๋์จ๋ค.
ํ๋. ์ถ์ ์๊ฐ ์์๋ฅผ ๊ทธ๋ฅ ๊ณ ๋ฅธ ๊ฒ ์๋๋ค.
ํ๋๊ทธ๊ฐ WaRP{...} ๋ก ์์ํ๋ ๊ฑธ ์๊ณ , ์ ๋ ๊ธ์ Wa ๋ฅผ ์์ ์ต์์์ ์ฌ์ด ๋๋ค.
25์ 23์ด๋ผ๋ ๊ธธ์ด ์ฐจ์ด๋ ๊ทธ๋์ ๋์จ ๊ฒ์ด๋ค. ์ฐ์ฐ์ด ์๋๋ค.
๋. ๊ทธ๋์ Wa ๋ ๊ฒ์ฆ์ ์ธ ์ ์๋ค.
์
๋ ฅ์ด ๋ญ๊ฐ ๋๋ ์ถ๋ ฅ์ Wa ๋ก ์์ํ๋ค. ์ฝ์ง 3 ์ ์คํจ ์ผ์ด์ค๋ค์ด ์ค์ ๋ก ๊ทธ๋ฌ๋ค.
ํ ๊ฐ์ง ๋. long_to_bytes ๊ฐ bit_length() ๋ก ๊ธธ์ด๋ฅผ ์ก๊ธฐ ๋๋ฌธ์,
XOR ๊ฒฐ๊ณผ์ ์ต์์ ๋ฐ์ดํธ๊ฐ 0 ์ด ๋๋ฉด ์ถ๋ ฅ์ด ๊ทธ๋งํผ ์งง์์ง๋ค.
์ด ๋ฌธ์ ์์๋ ๊ทธ ์๋ฆฌ๊ฐ ์์์ 0x57 ๋ก ๊ณ ์ ์ด๋ผ ํญ์ 25๋ฐ์ดํธ๊ฐ ๋์ค์ง๋ง,
์๋ ์๋ฆฌ์์ 0 ์ด ๋์ค๋ ๊ฑด ์ผ๋ง๋ ์ง ๊ฐ๋ฅํ๋ค.
์ฝ์ง 3 ์ "๋ง์ง๋ง ํ ๊ธ์ ๋๋ฝ" ์ผ์ด์ค๊ฐ ๊ทธ๋์ ๊ธธ์ด๊ฐ ๋ค์ญ๋ ์ญํ๋ค.
ํ๋๊ทธ ์๋ฆฌ์ ์ค์ ๋ก ๋ค์ด๊ฐ ๊ฐ์ ์ญ์ผ๋ก ํ์ธํด ๋ณด๋ฉด ์ด๋ ๋ค.
| ์์น | ์์ ๋ฐ์ดํธ | b64 ์ฌ๋ผ์ด์ค | XOR ๊ฒฐ๊ณผ |
|---|---|---|---|
| 0 | 0x57 | (์์) | W |
| 1 | 0x61 | (์์) | a |
| 2 | 0x13 | A (0x41) | R |
| 3 | 0x66 | 6 (0x36) | P |
| 4 | 0x03 | x (0x78) | { |
| 24 | 0x3a | G (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/
์ฌ๋ผ์ด์ค๊ฐ 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
ํ์ ๋ง์ปค๋ ์ด๋ ๊ฒ ์ฝ์ผ๋ฉด ๋๋ค.
| ํ๋ฉด์ ๋จ๋ ๊ฒ | ๋ป |
|---|---|
๋ณธ๋ฌธ ๊ธธ์ด: 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 ์ผ๋ก ๋ฐ๋์๊ณ ์ฌ๋ผ์ด์ค๋ ํ๋๊ทธ๋ ๋ผ์ด๋ธ์ ๊ฐ๋ค.
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
๋๊ธ
๋๊ธ์ ๋จ๊ธฐ๋ ค๋ฉด ๋ก๊ทธ์ธ์ด ํ์ํด์. (๋ค์ด๋ฒ ยท ๊ตฌ๊ธ ๊ณ์ )
๋๊ธ ๋ถ๋ฌ์ค๋ ์คโฆ