看到大家在讨论前端的加密问题,就把我现在用的加密方案做了个 demo ,大佬们看看能破掉吗,要是能给点建议就更好了。
http://34.16.118.34,怕被大手子 gank 没用 cdn 第一次打开有点慢
1
ovtfkw 2023-08-23 19:36:39 +08:00 1
卧槽,你这什么魔法,咋邮件和 f12 都不起作用了
|
2
wangkun025 2023-08-23 19:41:49 +08:00
http://34.16.118.34/static/js/chunk-vendors-149-1692789542152.js
我不知道自己发了啥 |
3
shuxhan 2023-08-23 19:42:08 +08:00
有点意思啊,打开控制台自动关闭标签
|
4
tmtstudio OP @wangkun025 #2 这是基础包,混完之后变得超大,我线上项目接近 4M ,有没有大佬知道怎么瘦身呀
|
5
rageyourdream8 2023-08-23 19:52:09 +08:00
发送的原文:"content: v2ex: sender: rageyourdream8"
下面是 post body ,不确定有没有正确发过去 { "status": 1, "info": "\u63a5\u53e3\u5de5\u4f5c\u6b63\u5e38", "data": { "data": "goSPs5L7+pqEj7DDKjUQD7P0opmOBnDGtjW+h+56ZDyifVb8vJhyFmdY3s2FIOk7d0cR6K4AW97Zs8g2SNYPzg==", "code": "eCfjYehyrwjPDnaHaKvLr0PIdgJpzMkDsvQFF\/+gagrIrPoAONGDkiFpJO7Ct942grdbhpbsSHjuTnFBPWF51EYnccClu8fc6ku4KIXLripCS00xSfJ\/IQPLgvJRe8e7paMgAdABjr3Qrh1x9t\/tBnYUJwP0\/NAglWnvD\/oS2LI=" } } |
6
dcdlove 2023-08-23 19:59:33 +08:00
前端何苦为难前端
http://120.79.59.207:8081/Home/Api/handShake http://120.79.59.207:8081/Home/Api/test |
8
gogogo2000 2023-08-23 20:11:43 +08:00
[url=https://imgse.com/i/pPYG43Q][img]https://s1.ax1x.com/2023/08/23/pPYG43Q.png[/img][/url]
|
10
EyebrowsWhite 2023-08-23 21:09:38 +08:00
|
11
ArtSword 2023-08-23 21:31:18 +08:00
|
12
pengtdyd 2023-08-23 21:34:52 +08:00
有点东西,看来我的爬虫技术还有很大的提升空间。
|
13
weekidjoker 2023-08-23 21:36:03 +08:00
666
|
14
hsuehly 2023-08-23 21:39:32 +08:00 via iPhone
|
15
hsuehly 2023-08-23 21:40:47 +08:00 via iPhone
@hsuehliuyang 主要加密在这个接口上破解返回的内容 https://api.yangtu.link/v2/jx1
|
16
nickfox5880 2023-08-23 21:46:59 +08:00
怎么监控的是否打开了控制台
|
17
nickfox5880 2023-08-23 22:07:16 +08:00
// 搜到一个检测控制台的库,还没看源码,不知道原理。但是确实能监听到
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script src="https://cdn.bootcdn.net/ajax/libs/devtools-detector/2.0.14/devtools-detector.js"></script> <script> devtoolsDetector.addListener(function(isOpen) { console.log('isOpen', isOpen) if (isOpen) { window.location.href = 'https://www.baidu.com' } }); devtoolsDetector.launch(); </script> </body> </html> |
18
nickfox5880 2023-08-23 22:08:37 +08:00
|
19
vmex 2023-08-23 23:19:57 +08:00
getParams({"text":"v2ex"}); // 牛逼呀兄弟
|
20
DreamNya 2023-08-24 02:08:05 +08:00 2
写了个油猴脚本 全自动牛逼 [
// ==UserScript== // @name New Userscript // @namespace https://bbs.tampermonkey.net.cn/ // @version 0.1.0 // @description try to take over the world! // @author DreamNya // @match http://34.16.118.34/* // @run-at document-start // ==/UserScript== window.setInterval = () => 1; //偷鸡? //window.Math.max=()=>10000000000000; localStorage.setItem = new Proxy(localStorage.setItem, { apply: function (target, thisArg, argumentsList) { console.log(argumentsList) //debugger return Reflect.apply(target, thisArg, argumentsList) }, }); const realSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function (...args) { const realGet = document.querySelector("body > uni-app").__vue__.$children[0].$children[0].$children[0].$children[1].$children[0].getParams; document.querySelector("body > uni-app").__vue__.$children[0].$children[0].$children[0].$children[1].$children[0].getParams = function (...args_) { args_[0].text = 'v2ex' return realGet.call(this, ...args_) } XMLHttpRequest.prototype.send = realSend return realSend.call(this, ...args) } |
21
witcat 2023-08-24 02:10:55 +08:00
开控制台页面自动关了可太秀了
|
23
gzlock 2023-08-24 06:36:51 +08:00 16
要监控是否打开开发者工具,无非就是两三种方法而已,1 监听 f12 按键(还能通过浏览器菜单打开开发者工具,所以监听 f12 就是掩耳盗铃),2 监听网页尺寸突然变小(例如高度从 1080 直接变为 700 ,但是误判几率很大,例如浏览器最大化和取消最大化就会误判),3 就是使用 debugger
但是但是但是,以上方法是都基于已经打开网页后再打开开发者工具 我们打开思路,先打开一个网页标签,提前打开开发者工具,再去开发者工具的 [源代码] 关闭 debugger 断点功能 这时候再在这个网页标签打开楼主的网址,就可以使用开发者工具了 https://img.urlnode.com/file/5bce421d46563748dc4cb.png 我不擅长看别人的 js ,其余步骤就不献丑了 |
24
chnwillliu 2023-08-24 07:54:49 +08:00 via Android 3
还有一个是使用 console.table 之类的方法打印大 object ,如果 devtools 打开了那么就会产生一个延迟,从而检测到 devTools 打开了。
破解方法是找到一个比任何代码都早的时机,把 console 上的一堆方法覆盖成空函数。Event Listener Breakpoints 下 Script > Script First Statement 勾上,断点就会打在所有脚本的第一条语句。 |
25
villivateur 2023-08-24 08:33:36 +08:00
只是想了一下,感觉开个 fiddler 然后在浏览器之外做个中间人攻击就行了
|
26
monkeyWie 2023-08-24 08:53:44 +08:00 via Android
前端就不要想有啥安全了,无非就是破解成本提高点,目前我碰到过最吊的前端加密就是以前把密钥放在 flash 调用的一个 c 写的混淆模块里,以我的水平是完全无解
|
27
luzemin 2023-08-24 08:57:07 +08:00
好家伙,我连代码没看到,就给我关了 (流下了菜鸟的眼泪
|
31
chnwillliu 2023-08-24 09:02:32 +08:00 via Android
@tmtstudio 方法别挂 vue 实例上
|
32
gzlock 2023-08-24 09:17:21 +08:00
@tmtstudio #30 如上操作,没有触发自动关闭网页。
你是根据我的描述增加了判断历史记录的新功能吧,现在会自动回到上一个网页了 |
33
lizhenda 2023-08-24 09:19:52 +08:00
确实大开眼界,哈哈
|
34
MEIerer 2023-08-24 09:21:49 +08:00
强啊,大佬解析解析
|
35
chnwillliu 2023-08-24 09:21:58 +08:00 2
|
36
weekidjoker 2023-08-24 09:23:15 +08:00
@chnwillliu 确实是 console.table 触发的。op 应该用的是 https://github.com/theajack/disable-devtool 这个库,在油猴把 console 复写就可以了
|
37
jsonfork 2023-08-24 09:39:40 +08:00
http://120.79.59.207:8081/Home/Api/test1
tp3.2 不要用了,现在都 6 了。 |
38
davin 2023-08-24 09:45:24 +08:00
favicon.ico 用 B 站的这样真的好么😂
|
39
weekidjoker 2023-08-24 09:47:07 +08:00
@chnwillliu 大佬牛逼!放闭包的话,把相关的逻辑拷出来执行是不是也可以破
|
40
NoobNoob030 2023-08-24 10:06:51 +08:00
改了 js ?还在更新是吧
|
41
tmtstudio OP @NoobNoob030 #40 吸收了上面大佬的建议
|
43
lasuar 2023-08-24 10:38:23 +08:00
你这两个接口也没传 text 参数
|
44
webbillion 2023-08-24 10:39:49 +08:00
请问 op 是怎么做到可以关闭标签页的,我看了下代码,确实是和 10 楼说的一样,但是我复制到自己的网页里调用时却没办法关闭网页(无论是通过链接打开新窗口还是直接输入地址)。是需要什么前置条件吗?
|
45
linshenqi 2023-08-24 10:43:13 +08:00
各种监听是吧
|
46
frandy 2023-08-24 10:47:23 +08:00
@webbillion #44 36 楼已经给出了库了,我在我的项目里实验有效,https://readmagic.github.io
|
47
webbillion 2023-08-24 11:20:00 +08:00
@frandy #46 https://github1s.com/theajack/disable-devtool/blob/master/src/utils/close-window.ts#L18-L22 这个么,确实你给出的网站和 op 给出的网址都是可以生效的,我将你这句回复里 a 标签的 href 替换为本地开发地址,再点击按钮触发这个函数,是没有反应的,也不会报 Scripts may close only the windows that were opened by them. 的错。可能还有什么隐藏机制吧,试了下纯 html 是可以的,可能我用的业务框架有做一些拦截处理。
|
50
huihushijie1996 2023-08-24 11:37:52 +08:00
控制台直接把方法重写了可以停止关闭
function clear(){ var num = 1000000; for(var i = 0;i<num;i++){ clearInterval(i); clearTimeout(i); cancelAnimationFrame(i) } } window.close = function(){} clear() 然后打上 debug 就可以调试了 然后搜索 http 就找到了 其实楼主可以把 请求地址加密用一个简单的异或加密 function or(str){ var endstr = "" var code = 15 //可以随便取一个数字 for(var i =0;i<str.length;i++){ endstr+=String.fromCharCode((str[i].charCodeAt(0))^code) } return endstr } 这样搜索就搜不到了 但是调出控制台了 还是可以在请求里面看到 抓包工具也能看到 |
51
lisxour 2023-08-24 11:39:26 +08:00
@monkeyWie 现在谁还用 flash 做交互啊,网页分分钟报错,现在的前端加密方案已经很成熟了,你随便用一个付费的,比如 Jscrambler ,就足以让 90%的人止步。
|
53
DreamingCTW 2023-08-24 11:53:48 +08:00
我之前也写过打开控制台就跳转网页,确实好用。
|
55
phpfpm 2023-08-24 13:46:37 +08:00
整挺好,加密的挺好的,但是你这么搞你家的产品我就不用了。抬走换下一个。
|
56
ZeroDu 2023-08-24 13:54:21 +08:00
op 是改了吧,我这边控制台打开 网页就关了
|
57
xz410236056 2023-08-24 13:55:38 +08:00
@tmtstudio #30 先打开页面让你加载,加载好了再禁用 JS
|
59
42is42is42 2023-08-24 14:12:04 +08:00
|
60
Al0rid4l 2023-08-24 14:17:11 +08:00 5
先 BurpSuite 拦截响应, 在 chunk-vendors-xxx.js 里面找到 ondevtoolopen 对应的函数, 通常就在这个对象前面一点, 函数体有 setTimeout 和 timeOutUrl 这两个关键字, 修改此函数为空函数(没仔细看具体内容, 大概是反调试相关的)后放行响应, 干掉反调试, 后面可以比较愉快地调试了
反调试用的是 https://github.com/theajack/disable-devtool 这个库 在 page-index-xxxx.js 下的 onLoad 周期下调用了 this.$u.request 发起请求, 里面调用了另一个模块的 getParams({}) 来构造请求参数, 可以直接在这里给对象加入 text:'v2ex', 也可以在 getParams 里面断点, 在 aesEncrypt 加密之前修改对象, 参数 param 由 aesEncrypt 函数加密一个类似 {"h5Version":1,"public":1692855534,"private":"05b035bf90fee199b4114b97ee277571", "text": "v2ex"} 的 JSON 得到 混淆是在每个文件开头或结尾有两个函数, 一个构造各种变量名和属性名的词典, 一个从词典中取值, 对于感兴趣的关键字直接到这两个函数里面找, 然后条件断点即可, 有些关键词不在词典中而是直接作为字符串没有混淆 |
61
Al0rid4l 2023-08-24 14:23:08 +08:00
因为有词典, 其实关键字还挺好找的, 想进一步混淆建议少用对象, 打包工具和混淆工具不会对属性名压缩或混淆, 把一些关键对象的属性名手动拆字典, 这样就很难搜索到了, 只不过这样自己的代码也基本不可能可读了
|
62
lasuar 2023-08-24 14:25:41 +08:00
混淆的时候 不要留明文函数名
|
63
Pionxzh 2023-08-24 14:33:06 +08:00
混淆强度有点高 找了几个工具解不开
|
64
jaycezhang7890 2023-08-24 14:36:52 +08:00
@dcdlove 怎么找得到接口的,前端小白求教
|
65
jaycezhang7890 2023-08-24 14:38:47 +08:00
我直接先打开控制台,停用 js ,然后进网页后提示启用 js 后启用 js ,然后刷新页面,在页面没跳转前再停用 js ,一样可以打开控制台啥的呀
|
66
Al0rid4l 2023-08-24 14:49:16 +08:00
补个 flag
https://imgur.com/a/Lv5QJdl |
67
bhbhxy 2023-08-24 15:01:02 +08:00
似乎换地址了
http://34.16.118.34/static/js/chunk-vendors-1-1692842024601.js |
68
Features 2023-08-24 15:27:52 +08:00
@jaycezhang7890 找接口简单啊,抓个包就行了
|
69
cherryas 2023-08-24 15:47:36 +08:00
没破解成功,但是抓包了,并没发现连接 120.79.59.207 这个后端的记录。
|
71
CodFrm 2023-08-24 15:56:25 +08:00
|
72
NoobNoob030 2023-08-24 16:17:57 +08:00
按照 60 楼大佬的思路,传入"text": "v2ex"参数错误,是不是又修改了
|
73
oppoic 2023-08-24 16:44:57 +08:00
你们不要给楼主提了,他偷偷的都给修复了
|
74
freeup 2023-08-24 17:32:28 +08:00
28997 行下断 然后执行表达式修改变量 _0x53b71f['ignore']=function(){return true;} _0x53b71f 变量为禁用调试工具的配置 详见 https://github.com/theajack/disable-devtool 但是 后续放行后 控制台报错了 ReferenceError: getToken is not defined |
75
lxxxv5 2023-08-24 18:21:58 +08:00
op 在背后疯狂修复
|
76
lzgshsj 2023-08-24 19:57:01 +08:00
搁这玩红蓝对抗是吧😆
|
77
DreamNya 2023-08-24 21:32:57 +08:00
还是油猴脚本 还是全自动牛逼
换一个地方 hook ,比之前代码还要简洁…… ``` // ==UserScript== // @name 全自动牛逼 // @namespace https://bbs.tampermonkey.net.cn/ // @version 0.2.0 // @description try to take over the world! // @author DreamNya // @match http://34.16.118.34/* // @grant none // @run-at document-start // ==/UserScript== window.setInterval = () => 1; //偷鸡? const realAssign = window.Object.assign; window.Object.assign = function (...args) { if (args[0].h5Version) { args[0].text = 'v2ex' } return realAssign.call(this, ...args) }; ``` 对策就是不要用任何对象方法。 前端就是这样,你防住了一下,不一定能防住下一个,总有地方有机可趁,而且有些漏洞是难以修复的,除非重构整个函数,伤人先伤己。 前端代码都在本地运行,只能通过加密混淆增加难度,从防 50%的人提升到防 90 、95 、99%的人,做不到 100%安全。 增加难度的同时也在考验自己的代码水平,相当于七伤拳了 有没有必要加密混淆填补漏洞,主要看成本与收益 |
78
Al0rid4l 2023-08-24 21:37:35 +08:00 2
@NoobNoob030 getParams() 的参数(目前是对象_0x52aa82)上增加属性 text: 'v2ex', 接口 formdata 中的 param 参数是由 getParams() 的参数加密得到, 需要在某个函数(_0x9b992, 也就是这句 var _0x510f37 = _0x9b992(_0x52aa82, _0x38bd00, _0x458a78))之前加上这个属性, 否则对象会和时间戳等信息一起生成其他参数导致参数错误
|
79
MegatronKing 2023-08-24 22:45:11 +08:00 1
我用 Reqable 抓包测试了下,定位到了 Reqable 的一个 bug ,尴尬。
|
80
jones2000 2023-08-25 00:25:11 +08:00
CEF 重载 DoClose 事件, 不让关闭窗口就可以。
|
81
NoobNoob030 2023-08-25 09:20:00 +08:00
@Al0rid4l 感谢大佬指点,拿到 flag 了
|
82
NoobNoob030 2023-08-25 09:22:56 +08:00
|
83
ebony0319 2023-08-25 09:31:13 +08:00
尝试了一下,不会,期望大哥们给我一个标准答案
|
84
dtboy 2023-08-25 09:59:56 +08:00
@DreamNya 很赞很牛
昨天通过也是通过此老哥的第一个回复的思路. 后面修改对象(不管是用什么 hook 方法,还是覆盖执行(比如 chrome override)) 都可以 这里回复下 DreamNya 的 window.setInterval = () => 1; 操作是因为屏蔽库内是靠 setInterval 去检测逻辑的,代码源在 https://github.com/theajack/disable-devtool/blob/master/src/utils/interval.ts#L26 |
85
dtboy 2023-08-25 10:03:32 +08:00
给 nodejs 栈同好的爆破建议是用 electron 的 preload 思路,搭配 source override(毕竟可以实时覆盖修改代码)
|
86
dtboy 2023-08-25 10:15:31 +08:00
op 的第一个 handShake 请求没看懂.(细心老哥可以继续追)
后来 DreamNya 发现的 getParams 里面的逻辑应该是 1.生成一组用于 aes 加密的 key 和 iv 2.用 RSA 加密这个 iv 和 key ,也就是{C: '', P: ''} 加密后得到的就是请求参数中的 code 3.请求中的 param 就是用 key 和 iv 加密的 JSON.stringify({ h5Version: '',private: '', public: 'unix 时间戳' }) 总结就是,用 RSA 公钥加密了 AES 加密需要的 key 和 iv ,然后又用 key 和 ivAES 加密了真正传到服务器的内容. 服务端应该是用私钥解开 code 中的 iv 和 key ,之后再用 iv 和 key 解密请求正文. - 靠纯技术是解决不了安全性问题的,二进制是死的,人是活的,只要是死的东西就会有问题。最终解决安全性得靠法律吧。。而不是技术,毕竟踩缝纫机要可怕的多。 |
87
zeroFans 2023-08-25 10:52:48 +08:00
@DreamNya #77 window.setInterval = () => 1;设置之后是可以关闭 disable-devtool 库吗,我试了下还是不能打开 F12
|
89
DreamNya 2023-08-25 12:12:22 +08:00
@zeroFans
这个代码只关闭检测。 网页屏蔽只能屏蔽按键,但无论如何都无法屏蔽控制台开启,因为这是浏览器权限。 可以通过浏览器右上角菜单强制开启控制台 @dtboy 因为检测控制台都是通过定时器循环去检测的,定时器循环一共就那么几种方式,所以从源头直接把定时器掐断了,就完全不用管具体检测的逻辑了。 如果不通过定时器那检测更容易被绕过了,这是没法克服的硬伤。 偷鸡是因为摆烂了没有判断检测函数特征,一股脑全掐断了,真正网页上线的时候这种方式可能会把其他定时器也误伤。 另外前端加密混淆虽然无法做到 100%安全,总是能被绕过,但是我们可以加大绕过的难度, 换一个角度思考,只要减少被绕过的数量也算一种胜利。 比如: 油猴分发很容易,只要写成脚本形式发到脚本站,其他用户点一下安装一个脚本就能做到傻瓜式全自动绕过。 而 overrides 虽然是绝对无法避免的硬伤,但是操作难度大,光是开启 overrides 、定位代码、修改代码、保存代码就能筛选掉 90%的普通用户(可能还说少了,毫不避讳的说大多数普通用户都是傻子,文字都看不懂更别说操作了)。 根据上述情况就可以针对油猴,做一些针对性防御操作,比如核心函数完全不用对象方法让油猴无处 hook ,从而减少能破解的用户数量,来提高安全性。 当然这种针对性防御首先考验的是开发者代码水平,所有防御都是双刃剑。 |
90
dtboy 2023-08-25 12:48:19 +08:00
@DreamNya 感谢回复和讲解
请问针对 ``` 根据上述情况就可以针对油猴,做一些针对性防御操作,比如核心函数完全不用对象方法让油猴无处 hook ,从而减少能破解的用户数量,来提高安全性。 当然这种针对性防御首先考验的是开发者代码水平,所有防御都是双刃剑。 ``` 这一段可以给一些例子,或者伪代码吗,学习一下。要是没有你的那段 getParams ,我想大多人 |
91
dtboy 2023-08-25 12:51:36 +08:00
手抖了,ctrl+enter 发布了直接...
请问 getParam 是如何定位到这里的,像我昨天去 crack 的时候,只是想到了跳过屏蔽,但是还是看了你的回复后才有思路。也就是 getParam 这个函数的操作。 另外,你懒得处理的 hook 我是这么写的(但是也有例外吧,不过针对此项目,起码不会破坏其他定时器) let sI = window.setInterval function holder() { } window.setInterval = function (...args) { let fn = args[0] let ms = args[1] if (fn.toString().includes('ondevtoolclose')) { return sI.call(this, holder, ms) } else { return sI.apply(this, args) } } |
92
DreamNya 2023-08-25 13:14:17 +08:00
@dtboy getParam 是逆向发请求的堆栈一步步找到的,没啥诀窍……就是硬破……
Devtools 网络选项卡里面能看到所有请求还有堆栈,在里面打个断点就能调试 所有请求的参数不可能是凭空出现的,一定有一个源头,无论是静态定义还是通过函数动态计算又或者是通过请求响应返回,总有一个出处,通过堆栈一步步找到源头出处就行了,然后针对这个出处进行一些 hook setInterval 没啥作用域这些花样,this 一般都指向 window ,可以不用 call 或者 apply ,我习惯写的简单一点 const realInterval=window.setInterval; window.setInterval=(...args)=>{ if(args[0].toString().includes('ondevtoolclose')){ return 99999999 //尽量大 防止被 clearInterval 误伤;或者不写,这种检测定时器一般不会停止 }else{ return realInterval(...args) } } |
93
DreamNya 2023-08-25 13:49:35 +08:00
@dtboy
JS 最大特点就是对象和方法的引用可以被改写即使是 JS 原生对象,这就给 hook 带来极大便利了。 针对 hook ,基本上就是不用 JS 原生对象方法,改用一些操作符之类的。 比如 a=Object.assign({b:1},{c:2})可以改写成 a={...b,...c} a=new Array()可以改写成 a=[] 因为 Object.assign 和 Array 都是全局对象方法能直接访问到并改写,而{}、[]和...都是无法改写的 fuc.call(null,arg)也可以改写成 fuc(arg) 这类几乎无法 hook ,只能通过 override 或者断点的形式去针对了,webpack5 编译出来的源码就用的这种方法然后无处 hook ,而 webpack4 随便 hook |