Chrome 沙箱逃逸 -- Plaid CTF 2020 mojo

前置知识

Mojo & Services 简介
chromium mojo 快速入门
Mojo docs
Intro to Mojo & Services

参考文章

本文主要参考 Plaid CTF 2020 mojo Writeup

环境搭建

题目环境

给了 docker 环境,所以直接启 docker 即可。

安装 docker

sudo snap install docker

运行 run.sh 脚本:

./run.sh

运行 chrome

./chrome --disable-gpu --remote-debugging-port=1338 --enable-blink-features=MojoJS,MojoJSTest url

调试环境

这里单独启一个 web 服务:

python3 -m http.server 8000

调试脚本:

# gdbinit
# 读取符号
file ./chrome
# 设置启动参数
set args --disable-gpu --remote-debugging-port=1338 --user-data-dir=./userdata --enable-blink-features=MojoJS url
# 设置执行fork后继续调试父进程
set follow-fork-mode parent

然后 gdb 调试即可:

gdb -x gdbinit

题目分析

附件分析

题目新定义了一个 PlaidStore 接口:

module blink.mojom;

// This interface provides a data store
interface PlaidStore {
   

  // Stores data in the data store
  StoreData(string key, array<uint8> data);

  // Gets data from the data store
  GetData(string key, uint32 count) => (array<uint8> data);
};

该接口定义了两个方法 StoreDataGetData 分别用于向 data store 中存储数据和获取数据。

然后在浏览器端实现 PlaidStore 接口:

namespace content {
   

class RenderFrameHost;

class PlaidStoreImpl : public blink::mojom::PlaidStore {
   
 public:
  explicit PlaidStoreImpl(RenderFrameHost *render_frame_host);

  static void Create(
      RenderFrameHost* render_frame_host,
      mojo::PendingReceiver<blink::mojom::PlaidStore> receiver);

  ~PlaidStoreImpl() override;

  // PlaidStore overrides:
  void StoreData(
      const std::string &key,
      const std::vector<uint8_t> &data) override;

  void GetData(
      const std::string &key,
      uint32_t count,
      GetDataCallback callback) override;

 private:
  RenderFrameHost* render_frame_host_;
  std::map<std::string, std::vector<uint8_t> > data_store_;
};

}

可以看到这里存在两个私有变量其中一个是 data_store_,这个好理解,其就是用来存储数据的;这里的 render_frame_host_ 是神马东西呢?

render 进程中的每一个 frame 都在 browser 进程中对应一个 RenderFrameHost,很多由浏览器提供的 mojo 接口就是通过 RenderFrameHoset 获取的。在 RenderFrameHost 初始化阶段,会在 BinderMap 中填充所有公开的 mojo 接口:

@@ -660,6 +662,10 @@ void PopulateFrameBinders(RenderFrameHostImpl* host,
   map->Add<blink::mojom::SerialService>(base::BindRepeating(
       &RenderFrameHostImpl::BindSerialService, base::Unretained(host)));
 #endif  // !defined(OS_ANDROID)
+
+  map->Add<blink::mojom::PlaidStore>(
+      base::BindRepeating(&RenderFrameHostImpl::CreatePlaidStore,
+                          base::Unretained(host)));
 }

当一个 render frame 请求该接口时,在 BinderMap 中关联的回调函数 RenderFrameHostImpl::CreatePlaidStore 就会被调用,其定义如下:

void RenderFrameHostImpl::CreatePlaidStore(
    mojo::PendingReceiver<blink::mojom::PlaidStore> receiver) {
   
  PlaidStoreImpl::Create(this, std::move(receiver));
}

其直接调用了 PlaidStoreImpl::Create 函数:

// static
void PlaidStoreImpl::Create(
    RenderFrameHost *render_frame_host,
    mojo::PendingReceiver<blink::mojom::PlaidStore> receiver) {
   
  mojo::MakeSelfOwnedReceiver(std::make_unique<PlaidStoreImpl>(render_frame_host),
                              std::move(receiver));
}

通过该函数,一个 PlaidStoreImpl 就被创建,并且该 PendingReceiver 与一个 SelfOwnedReceiver 绑定。

漏洞分析

该题存在两个漏洞,分别是 OOBUAF,接下来直接分别讲解。

OOB

来分析下存取数据的操作:

void PlaidStoreImpl::StoreData(
    const std::string &key,
    const std::vector<uint8_t> &data) {
   
  if (!render_frame_host_->IsRenderFrameLive()) {
   
    return;
  }
  data_store_[key] = data;
}

void PlaidStoreImpl::GetData(
    const std::string &key,
    uint32_t count,
    GetDataCallback callback) {
   
  if (!render_frame_host_->IsRenderFrameLive()) {
   
    std::move(callback).Run({
   });
    return;
  }
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值