Intodoctions to Cryptohack

원상윤·2022년 8월 26일
0

Cryptohack.org

목록 보기
1/3

From Cryptohack.org

- course 1 ( Introdoctions to Cryptohack ) -

< 1 >

그냥 문제들에 대해서 설명해주고, flag 를 알아내는 것이 목표인 문제들로 이루어져 있다. 앞으로 문제들을 보며 flag 를 얻어내도록 하자.


< 2 >

현대 암호에 들어서면서, 암호 공격이나 암호 체계를 완성할 때 python3 이라는 프로그래밍 언어를 주로 사용한다고 한다.

주어진 python 파일을 실행시켜서 flag 를 얻을 수 있다고 한다.

#!/usr/bin/env python3

import sys
# import this

if sys.version_info.major == 2:
    print("You are running Python 2, which is no longer supported. Please update to Python 3.")

ords = [81, 64, 75, 66, 70, 93, 73, 72, 1, 92, 109, 2, 84, 109, 66, 75, 70, 90, 2, 92, 79]

print("Here is your flag:")
print("".join(chr(o ^ 0x32) for o in ords))

각 ascii code 에 맞는 것들을 그냥 출력시켜주는 코드인 것 같다. 바로 실행해보자.

출력은 다음과 같다.

Here is your flag: crypto{z3n_0f_pyth0n}


< 3 >


아스키 코드는 7 비트로 이루언진 표준 인코딩 코드라고 한다. 0 부터 127 까지의 숫자를 대응시키는데, 아래에 나와있는 ascii code 를 다시 문자로 바꾼다면 flag 를 얻을 수 있을 것 같다.

ords = [99, 114, 121, 112, 116, 111, 123, 65, 83, 67, 73, 73, 95, 112, 114, 49, 110, 116, 52, 98, 108, 51, 125]
flag = ''
for asciicode in ords:
    flag += chr(asciicode)
print(flag)

이렇게 코드를 작성할 수 있겠다.

바로 실행해보자.

crypto{ASCII_pr1nt4bl3}


< 4 >

우리가 어떤 것을 암호화할 때, 보통 암호문은 출력되지 않는 ( 즉, ascii code 범위를 벗어난 ) 경우가 많다. 우리는 이를 표현하기 위해서 hex 로 흔히 바꾸어서 나타내곤 한다.

주어진 hex 열을 다시 bytes 로 바꾸면 flag 를 얻을 수 있겠다.

hexcode = '63727970746f7b596f755f77696c6c5f62655f776f726b696e675f776974685f6865785f737472696e67735f615f6c6f747d'
print(bytes.fromhex(hexcode).decode())

문제에도 나와있듯이, bytes.fromhex() 명령어로 쉽게 바꿔줄 수 있다.

바로 실행해보자.

crypto{You_will_be_working_with_hex_strings_a_lot}


< 5 >

앞서 설명했던 것과 동일하게, hex 말고도 Base64 라는 방법을 통해서 ascii string 으로 나타내는 방법 있다고 한다.

base64는 말 그대로 64, 즉 6 비트만을 사용하는 방식이다. 원래 기존의 비트는 8 비트를 기준으로 하는데, 6 비트로 바꾸게 되면 표현가능한 수는 0~64 로 작아지게 된다.

그 후에, 이 표를 통해서 문자로 변경하게 된다.
아래는 base64 encoding 의 한 예시이다.


이 사진과 같이, abc 가 YWJj 로 바뀌게 된다.

그렇다면, 우리는 주어진 hex string 을 base64 로 인코딩해서 flag 를 얻어보도록 하자.

from base64 import b64encode
hexstring = '72bca9b68fc16ac7beeb8f849dca1d8a783e8acf9679bf9269f7bf'
print(b64encode(bytes.fromhex(hexstring)).decode())

먼저, hexstring 을 bytes 로 바꾸고, b64encode 를 해줄 수 있겠다.

바로 실행해보자.

crypto/Base+64+Encoding+is+Web+Safe/


< 6 >

암호시스템 ( RSA ) 같은 것들은 수를 이용해서 암호화되지만, 여러 메세지들은 character 로 이루어져 있다. 이들을 암호화해주기 위해서는, 메세지를 숫자로 바꿔주는 방식이 필요하다.

지금까지 hex string ( base 16 ) , base64 방법을 알아왔는데, RSA 처럼 10진수 계산을 통한 암호화 방식을 이용하기 위해서 base 10 방식도 사용하게 된다. ( base n 은 단순이 n 진법이라고 생각하면 편할 것 같다)

주어진 10진수를 다시 byte 로 바꿔주면 될 것 같다.

from Crypto.Util.number import long_to_bytes
dec = 11515195063862318899931685488813747395775516287289682636499965282714637259206269
print(long_to_bytes(dec).decode())

바로 실행해보자.

crypto{3nc0d1n6_4ll_7h3_w4y_d0wn}


< 7 >

XOR 연산은 비트 연산이다. 2진수로 바꿔서 연산이 진행되는데, 위의 사진에 나온 표에서 보다시피, A 와 B 가 같으면 0, 다르면 1 을 반환하는 연산이다.

