【原创】chrome已提交的两个漏洞分析(二)
base::Optional<BitfieldCheck> TryCombine(const BitfieldCheck& other) {if (source != other.source ||
truncate_from_64_bit != other.truncate_from_64_bit)
return {};
uint32_t overlapping_bits = mask & other.mask;
// It would be kind of strange to have any overlapping bits, but they can be
// allowed as long as they don't require opposite values in the same
// positions.
if ((masked_value & overlapping_bits) !=
(other.masked_value & overlapping_bits)) <---------
return {};
return BitfieldCheck{source, mask | other.mask, <------------
masked_value | other.masked_value,
truncate_from_64_bit};
}
我们可以看到满足处的检查之后就会由完成合并BitfieldCheck的操作,但是这个检查靠谱吗?
对 (x & A) == B来说,masked_value就是B,mask就是A(猜测)。
overlapping_bits = mask & other.mask,这一条件当mask1和mask2的bit的集合完全没有交集时,overlapping_bits就成了0。那么masked_value & overlapping_bits中无论masked_value多大,结果都是0,所以处的判断在overlapping_bits == 0时是不成立的,那么这会导致之后的合并结果出错吗?
答案显然是会的,思考((x & 0) == 1) & ((x & 1) == 0)经优化后会成为(x & (1|0)) == (1|0) => (x & 1) == 1,与优化前,也就是合并前的结果是截然不同的。
漏洞利用
要想达到rce的效果需要与CVE-2021-30598中对typer的patch结合才行,不然绕不掉CheckBounds(CheckMap)没法越界。我们先构造到typer认为x == 0, y == 0, 但是 (x&y) == 1的地步,下面描述下漏洞作者的记录。
首先最简单的做法就是做一个明显无法成真的等式,来赋值x和y满足以上,比如 (a & 1) == 42,这个显然无论a为多少都会得到0,但是正是因为如此,在优化过程中会触发常量折叠导致直接从一个等式变为了常量false,我们虽然可以通过let x = bool_var |0 来使得false变为0,但也会使得后续无法进展。
所以我们需要使用不是特别明显只有一种结果的等式,比如(a & 5) == 2 and (a & 6) == 1这样二者合并后,(a & 7) == 3,在a=3时结果为1,但这还远远不够。
其实我们可以引入一个不确定变量来防止前期优化阶段的常量折叠,比如上面的a就是给优化的函数传入的参数,因为不确定a到底是多少所以就不会被折叠掉。但是因为优化的原因当我们多次传入同一个数时,他还是会按传入的数去优化直接替换成对应的数。类似的还有把直接用0,改为o1 = {a : 0},然后用o1.a去替代0的位置,但是这个虽然在typer阶段不会被折叠,但是在后续的优化阶段还是会被识破的,比如LoadElimination阶段会把其直接替换成常量0。
真正可以用上的方法是string的下标取值操作,array-length节点会很晚才被常量折叠掉,不过因为如此操作产生typer的是CheckBounds节点,显然不属于哪个变量,我们无法直接使用,ReduceSpeculativeNumberOperation中会将CheckBounds节点替换成NumberConstant节点。
#【原创】chrome已提交的两个漏洞分析(三)#
http://cdn.u1.huluxia.com/g4/M01/63/9B/rBAAdmHv7GCANYHUAAKIAM3gtFQ299.jpg 确实不错,顶先 我擦!我要沙发! 一直在看 打酱油的人拉,回复下赚取积分 是爷们的娘们的都帮顶!大力支持 传说中的沙发???哇卡卡
页:
[1]