앵하니의 더 나은 보안
딥러닝으로 OTP 추측이 가능할까 본문
취약점 진단 대상 시스템에서 취약점 도출이 안돼서 뭐라도 잡아내려 MFA의 OTP를 딥러닝을 통해 학습시켜
OTP 발급 신청에 따른 OTP 결과 값 예측이 가능한지 확인해보려 했다.
결과적으로는 실패했지만 그 과정을 한번 살펴보자.
학습시킬 샘플 OTP 값을 뽑아내기 위한 수집/분석 요소로는 아이디와 OTP 발급 신청에 따른 서버 응답 시간을 택했다.
먼저 아래는 OTP 요청 아이디와 응답 패킷 내 존재하는 서버 시간을 추출해 파일로 저장하는 소스코드다.
해당 시스템에서는 OTP를 5분단위로 전송이 가능해
time.sleep(301)을 통해 5분 1초 간격으로 OTP 요청 및 수집을 반복시켰다.
import requests
from datetime import datetime
import time
def convert_gmt_to_utc(gmt_time_str):
time_format = "%a, %d %b %Y %H:%M:%S %Z"
date_object = datetime.strptime(gmt_time_str, time_format)
unix_time = time.mktime(date_object.timetuple())
return unix_time
userId_list = ["id_1","id_2","id_3"]
try:
while True:
for userId in userId_list:
response = requests.post("https://service_domain/OTP_send",data = {"UserId":userId}, headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.127 Safari/537.36","Referer":"https://e-joystore.joymax.com/Index/Login.aspx"})
response_data = response.headers.get('Date')
reponse_Unix_time = str(int(convert_gmt_to_utc(response_data)))
print(reponse_Unix_time+" : "+response.text)
if "-3" not in response.text:
try:
with open("otp_requested.txt", 'a') as file:
content = file.write(userId+", "+reponse_Unix_time+"\n")
except FileNotFoundError:
with open("otp_requested.txt", 'w') as file:
content = file.write(userId+", "+reponse_Unix_time+"\n")
time.sleep(301)
except KeyboardInterrupt:
print("The Tool was stopped by user's interrupt")
그리고 OTP는 gmail을 통해 수신되는데, 이 값이 요청한 시간에 따라 유효한 OTP 값이다.
해당 값을 ID,time,result OTP 순으로 나열하기 위해 수신된 이메일을 전부 파일형태로 다운로드 한 후 파이썬을 이용해
수집한다.(eml 파일의 내용은 base64로 인코딩 돼 있기에 내용 확인 및 저장을 위해 디코딩이 필요하다.)
#디렉토리 내 파일 스캔
#리스트화 된 파일들 싹 읽어서 날짜는 유닉스타임으로, 그리고 코드 입력
#저장 이후 a로 파일 계속 붙여넣기...
import os
import base64
from datetime import datetime
unix_time = ""
base64_decoded = ""
eml_dir = input("폴더 경로 입력 > ")
file_list = os.listdir(eml_dir)
for file_name in file_list:
with open(eml_dir+"/"+file_name,'r') as eml_file:
file_content = eml_file.readlines()
for line in file_content:
if "Date" in line[:5]:
#PDT to Unix time
date_time = line[6:].replace(" (PDT)","").strip()
dt = datetime.strptime(date_time, "%a, %d %b %Y %H:%M:%S %z")
unix_time = str(int(dt.timestamp()))
elif "RW1haWwgQXV0aGVudGljYXRpb24gQ29kZSA6" in line:
#base64 디코딩 이후 Email Authentication Code : 를 기준으로 잘라서 뒤에 데이터 변수에 할당
base64_decoded = base64.b64decode(line).decode().split("Email Authentication Code : ")[1]
if unix_time and base64_decoded:
with open("id_1.txt",'a') as file:
#이후 날짜랑 변수할당한거 각각 파일에 작성
data_worked = unix_time+", "+base64_decoded+"\n"
file.write(data_worked)
unix_time = ""
base64_decoded = ""
그리고 수집된 데이터 id_1.txt, id_2.txt, id_3.txt 파일을 파일 하나(final_combined_data.txt)로 합친다.
from datetime import datetime
import pytz
unix_time = ""
OTP_code = ""
email = input("email > ")
with open(email+".txt",'r', encoding='utf-8') as eml_file:
file_content = eml_file.readlines()
for line in file_content:
if "Date" in line[:5]:
#KST to Unix time
kST_time = line[6:]
year, month, day, _, am_pm, time = kST_time.split(" ")
hour, minute = time.split(":")
hour = int(hour)
if am_pm == "오후" and hour != 12:
hour += 12
elif am_pm == "오전" and hour == 12:
hour = 0
dt = datetime(int(year[:-1]), int(month[:-1]), int(day[:-1]), hour, int(minute))
kst = pytz.timezone('Asia/Seoul')
localized_dt = kst.localize(dt)
unix_time = str(int(localized_dt.timestamp()))
#초가 없어서 +- 60까지 포함시켜야 함 ㅜ
elif "Email Authentication" in line:
OTP_code = line.split("Email Authentication Code : ")[1]
if unix_time and OTP_code:
with open(email+"_parsed.txt",'a') as file:
#이후 날짜랑 변수할당한거 각각 파일에 작성
data_worked = unix_time+", "+OTP_code
file.write(data_worked)
unix_time = ""
OTP_code = ""
이후 해당 파일을 기반으로 딥러닝을 수행하는 소스코드를 작성한다.
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.preprocessing import LabelEncoder
import numpy as np
from joblib import dump
# Let's assume you have input data X and output data Y
# X = ...
# Y = ...
input_list = []
output_list = []
learning_data = []
with open('final_combined_data.txt','r') as readfile:
learning_data = readfile.readlines()
for learning_data_one in learning_data:
separate_learning_data = learning_data_one.split(",")
unix_time = separate_learning_data[0]
id = separate_learning_data[1]
tmp_list = [unix_time, id]
input_list.append(tmp_list)
output_list.append(separate_learning_data[2])
# input_list에서 unix time과 문자열을 분리합니다.
unix_time = [int(i[0]) for i in input_list] # unix time을 문자열에서 정수로 변환합니다.
strings = [i[1] for i in input_list]
# 문자열을 벡터로 변환합니다.
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(strings)
print(X)
# unix time을 2차원 배열로 변환합니다 (각 unix time은 배열입니다).
unix_time = np.array(unix_time).reshape(-1, 1)
# unix time과 벡터화된 문자열을 연결합니다.
input_data = np.concatenate((unix_time, X.toarray()), axis=1)
# output_data를 인코딩합니다.
encoder = LabelEncoder()
#output_data = encoder.fit_transform(output_list)
output_data = [int(x, 16) for x in output_list]
# 데이터를 학습 데이터와 테스트 데이터로 분할합니다.
X_train, X_test, y_train, y_test = train_test_split(input_data, output_data, test_size=0.2, random_state=42)
# 선형 회귀 모델을 생성하고 학습 데이터로 학습시킵니다.
model = LinearRegression()
model.fit(X_train, y_train)
# 학습된 모델을 파일로 저장합니다.
dump(model, 'trained_model.joblib')
def predict_output(new_input):
# new_input에서 unix time과 문자열을 분리합니다.
new_unix_time = new_input[0]
new_string = new_input[1]
# 문자열을 벡터로 변환합니다.
new_X = vectorizer.transform([new_string])
# unix time을 2차원 배열로 변환합니다.
new_unix_time = np.array(new_unix_time).reshape(-1, 1)
# unix time과 벡터화된 문자열을 연결합니다.
new_input_data = np.concatenate((new_unix_time, new_X.toarray()), axis=1)
# 출력을 예측합니다.
predicted_output = model.predict(new_input_data)
# 예측된 출력을 16진수 문자열로 변환합니다.
return hex(int(predicted_output[0]))[2:]
# 예측 함수를 테스트합니다.
new_input = [1721211011, 'id_1']
print(f"입력 데이터 {new_input}에 대한 예측 출력: {predict_output(new_input)}")
#B461DF28B2877DF
학습 시킨 뒤 해당 모델을 사용해 id_1 아이디에서 1721211011 시간에 보낸 OTP값을 추측하라고 마지막에 질의하는데, 이 값들은 기존 학습 데이터에 존재하는 값이라 B461DF28B2877DF가 나와야 하지만 영 엉뚱한 값을 도출해냈다.
ㅠ
딥러닝 소스코드도 전부 gpt가 작성해줘서 어디가 틀렸는지도 가늠하기 힘들어
여기서 더 진행해보려면 딥러닝에 대한 공부가 필요할 듯 하다.
수집데이터 양 자체도 많지 않았을 뿐더러, 딥러닝으로 공부를 어느정도 한 동료에게 듣기로서는 수집데이터 user id와 시간 데이터 만으로 패턴을 학습하고 정확한 결과를 예측하려면 샘플 데이터가 엄청 방대하게 필요 (100~1000만 단위) 할 것 이라는 말을 들었다. 그 말 대로라면 5분단위로 데이터를 수집해야해서 현실성 없을 것 같다는 생각을 했다. 😅
수집 데이터가 부족해서 그런 것일 수도 있고, 소스코드가 잘못됐을 수도 있고 그렇다.
아무튼 OTP 샘플 수집을 통한 결과 예측에는 실패했다.
'보안 기술 > ETC' 카테고리의 다른 글
XZ Utils Backdoor(CVE-2024-3094) (0) | 2024.06.23 |
---|---|
Log4shell(CVE-2021-44228) (0) | 2024.06.23 |
(reversing.kr) Easy CrackMe (2) | 2023.11.22 |
(reversing.kr) Easy Keygen (2) | 2023.11.22 |
AWS Pentesting tool PACU (0) | 2022.11.10 |