INDEX
1. Introduce
2. Analysis Scenario
3. How To Use Microsoft Edge Auto-Login
4. Current Local State Analysis
5. Automatic Login Status Analysis
6. Conclusion
7. Reference
1. Introduce
이번 분석 실습에서는 필자의 로컬 컴퓨터의 마이크로소프트 엣지 자동로그인을 분석하고 복호화하여 비밀번호를 알아내고자한다.
필자는 자동로그인을 무조건 사용하지 않으므로 자동로그인을 사용하지 않은 상태와 자동로그인을 사용한 후의 상태를 나누어 분석하고자 한다.
또한 마이크로소프트 엣지는 크롬과 마찬가지로 Chromium 기반 브라우저이기에 따로 개념은 포스팅하지 않겠다.
이와 관련한 개념을 알고싶다면 Chorme Auto-Login 포스팅을 참고바란다.
밑의 표에서 사용한 분석 도구를 참고하길 바란다.
Tools Used | Version |
DB Brower for SQLite | v3.12.2 |
2. Analysis Scenario
- 자동로그인을 사용하지 않은 상태 분석
필자는 자동로그인을 사용하지 않으므로 마이크로소프트 엣지 비밀번호 관리자에서 거부당한 사이트들을 확인한 후 Login Data를 열어 복호화된 상태를 확인한다.
그후 AES 복호화 코드를 통해 복호화를 진행한 후 복호화된 사이트의 비밀번호를 확인한다.
- 자동로그인을 사용한 후 상태 분석
이번엔 자동로그인을 사용한 후 마이크로소프트 엣지 비밀번호 관리자에서 사용된 사이트를 확인한다.
이후 똑같이 Login Data를 열어 복호화된 상태를 확인하고 AES 복호화 코드로 복호화를 진행한 후 복호화된 사이트의 비밀번호를 확인한다.
3. How To Use Microsoft Edge Auto-Login
간단하게 마이크로소프트 엣지 자동로그인의 사용법을 알아보자.
어떠한 사이트에 처음 로그인을 하면 우측 상단에 자동로그인을 저장 할 것이냐고 프롬프트가 뜬다. 거기서 저장할 수 있고
설정 - 프로필 - 암호
로 들어가서 관련 설정을 할 수 있다.
암호 탭에서 저장한 사이트의 수정 및 삭제가 가능하고
우측 상단 점 3개를 통해서 .CSV파일로 비밀번호 내보내기와 가져오기가 가능하다.
또한 거부된 사이트도 확인, 설정이 가능하다.
4. Current Local State Analysis
분석에 앞서 설정에서 마이크로소프트 엣지 암호를 열어 저장된 비밀번호가 없음을 확인한다.
더불어서 자동로그인이 거부된 사이트들도 확인한다.
C:\Users\<PC Name>\AppData\Local\Microsoft\Edge\User Data\Local State
위의 경로에서 Local State라는 파일을 확인 할 수 있는데 이 파일을 통해 암호화 키를 찾을 수 있다.
메모장으로 열어주고 encrypted_key를 검색하면
이렇게 암호화 키를 찾을 수 있다.
C:\Users\<PC Name>\AppData\Local\Microsoft\Edge\User Data\Default\Login Data
위의 경로에서는 Login Data 파일을 확인할 수 있다.
이 파일을 복사해서 가져온다.
이후 DB Brower로 열어보면 자동로그인이 거부된 사이트들을 볼 수 있으며 username_value와 password_element에 저장된 데이터가 없음도 확인가능하다.
이후 Python으로 작성된 복호화 코드를 통해 Login Data를 복호화 해보려고한다.
밑의 복호화 코드를 돌려주면 된다.
import os
import re
import sys
import json
import base64
import sqlite3
import win32crypt
import shutil
from Cryptodome.Cipher import AES
def get_encrypted_key(home_folder):
try:
with open(os.path.normpath(home_folder + "\Local State"), "r", encoding="utf-8") as f:
local_state = json.loads(f.read())
encrypted_key = base64.b64decode(local_state["os_crypt"]["encrypted_key"])[5:]
return win32crypt.CryptUnprotectData(encrypted_key, None, None, None, 0)[1]
except Exception as e:
print(f"{str(e)}\n[E] Couldn't extract encrypted_key!")
return None
def decrypt_password(ciphertext, encrypted_key):
try:
chrome_secret = ciphertext[3:15]
encrypted_password = ciphertext[15:-16]
cipher = AES.new(encrypted_key, AES.MODE_GCM, chrome_secret)
return cipher.decrypt(encrypted_password).decode()
except Exception as e:
print(f"{str(e)}\n[E] Couldn't decrypt password. Is Chromium version older than 80?")
return ""
def get_db(login_data_path):
try:
shutil.copy2(login_data_path, "login_data_copy.db")
return sqlite3.connect("login_data_copy.db")
except Exception as e:
print(f"{str(e)}\n[E] Couldn't find the \"Login Data\" database!")
return None
def get_chromium_creds(user_data, browser_name):
if (os.path.exists(user_data) and os.path.exists(user_data + r"\Local State")):
print(f"[I] Found {os.environ['USERPROFILE']}'s {browser_name} folder - decrypting...")
encrypted_key = get_encrypted_key(user_data)
folders = [item for item in os.listdir(user_data) if re.search("^Profile*|^Default$",item)!=None]
for folder in folders:
# Get data from the Login Data file (SQLite database)
login_data_path = os.path.normpath(fr"{user_data}\{folder}\Login Data")
db = get_db(login_data_path)
if(encrypted_key and db):
cursor = db.cursor()
cursor.execute("select action_url, username_value, password_value from logins")
for index,login in enumerate(cursor.fetchall()):
url = login[0]
username = login[1]
ciphertext = login[2]
if (url!="" and username!="" and ciphertext!=""):
decrypted_pass = decrypt_password(ciphertext, encrypted_key)
print(str(index)+" "+("="*50)+f"\nURL: {url}\nUsername: {username}\nPassword: {decrypted_pass}\n")
# Remove the temporary file
cursor.close()
db.close()
os.remove("login_data_copy.db")
try:
# Extract Google Chrome passwords
chrome_user_data = os.path.normpath(fr"{os.environ['USERPROFILE']}\AppData\Local\Google\Chrome\User Data")
get_chromium_creds(chrome_user_data, "Google Chrome")
# Extract Microsoft Edge passwords
edge_user_data = os.path.normpath(fr"{os.environ['USERPROFILE']}\AppData\Local\Microsoft\Edge\User Data")
get_chromium_creds(edge_user_data, "Microsoft Edge")
except Exception as e:
print(f"[E] {str(e)}")
결과를 보면 당연하게도 저장된 데이터가 없기 때문에 아무것도 나오지 않는다.
5. Automatic Login Status Analysis
이번엔 한 사이트에서 자동로그인을 등록하고 마이크로소프트 엣지 암호를 열어 확인하였다.
C:\Users\<PC Name>\AppData\Local\Microsoft\Edge\User Data\Default\Login Data
이후 다시 Login Data를 가져오고 DB Brower로 열어보았다.
자동로그인하는 사이트의 username_value에 ID가 저장이 되고 password_element에는 비밀번호가 암호화가 되어서 저장된 것을 볼 수 있다.
이제 Ptyhon으로 다시 복호화 코드를 돌려주면
사이트의 ID와 PW가 복호화되어 평문으로 나오는 것을 볼 수 있다.
6. Conclusion
마이크로소프트 엣지 자동로그인 분석을 통해 복호화로 ID와 PW를 평문으로 알 수 있었으며, 생각한 것보다 더 취약함을 알 수 있었다.
필자는 자동로그인을 사용하지 않았지만 앞으로 더 경각심이 생겼으며, 지인들에게도 자동로그인의 위혐성을 전파할 생각이다.
또한 같은 Chromium 기반 브라우저들은 모두 취약하기 때문에 마이크로소프트 뿐만아니라 네이버 웨일이나 오페라 같은 브라우저에서도 자동로그인을 사용하지 않는 것이 좋을 것 같다.
7. Reference
[Decrypt Microsoft Edge Passwords]
→ https://gist.github.com/neonfury/a34a2aadc7c084f08cb046728cd25b54