본인이 작성한 오피스(워드, 엑셀, 파워포인트)나 집파일에 암호를 걸어두고, 시간이 지나 비밀번호가 생각나지 않을때가 종종 있어 난처한 경우가 발생합니다. 이때, 시간 여유가 많이 있고 또한 아주 간단한 암호를 설정했다면 '단순 brute-force(무차별 대입) 방식'을 시도해 볼 수 있습니다. (*암호화된 파일을 분실한 경우, 개발사에서도 암호를 복구해 주지 않는 것으로 알고 있습니다. 사본/이전본을 찾는 게 현실적인 해법입니다. 추가로, 본문 하단에 암호분실을 대비한 예방팁을 정리하였습니다.)
- ZIP 파일
- zipfile 모듈로 열 수 있고, extractall(pwd=...) 같은 방식으로 비밀번호 검증 가능.
- MS Office (ppt, pptx, doc, docx, xls, xlsx 등)
- pptx/docx/xlsx는 사실상 ZIP 압축 기반 구조지만, 내부에 MS가 정한 암호화 헤더가 포함돼 있음.
- 단, 전용 라이브러리 필요.
- 아래한글(HWP)
- HWP 5.0 이후는 OLE Compound File 포맷 (마이크로소프트 OLE 구조).
- 암호화는 자체 알고리즘으로 되어 있어 파이썬에서 직접 풀 수 있는 공개 라이브러리는 사실상 없음.
- → olefile + 한글 암호화 해석 구현이 필요 (공식 라이브러리 없음).
- 암호화된 HWP는 한글에서 AES, SHA1 기반 암호화를 쓰는데, 비밀번호 없이는 복호화 불가.
- 가능하다면 “암호 해제 프로그램” (상용 소프트웨어) 사용이 현실적이나, 현재까지 그러한 프로그램은 없다고 알고 있음.
1. 통합 코드 (ZIP + MS Office 파일 비밀번호 찾기)
# pip install msoffcrypto-tool
import itertools
import zipfile
import msoffcrypto
import io
import os
class PasswordCracker:
"""
다양한 조합으로 비밀번호를 추측하여 ZIP, DOCX, XLSX, PPTX 파일의
암호를 해독하는 클래스입니다.
"""
def __init__(self, passwd_string, min_len, max_len):
"""
클래스를 초기화합니다.
Args:
passwd_string (str): 비밀번호에 사용될 문자열(예: '0123456789').
min_len (int): 추측할 비밀번호의 최소 길이.
max_len (int): 추측할 비밀번호의 최대 길이.
"""
self.passwd_string = passwd_string
self.min_len = min_len
self.max_len = max_len
def crack(self, file_path):
"""
주어진 파일의 암호를 해독하는 메인 함수입니다.
파일 확장자에 따라 적절한 해독 메서드를 호출합니다.
Args:
file_path (str): 암호를 해독할 파일의 경로.
Returns:
str or None: 비밀번호를 찾으면 비밀번호를, 찾지 못하면 None을 반환.
"""
file_ext = os.path.splitext(file_path)[1].lower()
if file_ext == ".zip":
return self._crack_zip(file_path)
elif file_ext in [".pptx", ".docx", ".xlsx"]: # 'xlsx'는 문자열로 변경
return self._crack_office(file_path)
else:
print(f"[!] {file_ext} 형식은 지원하지 않습니다.(zip, office만 지원)")
return None
def _crack_zip(self, file_path):
"""
ZIP 파일의 암호를 해독하는 함수입니다.
비밀번호를 찾으면 즉시 해당 비밀번호를 반환하고, 함수를 종료합니다.
"""
try:
zFile = zipfile.ZipFile(file_path)
except zipfile.BadZipFile:
print("[-] 유효하지 않은 ZIP 파일입니다.")
return None
for length in range(self.min_len, self.max_len + 1):
for attempt in itertools.product(self.passwd_string, repeat = length):
passwd = "".join(attempt)
# 시도 중인 비밀번호를 터미널에 표시 (동일 라인에 덮어쓰기)
print(f"[*] 시도 중: '{passwd}'", end='\r')
try:
zFile.extractall(pwd=passwd.encode('utf-8'))
print(f"\n[+] 비밀번호는 '{passwd}'입니다.(zip)")
return passwd # 비밀번호를 찾으면 즉시 반환
except (RuntimeError, zipfile.BadZipFile):
# 비밀번호가 틀렸을 때 발생하는 예외는 무시하고 다음 시도를 계속
continue
print("\n[-] 비밀번호를 찾지 못했습니다.(zip)")
return None
def _crack_office(self, file_path):
"""
MS Office 파일의 암호를 해독하는 함수입니다.
비밀번호를 찾으면 즉시 해당 비밀번호를 반환하고, 함수를 종료합니다.
"""
for length in range(self.min_len, self.max_len + 1):
for attempt in itertools.product(self.passwd_string, repeat=length):
passwd = "".join(attempt)
# 시도 중인 비밀번호를 터미널에 표시 (동일 라인에 덮어쓰기)
print(f"[*] 시도 중: '{passwd}'", end='\r')
try:
with open(file_path, "rb") as f:
office_file = msoffcrypto.OfficeFile(f)
office_file.load_key(password=passwd)
decrypted = io.BytesIO()
office_file.decrypt(decrypted)
print(f"\n[+] 비밀번호는 '{passwd}'입니다.(office)")
return passwd # 비밀번호를 찾으면 즉시 반환
except Exception as e:
# 비밀번호가 틀렸을 때 발생하는 예외는 무시하고 다음 시도를 계속
continue
print("\n[-] 비밀번호를 찾지 못했습니다.(office)")
return None
if __name__ == "__main__":
# 비밀번호에 사용될 문자와 최소/최대 길이 설정
passwd_string = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
cracker = PasswordCracker(passwd_string, min_len=3, max_len=4)
# 파일 경로 지정
file_path = "워드암호파일_123.docx"
cracker.crack(file_path)
- 파일 확장자 자동 구분
- .zip → zipfile 모듈로 brute-force
- .pptx/.docx/.xlsx → msoffcrypto-tool로 brute-force
- 무차별 대입(brute-force)
- min_len ~ max_len 길이의 모든 조합을 생성 (itertools.product)
- 하나씩 대입 → 맞으면 성공, 프로그램 종료
[ 예방 팁 ]
- 비밀번호 관리자 사용: 조직/개인별로 안전하게 공유·보관.
- 버전 기록이 있는 저장소 사용: OneDrive/SharePoint/Google Drive 등.
- 중요 문서는 이중 보호: 암호+접근권한(ACL)로 관리하고, 비상 복구 담당자/절차를 미리 지정.
- 규칙적 백업: 로컬+클라우드 3-2-1 규칙(사본 3개, 매체 2종, 오프사이트 1개).
반응형
'AI, 클라우드, 문서, 자동화 > 파이썬 요리조리' 카테고리의 다른 글
간단한 Word 자동화 프로그램, 다산 정약용의 유배지에서 보낸 편지 (0) | 2025.09.05 |
---|---|
간단한 번역 프로그램, 파일로 저장하기 (0) | 2025.08.24 |
당황하지 말자, 기억나지 않는 문서 암호/비밀번호 찾기(2) (0) | 2025.08.22 |
내부 IP & 외부 IP 조회(함수, 클래스까지 정리) (0) | 2025.08.21 |