본인이 작성한 오피스(워드, 엑셀, 파워포인트)나 집파일에 암호를 걸어두고, 시간이 지나 비밀번호가 생각나지 않을때가 종종 있어 난처한 경우가 발생합니다. 이때, 시간 여유가 많이 있고 또한 아주 간단한 암호를 설정했다면 '단순 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개).
반응형

+ Recent posts