首页 / 资讯中心 / 文章详情

Office文档密码恢复:加密结构、哈希提取与hashcat策略

Office文档密码恢复:加密结构、哈希提取与hashcat策略 ★ FEATURED ARTICLE
简介面向因遗忘密码而无法打开 Word、Excel、PowerPoint 等 Office 文档的个人用户与日常办公维护人员这份资源提供 Office 密码恢复类工具的整理与使用参考定位为应急解锁与密码找回场景下的辅助材料。资源以 RAR 压缩包形式分发包体约 2.77MB页面显示文件总数为 0、类型明细暂无有效数据实际文件构成需以压缩包内为准。已有 123 人浏览学习说明其在小范围内具备一定参考价值。读者可借助其中的工具与说明了解 Office 文档密码恢复的基本思路、常见文档类型的处理入口以及操作前的注意事项适合需要快速排查文档打不开问题、又不想逐一试错的人保存备用建议仅用于处理本人拥有合法权限的文件并提前做好原文件备份。1. 一个被碎纸机吃掉的密码和它背后的真实需求某公司做交接时一份加密的对账表格连同写在便签上的密码一起进了碎纸机。当事人搜了一整晚「OFFICE 密码破解器」装了三四个来路不明的一键工具表格没打开机器先杀了两轮毒。这类需求的真实形态其实很朴素——自己的文档、自己设的密码、自己忘了或者团队交接时密码没跟着走。它解决的是「合法持有者重新获得文档访问权」这件事适合运维、行政、财务、法务这些经常接手加密文件的岗位也适合做数据归档审计的人。但前提必须钉死只能对自己拥有或获授权的文档操作。2. Office 加密的四代结构文件里到底存了什么很多人以为 Office 加密就是给 ZIP 套个密码实际完全不是。不同年份保存的文档加密结构差了好几代选错识别方式后面所有参数都是白设。2.1 两套容器四代算法OOXML 文档.docx/.xlsx/.pptx本质是个 ZIP 包。加密之后它不再是可以直接解压的 ZIP而变成 OLE 复合文档里面挂两个特殊流/EncryptionInfo存版本号、算法标识、盐值、迭代次数和加密后的校验值/EncryptedPackage存原始 ZIP 被切成 4096 字节块后逐块加密的结果。老二进制格式.doc/.xls/.ppt97-2003是另一套加密标识藏在 FIBFile Information Block里通过fEncrypted标志位判断紧跟其后是一个 EncryptionHeader 结构算法通常是 RC4。按生成年份主流可以分成四代文件格式加密算法密钥派生迭代次数hashcat 模式.doc/.xls/.ppt97-2003RC4 40/128 bitMD51 次9700OOXML2007AES-128-CBCSHA-1500009400OOXML2010AES-128-CBCSHA-11000009500OOXML2013 及以后AES-256-CBCSHA-5121000009600这张表是整篇文章的锚点。你拿到任何一个加密文档第一件事不是急着跑工具而是先确认它属于哪一行。同一份 .xlsx用 2007 保存和用 2013 另存迭代次数和哈希算法都可能变模式选错就是跑一万年也不出结果。2.2 密钥派生为什么把穷举攻击判了死刑Agile 加密2010 起的密钥派生流程大致是先算H0 Hash(salt password)然后对结果反复迭代Hn Hash(Hn-1 blockKeyIterator)迭代 spinCount 次通常是 100000最后再和 blockKey 混合出真正的 AES 密钥。这意味着验证一个候选密码是否正确必须把 10 万次 SHA-512 完整跑完中间没有任何捷径。对比一下数量级就明白了普通 MD5 明文哈希用一块消费级显卡一秒能算几十亿次而 Office 2013 的哈希一秒只能算十万量级差了四到五个数量级。把候选空间摊开算一遍更直观。纯 8 位数字是 10^8 个候选按每秒十万算大约一千秒十几分钟能出。8 位大小写字母混合是 52^8 约 5.3×10^13需要五年多。8 位全字符集大小写字母加数字加符号是 10^15 量级直接放弃。所以「暴力穷举」这三个字在现代 Office 文档上基本是不成立的能跑通的一定是带了先验信息的定向攻击——字典、规则、掩码这三样才是主力。血泪经验是拿到文档先问清楚「密码大概是什么风格」比直接挂上显卡跑三天有用得多。人设的密码有强规律生日、工号、姓名拼音、公司缩写、年份后缀这些信息能把搜索空间从 10^15 压到 10^7 以内。2.3 先把加密参数读出来再动手在跑任何恢复工具之前先确认两件事文档到底加没加密加密参数是什么。判断是否加密用msoffcrypto-tool就够它不做任何网络请求纯本地读文件头。# probe_office.py —— 只读文件头不做任何解密尝试 import msoffcrypto def probe(path: str) - None: with open(path, rb) as f: container msoffcrypto.OfficeFile(f) # is_encrypted() 会读 /EncryptionInfo 或 FIB 里的 fEncrypted 标志 encrypted container.is_encrypted() # 类型名能反推出容器格式OOXMLFile 对应 docx 系Doc97File 对应老二进制 print(f是否加密: {encrypted}) print(f容器类型: {type(container).__name__}) if encrypted: # 不同版本暴露的属性名有差异用 getattr 兜底 info getattr(container, format, None) print(f加密格式标识: {info}) salt getattr(container, salt, None) print(f盐值: {salt.hex() if salt else 未暴露}) if __name__ __main__: probe(./季度对账.xlsx)这段代码的作用是把「猜测」变成「读数」。is_encrypted()返回 False 说明文档根本没加密后面所有工作都可以省掉——这种情况比想象中多很多人拿到打不开的文件就以为是加密实际是文件损坏或格式不兼容。type(container).__name__反推出容器是 OOXML 还是 97 格式直接决定后面该用 9400/9500/9600 还是 9700。如果msoffcrypto没暴露迭代次数也别纠结下一步用office2john提取哈希串时这些字段会全部摊在明面上。3. 把恢复环境跑起来从哈希提取到第一次碰撞环境搭不起来的常见原因不是工具装不上是哈希格式和模式编号对不上。这一段把链路完整走一遍。3.1 提取可校验的哈希字段拆解office2john.py是 John the Ripper 自带的一个脚本作用是从加密文档里把「可以用来校验的哈希」抽出来格式和 hashcat 兼容。# office2john.py 在 JtR 的 run/ 目录下用绝对路径调用最稳 python3 /opt/john/run/office2john.py ./季度对账.xlsx ./raw_hash.txt # 输出会带文件名前缀看一眼完整内容 cat ./raw_hash.txt输出长这样盐值和校验值已省略季度对账.xlsx:$office$*2013*100000*256*16*a1b2...*c3d4...*e5f6...逐字段拆开看第一段2013是生成版本直接决定模式第二段100000是迭代次数这个数字越大跑得越慢第三段256是密钥长度bit第四段16是盐长度字节后面三段分别是盐值、加密后的校验输入、加密后的校验哈希。注意文件名前缀那个冒号。hashcat 默认会把每一行当成纯哈希遇到文件名:哈希的结构会直接报 token length exception一行都跑不了。两种处理方式加--username让 hashcat 跳过冒号前的内容或者提取时就用管道剥掉。# 方式一提取阶段直接剥掉文件名前缀 python3 /opt/john/run/office2john.py ./季度对账.xlsx | sed s/^[^:]*:// ./hash.txt # 确认只剩哈希本体开头应该是 $office$ head -c 40 ./hash.txt剥掉前缀的好处是后面所有命令都不用再带--username减少一个出错点。但文件名信息就丢了如果一次要处理多个文档建议保留文件名前缀然后统一加--username否则跑出结果都不知道对应哪个文件。3.2 模式编号怎么对号入座hashcat 的 Office 模式编号不是靠背的靠查。每个版本编号可能有微调最稳的办法是现场查一遍。# 列出所有和 Office 相关的示例哈希输出里带模式编号和结构说明 hashcat --example-hashes | grep -i -B1 -A6 MS Office # 也可以只查模式列表速度更快 hashcat -hh | grep -i office对照第 2 章那张表$office$*2007*对应 9400*2010*对应 9500*2013*和*2016*对应 9600老二进制的$oldoffice$*对应 9700。这里有个容易翻车的点——文档后缀是 .xlsx 不代表它就是 2013 代际实际算法由保存时用的 Office 版本决定哈希串里那个年份字段才是唯一依据。如果哈希串里的年份字段是 2016 或 2019不用慌它们的密钥派生流程和 2013 一致都走 9600。反过来如果拿到的是 2007 存的文档但用新版软件另存过年份字段会跟着变一定要以哈希串为准而不是文件属性里的创建时间。3.3 第一次跑先用字典探底第一次跑不要上掩码先用中等强度的字典加规则目的是快速判断「这个密码是不是常见密码」同时观察显卡的实际速度为后面的策略定预算。# -m 9600 对应 2013 代际-a 0 是纯字典模式 # -r 挂 best64 规则把字典里每个词做 64 种常见变形首字母大写、加数字后缀等 # -O 启用优化内核速度快但限制候选长度不超过 31 # -w 3 是最高工作负载会让桌面明显卡顿跑之前先保存工作 hashcat -m 9600 -a 0 ./hash.txt \ ./wordlists/top100k.txt \ -r ./rules/best64.rule \ -O -w 3 \ --status --status-timer20 \ -o ./found.txt参数逐个说清楚。-m 9600是算法模式选错等于白跑。-a 0是攻击模式0 是字典3 是掩码1 是组合6 和 7 是字典加掩码的混合。-r挂规则文件best64 是最通用的入门规则能把 10 万词的字典膨胀成 640 万候选。-O启用优化内核能提速 20% 到 50%代价是候选密码长度不能超过 31 字符——正常密码远达不到这个长度但如果你在测超长短语这里会静默截断属于后面避坑章要讲的点。--status --status-timer20让 hashcat 每 20 秒打印一次进度包括已尝试数量、当前速度和预计剩余时间。这个数据是定预算的关键看到速度是每秒 12 万就知道 8 位纯数字需要 800 秒左右心里有数才不会被「跑了三天没动静」拖垮。-o ./found.txt把命中的明文单独落盘避免和 potfile 混在一起。跑完之后用--show回看结果这一步很多人漏掉导致重复劳动。# 从 potfile 里回显已恢复的明文不重新计算 hashcat -m 9600 ./hash.txt --show # 如果用了自定义 potfile 路径要同步指定 hashcat -m 9600 ./hash.txt --show --potfile-path ./office.potfile--show只读 potfile 不重算毫秒级返回。养成习惯每次换策略之前先--show一次确认没有已经跑出来的结果被重复计算。hashcat 默认的 potfile 路径在~/.local/share/hashcat/hashcat.potfile如果不确定之前用过什么路径先用--potfile-path显式指定一个项目内路径所有命令统一用它。4. 三条恢复路径字典、掩码与结构推断到这里环境已经通了剩下的是策略问题。三条路径的适用场景完全不同选错了不是慢一点是根本跑不出来。4.1 字典加自定义规则攻人脑密码的生成规律通用字典比如网上流传的那些泄露口令集覆盖的是「全球常见密码」但对中文环境的企业文档命中率并不高。真实场景里的密码往往是「姓名拼音首字母 年份」「公司缩写 工号」「项目代号 特殊符号」这些得自己写规则。# corp.rule —— 针对中文企业环境常见构造方式的规则集 # 每行一组规则hashcat 会按顺序叠加执行 c c $2 $0 $2 $4 c $2 $0 $2 $3 sa4 se3 si1 so0 c $! $! $ $2 $0 $2 $4规则语法解释c把首字母大写$X在末尾追加字符 X^X在开头插入 XsXY把所有的 X 替换成 Y。所以c $2 $0 $2 $4的意思是「首字母大写末尾追加 2024」能把zhangsan变成Zhangsan2024。sa4 se3 si1 so0是 leetspeak 替换把 a 换成 4、e 换成 3、i 换成 1、o 换成 0能覆盖pssw0rd这类变形。规则文件的价值在于「用几十行规则放大字典的覆盖面」。10 万词的字典配上 50 条规则就是 500 万候选跑一轮在消费级显卡上大概几分钟成本极低。我一般会准备三套规则一套通用best64、一套中文姓名年份、一套 leetspeak 变形按顺序跑每跑完一套先--show一次。字典本身也有讲究。中文环境的密码经常是拼音而网上大部分字典是英文词表直接跑命中率很低。可行的做法是自己生成一份「常见姓氏拼音 常见名字拼音」的组合表几十万条量级配合规则使用。生成脚本不复杂用 Python 拼一下就行但注意别把生成的文件搞成 GBK 编码——hashcat 只认 UTF-8编码不对的话中文候选全部失效。4.2 掩码攻击已知结构该怎么拆位当你从文档主人那里问出「好像是 8 位首字母大写后面全是数字」这类信息时掩码就是最优解。掩码用字符集占位符描述每一位的可能范围直接把搜索空间卡死。# 已知结构1 位大写 7 位数字总长 8 # ?u 是大写字母集26 个?d 是数字集10 个 hashcat -m 9600 -a 3 ./hash.txt ?u?d?d?d?d?d?d?d -O -w 3这个掩码的搜索空间是 26 × 10^7 2.6×10^8按每秒 12 万算大约 36 分钟。对比不加信息的全字符集 8 位10^15 量级压缩了七个数量级。掩码的威力全在「先验信息」上没有信息就别用掩码。如果只知道长度范围不知道具体结构用增量模式从短往长扫避免一上来就怼满长度。# 长度 6 到 9 位全小写字母由短到长递增 # -i 开启增量--increment-min/max 指定长度区间 hashcat -m 9600 -a 3 ./hash.txt \ -i --increment-min6 --increment-max9 \ ?l?l?l?l?l?l?l?l?l -O -w 3增量模式的实际执行顺序是「先跑 6 位全部组合再跑 7 位依次类推」。这个顺序很重要因为短密码的命中概率远高于长密码先扫短的能在几分钟内给出「有没有」的答案。如果 6 位和 7 位都空手再决定要不要投入几小时跑 8 位决策依据就有了。字符集占位符的完整对照?l小写字母、?u大写字母、?d数字、?s特殊符号、?a全部可打印 ASCII、?b全部字节。中文字符没法用内置占位符表示得用自定义字符集-1参数指定但实践中中文密码的搜索空间太大一般不作为首选路径。4.3 结构推断与降级什么时候该放弃暴力现代 AES 加密没有已知明文捷径。老版 RC4 因为密钥流复用理论上存在已知明文恢复密钥流的路径但 40-bit 密钥空间本身只有 10^12对显卡来说是几小时的事直接暴力反而更省事。所以对 97-2003 格式优先考虑直接穷举对 2013 及以后只能靠先验信息。给一张务实的预期表避免把时间浪费在不可能的任务上文档代际8 位纯数字8 位大小写混合8 位全字符集2003RC4秒级分钟级小时级2007SHA-15 万次分钟级数天不可行2013SHA-51210 万次十几分钟数年不可行看到这张表就该明白如果文档是 2013 之后保存的且密码是随机生成的强密码恢复的可行性基本为零这时候正确的做法是回到业务侧找原始密码而不是继续烧显卡。这个判断越早做越好别等到跑了三天才承认。降级思路还有一层先试「零信息高频密码」。123456、password、admin、888888、文件名本身、文档标题拼音这几百个候选用字典模式一秒就能扫完成本几乎为零。我见过不少案例就是卡在这一步——文档主人信誓旦旦说「设了复杂密码」结果一跑字典三十秒就出来了。5. 避坑记录六个让我白跑一整晚的问题下面六条都是实际撞过的每条按「现象 → 原因 → 解决」写。看完能省下至少两个通宵。5.1 环境与工具链层面的坑坑一hashcat 报 Token length exception一行都没跑起来。现象是命令执行后立刻报错退出提示Token length exception或Separator unmatched。原因是office2john.py的输出带文件名:前缀hashcat 把冒号当分隔符解析失败。解决办法两条路提取时用sed s/^[^:]*://剥掉前缀或者跑的时候加--username让 hashcat 跳过冒号前的内容。批量处理多个文档时推荐后者因为能保留文件名做映射。坑二模式选对、命令没错但速度慢到离谱一晚上才跑了百分之几。现象是--status显示速度只有几百 H/s比正常低了三个数量级。原因通常是显卡的 OpenCL 运行时没装好hashcat 回退到 CPU 后端在跑。用hashcat -I检查设备列表如果只列出 CPU 没列出 GPU就确认了。解决方式是按显卡厂商装对应的计算运行时装完hashcat -I应该能看到 GPU 型号和显存。另一个可能原因是-D 1参数限制了只用 CPU 后端检查命令行里有没有这个参数。坑三中文密码怎么都跑不出来字典里明明有。现象是字典文件里肉眼可见有正确的拼音组合但 hashcat 跑完显示未命中。原因是字典文件编码是 GBK而 hashcat 按字节读取GBK 编码的中文字节序列和 UTF-8 完全不同。用file -i ./dict.txt确认编码iconv -f GBK -t UTF-8转一遍再跑。这个坑的隐蔽之处在于文件用编辑器打开看起来完全正常只有比对字节才能发现。5.2 策略与预期层面的坑坑四以为要跑三天结果 potfile 里早就有结果。现象是启动后立刻显示Recovered但命令行输出看起来像刚跑出来的。原因是 hashcat 默认会先查 potfile命中就直接返回不重新计算。这不是 bug是特性。但如果你换了--potfile-path却没注意到旧结果在默认路径里就会反复「跑出来」同一个密码还纳闷为什么这么快。解决方式所有命令统一显式指定--potfile-path项目开始就定好路径别用默认值。坑五开了-O优化内核超长候选被静默截断。现象是明明字典里有正确的长密码比如 40 字符的短语跑完却未命中。原因是-O启用优化内核后候选密码长度上限是 31 字符超出的部分被截断后再参与计算自然不会命中。解决办法如果怀疑密码是长短语去掉-O速度会降 20% 到 50% 但不会截断。判断依据是先看哈希串的密钥长度字段再看业务场景——大多数人的密码远不到 31 字符这个坑主要出现在自动生成的密钥场景。坑六掩码写反了位序白跑六小时。现象是掩码攻击跑完全程未命中但事后手工验证密码确实符合描述的结构。原因是把「首字母大写」错写成?d?u?l?l...之类位序和实际密码对不上。掩码是按位严格匹配的第一位是什么类型就必须写什么占位符写反一位整个搜索空间就错过正确答案。解决办法写掩码前先用一个小样本验证比如拿?u?d去跑一个已知的A1测试文档确认位序理解正确再上真实文档。这个验证花两分钟能省几小时。6. 进阶把恢复流程固化成一份可复用的脚本单次恢复跑通之后真正有价值的是把流程固化下来。接手加密文档的场景会反复出现每次都手工敲命令容易漏参数、漏检查。我一般会写一个带前置校验的脚本把「判断是否加密 → 提取哈希 → 映射模式 → 分阶段跑策略」串起来。#!/usr/bin/env bash # office_recover.sh —— 单文档密码恢复流程封装 set -euo pipefail DOC${1:?用法: ./office_recover.sh 加密文档路径} WORK./office_recover mkdir -p $WORK # 阶段一提取哈希并剥掉文件名前缀 python3 /opt/john/run/office2john.py $DOC | sed s/^[^:]*:// $WORK/hash.txt # 阶段二从哈希串里读出版本年份映射到 hashcat 模式 YEAR$(grep -o \*20[0-9][0-9]\* $WORK/hash.txt | tr -d * | head -1 || true) case ${YEAR:-} in 2007) MODE9400 ;; 2010) MODE9500 ;; 2013|2016|2019) MODE9600 ;; ) MODE9700 ;; # 老二进制格式的哈希串里没有年份字段 *) echo 未知版本 $YEAR需手工确认模式; exit 1 ;; esac echo 识别版本: ${YEAR:-97-2003} 使用模式: $MODE # 阶段三先扫高频弱口令成本最低 hashcat -m $MODE -a 0 $WORK/hash.txt ./dict/top1k.txt \ --potfile-path $WORK/office.potfile -O -w 3 --quiet || true # 阶段四字典加规则中等强度 hashcat -m $MODE -a 0 $WORK/hash.txt ./dict/top100k.txt \ -r ./rules/best64.rule \ --potfile-path $WORK/office.potfile -O -w 3 --status --status-timer30 || true # 阶段五回显结果 hashcat -m $MODE $WORK/hash.txt --show --potfile-path $WORK/office.potfile脚本里有三个关键设计。第一版本映射用哈希串里的年份字段而不是文件后缀这是前面反复强调的点脚本化之后就不会因为手滑选错模式。第二--potfile-path全程统一阶段三跑出来的结果阶段四不会重复计算阶段五直接回显整个流程没有冗余计算。第三每个 hashcat 调用后面都跟|| true因为 hashcat 在「未命中」时的退出码非零不加的话set -e会让脚本在中途直接退出。再补一个实用技巧组合攻击。当怀疑密码是「两个词拼起来」时用-a 1做字典乘字典或者用-a 6/7做字典加掩码的混合。比如-a 6 dict.txt ?d?d?d?d会把字典里每个词后面接四位数字适合「英文单词 年份」这类结构。成本是候选数相乘跑之前先用--stdout估算总量别一头撞进 10^12 的坑里。# 估算组合攻击的候选总量不实际计算哈希 hashcat -a 6 ./dict/top100k.txt ?d?d?d?d --stdout | wc -l最后是那句教训。早些年我接手一个加密表格凭直觉判断是 2013 代际挂上显卡跑了整晚没出第二天才发现哈希串里的年份字段是 2007模式从头就选错了。从那以后我每次动手前都强制走一遍「提取哈希 → 打印版本字段 → 查示例哈希确认模式」这三步哪怕文档后缀看起来再熟悉也不跳过。这套前置检查花不到一分钟能挡掉后面绝大部分白跑。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站