지난 26회 해킹캠프에 다녀왔을 때 못 푼 CTF문제가 아쉬워서 관련된 CTF 문제를 풀어보았습니다.
SIde channel attack(부 채널 공격)을 이용해서 문제를 푸는 방식 이였습니다.
Side channel attack에 대해서 위키백과에 나온 내용입니다.
암호학에서 부채널 공격(side channel attack)은 알고리즘의 약점을 찾거나(암호 해독과는 다름) 무차별 공격을 하는 대신에 암호 체계의 물리적인 구현 과정의 정보를 기반으로 하는 공격 방법이다. 예를 들어, 소요 시간 정보, 소비 전력, 방출하는 전자기파, 심지어는 소리를 통해서 시스템 파괴를 위해 악용할 수 있는 추가 정보를 얻을 수 있다. |
즉 직접적으로 문제를 뜯지 않아도 소요 시간 정보, 소비전력, 방출하는 전자기파 등을 이용해서 문제를 풀 수 있다는 것 입니다.
side channel attack의 종류는 위와 같이 다양한데 이번에 사용할 방법은 소요 시간 분석 입니다.
정답인 경우와 오답인 경우 걸리는 시간이 0.0000000000000001 초 차이라도 다르기 때문에 그 차이를 이용해서 문제를 푸는 방식입니다.
문제 풀이
문제는 위와 같이 elf파일 하나와 nc로 접속 할수 있는 문제 두개를 주어 줬습니다.
일단 우리가 문제만 보고 얻을 수 있는 정보는 2개입니다.
1. elf 파일이니까 리눅스에서 실행하면 되겠다.
2. pin이니까 숫자로된 8자리겠다.
위의 사진은 인자값을 넣었을 때 걸린 시간의 예시 입니다. 문제마다 다를 수 있지만 걸리는 시간이 가장 오래 걸리거나 적게 걸리는 것이 정답이라고 할수 도 있습니다. 하지만 여기서 주의 사항이 있는데 늘 그렇지만 변수가 있을 수도 있습니다. 위 사진을 예시로 했을때 어떠한 값이 아무 이유없이 오래 걸리거나 짧게 걸릴 수도 있습니다. 그렇다면 이에 따른 해결 방법은 1개입니다. 정답이 아닌데 아무 이유 없이 오래(혹은 짧게) 걸리는 변수는 한번입니다. 그렇다면 여러번 시도해서 평균치가 가장 큰것을 정답으로 하면 해결되는 문제입니다.
이 문제는 nc로도 풀 수도 있지만 nc로 하면 네트워크 or 서버간의 통신의 이유로 값이 이상하게 나올 수도 있습니다. 다행히도 이 문제는 문제 파일을 제공 했습니다. 이 문제파일을 이용한 파이썬 코드 입니다.
from pwn import *
import time
def check_time(pin):
io = process("pin_checker") #pin_checker 프로그램 실행
io.recvline() # "Please enter your 8-digit PIN code:" 라는 츌력된 글씨를 읽겠다
io.sendline(pin) #pin을 입력하겠다
io.recvline() # PIN length이 출력되는 글씨를 읽겠다
io.recvline() # "Checking PIN..." 라는 출력된 글씨를 읽겠다.
start = time.time() #여기서 답의 검증이 시작된다. 그래서 여기서 부터 시간을 잰다
io.recvline() # "Access denied." 글씨를 읽겠다.
ending = time.time() #검증이 끝났으니 시간도 끝
io.close()
return ending - start #걸린 시간을 리턴값으로 준다
best_pin = '' #핀 찾기
connection_count = 0 # 몇번 반복 했는지 사실 이건 없어도 된다.
for i in range(8): #각 자리 마다 돌아가겠다.
maxtime = float('-inf') #gpt가 알려준 최소값 찾는 방법 이렇게 쓰면 최소값이나 최대값을 갱신 할 수 있다고 한다
right_ans = 0
for j in range(10): #0 ~ 9까지 반복
total_time = 0 #총합시간
for _ in range(5): #한 숫자당 5번 씩 반복
pin = best_pin + str(j) + '0'*(7-i) #왼쪽부터 핀을 채우는데 정해진 핀은 고정시키게
time_taken = check_time(pin) #걸린 시간 확인
total_time += time_taken #걸린 시간 더하기
connection_count += 1 #횟수에 1더하기
avg_time = total_time / 5 #평균값 내기
if avg_time > maxtime: # 제일 오래걸린얘 찾기
maxtime = avg_time # 만약 오래걸리면 걔를 저장해두기
right_ans = j #오래 걸린 숫자 저장
best_pin += str(right_ans) #오래 걸린 얘를 pin에 입력하고 고정
print(f"Best PIN found: {best_pin}")
print(f"Total connections made: {connection_count}")
해결 완
'리버싱에 관하여 > ctf' 카테고리의 다른 글
CodeEngn<Basic RCE L05> (0) | 2020.09.08 |
---|---|
Codeengn<Basic RCE L04> (0) | 2020.09.07 |
CodeEngn <Basic RCE L03> (0) | 2020.09.07 |
CodeEngn <Basic RCE L02> (0) | 2020.09.06 |
CodeEngn <Basic RCE L01> (0) | 2020.09.06 |