We found a brand new type of encryption, can you break the secret code?
mlnklfnknljflfjljnjijjmmjkmljnjhmhjgjnjjjmmkjjmijhmkjhjpmkmkmljkjijnjpmhmjjgjj
https://play.picoctf.org/practice/challenge/158?page=1&search=new%20caesar
우리가 찾을 값은 flag
이다. assert문을 통해 key
값은 a와 p 사이의 값임을 알 수 있다.
flag를 b16_encode
함수로 인코딩하고, shift
함수로 한 번 더 암호화한다. 이 때, key[i%len(key)]
는 말장난으로, key[0]
과 같다.
b16_encode
함수
첫글자를 'a'라고 했을 때 아래 과정을 거쳐 암호화된다.
'a' --> 97 --> 0110|0001 --> 6|1 --> 'gb'
shift
함수
key 값은 고정이므로 t2는 고정된 값이고, 해당 연산으로 한 번 더 암호화한다.
import string
LOWERCASE_OFFSET = ord("a") # 97
ALPHABET = string.ascii_lowercase[:16] # a ~ p
enc = "mlnklfnknljflfjljnjijjmmjkmljnjhmhjgjnjjjmmkjjmijhmkjhjpmkmkmljkjijnjpmhmjjgjj"
for key in ALPHABET :
dec = ""
for e in enc :
dec += unshift(e, key)
dec = b16_decode(dec)
print(f"key : {key}, flag : {dec}")
문제는 b16_encode
-> shift
과정을 거쳤으므로
나는 반대로 unshift
-> b16_decode
과정으로 코드를 작성했다.
key
값은 알 수 없기 때문에 a부터 p까지 모든 경우를 출력해준다.
def unshift(c, k) :
t1t2 = ord(c) - LOWERCASE_OFFSET
t2 = ord(k) - LOWERCASE_OFFSET
t1 = t1t2 - t2
if t1 < 0 :
t1 += 16
return chr(t1 + LOWERCASE_OFFSET)
t1t2는 shift
함수의 (t1 + t2) % 16
을 의미한다.
t2는 shift
함수의 t2와 동일하다.
두 수의 차로 t1을 생성해 주었다.
shift
함수의 모듈러를 무시하고 if문을 작성하지 않아 답을 찾지 못했었다.
t1이 음수가 될 수 있음을 고려하여 if문을 추가해 주었다.
shift
함수의 t1 + t2
가 최대 32임을 계산하여
t1에 16을 한 번만 더해도 괜찮다고 판단하였다.
def b16_decode(txt) :
res = ""
for i in range(0, len(txt), 2) :
tmp1 = ALPHABET.index(txt[i])
tmp2 = ALPHABET.index(txt[i+1])
res += chr((tmp1 << 4) + tmp2)
return res
문제 분석 3번에 작성한
'a' -> 97 -> 0110|0001 -> 6|1 -> 'gb'
과정을 reverse한다는 생각으로 차근차근 코드를 작성했다.
위와 같은 결과가 출력되었고 key가 g일 때 가장 괜찮은 답이 나온다.
picoCTF{et_tu?_5723f4e71a0736d3b1d19dde4279ac03}