CVE-2018-5996 7zip学习笔记
CVE-2018-5996 7zip学习笔记
前置知识
Range encoding
顾名思义,就是把一个字符串流根据字符出现的频率,转化成一个范围(阈值)
https://en.wikipedia.org/wiki/Range_encoding
简介
原文
https://landave.io/2018/01/7-zip-multiple-memory-corruptions-via-rar-and-zip/#fn:2
可触发堆溢出和栈溢出
PPMd是压缩算法RAR3压缩算法的实现
bug
对于每个RAR版本,最多创建一个coder。如果同一个版本有多个实例,就使用同一个coder。
调用code可能返回失败S_FALSE,而且被创建的coder下次仍然会使用。我们找到一个能让它返回
S_FALSE的函数。
CInBufferException,当从输入流中读入时,这个异常可能会被抛出,我们可以用一个RAR3实例
来触发这个异常,抛出S_FALSE
一旦RAR3在PPMd更新时抛出异常,会让PPMd模型处于不稳定状态,同样的coder会被用作下个实例,
即使在CInBufferException已经抛出S_FALSE的异常码
RAR3解码器维持PPMd模型的状态,PPMd模型只有在一个item显示要求时才会重新初始化,
这意味着我们可以这样做:
- 当PPMd模型在更新时,构造一个RAR3实例来触发ClnBufferException,
- 之后的item没有重置,因此PPMd会处于不稳定状态
PPMd Preliminaries
PPMd压缩算法是建立有限阶D的马尔科夫模型,模型状态实质是一个256元的上下文树,最大深度为D。
从根到上下文节点的路径将被解释为字节符号序列,父关系将被理解为后缀关系。除此之外,每一个
上下文结点保存与后继节点相关的后继符号的统计频率。
使用以下名为CPpmd7_Context的结构体来表示一个上下文结点
typedef struct CPpmd7_Context_ {
UInt16 NumStats; //Stats array中元素个数
UInt16 SummFreq;
CPpmd_State_Ref Stats;
CPpmd7_Context_Ref Suffix;
} CPpmd7_Context;
typedef struct {
Byte Symbol;
Byte Freq;
UInt16 SuccessorLow;
UInt16 SuccessorHigh;
} CPpmd_State;
- 第一个RAR3实例创建的同时,一些上下文节点也同时被创建,Ppmd7_DecodeSymbol将p->MinContext
向上移动一次,知道找到相应的符号为止。解码器方法会因为CInBufferException失败。 - 由于下一个RAR3实例并没有重置位,我们会继续使用之前创建的PPMd模型。
- Ppmd7_DecodeSymbol使用一个新的范围解码器,并且
p->MinContext!=p->maxContext
。
它在p->MinContext中寻找对应的符号,但这个符号事实上已经在p->MaxContext和p->MinContext之间
的上下文,当UpdateModel函数被调用,这个符号就会被重复添加到State数组
栈溢出和堆溢出
state指针数组固定大小且存放在栈中,并且在向其中添加新state指针时不会检查长度,故能构建栈溢出
state内容存放在堆中,溢出原理和上述相同