picoCTF
Play Nice
h34hg0
2022. 6. 22. 22:29
문제
모든 고대 암호들이 그렇게 나쁜 것은 아니었다... 플래그가 표준 형식이 아닙니다. nc mercury.picoctf.net 30568 playfair.py
풀이
문제를 풀기에 앞서, 이 문제는 플레이 페어 암호화 방식을 사용한다 다음 링크를 참고하기 바란다.
문제에서 준 파일인 playfair.py의 코드는 다음과 같다
#!/usr/bin/python3 -u
import signal
SQUARE_SIZE = 6
def generate_square(alphabet):
assert len(alphabet) == pow(SQUARE_SIZE, 2)
matrix = []
for i, letter in enumerate(alphabet):
if i % SQUARE_SIZE == 0:
row = []
row.append(letter)
if i % SQUARE_SIZE == (SQUARE_SIZE - 1):
matrix.append(row)
return matrix
def get_index(letter, matrix):
for row in range(SQUARE_SIZE):
for col in range(SQUARE_SIZE):
if matrix[row][col] == letter:
return (row, col)
print("letter not found in matrix.")
exit()
def encrypt_pair(pair, matrix):
p1 = get_index(pair[0], matrix)
p2 = get_index(pair[1], matrix)
if p1[0] == p2[0]:
return matrix[p1[0]][(p1[1] + 1) % SQUARE_SIZE] + matrix[p2[0]][(p2[1] + 1) % SQUARE_SIZE]
elif p1[1] == p2[1]:
return matrix[(p1[0] + 1) % SQUARE_SIZE][p1[1]] + matrix[(p2[0] + 1) % SQUARE_SIZE][p2[1]]
else:
return matrix[p1[0]][p2[1]] + matrix[p2[0]][p1[1]]
def encrypt_string(s, matrix):
result = ""
if len(s) % 2 == 0:
plain = s
else:
plain = s + "0fkdwu6rp8zvsnlj3iytxmeh72ca9bg5o41q"[0]
for i in range(0, len(plain), 2):
result += encrypt_pair(plain[i:i + 2], matrix)
return result
alphabet = open("key").read().rstrip()
m = generate_square(alphabet)
msg = open("msg").read().rstrip()
enc_msg = encrypt_string(msg, m)
print("Here is the alphabet: {}\nHere is the encrypted message: {}".format(alphabet, enc_msg))
signal.alarm(18)
resp = input("What is the plaintext message? ").rstrip()
if resp and resp == msg:
print("Congratulations! Here's the flag: {}".format(open("flag").read()))
# https://en.wikipedia.org/wiki/Playfair_cipher
키 테이블로 6x6행렬을 사용하는 것 외에는 플레이페어와 동일한 암호화 방식을 가진다.
연결을 해보면 두 문자열을 준다. 여기서 alphabet 문자열이 키테이블에 사용될 문자열이다.
key = "0fkdwu6rp8zvsnlj3iytxmeh72ca9bg5o41q"
m = "herfayo7oqxrz7jwxx15ie20p40u1i"
SQUARE_SIZE = 6
def get_index(letter, matrix):
for row in range(SQUARE_SIZE):
for col in range(SQUARE_SIZE):
if matrix[row][col] == letter:
return (row, col)
print("letter not found in matrix.")
exit()
def generate_square(alphabet):
assert len(alphabet) == pow(SQUARE_SIZE, 2)
matrix = []
for i, letter in enumerate(alphabet):
if i % SQUARE_SIZE == 0:
row = []
row.append(letter)
if i % SQUARE_SIZE == (SQUARE_SIZE - 1):
matrix.append(row)
return matrix
def decrypt_pair(pair, matrix):
p1 = get_index(pair[0], matrix)
p2 = get_index(pair[1], matrix)
if p1[0] == p2[0]:
return matrix[p1[0]][(p1[1] - 1) % SQUARE_SIZE] + matrix[p2[0]][(p2[1] - 1) % SQUARE_SIZE]
elif p1[1] == p2[1]:
return matrix[(p1[0] - 1) % SQUARE_SIZE][p1[1]] + matrix[(p2[0] - 1) % SQUARE_SIZE][p2[1]]
else:
return matrix[p1[0]][p2[1]] + matrix[p2[0]][p1[1]]
def encrypt_string(s, matrix):
result = ""
if len(s) % 2 == 0:
plain = s
else:
plain = s + "0fkdwu6rp8zvsnlj3iytxmeh72ca9bg5o41q"[0]
for i in range(0, len(plain), 2):
result += decrypt_pair(plain[i:i + 2], matrix)
return result
matrix = generate_square(key)
flag = encrypt_string(m, matrix)
print(flag)
문제에서 제공한 코드를 약간의 변형을 거쳐서 복호화를 할 수 있도록 만들었다.
def decrypt_pair(pair, matrix):
p1 = get_index(pair[0], matrix)
p2 = get_index(pair[1], matrix)
if p1[0] == p2[0]:
return matrix[p1[0]][(p1[1] - 1) % SQUARE_SIZE] + matrix[p2[0]][(p2[1] - 1) % SQUARE_SIZE]
elif p1[1] == p2[1]:
return matrix[(p1[0] - 1) % SQUARE_SIZE][p1[1]] + matrix[(p2[0] - 1) % SQUARE_SIZE][p2[1]]
else:
return matrix[p1[0]][p2[1]] + matrix[p2[0]][p1[1]]
크게 바뀐 것은 없고, encrypto_pair 함수를 decrypto_pair 로 이름을 바꾸고 기존에 p[1] + 1 꼴로 된 부분을 p[1] - 1로 변경해서 암호화 하기 전의 위치로 돌아가게 바꿔줬다.
프로그램을 실행해서 나온 문자열을 입력함으로 플래그가 007d0a696aaad7fb5ec21c7698e4f754 임을 알 수 있다..