워게임/root-me(Cryptanalysis)

[rootme] Side Channel - AES : first round

crypsec 2024. 11. 27. 18:02
반응형

https://www.root-me.org/

 

Bienvenue [Root Me : plateforme d'apprentissage dédiée au Hacking et à la Sécurité

Plusieurs centaines de challenges sont à votre disposition pour vous entrainer dans des environnements variés, réalistes et maitriser un grand nombre de techniques de hack !

www.root-me.org

rootme 라는 war game 사이트가 있다 여기서 Side Channel 관련 문제를 예전에 풀었었는데 이를 지금에서야 올린다.


Side Channel CTF

root-me에 있는 문제는 아래와 같다. AES의 1라운드를 공격하는 문제다.

 

문제를 해석해 보자.

 

1. AES key가 flag(정답)이고, AES key size가 최소라고 하였으니 flag의 길이는 16-byte임을 알 수 있다.

2. .bini8의 첫 8바이트는 AES 연산을 수행했을 때 전력파형의 개수와 전력값 정보가 들어가 있다.

 

Windows라면 HxD(https://mh-nexus.de/en/hxd/)라는 응용프로그램을 이용, Linux라면 xxd 명령어를 이용하여 확인 가능하다.

 

한 번같이 보자. 먼저 나오는 4바이트는 AES를 1번 연산했을 때 모은 전력정보가 총 864개라고 생각하면 된다.

 

이후 4바이트는 이런 AES 연산 과정을 10000번 반복했다는 뜻이다.

 

즉, AES 연산을 1회 진행했을 때, 수집하는 전력정보는 864개의 정보로 이루어져 있고 이런 정보가 10000개 있다는 것이다.

그림으로 한 번 보는 게 더 빠를 것 같다.

해당 그림은 첫 번째 AES 연산을 했을 때의 전력파형을 그림으로 나타낸 것이다.

 

이를 그릴 수 있는 python 코드를 같이 적어놓는다.

import matplotlib.pyplot as plt
import numpy as np

# 바이너리 파일 경로
file_path = "traces.bini8"

with open(file_path, 'rb') as file:
    # 8바이트 이후부터 864바이트까지만 읽기
    file.seek(8)  # 8바이트 이후로 이동
    raw_data = file.read(864)  # 864바이트까지 읽기

# 부호 있는 값을 부호 없는 값으로 변환
# np.int8 -> -128~127 범위
data = np.frombuffer(raw_data, dtype=np.int8)

# 데이터를 1바이트씩 포인트로 변환
x = np.arange(len(data))
y = data

plt.figure(figsize=(10, 6))
plt.plot(x, y, color='skyblue')
plt.xlabel("Time")
plt.ylabel("Power")
plt.show()

 

두 번째도 파형 개형은 비슷하니 그려보고 싶다면 file.seek(8 + 864)로 바꾸면 된다. 좀 더 기술이 있는 분이라면 10000개의 파형을 모두 겹쳐서 그려보길 바란다.

 

3.plaintext(평문)도 주어져있는데 이 또한 HxD나 xxd 명령어로 열어볼 수 있다.

Decoded text 부분을 보면 첫 번째 AES 연산에 사용한 평문(16진수)이 4a 8d 4d 54 2f b3 6e 57 a4 ad 84 cd ab f7 42 88이라는 것이다.

 

그다음 연산에 사용된 평문은 한 바이트 이후에 나온다. 이런 패턴이 반복된다.

 

해당 문제에는 친절하게도 CPA(상관전력분석)에 대한 논문도 함께 첨부되어 있다. 이를 이해해서 구현하면 좋겠지만, 글로 이를 설명하여 이해시키는 것은 진짜 어려운 일이기에 생략한다.

 

CPA를 이용한 공격 논리는 AES-128의 첫 번째 subbytes 연산을 공격 타깃으로 한다. 이 연산을 공격하는 이유가 있는데, 우선 문제 제목에도 first round라고 적혀있고  첫 번째 subbytes이 비선형 연산이라는 특징으로 인해 공격이 잘 된다. 비선형 연산이 공격이 잘된다고 하는 이유에는 Ghost key라는 특징이 안 나타나기 때문인데, Ghost key는 간단하게 실제 AES연산에 사용한 key 값이 아닌데도 불구하고 실제 사용한 key와 값만 다르고 나머지 분석결과가 모두 동일한 수준으로 나타나 분석에 혼란을 주기 때문이다.

 

또한 이런 공격이 가능한 이유가 실제 CPU에서 암호 연산 시 8-bit register 기준으로 전력량이 차이가 날 수밖에 없는데 이게 Hamming Weight라는 모델과 비례한다. 이에 대한 자세한 내용은 댓글로 남겨주면 따로 글을 쓰던지 하겠다.

 

아래 압축파일에는 rootme에서 제공하는 문제파일과 풀이에 필요한 코드가 들어있다.

 

 

간단하게, 이미 나는 Side Channel시 사용하고 있는 파일형식이 있는데 주어진 파일을 그대로 사용하려면 분석코드를 바꿔야 하기 때문에(사실 그렇게 어렵진 않은데) 문제파일을 바꿔주는 python 코드가 있다.

반응형

rootme.zip
6.78MB

 

아래는 ubuntu 환경에서 테스트할 때 사용한 명령어 과정이다.

$ unzip ch55.zip
$ python3 bin2trace.py
$ make
$ cd output
$ ./main

 

한 3 ~ 4분 정도 기다리면 아래와 같이 결과가 나온다

 

 

master key( 63 30 6e 47 72 34 37 75 7c 5f 61 54 21 30 6e 53 ) 부분을 ASCII로 바꾸면 그게 flag가 된다.

아래 사이트에서 편하게 변환가능하다.

 

https://www.rapidtables.com/convert/number/hex-to-ascii.html

 

Hex to ASCII Text String Converter

From Binary Decimal Octal Hexadecimal Text To Binary Decimal Octal Hexadecimal Text Character encoding ASCII Unicode UTF-8 UTF-16 UTF-16 little endian UTF-16 big endian Windows-1252 Big5 (Chinese) CP866 (Russian) EUC-JP (Japanese) EUC-KR (Korean) GB 18030

www.rapidtables.com

 

 

flag는 다음과 같다.

 

c0nGr47u|_aT!0nS

반응형