-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
425 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,92 @@ | ||
# Armor | ||
Armor 浏览器反蜜罐插件 | ||
# 蜜罐溯源技术原理 | ||
|
||
|
||
蜜罐溯源这部分用到的技术主要是jsonp | ||
jsonp全称是 JSON with Padding ,是基于 JSON 格式的为解决跨域请求资源而产生的解决方案。 | ||
|
||
|
||
如果某些站点存在jsonp劫持漏洞,如web1这个站点有个jsonp接口暴露者,功能就是返回用户的姓名: | ||
```php | ||
<?php | ||
$callback = $_GET['callback']; | ||
print $callback.'({"id" : "1","name" : "readname"});'; | ||
?> | ||
``` | ||
正常的请求是这样的: | ||
![image.png](https://cdn.nlark.com/yuque/0/2021/png/338445/1623051982711-1a18f09d-0833-4929-9c20-a931ef6cb8fc.png#align=left&display=inline&height=197&margin=%5Bobject%20Object%5D&name=image.png&originHeight=394&originWidth=823&size=31821&status=done&style=none&width=411.5) | ||
这时候就可以在蜜罐中插入一个script脚本来跨域获取攻击者登陆的web1站点的姓名信息了 | ||
```html | ||
<html> | ||
<h1>jsonp窃取信息</h1> | ||
<script type="text/javascript" src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script> | ||
<script type="text/javascript"> | ||
$.getJSON("http://127.0.0.1:91/getuser.php?callback=?", function(getUsers){ | ||
alert(getUsers.name); | ||
}); | ||
</script> | ||
</html> | ||
|
||
``` | ||
![image.png](https://cdn.nlark.com/yuque/0/2021/png/338445/1623052379202-f1676578-9f8f-47d1-8972-c8fdbbeec8e8.png#align=left&display=inline&height=303&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1210&originWidth=1574&size=116802&status=done&style=none&width=394) | ||
实际的蜜罐产品则是收集了非常多常用站点的jsonp漏洞,用来窃取攻击者的个人信息。 | ||
本文中的反蜜罐主要指的是,识别蜜罐、并且阻止蜜罐通过jsonp接口拿到攻击者的个人信息。反蜜罐插件更加强调的是后者,识别不到蜜罐问题不大,但是一旦信息被蜜罐窃取走,后果就很严重了。 | ||
|
||
|
||
# 反蜜罐浏览器插件Armor | ||
被动探测主要是浏览器插件的形式,在访问的时候插件检测当前是否为蜜罐 | ||
目前github上比较好用的两款反蜜罐插件主要是: | ||
|
||
- [https://github.com/cnrstar/anti-honeypot](https://github.com/cnrstar/anti-honeypot) | ||
|
||
判断当前网页是否有跨域请求,且有黑白名单,黑名单主要就是蜜罐常用的jsonp劫持接口,匹配到则报蜜罐 | ||
|
||
- [https://github.com/iiiusky/AntiHoneypot-Chrome-simple](https://github.com/iiiusky/AntiHoneypot-Chrome-simple) | ||
|
||
主要通过匹配js名称及内容来检测常见的蜜罐 | ||
|
||
|
||
这两个第一个存在漏报的可能,如果黑名单不全的话,还是会被蜜罐拿到信息 | ||
第二个也是一样的,不同蜜罐使用的js名称不一样,js内容不一样,比较难很全面的识别拦截 | ||
二者都很依赖规则库的完备性。 | ||
|
||
|
||
honpot-Armor里将二者结合起来进行改进,整体流程如下: | ||
主要分三个阶段,分别是 | ||
|
||
- 探测白名单,由于检测的jsonp接口较多,在正常站点为了不影响使用,添加了白名单 | ||
- 对页面加载的js文件进行文件名和文件内容匹配,如Hfish蜜罐,特征就是**x.js**,且里面包含**sec_key**字段 | ||
- 对于页面发出的所有请求,对于源地址与目的请求地址,如果相同则忽略,如果不同则进入下一步 | ||
- 对于源地址,请求地址不同的请求,黑名单进行匹配,匹配到则直接拦截 | ||
- 对于黑名单未匹配到的,则检测请求路径中是否包含callback,cb等字符串,这是由jsonp的特性决定的,还有一些包含ooxx字段(默安的蜜罐),将这些请求进行拦截,标记为可疑请求。 | ||
- 为了减少规则匹配不完全导致漏报的危险,增加了jsonp跨域提醒,跨域请求仍然放行(数量比较多,如百度统计服务,很多网站都有,是正常的jsonp请求),但是会有通知提醒,用户可以自己选择开启提醒功能或关闭。 | ||
|
||
|
||
|
||
![Armor.png](https://cdn.nlark.com/yuque/0/2021/png/338445/1624036781615-2ecaf28a-e635-4942-b3f8-67e8212c2deb.png#align=left&display=inline&height=1399&margin=%5Bobject%20Object%5D&name=Armor.png&originHeight=1399&originWidth=2748&size=242213&status=done&style=none&width=2748) | ||
|
||
|
||
|
||
|
||
# 使用 | ||
开发者模式,选择项目文件夹即可 | ||
![image.png](https://cdn.nlark.com/yuque/0/2021/png/338445/1624037689549-bf770eb6-00d6-453c-a1ad-f6f158aa6c23.png#align=left&display=inline&height=405&margin=%5Bobject%20Object%5D&name=image.png&originHeight=809&originWidth=2731&size=306757&status=done&style=none&width=1365.5) | ||
![image.png](https://cdn.nlark.com/yuque/0/2021/png/338445/1624037744510-6ce6700a-f8e1-45bf-8ac0-025de4ef3bd7.png#align=left&display=inline&height=220&margin=%5Bobject%20Object%5D&name=image.png&originHeight=439&originWidth=1282&size=31967&status=done&style=none&width=641) | ||
在一些正常网站上,黑名单导致一些正常功能不能使用,可以直接点击关闭反蜜罐功能 | ||
jsonp跨域提醒误报太多时,可以关闭jsonp跨域提示 | ||
如果识别到会以chrome通知的形式在右下角弹窗,自己会消失 | ||
![image.png](https://cdn.nlark.com/yuque/0/2021/png/338445/1624037735381-945f430f-c881-49d7-b268-7671e8abc05a.png#align=left&display=inline&height=803&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1605&originWidth=2982&size=238899&status=done&style=none&width=1491) | ||
![image.png](https://cdn.nlark.com/yuque/0/2021/png/338445/1624037891295-afdb0ad0-2e30-4022-9062-ba0edaabe849.png#align=left&display=inline&height=784&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1567&originWidth=2974&size=221911&status=done&style=none&width=1487) | ||
# todo | ||
|
||
- 当前通知使用的是Notification函数,通知相对于检测延迟有点多,会导致开关切换之后,之前的通知还在弹 | ||
- 增加右键加入白名单之类的更多的交互 | ||
- 增加更多规则 | ||
|
||
|
||
|
||
# 参考 | ||
[https://juejin.cn/post/6844904127932137485](https://juejin.cn/post/6844904127932137485) | ||
[https://github.com/sxei/chrome-plugin-demo](https://github.com/sxei/chrome-plugin-demo) | ||
[http://www.ptbird.cn/chrome-extensions-storage.html](http://www.ptbird.cn/chrome-extensions-storage.html) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,231 @@ | ||
'use strict' | ||
var keyflag = 0; //是否提示有跨域的jsonp请求 | ||
var switchon = 1; //是否开启蜜罐 | ||
chrome.storage.sync.set({ keyflag: 0, switchon: 1 }); | ||
const manifest = chrome.runtime.getManifest(); | ||
var honeypotUrlCache = {}; | ||
var http = {}; | ||
var ruleStr = ` | ||
{ | ||
"默安幻阵": [ | ||
{ | ||
"filename": "record.js", | ||
"content": "document[__Ox3f21b[0xd]](__Ox3f21b" | ||
} | ||
], | ||
"HFish": [ | ||
{ | ||
"filename": "x.js", | ||
"content": "sec_key" | ||
} | ||
] | ||
} | ||
` | ||
var rule = JSON.parse(ruleStr); | ||
const { | ||
version | ||
} = manifest; | ||
|
||
|
||
// 给数组添加push2方法,用于向数组push不重复的数据 | ||
Array.prototype.push2 = function() { | ||
for (var i = 0; i < arguments.length; i++) { | ||
var ele = arguments[i]; | ||
if (this.indexOf(ele) == -1) { | ||
this.push(ele); | ||
} | ||
} | ||
}; | ||
|
||
// 规则匹配,匹配成功将数据放入缓存 | ||
function checkForRule(url, content) { | ||
for (var item in rule) { | ||
for (var r1 in rule[item]) { | ||
if (rule[item][r1]["filename"] === '{{honeypotAny}}' && content.indexOf(rule[item][r1]["content"]) != -1) { | ||
honeypotUrlCache[url] = item; | ||
return | ||
} else if (url.indexOf(rule[item][r1]["filename"]) != -1) { | ||
if (rule[item][r1]["content"] === '{{honeypotAny}}') { | ||
honeypotUrlCache[url] = item; | ||
return | ||
} else if (content.indexOf(rule[item][r1]["content"]) != -1) { | ||
honeypotUrlCache[url] = item; | ||
return | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
||
// 传入 URL 检查是否为蜜罐 | ||
function checkHoneypot(url) { | ||
|
||
console.log("[Honeypot] check url:" + url) | ||
let status = false | ||
|
||
// 判断是否在历史检测出来中的缓存中存在 | ||
//console.log(honeypotUrlCache) | ||
if (honeypotUrlCache.hasOwnProperty(url)) { | ||
status = true | ||
} else { | ||
// 不存在就进行请求,然后解析内容用规则去匹配 | ||
$.ajax({ | ||
type: "get", | ||
async: false, | ||
url: url, | ||
success: function(data) { | ||
checkForRule(url, data) | ||
console.log("[Honeypot] checkForRule over.") | ||
} | ||
}); | ||
} | ||
|
||
// 再次从缓存中检查 | ||
if (honeypotUrlCache.hasOwnProperty(url)) { | ||
status = true | ||
} | ||
|
||
return status | ||
} | ||
|
||
var count = 0 | ||
//每次请求前触发,可以拿到 requestBody 数据,同时可以对本次请求作出干预修改 | ||
chrome.webRequest.onBeforeRequest.addListener( | ||
function(details) { | ||
chrome.storage.sync.get('keyflag', (res) => { | ||
keyflag = res.keyflag; | ||
}); | ||
chrome.storage.sync.get('switchon', (res) => { | ||
switchon = res.switchon; | ||
}); | ||
console.log(switchon, keyflag); | ||
if (switchon == 0) { | ||
return; | ||
} | ||
// console.log(details); | ||
if (details.type == 'script') { // | ||
if (checkHoneypot(details.url)) { | ||
new Notification("当前为" + honeypotUrlCache[details.url] + "蜜罐,快跑,当前蜜罐脚本已屏蔽!"); | ||
return { cancel: true }; | ||
} | ||
} | ||
|
||
//url:当前的url;initiator:浏览器状态栏里的domain | ||
let { | ||
url, | ||
initiator | ||
} = details; | ||
// console.log(url, initiator); //http://mbd.baidu.com/newspage/api/getusername?cb=jQuery15204197566477288597_1623140159838&_=1623140160171 http://103.43.19.111 | ||
|
||
//如果发起者为空,直接赋值url | ||
if (initiator == "undefined" || initiator == "null" || typeof(initiator) == "undefined") { | ||
initiator = url; | ||
} | ||
const protocal = url.split("://")[0]; | ||
|
||
//根据url返回域名和对应的path | ||
function GetHostAndPath(url) { | ||
var arrUrl = url.split("//"); // http://mbd.baidu.com/newspage/api/getusername?cb=jQuery15204197566477288597_1623140159838&_=1623140160171 | ||
var start = arrUrl[1].indexOf("/"); | ||
var host = arrUrl[1].substring(0, start); | ||
var path = arrUrl[1].substring(start); //stop省略,截取从start开始到结尾的所有字符 | ||
|
||
var result = new Array(host, path); | ||
return result | ||
} | ||
//根据url获取主域名 | ||
function get_domain(url) { //http://103.43.19.111 | ||
var domain = url.split("://")[1]; | ||
if (domain.includes('/')) { | ||
domain = domain.split('/')[0]; | ||
} | ||
// var re_domain = /([a-zA-Z0-9-]+)(.com\b|.net\b|.edu\b|.miz\b|.biz\b|.cn\b|.cc\b|.org\b){1,}/g; | ||
// domain = url.match(re_domain); | ||
return domain; | ||
|
||
} | ||
//判断host是否在黑名单内 | ||
function inBlackList(host) { | ||
//黑名单host来自长亭D-sensor的溯源api,共47个 | ||
const BlackList = ["account.itpub.net", "accounts.ctrip.com", "ajax.58pic.com", "api.csdn.net", "api.ip.sb", "api.passport.pptv.com", "bbs.zhibo8.cc", "bit.ly", "blog.csdn.net", "blog.itpub.net", "c.v.qq.com", "chinaunix.net", "cmstool.youku.com", "comment.api.163.com", "databack.dangdang.com", "dimg01.c-ctrip.com", "down2.uc.cn", "github.com", "hd.huya.com", "home.51cto.com", "home.ctfile.com", "home.zhibo8.cc", "hudong.vip.youku.com", "i.jrj.com.cn", "iask.sina.com.cn", "itunes.apple.com", "m.ctrip.com", "m.game.weibo.cn", "mapp.jrj.com.cn", "my.zol.com.cn", "passport.ctrip.com", "passport.game.renren.com", "passport.iqiyi.com", "playbill.api.mgtv.com", "renren.com", "skylink.io", "u.faloo.com", "ucenter.51cto.com", "v.huya.com", "v2.sohu.com", "vote2.pptv.com", "wap.sogou.com", "webapi.ctfile.com", "weibo.com", "www.58pic.com", "www.iqiyi.com", "www.iteye.com", "www.zbj.com", "www.cndns.com", "mozilla.github.io", "www.sitestar.cn", "api.fastadmin.net", "m.site.baidu.com", "restapi.amap.com", "login.sina.com.cn", "now.qq.com", "message.dangdang.com", "musicapi.taihe.com", "api-live.iqiyi.com", "api.m.jd.com", "tie.163.com", "pcw-api.iqiyi.com", "so.v.ifeng.com", "passport.baidu.com", "wz.cnblogs.com", "passport.cnblogs.com", "hzs14.cnzz.com", "mths.be", "validity.thatscaptaintoyou.com", "stc.iqiyipic.com", "s14.cnzz.com", "sb.scorecardresearch.com", "js.cndns.com", "datax.baidu.com", "assets.growingio.com", "www.gnu.org", "wappassalltest.baidu.com", "baike.baidu.com", "ka.sina.com.cn", "p.qiao.baidu.com", "map.baidu.com", "www.dangdang.com", "g.alicdn.com", "s.faloo.com", "msg.qy.net", "morn.cndns.com", "i.qr.weibo.cn", "github.comgithub.com", "uis.i.sohu.com", "www.tianya.cn", "passport.mop.com", "commapi.dangdang.com", "comment.money.163.com", "chaxun.1616.net", "tieba.baidu.com", "remind.hupu.com", "service.bilibili.com", "node.video.qq.com", "api.weibo.com", "www.jiyoujia.com", "mbd.baidu.com", "wapsite.baidu.com", "zhifu.baidu.com", "m.iask.sina.com.cn", "mooc1-1.chaoxing.co", "myjr.suning.com", "mooc1-1.chaoxing.com", "my.zol.com.cn", "passport.tianya.cn", "account.cnblogs.com", "passport2.chaoxing.com", "zhifu.duxiaoman.com"]; | ||
for (const BlackSite of BlackList) { | ||
if (host == BlackSite) { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
var mainDomain = get_domain(initiator); //发起者的主域名 | ||
var targetHost = GetHostAndPath(url)[0]; //跨域或本域访问的目标主机 | ||
var targetPath = GetHostAndPath(url)[1]; //跨域或本域访问的目标路径 | ||
console.log(mainDomain, targetHost, targetPath); | ||
|
||
const WhiteList = ['www.baidu.com', 'www.qq.com', 'www.csdn.net', 'www.weibo.com', 'www.cnblogs.com', 'www.aliyun.com', 'www.ctrip.com', 'www.weibo.cn', 'www.iqiyi.com', 'www.163.com', 'www.126.com', 'www.51cto.com', 'www.taobao.com', 'www.sogou.com', 'www.iteye.com', 'www.58.com', 'www.google.com', 'www.fofa.so', 'www.jd.com', 'www.tmall.com', 'www.github.io', 'www.github.com', 'www.sina.com.cn', 'www.mi.com', 'www.zhihu.com', 'quake.360.cn', 'www.bilibili.com', 'www.csdn.com'] //白名单 | ||
for (var WhiteSite of WhiteList) { | ||
if (mainDomain == WhiteSite) { | ||
console.log('命中白名单' + mainDomain); // 访问这些网站时退出 | ||
return; | ||
} | ||
} | ||
|
||
let redirectUrl; | ||
let cancel; | ||
|
||
if (mainDomain == targetHost) { //如果相等表示正常域内访问 | ||
return; | ||
} else { //如果不相等,可能是跨域访问,需要继续判断 | ||
let flag = 0; | ||
const blockQueryStringList = ['callback', 'jsonp', 'javascript', 'cb=', 'xxoo']; //如果url中存在这些字段,说名可能时jsonp请求,归类为可疑请求,进行拦截 | ||
// `默安蜜罐特征:xxoo=chrome-extension` | ||
if (protocal == 'http' || protocal == 'https') { | ||
if (inBlackList(targetHost)) { | ||
// 黑名单拦截 | ||
count += 1; | ||
flag = 1; | ||
new Notification('拦截黑名单' + count + '次:' + targetHost + '\n建议立即关闭页面 => ' + mainDomain); | ||
console.log('拦截黑名单' + count + '次:' + targetHost + '\n建议立即关闭页面 => ' + mainDomain); | ||
} else { | ||
for (const q of blockQueryStringList) { | ||
if (q && targetPath.includes(q)) { | ||
redirectUrl = 'data:text/javascript;charset=UTF-8;base64,' + btoa(`;`); //拦截 | ||
new Notification('拦截可疑溯源请求:' + targetHost + targetPath + '\n建议立即关闭页面 => ' + mainDomain); | ||
console.log('拦截可疑溯源请求:' + targetHost + targetPath + '\n建议立即关闭页面 => ' + mainDomain); | ||
flag = 1; | ||
} | ||
} | ||
} | ||
if (keyflag == 1) { | ||
if (flag == 0) { //黑名单不一定全,如果callback关键字匹配也失效的话,就可能拦截失败,通过提示存在所有jsonp跨域请求,让用户自己来判断 | ||
const jsonp_WhiteList = [".css", ".js", ".png", ".jpg", ".gif", "api.map.baidu.com", "miao.baidu.com", "img", "imges"] //path中含有这些字符串的被划分为正常的jsonp请求//会比较多 | ||
let flag2 = 1; | ||
for (const q of jsonp_WhiteList) { | ||
let request_url = targetHost + targetPath; | ||
if (request_url.includes(q)) { | ||
flag2 = 0; | ||
} | ||
} | ||
if (flag2 == 1) { | ||
new Notification('存在跨域jsonp:\n' + targetHost + targetPath); | ||
console.log('存在跨域jsonp:\n' + targetHost + targetPath); | ||
} | ||
|
||
} | ||
} | ||
|
||
|
||
} | ||
} | ||
|
||
if (cancel) return { | ||
cancel | ||
}; | ||
else if (redirectUrl) return { | ||
redirectUrl | ||
} | ||
else return {}; | ||
}, { | ||
urls: ["<all_urls>"] | ||
}, ["blocking"] | ||
); |
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
{ | ||
"name": "Armor - antiHoneyPot", | ||
"version": "1.0.0", | ||
"manifest_version": 2, | ||
"description": "Armor反蜜罐", | ||
"icons": { | ||
"128": "/img/bee.png" | ||
}, | ||
"browser_action": { | ||
"default_popup": "popup.html", | ||
"default_title": "Armor - antiHoneyPot", | ||
"default_icon": "/img/bee.png" | ||
}, | ||
"background": { | ||
"persistent": true, | ||
"scripts": [ | ||
"background.js", | ||
"thirdParty/jquery-3.5.1.min.js" | ||
] | ||
}, | ||
"permissions": [ | ||
"notifications", | ||
"activeTab", | ||
"tabs", | ||
"storage", | ||
"https://*/*", | ||
"http://*/*", | ||
"webRequest", | ||
"webRequestBlocking" | ||
], | ||
"web_accessible_resources": ["*"], | ||
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
|
||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Armor蜜罐检测插件</title> | ||
<script src="./thirdParty/jquery-3.5.1.min.js"></script> | ||
<style> | ||
body { | ||
width: 200px; | ||
height: 140px; | ||
} | ||
</style> | ||
|
||
</head> | ||
|
||
|
||
<body> | ||
<div class="jumbotron"> | ||
<p>反蜜罐功能: <input id="switch1" type="checkbox"></p> | ||
<p>jsonp跨域提示: <input id="switch2" type="checkbox"></p> | ||
</div> | ||
|
||
<script src="popup.js"></script> | ||
</body> | ||
|
||
|
||
</html> |
Oops, something went wrong.