๋ฌธ์ : DreamHack โ EVER-igen ๋ถ๋ฅ: Crypto ๋์ด๋: ๐ฅ Bronze 3 FLAG:
DH{10587bd243d302e95d4b4b0fe331166605b85dd6660e18a305e1fc3db72bf3be}
๋น์ ๋ค๋ฅด ์ํธ๋ก ๋ฌธ์ฅ์ ๊ฐ๋ฆฐ ๋ฌธ์ ๋ค. ํค๊ฐ 16๊ธ์๋ผ ๊ทธ๋ฅ ์ ๋ถ ์๋ํ ์๋ ์์ง๋ง, ๋น์ ๋ค๋ฅด์ ๊ตฌ์กฐ์ ๊ฐ์ ํค๊ฐ ๊ท์น์ ์ผ๋ก ๋ฐ๋ณต๋๋ค. ๊ทธ ๋ฐ๋ณต์ ์ด๋ก ์ชผ๊ฐ๋ฉด ์ด๋ ค์ด ๋ค์ค์นํ์ด ์ฌ์ด ๋จ์ผ์นํ 16๊ฐ๋ก ๋ถํด๋๋ค.

๋ฌธ์ ๊ฐ์
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ๋ฌธ์ ๋ช | EVER-igen |
| ๋์ด๋ | ๐ฅ Bronze 3 |
| ๋ถ๋ฅ | Crypto |
| ์ ๊ณต ํ์ผ | prob.py, output.txt |
| ํต์ฌ ๊ธฐ๋ฒ | ์ฃผ๊ธฐ 16 ๋น์ ๋ค๋ฅด๋ฅผ ์ด๋ณ ๋น๋๋ถ์์ผ๋ก ๋ถํด |
output.txt์ ์ํธ๋ฌธ๋ง์ผ๋ก ์คํ๋ผ์ธ์์ ํ ์ ์๋ค.
๐ฌ ์ฝ๋ ์ ์ฐฐ โ 62์ ์ํ๋ฒณ ๋น์ ๋ค๋ฅด
prob.py์ ์ํธ๋ ๋๋ฌธ์ยท์๋ฌธ์ยท์ซ์ 62์๋ฅผ ํ ์ํ๋ฒณ์ผ๋ก ์ฐ๋ ๋น์ ๋ค๋ฅด๋ค.
words = ascii_uppercase + ascii_lowercase + digits # 62์
class Vigenere:
def shift(self, a, d):
if a not in words: return a # ๊ณต๋ฐฑยท๋ฌธ์ฅ๋ถํธ๋ ๊ทธ๋๋ก
return words[(words.index(a) + d) % len(words)]
def encrypt(self, pt):
return "".join(self.shift(pt[i], self._key[i % len(self._key)]) for i in range(len(pt)))
key = [random.randint(0, len(words)) for _ in range(16)] # 16๊ธ์ ํค๊ฐ ๊ธ์๋ฅผ key[i % 16]๋งํผ ์ํํธํ๋ค. words์ ์๋ ๋ฌธ์(๊ณต๋ฐฑ, ๋ง์นจํ ๋ฑ)๋ ์ํํธํ์ง ์๊ณ ํต๊ณผ์ํค์ง๋ง, ํค ์ธ๋ฑ์ค i๋ ์ ์ฒด ์์น๋ฅผ ๋ฐ๋ผ ๊ณ์ ์ฆ๊ฐํ๋ค. ํค๋ 16๊ธ์, ๊ฐ ๊ฐ์ 0~62์ด๋ผ ํค๊ณต๊ฐ์ด 62^16์ด๋ค. ํต์งธ๋ก ์ ์์กฐ์ฌํ๊ธฐ์ ๋๋ฌด ํฌ๋ค.
๐ฃ ํต์ฌ โ ์ฃผ๊ธฐ๋ฅผ ์ด๋ก ์ชผ๊ฐ ๋ค
๋น์ ๋ค๋ฅด์ ์ฝ์ ์ ํค๊ฐ ์ฃผ๊ธฐ์ ์ผ๋ก ๋ฐ๋ณต๋๋ค๋ ๊ฒ์ด๋ค. ํค ๊ธธ์ด๊ฐ 16์ด๋, ์ ์ฒด ๋ฌธ์์ด์์ ์์น i๊ฐ i mod 16์ผ๋ก ๊ฐ์ ์๋ฆฌ๋ค์ ์ ๋ถ ๊ฐ์ ํค ๊ฐ์ผ๋ก ์ํํธ๋๋ค.
๊ทธ๋์ ์ํธ๋ฌธ์ i mod 16 ๊ธฐ์ค์ผ๋ก 16๊ฐ ์ด๋ก ๋๋๋ฉด, ๊ฐ ์ด์ ๋จ ํ๋์ ์ํํธ๋ง ์ ์ฉ๋ ๋จ์ผ์นํ(์นด์ด์ฌ๋ฅด) ์ํธ๊ฐ ๋๋ค. 62๊ฐ์ง ์ํํธ๋ง ์๋ํ๋ฉด ๋๋ ๋ฌธ์ 16๊ฐ๋ก ์ชผ๊ฐ์ง ๊ฒ์ด๋ค.
๋ง๋ ์ํํธ๋ ์ด๋ป๊ฒ ๊ณ ๋ฅผ๊น. ํ๋ฌธ์ด ์์ด ๋ฌธ์ฅ์ด๋ผ๋ ์ ์ ์ด๋ค. ์์ด๋ ์๋ฌธ์๊ฐ ์๋์ ์ผ๋ก ๋ง๋ค(e, t, a, o โฆ). ์ด๋ค ์ํํธ๋ก ๋ณตํธํ์ ๋ ๊ทธ ์ด์ ๋ฌธ์๋ค์ด ์๋ฌธ์ ์์ด ๊ธ์์ ๋ชฐ๋ฆฌ๋ฉด, ๊ทธ๊ฒ ์ ๋ต ์ํํธ๋ค. ์ด๋ง๋ค ์๋ฌธ์ ๋น๋ ์ ์๊ฐ ์ต๋์ธ ์ํํธ๋ฅผ ๊ณ ๋ฅด๋ฉด ํค ํ ๊ธ์๊ฐ ์ ํด์ง๋ค.
๐ฏ ํ์ด โ ์ด๋ณ ๋น๋๋ก ํค 16๊ธ์ ๋ณต์
๊ฐ ์ด์ ๋ํด 62๊ฐ์ง ์ํํธ๋ฅผ ๋๋ฆฌ๊ณ , ๋ณตํธ ๊ฒฐ๊ณผ์ ์๋ฌธ์ ์์ด ๋น๋ ์ ์๊ฐ ๊ฐ์ฅ ๋์ ์ํํธ๋ฅผ ๊ทธ ์๋ฆฌ ํค๋ก ์ผ๋๋ค.
# solve.py (ํต์ฌ)
ct = open("output.txt").read().split(">",1)[1].strip()
def score(chars): # ์์ด๋ค์ ๋ก๊ทธ๊ฐ๋ฅ๋
s = 0.0
for c in chars:
if c in ascii_lowercase: s += math.log(freq.get(c, 0.05) / 100 * 0.90)
elif c in ascii_uppercase: s += math.log(0.02)
else: s += math.log(0.01) # ์ซ์
return s
key = []
for col in range(16):
col_chars = [ct[i] for i in range(len(ct)) if i % 16 == col and ct[i] in words]
best = max(range(62), key=lambda sh: score(
[words[(words.index(c) - sh) % 62] for c in col_chars]))
key.append(best)
pt = "".join(words[(words.index(c) - key[i % 16]) % 62] if c in words else c
for i, c in enumerate(ct))
print(f"key: {key}")
print(pt)
๋ณตํธํ๋ฉด ๋น์ ๋ค๋ฅด ์ํธ์ ์ ๋๋ฅผ ์ค๋ช ํ๋ ์์ด ๋ฌธ๋จ์ด ๋์ค๊ณ , ๊ทธ ๋์ ํ๋๊ทธ๊ฐ ๋ถ์ด ์๋ค.
... OK, here comes the flag. DH{10587bd243d302e95d4b4b0fe331166605b85dd6660e18a305e1fc3db72bf3be}FLAG: DH{10587bd243d302e95d4b4b0fe331166605b85dd6660e18a305e1fc3db72bf3be}
๐ ๊ฒฐ๋ก
์ฃผ๊ธฐ๊ฐ ๋๋ฌ๋๋ฉด ๋น์ ๋ค๋ฅด๋ ์นด์ด์ฌ๋ฅด ์ฌ๋ฌ ๊ฐ๋ค.
๋น์ ๋ค๋ฅด๊ฐ ๋จ์ผ์นํ๋ณด๋ค ๊ฐํ ์ด์ ๋ ์๋ฆฌ๋ง๋ค ํค๊ฐ ๋ฐ๋๊ธฐ ๋๋ฌธ์ด๋ค. ํ์ง๋ง ํค๊ฐ ๋ฐ๋ณต๋๋ ์๊ฐ, ๊ฐ์ ํค๋ฅผ ์ฐ๋ ์๋ฆฌ๋ผ๋ฆฌ ๋ชจ์ผ๋ฉด ๊ฐ ๋ฌถ์์ ๋ค์ ๋จ์ผ์นํ์ผ๋ก ๋ฌด๋์ง๋ค. ํค ๊ธธ์ด๋ง ์๋ฉด(๋๋ ๊ฐ์ ํ๋ฉด) ๋ค์ค์นํ์ด ๊ทธ๋งํผ์ ๋จ์ ๋ฌธ์ ๋ก ๋ถํด๋๋ค.
์ธ์ด ํต๊ณ๊ฐ ํ๋ณ์๋ค.
62๊ฐ์ง ํ๋ณด ์ค ์ ๋ต์ ๊ณ ๋ฅด๋ ๊ฑด ๋น๋๊ฐ ํด ์ค๋ค. ํ๋ฌธ์ด ์์ฐ์ด๋ผ๋ ์ฌ์ค ํ๋๋ก, ์๋ฌธ์ ๋น์ค์ด๋ผ๋ ๊ฐ์ผ ์งํ๊ฐ ๊ฐ ์ด์ ์ ๋ต ์ํํธ๋ฅผ ์ง์ด ์ค๋ค. ํค๋ฅผ ๋ชฐ๋ผ๋ ํ๋ฌธ์ ์ฑ์ง์ ์๋ฉด ์ด์ ๊ฐ ์ค์ค๋ก ๋๋ฌ๋๋ ์ ์ด๋ค.
Comments
๋๊ธ
๋๊ธ์ ๋จ๊ธฐ๋ ค๋ฉด ๋ก๊ทธ์ธ์ด ํ์ํด์. (๋ค์ด๋ฒ ยท ๊ตฌ๊ธ ๊ณ์ )
๋๊ธ ๋ถ๋ฌ์ค๋ ์คโฆ