-
-
大数据安全试炼2
-
发表于: 2021-9-7 15:49 1191
-
<!-- @import "[TOC]" {cmd="toc" depthFrom=1 depthTo=6 orderedList=false} -->
<!-- code_chunk_output -->
<!-- /code_chunk_output -->
习题牛刀小试: 找出Flag
可见提示是 hook eval 那我们就试一下,那我们就用油猴脚本hook一下
1 2 3 4 5 6 | var _eval = eval ; eval = function (){ console.log(arguments) return _eval(arguments) } |
报了一个错,不能在严格模式下运行这个脚本,那么我们就取消严格模式,并且在一开始就hook他的eval函数
出现了一个假答案,额...(哼恶趣味),输入假答案看看是啥
额过分还有检测,那就上绝招,用代理器hook一下eval函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | eval = new Proxy( eval ,{ apply (target, thisArg, argArray) { let result = Reflect. apply (target, thisArg, argArray) console.log(`function name is ${target.name}, thisArg is ${thisArg}, argArray is [${argArray}], result is ${result}.`) return result }, construct(target, argArray, newTarget) { var result = Reflect.construct(target, argArray, newTarget) console.log(`construct function name is ${target.name}, argArray is [${argArray}], result is ${JSON.stringify(result)}.`) return result; } , get(target, p, receiver) { let res = Reflect.get(target, p, receiver); console.log(`get ${target.name} ${res}`) return res } , set (target, p, value, receiver) { let res = Reflect. set (target, p, value, receiver); console.log(` set ${target.name} ${value}`) return res; } }) |
让我看到了吧,调用了toString,跟进去看一下,打一个断点,f10开始
混淆了5555,看着好乱,我们就一个个的来看看它做了什么
1 2 | eval [_0x5572a4( 0x132 )]() = = = _0x5572a4( 0x13d ) ? window[ '$eval1' ] = !![] : window[_0x5572a4( 0x137 )] = ![], Function[_0x5572a4( 0x134 )][_0x5572a4( 0x132 )][_0x5572a4( 0x136 )]( eval ) = = = 'function\x20eval()\x20{\x20[native\x20code]\x20}' ? window[_0x5572a4( 0x131 )] = !![] : window[_0x5572a4( 0x131 )] = ![]; |
1 2 3 4 5 6 7 | _0x5572a4( 0x132 ) = "toString" _0x5572a4( 0x13d ) = "function eval() { [native code] }" _0x5572a4( 0x137 ) = "$eval1" _0x5572a4( 0x134 ) = "prototype" _0x5572a4( 0x132 ) = "toString" _0x5572a4( 0x136 ) = "call" _0x5572a4( 0x131 ) = "$eval2" |
翻译一下就是
1 2 | eval [ "toString" ] = = "function eval() { [native code] }" ?window[ '$eval1' ] = !![]:window[ '$eval1' ] = ![] Function[ 'prototype' ][ 'toString' ][ 'call' ]( eval ) = = = 'function\x20eval()\x20{\x20[native\x20code]\x20}' ?window[ "$eval2" ] = !![]:window[ "$eval2" ] = ![] |
那这样就清晰了,蓝师傅监控了toString方法和原型链上的toString方法
那么我们hook掉这两个方法就好了,最后的代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | var _eval = eval ; eval = function (){ console.log(arguments) return _eval(arguments) } eval .toString = function (){ console.log( 1111 ) return "function eval() { [native code] }" } Function.prototype.toString = function(){ return "function eval() { [native code] }" } |
接着刷新一下界面看一下
输入一下啊欢迎来到大数据安全技术学习JS课程
,成功了
题目 2021年6月份JS逆向第三题
观察题目只有一个按钮点击后出现浏览器的设备指纹
查看网络请求看他有没有发包
有的那就说明是通过后端校验的,这是我们可以hook AJAX或者通过查看网络请求的调用栈来获得发包的内容,我们采用查看包的调用栈的方式来跟踪,
在app.js中跟进去看一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | this.fingerprint = this.$Encrypt.sign(e), p()({ method: "post" , url: "http://www.dtasecurity.cn:35555/subject3202106" , data: { sign: this.fingerprint, fingerprint: window.btoa(e) }, transformRequest: [function (e) { var t = ""; for (var a in e) t + = encodeURIComponent(a) + "=" + encodeURIComponent(e[a]) + "&" ; return t = t.substring( 0 , t.lastIndexOf( "&" )) } ], headers: { "Content-Type" : "application/x-www-form-urlencoded" } |
发包方式知道了,关键参数就是sign和fingerprint,先看一下sign是如何生成的,追踪进去this.$Encrypt.sign
和e,e是明文的很容易就能看懂关键是sign函数我们继续跟踪
发现了md5字样菜猜测是md5算法,尝试一下,发现一模一样那么这里就是md5算法了
接着分析fingerprint也就是e是怎么来的,可以看到下面的这一行代码,那么就分析getfingerprint函数,跟踪进去
1 2 3 4 5 6 7 8 9 10 11 12 13 | var e = this.getfingerprint(); getfingerprint: function () { var e = [] , t = e.push.bind(e); return [navigator, location, history].forEach(function (e) { for (var a in _()(window, e), e) { var n = e[a]; n && "string" = = typeof n && t(a + ":" + n) } }), e.join( "###" ) } |
getfingerprint函数非常的简单,可以通过nodejs来模拟一下,尝试补出他的环境,如下图开始补环境
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 | let rawindexof = String.prototype.indexOf String.prototype.indexOf = function ( str ) { var res = rawindexof.call(this, str ) console.log(`[String] "${this}" is indexof "${str}" , res is ${res}`) return res } let mydocument = { "head" : {}, "documentElement" : { "getAttribute" : function () { } }, "readyState" : "complete" , "addEventListener" : function () { }, "createElement" : function () { return {} }, "getElementsByTagName" : function ( str ) { console.log( str ) if ( str = = = "meta" ) { let metaRes = [] metaRes[ "meta-pro" ] = { "content" : { "length" : 6 } } return metaRes } } } let mynavigator = Object .create({ "vendorSub" : "", "productSub" : "20030107" , "vendor" : "Google Inc." , "maxTouchPoints" : 0 , "userActivation" : {}, "doNotTrack" : null, "geolocation" : {}, "connection" : {}, "plugins" : { "0" : { "0" : {} }, "1" : { "0" : {} }, "2" : { "0" : {}, "1" : {} } }, "mimeTypes" : { "0" : {}, "1" : {}, "2" : {}, "3" : {} }, "webkitTemporaryStorage" : {}, "webkitPersistentStorage" : {}, "hardwareConcurrency" : 4 , "cookieEnabled" : true, "appCodeName" : "Mozilla" , "appName" : "Netscape" , "appVersion" : "5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36" , "platform" : "Linux x86_64" , "product" : "Gecko" , "userAgent" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36" , "language" : "zh" , "languages" : [ "zh" , "en-US" , "en" ], "onLine" : true, "webdriver" : false, "scheduling" : {}, "mediaCapabilities" : {}, "permissions" : {}, "mediaSession" : {} }); let mysrceen = Object .create({ height: 852 , width: 1918 , colorDepth: 24 , }); let mylocation = { "ancestorOrigins" : {}, "href" : "http://www.dtasecurity.cn:11080/details?url=http%3A%2F%2Fwww.dtasecurity.cn%3A30080%2Fsubject%2F%23%2F202106subject3" , "origin" : "http://www.dtasecurity.cn:11080" , "protocol" : "http:" , "host" : "www.dtasecurity.cn:11080" , "hostname" : "www.dtasecurity.cn" , "port" : "11080" , "pathname" : "/details" , "search" : "?url=http%3A%2F%2Fwww.dtasecurity.cn%3A30080%2Fsubject%2F%23%2F202106subject3" , "hash" : "" } let myhistory = { "length" : 4 , "scrollRestoration" : "manual" , "state" : { "key" : "680.400" } } let mywindow = { XMLHttpRequest: function () { }, sessionStorage: {}, localStorage: {}, navigator: mynavigator, scrollTo: function () { }, addEventListener: function () { }, attachEvent: function () { }, screen: mysrceen, location: mylocation, chrome: {}, document: mydocument, }; let Image = function () { }; let rawstringify = JSON.stringify; JSON.stringify = function ( Object ) { if (( Object ?.value ?? Object ) = = = global ) { return "global" } else { return rawstringify( Object ) } } function checkproxy() { / / Object .keys(window) window.a = { "b" : { "c" : { "d" : 123 } } } window.a.b.c.d = 456 window.a.b window.btoa( "123" ) window.atob.name "c" in window.a delete window.a.b Object .defineProperty(window, "b" , { value: "bbb" }) Object .getOwnPropertyDescriptor(window, "b" ) Object .getPrototypeOf(window) Object .setPrototypeOf(window, { "dta" : "dta" }) / / for (let windowKey in window) { / / windowKey / / } Object .preventExtensions(window) Object .isExtensible(window) } function getMethodHandler(WatchName) { let methodhandler = { apply (target, thisArg, argArray) { let result = Reflect. apply (target, thisArg, argArray) console.log(`[${WatchName}] apply function name is [${target.name}], argArray is [${argArray}], result is [${result}].`) return result }, construct(target, argArray, newTarget) { var result = Reflect.construct(target, argArray, newTarget) console.log(`[${WatchName}] construct function name is [${target.name}], argArray is [${argArray}], result is [${JSON.stringify(result)}].`) return result; } } return methodhandler } function getObjhandler(WatchName) { let handler = { get(target, propKey, receiver) { let result = Reflect.get(target, propKey, receiver) if (result instanceof Object ) { if (typeof result = = = "function" ) { / / console.log(`[${WatchName}] getting propKey is [${propKey}] , it is function`) / / return new Proxy(result,getMethodHandler(WatchName)) } else { console.log(`[${WatchName}] getting propKey is [${propKey}], result is [${JSON.stringify(result)}]`); } return new Proxy(result, getObjhandler(`${WatchName}.${propKey}`)) } console.log(`[${WatchName}] getting propKey is [${propKey?.description ?? propKey}], result is [${result}]`); return result; }, set (target, propKey, value, receiver) { if (value instanceof Object ) { console.log(`[${WatchName}] setting propKey is [${propKey}], value is [${JSON.stringify(value)}]`); } else { console.log(`[${WatchName}] setting propKey is [${propKey}], value is [${value}]`); } return Reflect. set (target, propKey, value, receiver); }, has(target, propKey) { var result = Reflect.has(target, propKey); console.log(`[${WatchName}] has propKey [${propKey}], result is [${result}]`) return result; }, deleteProperty(target, propKey) { var result = Reflect.deleteProperty(target, propKey); console.log(`[${WatchName}] delete propKey [${propKey}], result is [${result}]`) return result; }, getOwnPropertyDescriptor(target, propKey) { var result = Reflect.getOwnPropertyDescriptor(target, propKey); console.log(`[${WatchName}] getOwnPropertyDescriptor propKey [${propKey}] result is [${JSON.stringify(result)}]`) return result; }, defineProperty(target, propKey, attributes) { var result = Reflect.defineProperty(target, propKey, attributes); console.log(`[${WatchName}] defineProperty propKey [${propKey}] attributes is [${JSON.stringify(attributes)}], result is [${result}]`) return result }, getPrototypeOf(target) { var result = Reflect.getPrototypeOf(target) console.log(`[${WatchName}] getPrototypeOf result is [${JSON.stringify(result)}]`) return result; }, setPrototypeOf(target, proto) { console.log(`[${WatchName}] setPrototypeOf proto is [${JSON.stringify(proto)}]`) return Reflect.setPrototypeOf(target, proto); }, preventExtensions(target) { console.log(`[${WatchName}] preventExtensions`) return Reflect.preventExtensions(target); }, isExtensible(target) { var result = Reflect.isExtensible(target) console.log(`[${WatchName}] isExtensible, result is [${result}]`) return result; }, ownKeys(target) { var result = Reflect.ownKeys(target) console.log(`[${WatchName}] invoke ownkeys, result is [${JSON.stringify(result)}]`) return result }, apply (target, thisArg, argArray) { let result = Reflect. apply (target, thisArg, argArray) console.log(`[${WatchName}] apply function name is [${target.name}], argArray is [${argArray}], result is [${result}].`) return result }, construct(target, argArray, newTarget) { var result = Reflect.construct(target, argArray, newTarget) console.log(`[${WatchName}] construct function name is [${target.name}], argArray is [${argArray}], result is [${JSON.stringify(result)}].`) return result; } } return handler; } const navigator = new Proxy(mynavigator, getObjhandler( "navigator" )); const screen = new Proxy(mysrceen, getObjhandler( "screen" )); const location = new Proxy(mylocation, getObjhandler( "location" )); const document = new Proxy(mydocument, getObjhandler( "document" )); const history = new Proxy(myhistory, getObjhandler( "history" )); const window = new Proxy( Object .assign( global , mywindow), getObjhandler( "window" )); / / checkproxy() module.exports = { window, navigator, screen, location, String, Image, document, history } |
(ps:直接用蓝师傅的环境真香哈),之前讲过就不多说了,接着我们遇到了我们的第一个错误_没定义
回到浏览器中查看一下_是个什么东西,发现到了下面这里,然后继续打断点跟踪
1 2 3 | var n = r && r.__esModule ? function() { return r.default } |
查看一下r.default是什么,是一个属性删除函数,那么这一段的逻辑就是,在浏览器上删除不到这些属性,而在nodejs上能删除这些属性,那么其实_方法是无效的我们根本不需要这个删除方法,就把他删掉就好了
可以正常运行
最后打印一下这个匿名方法
1 2 3 4 5 6 7 8 9 10 11 | console.log((function () { var e = [] , t = e.push.bind(e); return [navigator, location, history].forEach(function (e) { for (var a in e) { var n = e[a]; n && "string" = = typeof n && t(a + ":" + n) } }), e.join( "###" ) })()); |
复制上去访问一下看看能不能过
通过了,可以看到蓝师傅的环境真好用
有兴趣可以一起学习一下呀
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
赞赏
- [原创]Base64 编码原理 && 实现 23440
- [原创]Lsposed 技术原理探讨 && 基本安装使用 26808
- [原创]Unidbg-Linker部分源码分析(下) 28684
- [原创]Unidbg-Linker部分源码分析(上) 26227