猿人学web端爬虫攻防大赛赛题解析_第六题:js混淆-回溯

猿人学web端爬虫攻防大赛赛题解析_第六题:js混淆-回溯

2023年6月29日发(作者:)

猿⼈学web端爬⾍攻防⼤赛赛题解析_第六题:js混淆-回溯第六题:js 混淆 - 回溯1、前⾔万万没想到,距离上次做完第四题之后,再次动⼿写猿⼈学赛题解析的博客已经是四个多⽉之后了。其中各种艰⾟,难以⾔表,只能说逆向这⿁东西⽔太深了,要掌握的各种知识和骚操作是真的不少,奈何⾃⼰⼈菜瘾还⼤,不信邪⾮要靠⾃⼰⼿撕代码,想在不借助外⼒的情况下,⾃⼰把代码还原出来,结果是撞南墙撞的头破⾎流,⼀颗勤奋好学的热⾎之⼼险些就此熄灭。第六题相⽐第五题还算简单,即使这样我也前前后后琢磨了差不多⼩半个⽉,惭愧啊,话不多说,直蹦主题。2、题⽬理解⼀开始看到这题的时候,我第⼀眼关注的是回溯两个字,想着肯定是要靠层层挖掘混淆后加密代码逻辑,最终还原出真实的加密代码。事实证明有时候过度理解不是啥好事,因为这题他尽管有回溯,但回的没我想象的那么多,最后证明了使⽤正确解题⽅法要⽐死扣代码⾼效的多!3、加密原理解析事实上,这题解析过程我⼤致经历了两个阶段,从⼀开始的⽣啃硬扣代码逻辑到后⾯得知这加密原理可以⼀眼看出,我的内⼼是崩溃的o(╥﹏╥)o,所以了解RSA的朋友们,可以直接跳到3.2了,如果需要的话。。。3.1、加密位置判断先看题⽬加载内容,既然是要找奖⾦总额,那想必奖⾦⾦额应该是通过ajax请求异步返回的:果不其然,在chrome浏览器的XHR请求⾥,找到了这个请求的url和对应的返回值,观察⼀下发现这些值只是三等奖的中奖⾦额,但题⽬要求的可是全部中奖⾦额,那⼀等奖和⼆等奖的值是从哪来的呢?这⾥回到⽹页的源码部分,可以很容易找到其他⾦额的⽣成逻辑,这段代码出现了跟数值相关的操作,推测就是其他奖⾦⾦额⽣成的位置。算了⼀下,⼆等奖是三等奖的8倍,⼀等奖是三等奖的15倍,总⾦额是⼀等奖的24倍,跟最终请求结果⾥的数值是⼀致的,所以这⾥的问题解决了。回到请求奖⾦的这个url这⾥,发现这⾥有两个参数,m和q,我们要模拟正确的请求必然要找到这两个参数的⽣成逻辑,对于有经验的爬⾍⽼⼿来说,在源代码⾥观察⼀下估计就能⼤概找到位置了。这⾥还是⽤朴素的寻找逻辑讲讲这个过程,万⼀有⽐我还萌新的萌新看到这篇博客了呢,这⾥我是选择设置XHR断点,当检测到发送了包含api/match/6?m=这段字符串的请求发起时,请求就会⾃动在这⾥断下来:然后我们就可以看到整个调⽤栈了,⼀步步⽹上追,观察m和q最早是在哪⾥被赋值的:很轻易的就在request函数这⾥找到了m和q被赋值的地⽅,粗略⼀看,m是由r函数⽣成的,q是由时间戳加其他字符⼀起拼接⽽成的,相对来说⽐较简单,q⾥的window.o在多观察⼏次以后发现就是翻页的页数,或者说每发送⼀次数据请求,这个值都会加1:再来看m,调试的时候⿏标放这⼀看,发现它是由⽂件⾥的r函数⽣成,好家伙,这就是第六题最难解决的加密参数了吧,毕竟⼀般能被单独放到js⽂件⾥加密的参数都不简单,反正我是经常惨败⽽归。3.2、解密_萌新试错版先看看我使⽤硬扣法,试图通过⼀步步还原m值的惨痛经历。⾸先在⽂件⽂件内,我们⼀开始就追到了r函数的位置,param1是前⾯的时间戳t,param2是翻页页数,初看是根据这两个值来进⾏加密。r函数⾥⼜调⽤了z函数,z函数内调⽤了函数_n:在这⾥,_n的本体是n函数,n函数是匿名函数function(i)的闭包函数:_n("jsencrypt")等于n("jsencrypt"),这个函数运⾏结果实际上就是这个函数内的匿名函数n:匿名函数n被new了⼀下之后,变成了g函数,也就是说最初的r函数最后实际上运⾏的是这个encode函数:这个函数内实际⼜调⽤的是t(i)这个函数,再往前追溯发现调⽤的是这个encrypt函数:⽽在它内部,他⼜调⽤了be函数:be函数的参数是getKey这个函数的结果加密⽽成,这个函数没有做其他操作,直接返回了:进⼀步找到了的⽣成位置,很明显它是qe对象实例化后的结果,经过调试,qe函数执⾏的就是ey(t),此处这个参数t就是代码⾥明⽂写出来的这段字符串:“-----BEGIN PUBLIC KEY----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDq04c6My441Gj0UFKgrqUhAUg+kQZeUeWSPlAU9fr4HBPDldAeqzx1UR92KJHuQh/zs1HOamE2dgX9z/2oXcJaqoRIA/FXysx+z2YlJkSk8XQLcQ8EBOkp//MZrixam7lCYpNOjadQBb2Ot0U/Ky+jF2p+Ie8gSZ7/u+Wnr5grywIDAQAB-----END PUBLIC KEY-----”:事实上,在经历了上⾯这⼀步步调试之后,我⼜往更深处追了⼗⼏个嵌套函数,⼀个个套娃函数,每当我以为差不多该找到尽头的时候,⾥⾯都会有新的其他函数的调⽤。总共追了⼩⼏⼗层调⽤逻辑后我终于有点失去耐⼼了,这是⼈⼲的事吗?难道真有要回溯⼏百次的加密?那还不如把整个代码全复制出来调试算了(我真后悔没有早点这么做,真的!),实在没辙了,开始⽹上找教程,才发现别⼈真的是直接把所有代码复制出来,并且⼀眼就看出了是个啥加密,还是吃了没⽂化的亏啊3.3、解密_⽼⼿经验版熟悉前段和逆向的⽼江湖们,见惯了各种⽹站使⽤的常⽤加密算法,他们往往⼀眼就通过代码的特征和结构看出⾯前是什么加密,⽐如这道题⾥,典型的特征就是代码⾥多次出现的jsencrypt,以及设置公钥和秘钥的相关内容,如果了解RSA加密相关知识的,确实能很容易通过这些特征看出来这就RSA加密算法。当然,这⾥作者肯定是对算法做了点修改的,代码调试过程中还是有⼏个坑。⾸先在⽂件⾥的头⼏⾏就有⼀段颜⽂字混淆的内容,就是下⾯这些看起来很可爱,但是为了混淆视听,增⼤理解难度的代码:对于这种混淆可以⽤解混淆⼯具直接还原,也可以直接在浏览器控制台调试,看看原始代码内容是什么,⽐如直接去掉颜⽂字混淆代码最后的('_')表情符号,在控制台运⾏后出现了如下代码:也就是说这⾥的混淆源代码就是定义了⼀个匿名函数,内容是window.o = 1,其实就是给这个变量赋了个值:ƒ anonymous() {window.o = 1}当然这⾥在本地运⾏时还要在代码开头给window对象赋值,并将原始的将window赋值为空的代码注释掉:window = global;上⾯是第⼀个坑,还有第⼆处,就是代码运⾏过程中会提⽰⼀个Message too long for RSA的错误:回到浏览器查看,找到这段字符输出的位置,是判断e和t这个字符串的长度⼤⼩:往上追,发现t就是时间戳字符串,那可以判断就是e这个字符串的值有误了:经过层层调试(这⾥就不细说了,毕竟反正找着也挺累,再加上看某个解析时⼤佬开头就给提⽰了,后⾯就没花太⼤功夫找了),最终找到了问题所在,就是这⾥的xe的值有问题:控制台输出⼀下,发现其实就是个false,将其替换⼀下,就能正常输出加密结果了nodejs环境下的运⾏结果:以上就是整个加密的还原过程,要说复杂吧也不是很复杂,要说简单吧,很多东西没有js基础还真的是会完全摸不着头脑,别⼈凭经验⼏⼗秒就能看出来的东西,可能你要摸索好⼏天才能梳理清楚来龙去脉,只能说逆向还是需要花时间好好打磨基础的。4、代码实现过程满⼼欢喜的以为掌握了真谛的⾃⼰,在⽤python实现过程中还是遇到了好⼏个坑,令我百思不得其解,苦思冥想,朝思暮想,最终也没想太透彻4.1、坑⼀:风控不通过第⼀个问题是在写好⽤于请求第⼀页内容的代码之后,运⾏了⼀波发现返回结果是风控不通过,⼀开始我还以为是请求速度太快,所以加了⼏秒暂停,但依然得不到正确响应,于是⼜从头到尾检查加密参数、请求头是不是有问题,反复跟浏览器端的请求对⽐,发现代码真的是没问题,但就是通过不了风控,直到我把代码拿到另⼀台电脑运⾏,返回结果就正常了。。。。那我就想肯定是我电脑环境出问题了,⽐如服务端检测了指纹信息什么的,但是加密参数⾥并没有跟指纹相关的信息传过去啊,最后当我⽤代理换了个ip以后,居然通过风控了,所以问题只能是出在服务器把我ip封了,且只针对第六题,后来把ip换回来发现也能正常响应了,这就让我有点迷了,按道理通过程序请求应该是没有太多其他特征可以检测的,可是为什么就换了⼀次ip再换回来就能正常请求结果了,这个问题有待⽇后了解。4.2、坑⼆:参数q设置有误第⼀题得到正确响应后马上写了个循环,期待得到所有正确返回值,结果程序⼀跑起来,第⼆题往后⾯⼜开始风控不通过了,真是吐了⼀⼝⽼⾎,毕竟按我的观察,每请求⼀次,参数q都会带上上⼀次的时间戳信息,所以我也是这么构造q值的。q = q+str(page) + '-' + t + '|'后来发现浏览器端跟本地端运⾏还是有区别的,在浏览器我们每次点击跳页的时候,window都会加1,不管是跳转到第⼏页,就是点⼀次值增加⼀点,这是靠浏览器端检测的。但是在本地运⾏时服务器并不会检测到我是第⼏次请求,所以参数q是可以不⽤累加上⼀次请求时间戳的,即可以把每次请求都当第⼀次请求,只改变时间戳t值就⾏。4.3、完全体代码Python实现代码如下,对应的6_js回溯.js源码在这⾥:# -*- coding: utf-8 -*-# @Time : 2021/4/20 21:44# @Author : zzt# @Email : zztoozzt@# @File : 6_js回溯.py# @Software: PyCharmimport requestsimport timefrom import execute_js, muterun_jsheaders = { 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Accept-Encoding': 'gzip, deflate', 'Accept-Language': 'zh-CN,zh;q=0.9', 'Host': '', 'Proxy-Connection': 'keep-alive', 'Referer': '/match/6', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36', 'X-Requested-With': 'XMLHttpRequest',}session = n()s=headersfor page in range(1, 6): t = str(int(())* 1000) '''第⼀种传参⽅式,按请求次数对应''' q = str(page) + '-' + t + '|' js_result = muterun_js('6_js回溯.js',t+' '+str(page)) '''第⼆种传参⽅式,每次都算第⼀次请求''' # q = str(1) + '-' + t + '|' # js_result = muterun_js('6_js回溯.js',t+' '+str(1)) m=js_() if page==1: params = ( ('m', m), ('q', q), ) else: params = ( ('page',page), ('m', m), ('q', q), ) if page>3: headers['User-Agent']='t' url = '/api/match/6' response = (url, params=params).json() print(response)5、结语搞逆向很痛苦,复盘学习过程也很痛苦,学习本⾝就是件挺痛苦的事,尤其是得不到正反馈的时候,多受⼏次打击很容易产⽣要放弃的念头,所以还是要循序渐进,由易到难,把基础搞扎实,下次再上来就挑战对⾃⼰这么有难度的题就扇⾃⼰⼤嘴巴⼦!6、参考⽂献

发布者:admin,转转请注明出处:http://www.yc00.com/news/1687982905a63567.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信