주어진 string 을 13 으로 XOR 한 값을 다시 string 으로 바꾸면 flag 가 되겠다.

string = 'label'.encode()
flag = ''
for chracter in string:
    flag += chr(chracter^ 13)
print(flag)

자, 실행해보자.

aloha , 따라서 flag 의 형식을 맞춰주면
crypto{aloha}


< 8 >

XOR 에 대한 설명이 나와있는 것 같다. XOR 이 만족하는 성질들에 대해서 말하고 있는데, XOR 은 다른 비트 연산과 달리 특이하게도 역연산이 자기 자신과 같다.

다시 말하면, A ^ B = C 라고 할 때, C ^ A = B 가 된다는 말이다.

이 조건을 잘 활용해서 문제를 풀어보자.

이 값들을 이용해서 FLAG 를 얻어내면 되는 문제인듯 하다.

A = bytes.fromhex('a6c8b6733c9b22de7bc0253266a3867df55acde8635e19c73313')
B = bytes.fromhex('37dcb292030faa90d07eec17e3b1c6d8daf94c35d4c9191a5e1e')
C = bytes.fromhex('c1545756687e7573db23aa1c3452a098b71a7fbf0fddddde5fc1')
ENC_FLAG = bytes.fromhex('04ee9855208a2cd59091d04767ae47963170d1660df7f56f5faf')
plain_flag = ''
for i in range(len(ENC_FLAG)):
    plain_flag += chr(A[i]^C[i]^ENC_FLAG[i])
print(plain_flag)

먼저, 각각의 형식들을 모두 bytes 로 바꿔준 뒤에, A, C, ENC_FLAG 를 XOR 연산해주면 된다.

FLAG ^ KEY1 ^ KEY3 ^ KEY2 에 차례대호 KEY 들을 모두 XOR 시키면 FLAG 를 얻을 수 있는데, KEY1 ^ KEY3 ^ KEY2 는 KEY1 와 KEY3 ^ KEY2를 XOR 시킨 값이기 때문에 다음과 같은 식을 얻어낼 수 있다.

바로 실행해보자.

crypto{x0r_i5_ass0c1at1v3}


< 9 >

이제 문제들이 얼마 남지 않았다. 이 문제는 XOR 문제인데, 어떤 single bytes 로 FLAG 를 XOR 했는데, 이는 secret 이라고 한다.

아마 brute-force 방법을 통해서 풀어야 할 것 같다.

enc_flag = '73626960647f6b206821204f21254f7d694f7624662065622127234f726927756d'
enc_flag = bytes.fromhex(enc_flag)
for i in range(256):
    plain_flag = ''
    for _ in enc_flag:
        plain_flag += chr(_^i)
    print(plain_flag)

나온 256개의 결과들 중에서, flag 형식처럼 보이는 것을 찾으면 된다.

crypto{0x10_15_my_f4v0ur173_by7e}

여기서 문제를 더 쉽게 풀 수 있는 방법은, flag 의 형식을 미리 알고 있다면, 앞자리가 'c' 인것을 이용해서 single bytes 를 미리 알아낼 수 있다.


< 10 >

자,, 마지막 문제이다.
flag 를 어떤 secret key 로 enc 했는데, 알아서 풀어내라고 하고 있다.
아마 flag 의 형식을 잘 기억하라는 것을 보니, 이를 이용해서 key 를 도출해내는 것 같다.

enc_flag = '0e0b213f26041e480b26217f27342e175d0e070a3c5b103e2526217f27342e175d0e077e263451150104'
enc_flag = bytes.fromhex(enc_flag)
flag_format = b'crypto{'

for i in range(len(flag_format)):
    print(chr(flag_format[i] ^ enc_flag[i]), end=' ')

힌트를 얻기 위해서 다음과 같이 형식이랑 XOR 을 해보았다.
그 후에 chr 로 string 으로 바꿔주었는데, 결과를 확인해보자.

m y X O R k e

뭔가 문자열이 말이 되는 것을 보니 일정한 key 가 반복되는 것 같다.
myXORkey 가 계속 반복되는 게 아닐까??

물론, 아닐수도 있지만 여기서는 딱히 별다른 힌트가 없으니 이를 이용해서 XOR 해보도록 하자.

enc_flag = '0e0b213f26041e480b26217f27342e175d0e070a3c5b103e2526217f27342e175d0e077e263451150104'
enc_flag = bytes.fromhex(enc_flag)
key = b'myXORkey'
plain_flag = ''

for i in range(len(enc_flag)):
    plain_flag += chr(key[i%8]^enc_flag[i])
print(plain_flag)

한번 실행해보자.

crypto{1f_y0u_Kn0w_En0uGH_y0u_Kn0w_1t_4ll}


여기까지 Intodoctions to Cryptohack 이 모두 완료되었다.

이 포스팅에서는 암호학의 기본중의 기본을 다루고 있기에 풀이 과정이 적어 상세하고 자세하게 작성하였다.

Cryptohack의 다음 섹션부터는 한문제씩 차례대로, 조금 더 빠르게 포스팅해보도록 하자.

0개의 댓글