메타마스크 지갑을 복구하는 방법: 비밀번호 분실, 볼트 저장소, 암호화 및 데이터 포렌식

피터 크립토리커버리 아바타
메타마스크 지갑을 복구하는 방법: 비밀번호 분실, 볼트 저장소, 암호화 및 데이터 포렌식

메타마스크 지갑을 복구하는 방법: 비밀번호 분실, 볼트 저장소, 암호화 및 데이터 포렌식

이 글을 읽고 계신다면, 아마 메타마스크(MetaMask) 지갑에 접속할 수 없게 되어 더 이상 할 수 있는 방법이 없는 상황일 것입니다. 저는 수년 동안 사람들의 지갑을 복구해 왔습니다. 노트북을 포맷해 버린 디파이(DeFi) 트레이더부터 브라우저 확장 프로그램을 "정리"해 버린 할아버지, 할머니에 이르기까지 다양한 분들을 도와드렸습니다. 이 가이드는 메타마스크가 키를 어떻게 저장하는지, 그 데이터가 디스크의 어디에 실제로 저장되어 있는지, 그리고 문제가 발생했을 때 어떻게 복구할 수 있는지에 대해 제가 알고 있는 모든 내용을 다룹니다. 이 내용은 모두 이론이 아닙니다. 여기에 소개된 모든 기법은 실제 복구 사례에서 나온 것입니다.

메타마스크가 실제로 키를 어떻게 저장하는지

무언가를 복구하기 전에, 무엇을 복구하는지 먼저 파악해야 합니다. MetaMask는 사용자의 개인 키를 private_keys.txt. 이를 ‘’라고 불리는 암호화된 블롭 안에 저장합니다. 금고, 이는 브라우저의 확장 프로그램 저장소에 저장됩니다.

MetaMask 지갑을 생성하고 비밀번호를 설정하면, 내부적으로는 다음과 같은 과정이 진행됩니다. MetaMask는 BIP-39 니모닉(12단어 비밀 복구 문구)를 가져와, 가져온 모든 개인 키와 함께 “keyring” 객체들로 구성된 JSON 배열로 묶습니다. 이 배열은 문자열로 직렬화된 후, AES-256-GCM 비밀번호를 통해 파생된 키를 사용하여 PBKDF2-HMAC-SHA256. 그 결과, 세 개 또는 네 개의 필드를 가진 JSON 데이터 블록이 chrome.storage.local (크로미움 기반 브라우저의 경우) 또는 IndexedDB (파이어폭스의 경우).

이전 버전에서 암호화된 볼트는 다음과 같이 표시됩니다:

{"data":"SGFuZGxlIHRoaXMgZW5jcnlwdGVkIGRhdGE=","iv":"MTIzNDU2Nzg5MDEyMzQ1Ng==","salt":"cmFuZG9tMzJieXRlc2FsdHZhbHVlaGVyZQ=="}

그리고 최신 버전(v11.16.x 이후)에는 네 번째 필드가 있습니다:

{"data":"...","iv":"...","keyMetadata":{"algorithm":"PBKDF2","params":{"iterations":600000}},"salt":"..."}

keyMetadata 이 부분이 바로 몇 분 만에 회복되는 경우와 몇 주가 걸리는 경우의 차이입니다. 이에 대해서는 잠시 후에 더 자세히 설명하겠습니다.

암호화 프로세스는 간단하지만 정확히 이해하는 것이 중요합니다. UTF-8 형식의 비밀번호는 Web Crypto API를 통해 원시 PBKDF2 키로 가져옵니다. A 32바이트 무작위 솔트 (다음에서 생성됨) crypto.getRandomValues())는 비밀번호와 함께 사용되어 256비트 AES-GCM 키를 도출합니다. 그런 다음 16바이트 무작위 IV 직렬화된 키링 데이터를 암호화합니다. 이 data 이 필드에는 암호문과 GCM 인증 태그가 모두 base64로 인코딩된 형태로 포함되어 있습니다. 한 가지 주목할 만한 점은, MetaMask는 AES-GCM용 16바이트 IV이는 표준 규격에 맞지 않습니다. NIST SP 800-38D에서는 12바이트를 권장합니다. 이로 인해 일부 암호화 라이브러리와 호환성 문제가 발생합니다(예를 들어, Ruby의 OpenSSL은 이를 지원하지 않습니다).

비밀번호로 MetaMask를 잠금 해제하면 이 과정이 역순으로 진행됩니다. KeyringController 영구 저장소에서 암호화된 볼트 문자열을 읽어와, 이를 browser-passworder’s decrypt 이 함수는 JSON을 파싱하고, 솔트를 추출한 뒤, 동일한 매개변수를 사용하여 PBKDF2로 키를 도출하고, AES-GCM으로 복호화한 후, 결과를 다시 키링 객체로 역직렬화합니다. 복호화된 키링은 오직 기억 속에만 – 이들은 memStore (한 ObservableStore (예: )이며, 절대 평문으로 디스크에 기록되지 않습니다.

암호 해독된 볼트에는 대개 다음과 같은 형태의 배열이 포함되어 있습니다:

[
  {
    "type": "HD Key Tree",
    "data": {
      "mnemonic": "abandon ability able about above absent ...",
      "numberOfAccounts": 3,
      "hdPath": "m/44'/60'/0'/0"
    }
  },
  {
    "type": "Simple Key Pair",
    "data": ["0xabc123..."]
  }
]

HD Key Tree 키링에는 니모닉 문구와 파생된 계정 수가 저장됩니다. Simple Key Pair 항목들은 개별적으로 가져온 개인 키입니다. 하드웨어 지갑을 연결한 경우, 다음 내용도 표시됩니다. Trezor Hardware 그리고 Ledger Hardware 키링 유형 – 단, 여기에는 파생 경로와 공개 주소만 저장되며, 개인 키는 저장되지 않습니다(개인 키는 하드웨어 장치에 남아 있습니다).

Manifest V3(2023년부터 Chrome이 도입한 서비스 워커 아키텍처)를 통해 MetaMask는 암호화 키를 내보낸 JWK로 캐시하는 기능을 추가했습니다. 이를 통해 서비스 워커가 재시작될 때 비밀번호를 다시 입력할 필요 없이 볼트를 다시 해독할 수 있습니다. encryptionKey 그리고 encryptionSalt 필드가 표시됩니다 memStore ~할 때 cacheEncryptionKey 이 활성화되어 있습니다.

각 플랫폼에서 MetaMask가 사용자의 데이터를 어디에 저장하는지

금고를 찾는 것이 성공의 절반이다. MetaMask는 브라우저와 운영 체제에 따라 데이터를 서로 다른 위치에 저장하며, 이러한 차이는 복구 과정에서 중요한 역할을 한다.

크롬ium 계열 브라우저(Chrome, Brave, Edge)

크롬ium 기반 브라우저에서는, chrome.storage.local ~에 저장됩니다 LevelDB 데이터베이스 디스크에 저장됩니다. 확장자 ID가 폴더 이름을 결정합니다.

Chrome 확장 프로그램 IDnkbihfbeogaeaoehlefnkodbefgpgknn – 모든 회복 전문가의 기억에 깊이 각인되어 있다. 용감한 Chrome 웹 스토어에서 설치하기 때문에 동일한 ID를 사용합니다. Edge Edge 애드온 스토어에서 설치할 경우 고유한 ID가 할당됩니다: ejbalbakoplchlghecdalmeeeajnimhm. 하지만 사용자가 크롬 웹 스토어(Edge에서 지원됨)를 통해 Edge에 MetaMask를 설치한 경우, Chrome ID가 유지됩니다. 이 차이점 때문에 사람들이 자꾸 헷갈려 합니다.

전체 경로는 다음과 같습니다:

Windows용 Chrome:
C:\Users\<USER>\AppData\Local\Google\Chrome\User Data\Default\Local Extension Settings\nkbihfbeogaeaoehlefnkodbefgpgknn\

macOS의 Chrome:
~/Library/Application Support/Google/Chrome/Default/Local Extension Settings/nkbihfbeogaeaoehlefnkodbefgpgknn/

리눅스용 크롬:
~/.config/google-chrome/Default/Local Extension Settings/nkbihfbeogaeaoehlefnkodbefgpgknn/

Windows용 Brave:
C:\Users\<USER>\AppData\Local\BraveSoftware\Brave-Browser\User Data\Default\Local Extension Settings\nkbihfbeogaeaoehlefnkodbefgpgknn\

macOS용 Brave:
~/Library/Application Support/BraveSoftware/Brave-Browser/Default/Local Extension Settings/nkbihfbeogaeaoehlefnkodbefgpgknn/

Windows용 Edge (Edge 스토어 설치):
C:\Users\<USER>\AppData\Local\Microsoft\Edge\User Data\Default\Local Extension Settings\ejbalbakoplchlghecdalmeeeajnimhm\

한 가지 중요한 사항: 사용자가 여러 개의 Chrome 프로필을 가지고 있는 경우, 다음을 Default ~와 함께 Profile 1, Profile 2등등. 사람들이 몇 시간 동안 잘못된 프로필을 검색하는 걸 본 적이 있습니다.

파이어폭스 – 완전히 다른 차원의 존재

Firefox는 LevelDB를 사용하지 않습니다. 확장 기능 데이터는 IndexedDB, 이는 Firefox가 SQLite를 기반으로 구현한 것입니다. 확장 프로그램 ID는 webextension@metamask.io, 하지만 파이어폭스는 설치마다 고유한 내부 UUID를 할당하는데, 대략 다음과 같은 형식입니다. 196319ec-3a5e-4efe-9413-c327a770d874. 다음에서 확인하실 수 있습니다. about:debugging “이 Firefox” 아래에서

데이터는 다음 위치에 있습니다:

Windows: %APPDATA%\Mozilla\Firefox\Profiles\<PROFILE>\storage\default\moz-extension+++<UUID>^userContextId=4294967295\idb\

macOS: ~/Library/Application Support/Firefox/Profiles/<PROFILE>/storage/default/moz-extension+++<UUID>^userContextId=4294967295/idb/

리눅스: ~/.mozilla/firefox/<PROFILE>/storage/default/moz-extension+++<UUID>^userContextId=4294967295/idb/

안쪽의 idb/ 폴더 안에는 숫자로 된 이름을 가진 바이너리 파일들이 있습니다. 이들은 Snappy 압축 – LevelDB 파일처럼 단순히 grep 명령어로 검색할 수는 없습니다. 먼저 다음과 같은 도구를 사용하여 압축을 해제해야 합니다. snappy-fox 볼트 데이터를 추출할 수 있게 되기 전입니다. 제가 목격하는 파이어폭스 복구 과정에서 가장 흔한 실수는 바로 이것입니다. 사용자들이 바이너리 파일을 열어 보았을 때, 알아볼 수 있는 텍스트 조각들과 뒤섞인 난독화된 데이터를 보고 볼트가 손상되었다고 단정 짓는 경우가 많습니다. 하지만 그렇지 않습니다. 단지 압축되어 있을 뿐입니다.

Firefox 63 이전에는 확장 기능 저장소가 storage.js 프로필 디렉터리에서. 아주 오래된 설치 환경을 복원하는 경우, 다음을 찾아보세요. storage.js 또는 storage.js.migrated.

LevelDB와 모두가 궁금해하는 0001.ldb 파일

LevelDB는 구글의 키-값 저장소 엔진이며, 크로미움 기반 브라우저에서 MetaMask를 복구하려면 이 파일 구조를 이해하는 것이 필수적입니다.

MetaMask LevelDB 디렉토리에는 여러 종류의 파일이 포함되어 있습니다. .ldb 파일 (정렬된 문자열 테이블, 즉 SSTable)은 영구적인 정렬된 키-값 저장소입니다. .log 파일 Write-Ahead Log(WAL)은 최근에 기록된 데이터가 디스크로 플러시되기 전까지 임시로 저장되는 버퍼입니다. .ldb 파일들. 거기에는 MANIFEST-###### 파일 추적 데이터베이스 메타데이터, a CURRENT 활성 매니페스트를 가리키는 파일과, LOCK 동시 액세스를 차단하는 파일.

볼트 데이터는 대개 번호가 낮은 .ldb 파일000003.ldb, 000005.ldb, 또는 이와 유사한 값입니다. MetaMask의 공식 문서에는 “낮은 수치여야 합니다. 숫자가 크다면 금고가 아닙니다.”라고 명시되어 있습니다. 0001.ldb 파일 (또는 000001.ldb)는 MetaMask가 처음 초기화될 때 생성된 가장 초기 SSTable 중 하나입니다. 여기에는 대개 지갑 생성 시 작성된 원래의 볼트가 포함되어 있습니다.

에서 볼트 데이터 추출 .ldb 파일 Chromium에서는 보통 간단합니다. 텍스트 편집기(Sublime Text, VS Code, 심지어 Notepad++도 가능)에서 파일을 열고 다음 문자열을 검색하세요 vault. LevelDB 레코드 구조 내에 암호화된 JSON 블롭이 포함되어 있습니다. 다음의 모든 내용을 복사하세요. {"data":" 마감 시까지 "} – 그게 바로 당신의 금고입니다.

Mac이나 Linux에서는 다음 한 줄의 명령어로 해결할 수 있습니다:

LC_ALL="C" egrep -roa 'vault":"(.*?\\"})' ~/Library/Application\ Support/Google/Chrome/Default/Local\ Extension\ Settings/nkbihfbeogaeaoehlefnkodbefgpgknn/ | sed -E 's/.*({.*}).*/\1/g' | head -1

주목할 점 하나: .ldb 파일은 다음을 사용할 수 있습니다 빠른 압축 데이터 블록에서. 문자열 검색이 실패하고 이진 쓰레기 데이터 블록이 보인다면, 필요한 데이터 블록이 Snappy로 압축된 것일 수 있습니다. .log 반면 파일은 항상 압축되지 않은 상태로, 32KB 단위의 원시 키-값 데이터로 구성됩니다. 만약 .ldb 접근 방식이 실패하면, 항상 다음을 확인하십시오 .log 파일. MetaMask의 공식 문서에는 다음과 같이 명시되어 있습니다. “ .ldb 파일을 사용하여 볼트를 복구할 수 없는 경우, .log 파일이 있는지 확인해 보세요.”

복구 작업에 매우 유용한 LevelDB의 특징은 다음과 같습니다: 추가 전용. 업데이트 및 삭제 작업은 기존 레코드를 수정하지 않고, 더 높은 시퀀스 번호를 가진 새로운 항목을 추가합니다. 기존 레코드는 압축 작업이 이를 병합하여 제거할 때까지 그대로 유지됩니다. 즉, 누군가가 기존 SRP 위에 새로운 SRP를 가져온 경우, 이전 볼트 데이터는 여전히 이전 버전의 .ldb 아직 압축되지 않은 파일입니다. 저는 이런 방식으로 “덮어쓴” 지갑을 한 번 이상 복구한 적이 있습니다.

프로그램 방식의 추출을 위해서는, btcrecover 이 프로젝트에는 다음이 포함됩니다 extract-metamask-vaults.py, 이는 LevelDB 데이터베이스를 올바르게 읽어들이고, 압축 해제되지 않은 파일에 숨어 있을 수 있는 오래된 항목을 포함해 모든 볼트 항목을 추출합니다. 이 cyclone-github/metamask_extractor 이 도구는 동일한 기능을 수행하며, hashcat 호환 형식으로 직접 출력할 수 있습니다.

볼트 파일이 손상되었을 때

볼트 손상은 대개 다음과 같은 몇 가지 원인 중 하나에서 비롯됩니다. 쓰기 작업 중 발생한 브라우저 충돌 (전원 차단, 커널 패닉, 강제 종료), 저장소를 재작성하는 도중에 중단된 MetaMask 업데이트, 실제 디스크 오류 (불량 섹터, SSD 마모), 또는 점점 더 흔해지고 있는 안티바이러스 소프트웨어가 MetaMask의 자바스크립트 파일을 격리하는 경우입니다. 이 경우 볼트 데이터 자체는 손상되지 않았더라도 LevelDB 데이터베이스가 일관성 없는 상태로 남을 수 있습니다.

JSON 파싱이 되지 않는다면 볼트가 손상된 것입니다. 중괄호가 빠졌거나, base64 문자열이 잘렸거나, 데이터 필드 중간에 null 바이트가 삽입된 경우 등이 해당됩니다. MetaMask 볼트 복호화 도구는 “볼트 디코딩 오류” 메시지를 표시하거나 아무런 오류 메시지 없이 단순히 실패할 수 있습니다.

복구 가능 여부는 손상의 유형과 정도에 따라 달라집니다. JSON 구조가 손상되었더라도 암호화된 데이터가 대부분 온전하다면, 대개 금고를 수동으로 복원하다. 형식이 엄격합니다 – 정확히 data, iv, 그리고 salt 필드 (및 keyMetadata (최신 볼트의 경우). null 바이트와 제어 문자를 제거합니다. 다음을 확인하십시오. data, iv, 그리고 salt 값은 유효한 base64입니다. 만약 data 그러나 필드가 잘려 있다면, 큰일입니다 – AES-GCM은 전체 암호문을 필요로 합니다 여기에 인증 태그(의 마지막 16바이트)를 더한 data (필드)를 해독해야 합니다. 단 한 바이트라도 누락되면 전체 과정이 실패합니다.

일부 데이터가 손상된 LevelDB 데이터베이스의 경우, .ldb 파일 자체가 손상된 경우, 다음을 읽어보세요. .log 대신 파일을 확인해 보세요. 이 파일은 더 간단한 형식(7바이트 헤더가 포함된 순차적 32KB 블록)이며, 데이터 손상 사태를 견뎌낸 최신 버전의 볼트 사본을 포함하고 있을 수 있습니다. 두 방법 모두 효과가 없다면, Python LevelDB 파싱 라이브러리(CCL Solutions Group에서 LevelDB 파싱, Snappy 압축 해제, V8 역직렬화를 위한 순수 Python 구현체를 공개함)를 사용하여 손상된 블록을 건너뛰고 손상된 데이터베이스 파일에서 레코드를 정밀하게 추출할 수 있는 경우도 있습니다.

단일 LevelDB 디렉터리 내에 여러 SRP가 공존할 수 있습니다. 사용자가 새로운 시드 문구를 가져온 경우, 기존 볼트 항목은 별도의 .ldb 파일 내 또는 심지어 동일한 파일 내의 다른 위치에서도. 항상 다음을 검색하십시오 모든 인스턴스 볼트 패턴의 첫 번째 것뿐만 아니라

파일 덮어쓰기 문제와 해결 방법

이것이 가장 가슴 아픈 상황입니다. 누군가 메타마스크를 삭제해 버리는 경우죠. 문제 해결을 하려던 것일 수도 있고, 브라우저를 ‘정리’하려던 것일 수도 있으며, 자신이 무슨 일을 하는지 깨닫지 못한 채 그랬을 수도 있습니다. 크로미움 기반 브라우저에서 확장 프로그램을 삭제하면 확장 데이터 폴더 전체를 삭제합니다, 다음을 포함하여 .ldb, .log, 그리고 매니페스트 파일. 파이어폭스에서는, moz-extension+++<UUID> 폴더가 삭제되고, 재설치할 때마다 새로운 UUID가 생성되기 때문에 새 설치본은 기존 위치에 접근하지 않습니다(하지만 기존 위치는 이미 사라진 상태입니다).

메타마스크의 공식 문서에는 이 점에 대해 다음과 같이 명확히 명시되어 있습니다. “브라우저 확장 프로그램을 제거하면 확장 프로그램 데이터가 삭제됩니다. 일반적으로 이는 금고 데이터가 사라진다는 것을 의미합니다.”

“일반적으로”라는 말이 많은 의미를 담고 있습니다. 데이터는 논리적으로 삭제됩니다 (파일 시스템이 해당 섹터를 사용 가능한 공간으로 표시함). 하지만 실제 바이트는 즉시 0으로 초기화되지는 않습니다. 기존 HDD의 경우, 해당 섹터가 새로운 파일에 의해 재사용될 때까지는 데이터가 그대로 남아 있습니다. 반면 SSD에서는 TRIM 명령을 통해 삭제된 데이터를 몇 분, 때로는 몇 초 만에 복구 불가능하게 만들 수 있습니다.

지워진 금고를 복구할 때의 첫 번째 규칙은 컴퓨터 사용을 즉시 중단하는 것입니다. 드라이브에 새로 저장되는 모든 파일이 금고가 있던 섹터를 덮어쓸 수 있습니다. 가능하다면 드라이브를 분리하여 다른 컴퓨터에 읽기 전용으로 연결하십시오.

이 상황에서 제가 가장 먼저 사용하는 복구 도구는 다음과 같습니다:

  • 논리적으로 삭제된 파일을 복구하기 위한 당사의 맞춤형 소프트웨어 (크로스 플랫폼)
  • Linux ext3/ext4 파일 시스템용 extundelete 또는 ext4magic
  • 원시 디스크 검색 최후의 수단으로: grep -rboa "vault" /dev/sdX 원시 디스크 장치에서 볼트 문자열을 검색하기 위해
  • 당사의 맞춤형 도구 파일 시스템 메타데이터가 손실된 경우 파일 추출을 위해 – 다음을 검색하도록 구성하십시오 {"data":" 패턴

저는 몇 주 전에 제거된 드라이브(HDD 기준)에서 금고 데이터를 복구한 적이 있습니다. 하지만 SSD의 경우, 단 몇 시간만 계속 사용해도 성공률이 급격히 떨어집니다. MetaMask를 다시 설치하는 것은 최악의 선택입니다. 왜냐하면 동일한 디렉터리에 새로운 LevelDB 데이터베이스를 생성함으로써 기존 섹터를 덮어쓸 가능성이 있기 때문입니다.

이 점에서 파이어폭스에는 한 가지 장점이 있습니다. 설치할 때마다 새로운 UUID가 할당되므로, 재설치 시 파일이 새로운 디렉터리 경로에 생성됩니다. 기존 moz-extension+++<OLD-UUID> 폴더가 삭제되었더라도 데이터는 새 설치 파일로 덮어쓰이지 않습니다. 또한 두 가지 숨겨진 Firefox 환경 설정도 있습니다 – extensions.webextensions.keepUuidOnUninstall 그리고 extensions.webextensions.keepStorageOnUninstall – 만약 이를 true 에서 about:config 제거하기 전에 브라우저가 확장 프로그램 저장소를 지우지 못하도록 막아야 합니다. 하지만 아무도 이를 사전에 설정해 두지 않습니다.

모바일용 메타마스크는 완전히 다른 차원의 경험입니다

MetaMask 모바일 버전은 React Native 기반으로 제작되었으며, 브라우저 확장 프로그램과는 완전히 다른 방식으로 데이터를 저장합니다. 암호화된 금고는 @react-native-async-storage/async-storage, 이는 플랫폼별 백엔드를 사용합니다.

안드로이드에서, AsyncStorage는 일반적으로 SQLite 데이터베이스 에서 /data/data/io.metamask/databases/RKStorage. 이 경로를 통해 직접 읽으려면 루트 권한이 필요합니다. 볼트 암호화는 PBKDF2 파생 키 방식을 동일하게 사용하지만, 데스크톱 확장 프로그램과는 중요한 차이점이 있습니다. 모바일 앱은 과거부터 오직 PBKDF2 반복 5,000회 그리고 다음을 사용하여 암호화합니다 AES-CBC AES-GCM 대신에. 즉, 비밀번호가 동일하더라도 모바일 볼트와 데스크톱 볼트는 서로 호환되지 않습니다.

iOS에서, 데이터는 앱 샌드박스 내의 <AppSandbox>/Documents/. iCloud 백업 복구의 경우, 관련 경로는 다음과 같습니다. Apps → MetaMask → Documents → persistStore → persist-root – Mac에서 iOS 백업을 확인하려면 iMazing과 같은 도구가 필요합니다. 이 방법이 작동하는지는 사용자가 MetaMask를 사용 중일 때 iCloud 백업을 활성화해 두었는지 여부에 달려 있으며, 애플 측의 변경 사항으로 인해 이 방법이 간헐적으로 작동하지 않는 것으로 알려졌습니다.

MetaMask 모바일 버전 또한 보안 키 체인 모듈 (기반) react-native-keychain)는 생체 인식 잠금 해제를 위해 사용자의 지갑 비밀번호를 iOS 키체인이나 Android 키스토어에 저장합니다. 보안 감사 결과, SecureKeychain이 “foxCode” 솔트를 사용하여 추가 암호화 계층을 적용하는 것으로 드러났는데, 이 솔트는 하드코딩된 문자열로 밝혀졌습니다. "encrypt". 메타마스크 팀은 이것이 보안상 중대한 비밀이라기보다는 다층 방어 전략의 일환이라고 인정했다.

모바일 복구에서 직면하는 근본적인 과제는 바로 수동으로 볼트 추출 기능을 지원하지 않습니다 ~를 찾는 것과 같다 .ldb 바탕화면의 파일들. 아이폰에 SSH로 접속해서 볼트 문자열을 grep으로 검색할 수는 없습니다. 다음부터 MetaMask 모바일 v6.3.0이 앱에는 데이터 손상이 감지되면 자동으로 실행되는 볼트 복구 기능이 포함되어 있습니다. 하지만 앱을 삭제하면 기기 백업이 없는 한 로컬 볼트 데이터는 모두 사라집니다. 특히 안드로이드의 백업 기능은 앱 내부의 모든 데이터를 완벽하게 백업하는 데 있어 신뢰성이 떨어집니다. 메타마스크의 공식 입장 안드로이드 볼트 복구 기능에 의존하기보다는 자산을 새로운 SRP로 옮길 것을 권장합니다.

모든 복구 도구를 무용지물로 만든 PBKDF2 반복 횟수 변경

수년 동안 MetaMask는 PBKDF2 반복 10,000회 – 의 하드코딩된 기본값 browser-passworder 라이브러리. 모든 복구 도구, 모든 해시캣 모듈, 모든 무차별 대입 스크립트는 10,000회 반복을 기준으로 조정되어 있었습니다. 그러다 2023년 말에서 2024년 초 무렵, 모든 것이 바뀌었습니다.

@metamask/browser-passworder 라이브러리 v4.2.0(2023년 11월 13일 출시)에서는 구성 가능한 키 도출 옵션에 대한 지원이 추가되었습니다. 라이브러리의 새로운 기본값은 90만 번의 반복, 하지만 MetaMask 확장 프로그램이 이를 사용하도록 설정했습니다 60만 회 반복 – OWASP의 2023년 PBKDF2-HMAC-SHA256 권고 사항을 따릅니다. MetaMask 확장 프로그램 기준 v11.16.11 (2024년 6월 해시캣(hashcat) 이슈에서 확인된 바와 같이), 60만 번의 반복 횟수를 가진 새로운 볼트가 생성되고 있었으며, 새로운 keyMetadata 필드.

이는 비밀번호 한 번 시도당 계산 비용이 60배 증가한 것입니다. 동일한 하드웨어에서 1만 번의 반복으로 하루가 걸리던 무차별 대입 공격이, 60만 번의 반복으로 두 달이 걸리게 되었습니다. 해시캣(hashcat) 커뮤니티는 새로운 형식을 처리하기 위해 사이클론(cyclone)이 기여한 모드 26620과 같은 맞춤형 커널을 개발해야 했습니다. 표준 모드 26600에는 1만 번의 반복 횟수가 하드코딩되어 있었습니다.

중요한 점은, 기존 볼트는 자동으로 재암호화되지 않는다는 것입니다. 2021년에 지갑을 생성한 경우, MetaMask가 명시적으로 재암호화를 실행하지 않는 한 금고는 여전히 10,000회의 반복을 사용합니다( updateVault 이 목적을 위한 함수가 존재하지만, MetaMask가 잠금 해제 시 이 함수를 얼마나 적극적으로 호출하는지는 불분명합니다). 다음의 유무로 현재 사용 중인 버전을 확인할 수 있습니다. keyMetadata 필드. 아니요 keyMetadata? 10,000번의 반복입니다. keyMetadata ~와 함께 "iterations": 600000? 새로운 형식이에요.

복구에 중요한 암호화 라이브러리 버전의 전체 일정은 다음과 같습니다:

  • browser-passworder v1.x–v2.x (2022년 이전): 10,000회 반복, 고정값으로 설정됨. 다음을 제외하고 게시됨 @metamask 범위.
  • v3.0.0 (2022년 8월): 이름을 변경하여 @metamask/browser-passworder. 반복 횟수 변경 없음.
  • v4.2.0 (2023년 11월): 추가됨 keyMetadata 지원. 기본 암호화 반복 횟수가 900,000회로 변경되었습니다. keyFromPassword 10,000에서 하위 호환됩니다.
  • v4.3.0 (2023년 11월): 추가됨 isVaultUpdated 볼트가 목표 매개변수를 충족하는지 확인하기 위해.
  • v5.0.0 (2024년 4월): Node.js v16 이상 지원. 암호화 관련 변경 사항 없음.
  • v6.0.0 (2024년 12월): Node.js v18.18 이상. 암호화 관련 변경 사항 없음.

복구 전문가분들께: 항상 먼저 볼트 형식을 확인하십시오. 이는 전체적인 접근 방식을 결정짓습니다.

메타마스크의 비밀번호 정책과 이것이 무차별 대입 공격에 미치는 의미

MetaMask는 비밀번호 길이를 최소 8자 이상으로 설정하도록 요구합니다. 그게 전부입니다. 대문자, 숫자, 특수 문자의 사용은 필수 사항이 아닙니다. 확장 프로그램은 시각적인 보안 등급 표시기("약함" / "좋음")를 제공하지만, 최소 길이를 충족하는 약한 비밀번호의 사용을 차단하지는 않습니다. 최대 길이 제한도 없으며, 유니코드 문자를 지원합니다. 이 정책은 적어도 2018년 초부터 적용되어 왔습니다(GitHub 이슈 #3515 참조).

일부 제3자 사이트에서는 메타마스크(MetaMask) 비밀번호에 대문자, 소문자, 숫자, 특수 문자가 모두 포함되어야 한다고 잘못 주장하고 있습니다. 이는 사실이 아닙니다. 유일한 필수 조건은 8자 이상이어야 한다는 점뿐입니다.

무차별 대입 공격의 경우, 이는 매우 중요한 요소입니다. 소문자만 포함된 8자리 비밀번호의 키 공간은 약 2,080억 가지 조합 (26^8)에 달합니다. 10,000회 반복을 사용하는 구형 금고의 경우, 최신 GPU를 탑재한 hashcat은 초당 수천 개의 해시를 테스트할 수 있어 며칠 만에 해독이 가능합니다. 600,000회 반복을 사용하는 금고의 경우, 소요 시간이 60배로 늘어납니다. 대소문자와 기호가 혼합된 12자 이상의 강력한 비밀번호라면? 현재 하드웨어로는 두 경우 모두 사실상 해독이 불가능합니다.

실제로 가장 많이 선택되는 복구 도구는 btcrecover – 메타마스크 측에서는 비밀번호를 대략적으로 기억하고 있는 사용자에게 이 방법을 권장합니다. 이 기능은 토큰 기반 및 패턴 기반 추측을 지원하며, 다음과 같은 템플릿을 정의할 수 있게 해줍니다. "my" + [dog|cat|bird] + [2019|2020|2021] + ["!"|"@"|"#"] 그리고 모든 조합을 효율적으로 테스트합니다. GPU 가속 공격의 경우, hashcat 모드 26600은 구형 금고를, 모드 26610은 모바일 금고를, 모드 26620(또는 반복 횟수가 업데이트된 재컴파일된 26600)은 새로운 60만 반복 횟수 형식을 처리합니다.

유출 경로와 ‘자금 유실’의 만연

자금 유출 경로는 “내 자금이 사라졌다”는 문제가 발생하는 주된 원인입니다. 메타마스크 이더리움의 BIP-44 표준 경로를 사용합니다: m/44'/60'/0'/0. 계수는 최종 인덱스를 1씩 더하여 구합니다: m/44'/60'/0'/0/0 (첫 번째 계정), m/44'/60'/0'/0/1 (둘째), m/44'/60'/0'/0/2 (세 번째), 그 외의 경우도 마찬가지입니다. 이 경로는 모든 EVM 호환 체인에 적용되며, 이더리움, 폴리곤, 아비트럼, BSC에서 동일한 주소를 사용합니다.

문제는 모든 사람이 같은 경로를 사용하는 것은 아니라는 점입니다. 레저 라이브 용도 m/44'/60'/x'/0/0, 다음을 증가시키며 account ~ 대신 address_index. 레저 레거시 (이전 MEW/MyCrypto 경로)는 m/44'/60'/0'/x – 5단계가 아닌 4단계뿐입니다. 첫 번째 주소(m/44'/60'/0'/0/0)는 MetaMask, Ledger Live, Trezor에서 모두 동일합니다. 하지만 두 번째 계정부터는 완전히 달라진다, 각 지갑이 경로의 서로 다른 구성 요소를 증가시키기 때문입니다.

이로 인해 매우 특정한 오류 패턴이 발생합니다. 사용자가 MetaMask에서 Ledger 시드를 복원하고 첫 번째 계정과 잔액을 확인한 뒤, 두 번째 계정을 추가하면 잔액이 ‘0’으로 표시되는 것입니다. 자금이 사라진 것은 아닙니다. 자금은 파생된 주소에 그대로 남아 있습니다. m/44'/60'/1'/0/0 (Ledger Live 방식), 하지만 MetaMask는 m/44'/60'/0'/0/1. 키도 완전히 다르고, 주소도 완전히 다릅니다.

Trezor의 기본 이더리움 파생 경로 MetaMask의 것과 일치합니다: m/44'/60'/0'/0/x. 따라서 Trezor에서 MetaMask로의 복구 기능은 일반적으로 모든 계정에서 작동합니다. 지갑 간 호환성 문제는 주로 Ledger ↔ MetaMask 및 Ledger ↔ Trezor 간에 발생합니다.

“잘못된” 파생 경로에서 자금을 찾으려면 다음과 같은 방법이 있습니다:

  • contact@cryptorecovery.io으로 이메일을 보내주시면 최선을 다해 도와드리겠습니다.
  • MyEtherWallet (MEW): “경로 추가”를 통해 사용자 지정 파생 경로를 지원합니다. 수동으로 입력하세요 m/44'/60'/1'/0/0, m/44'/60'/2'/0/0등 Ledger Live 형식의 주소를 확인하기 위해.
  • MyCrypto: 유사한 사용자 정의 도출 경로 지원.
  • Ian Coleman의 BIP-39 도구 (오프라인 실행): 니모닉을 입력하고, ETH를 선택한 다음, BIP-44 탭을 전환하며, 경로 구성 요소를 수동으로 조정합니다.
  • btcrecover: 다양한 도출 경로 체계에 걸쳐 테스트를 자동화할 수 있습니다.

한 가지 아쉬운 점은, MetaMask의 Trezor 통합 기능이 사용자 지정 파생 경로를 지원하지 않는다는 것입니다. Ledger용 사용자 지정 파생 경로 옵션은 병합되었지만(PR #9367), 최신 정보에 따르면 Trezor용 옵션(GitHub 이슈 #11197)은 아직 해결되지 않은 상태입니다. MetaMask와 Trezor를 통해 Ledger에서 파생된 계정에 접근하려는 경우, 대신 MEW나 MyCrypto를 사용해야 합니다.

메타마스크와 트레저: 삐걱거리는 관계

MetaMask와 Trezor의 연동은 다음을 통해 이루어집니다 트레저 브릿지 – 로컬에 설치된 백그라운드 프로세스 (trezord)에서 수신 대기하는 http://127.0.0.1:21325/ 그리고 브라우저 샌드박스와 USB 하드웨어 액세스 간의 간극을 메워줍니다. 다음을 입력하여 실행 중인지 확인할 수 있습니다. http://127.0.0.1:21325/status/.

가장 흔한 오류 원인은 겉보기에는 아주 단순합니다. 바로 Trezor Suite가 실행 중이라는 점입니다. Trezor Suite는 장치와의 USB 연결을 잠그기 때문에 MetaMask가 통신할 수 없게 됩니다. Suite를 단순히 최소화하는 것이 아니라, 시스템 트레이에서 완전히 종료해야 합니다. 제가 접한 “MetaMask가 Trezor를 찾을 수 없습니다”라는 문의 건수 중 약 40%가 이 문제 때문인 것으로 추정됩니다.

기타 일반적인 문제와 해결 방법:

“Trezor를 찾고 있습니다…”라는 메시지가 끝없이 맴돌고 있습니다 – Bridge가 설치되어 있는지 확인하고 trezord 실행 중입니다. 다른 USB 케이블과 포트를 사용해 보세요. VPN, 방화벽 및 브라우저 확장 프로그램(광고 차단기나 개인정보 보호 확장 프로그램이 자주 간섭을 일으킵니다)을 비활성화하세요. 시크릿 모드를 사용하면 확장 프로그램 간 충돌을 방지할 수 있습니다.

“장치 연결 중” – 다른 애플리케이션이나 브라우저 탭이 이미 Trezor와 통신 중입니다. 해당 장치에 접근할 수 있는 다른 모든 탭과 애플리케이션을 닫으십시오.

WebUSB의 제한 사항 – Firefox는 WebUSB를 전혀 지원하지 않으므로, Firefox에서 Trezor를 연결하려면 전적으로 Bridge에 의존해야 합니다. Chrome, Brave, Edge는 Chromium의 WebUSB/WebHID 구현을 통해 작동합니다.

Trezor Safe 5 파생 경로 경고 – 사용자들은 거래 검증 과정에서 Trezor 화면에 “선택한 계정의 파생 경로가 잘못되었습니다. m/44’/60’/0’/0”이라는 메시지가 표시된다고 보고합니다. 이 경고는 일반적으로 무시해도 무방합니다. 메시지가 표시되더라도 지갑은 정상적으로 작동합니다. 이는 Trezor 펌웨어가 표준 형식과 다른 경로를 검증하는 방식과 관련된 표면적인 문제입니다.

2025년, Trezor는 Trezor Suite 자체에 Bridge 기능을 통합하기 시작했습니다. 이러한 변화로 인해 일부 사용자는 MetaMask 연결을 위해 Suite를 백그라운드에서 실행해야 하는 반면, 다른 사용자는 Suite를 완전히 종료해야 하는 등 연결 관련 문제가 잇달아 발생했습니다. 관련 설정은 Trezor Suite → 설정 → 애플리케이션 → Trezor Connect에서 확인하시기 바랍니다.

MetaMask가 Trezor에 연결되면 생성되는 계정은 MetaMask의 소프트웨어 지갑 계정과 근본적으로 다릅니다. Trezor에서 파생된 계정은 금고(vault)에 공개 키와 파생 경로만 저장하며, 개인 키는 하드웨어 기기에 남아 있습니다. 메타마스크는 트레저가 연결되지 않은 상태에서도 잔액을 표시할 수 있지만(공개 키를 통한 읽기 전용), 실제 기기가 없으면 거래에 서명할 수 없습니다. 트레저 계정 생성 시 패스프레이즈를 사용한 경우, 동일한 주소를 재생성하려면 정확히 동일한 패스프레이즈를 입력해야 합니다.

실제로 효과가 입증된 회복 기법

수백 건의 복구 작업을 거치며, 제가 가장 자주 마주치는 상황들과 그에 대한 대처 방법은 다음과 같습니다.

시나리오 1: 비밀번호는 알고 있지만 시드 문구를 분실했고, 확장 프로그램은 여전히 설치된 상태

이건 아주 간단해요. 다음 링크를 통해 MetaMask의 백그라운드 페이지를 열어주세요. chrome://extensions → 개발자 모드 → “서비스 워커”(MV3) 또는 “백그라운드 페이지”(MV2)를 클릭합니다. 콘솔에서:

chrome.storage.local.get('data', result => {
    console.log(result.data.KeyringController.vault);
});

볼트 JSON을 복사한 다음, 이를 메타마스크 볼트 복호화 도구 (metamask.github.io/vault-decryptor), 비밀번호를 입력하면 니모닉과 가져온 모든 개인 키가 표시됩니다. Vault Decryptor는 MetaMask의 공동 창립자인 Dan Finlay가 개발했으며, 다음을 지원합니다. .ldb 파일 업로드를 통해 직접 파일을 업로드합니다.

시나리오 2: 비밀번호는 알고 있으나, 확장 프로그램이 제거되었지만 데이터가 디스크에 남아 있을 수 있는 경우

확장 프로그램 데이터 디렉터리로 이동하세요. 해당 폴더가 여전히 존재하는 경우(때로는 제거 시 완전히 삭제되지 않거나, 사용자가 확장 프로그램을 삭제하지 않고 비활성화만 한 경우), .ldb 그리고 .log 파일들. grep이나 텍스트 편집기를 사용하여 볼트를 추출하거나 btcrecover’s extract-metamask-vaults.py. Vault Decryptor를 사용하여 복호화하십시오.

폴더가 사라진 경우, contact@cryptorecovery.io으로 문의해 주시면 디스크 포렌식 조사를 도와드리겠습니다.

드라이브를 읽기 전용으로 마운트한 다음, 볼트 문자열 패턴에 대한 원시 디스크 검색을 수행할 수도 있습니다. 리눅스에서는: grep -rboa '{"data":"' /dev/sdX. 성공 여부는 삭제 후 디스크 활동이 얼마나 발생했는지, 그리고 드라이브가 SSD인지 HDD인지에 크게 좌우됩니다.

시나리오 3: 비밀번호를 잊어버렸지만 볼트 파일은 가지고 있는 경우

이것은 무차별 대입 공격 시나리오입니다. 볼트를 추출한 후 다음 명령어를 사용하여 hashcat 형식으로 변환하십시오. metamask2hashcat.py 또는 cyclone-github/metamask_extractor. 그런 다음, 기억나는 비밀번호 정보를 담은 토큰 파일을 사용하여 hashcat(구형 금고의 경우 모드 26600, 신형 금고의 경우 모드 26620)이나 btcrecover를 실행하세요. 비밀번호가 “myDog”에 연도와 기호를 더한 형태였다는 것을 알고 있다면, btcrecover를 통해 이러한 조합을 효율적으로 테스트할 수 있습니다.

시나리오 4: 파이어폭스 복구

다음 위치에서 MetaMask UUID를 찾으세요 about:debugging. 저장소 디렉터리로 이동합니다. 다음 명령어를 사용하여 IndexedDB 바이너리 파일을 압축 해제합니다. snappy-fox:

./snappy-fox input_file.snappy output.txt

압축을 푼 출력 파일에서 Vault JSON 파일을 찾으세요. 그런 다음 Vault Decryptor를 실행하세요. JesseBusman/FirefoxMetamaskWalletSeedRecovery 이 파이썬 스크립트는 이 전체 과정을 자동화합니다. 파이어폭스 프로필을 스캔하여 볼트 데이터를 찾아내고, 복호화할 수 있도록 형식이 지정된 JSON 데이터를 출력합니다.

시나리오 5: 시드 키를 가져온 후 자금이 사라진 것처럼 보임

파생 경로를 확인하세요. Ledger 시드를 MetaMask로 가져올 경우, 두 번째 계정부터는 다른 주소가 표시되고 잔액이 0으로 나타납니다. Ledger Live에서 자금을 찾으려면 사용자 지정 파생 경로를 사용하여 MEW 또는 MyCrypto를 사용하세요 (m/44'/60'/x'/0/0) 또는 Ledger Legacy (m/44'/60'/0'/x) 경로입니다. Trezor 비밀번호가 필요한 경우, 반드시 정확히 동일한 비밀번호를 입력해야 합니다. 비밀번호가 다르면 동일한 시드에서 완전히 다른 주소 집합이 생성됩니다.

도구 상자에 꼭 챙겨두면 좋은 포렌식 도구들

  • 메타마스크 볼트 복호화 도구 – 공식 버전, 오프라인에서 실행 가능, 직접 처리 .ldb 파일 업로드
  • btcrecover – 패턴 매칭을 통한 비밀번호 복구, MetaMask 추천
  • hashcat – GPU 가속 무차별 대입 공격 (모드 26600, 26610, 26620)
  • snappy-fox – Firefox Snappy 압축 해제
  • CCL Solutions Group의 Python 도구 – 순수 Python 기반 LevelDB 파싱, Snappy 압축 해제, V8 역직렬화

결론: 성공적인 회복과 실패를 가르는 요인

지갑을 되찾을 수 있는지 영원히 잃어버리게 될지는 거의 항상 문제를 발견한 직후의 몇 분 동안 어떤 조치를 취했는지에 달려 있습니다. 가장 치명적인 행동은 동일한 브라우저 프로필에 MetaMask를 다시 설치하는 것인데, 이 경우 LevelDB 디렉터리가 새로운 파일로 덮어쓰게 됩니다. 두 번째로 치명적인 행동은 볼트 삭제 후 SSD에서 평소처럼 컴퓨터를 계속 사용하는 것으로, 이는 TRIM을 실행시켜 섹터 단위의 복구를 불가능하게 만듭니다.

이 가이드에서 꼭 기억해야 할 세 가지는 다음과 같습니다. 시드 문구를 종이에 백업해 두세요. 금고(Vault)가 복사하여 보관할 수 있는 특정 폴더에 저장되어 있다는 점을 숙지하세요. 그리고 문제가 발생하면 복구 시도를 하기 전에 즉시 해당 컴퓨터 사용을 중단하세요. 암호화 자체는 견고합니다. 60만 번의 PBKDF2 반복을 거친 AES-256-GCM은 비밀번호가 취약하지 않은 한 무차별 대입 공격으로 뚫릴 수 없습니다. 하지만 데이터 자체는 의외로 취약합니다. LevelDB 데이터베이스에 저장된 몇 킬로바이트에 불과한 이 데이터는, 브라우저에서 '데이터 지우기'를 한 번 클릭하는 것만으로도 사라질 수 있습니다.

제가 복구하지 못한 모든 지갑의 근본 원인은 하나였습니다. 바로 데이터가 손실된 후에도 사용자가 계속 기기를 사용했다는 점입니다. 반면, 제가 성공적으로 복구한 모든 지갑은 데이터가 디스크에 남아 있던 경우였습니다. 때로는 의외의 장소에 있기도 했고, LevelDB의 추가 전용(append-only) 아키텍처 덕분에 여러 개의 복사본이 존재하기도 했지만, 항상 사용자가 행동에 나서기 전에 잠시 멈춰 생각했기 때문이었습니다.

메타마스크 지갑 복구에 도움이 필요하시면 이메일로 문의해 주세요: contact@cryptorecovery.io 전문적이고 무료인 상담을 원하시면 이메일을 보내주시거나 연락처 페이지를 방문해 주세요