当前位置: 首页 > 后端技术 > Python

[JSReverse100Cases]Changeyourthinking,avoiddetours,XmiEncryptionAnalysis

时间:2023-03-25 21:17:02 Python

declaresthatallcontentinthisarticleisforlearningandcommunicationonly,andthecontentofcapturedpackets,sensitiveURLs,anddatainterfaceshavebeendesensitized,andarestrictlyprohibitedforuseinCommercialuseandillegaluse,otherwiseallconsequencesarisingtherefromhavenothingtodowiththeauthor,ifthereisanyinfringement,pleasecontactmetodeleteimmediately!逆向目标目标:X米账号登录主页:aHR0cHM6Ly9hY2NvdW50LnhpYW9taS5jb20v接口:aHR0cHM6Ly9hY2NvdW50LnhpYW9taS5jb20vcGFzcy9zZXJ2aWNlTG9naW5BdXRoMg==逆向参数:FormData:hash:FCEA920F7412B5DA7BE0CF42B8C93759逆向过程抓包分析来到小米的登录页面,随便输入一个账号密码登陆,抓包定位到登录接口ForaHR0cHM6Ly9hY2NvdW50LnhpYW9taS5jb20vcGFzcy9zZXJ2aWNlTG9naW5BdXRoMg==POSTrequest,therearemanyparametersinFormData,let’sanalyzethemainparameters:serviceParam:{"checkSafePhone":false,"checkSafeAddress":false,"lsrp.0}fromtheliteralmeaning,parameter0":Itseemstobecheckingwhetherthemobilephoneandaddressaresafe.Asforthespecificmeaning,itistemporarilyunknown,anditisnotknownwhereitisset.callback:http://order.xxx.com/login/callback?followup=https%3A%2F%2Fwww.xx......,thecallbacklinkisgenerallyfixed,followedbyfollowupandsidparameter.qs:%3Fcallback%3Dhttp%253A%252F%252Forder.xxx.com%252Flogin%252Fcallback%2......,formatthevalueofqsandyoucanfindthatitisactuallycallback,sign,sid,_qrsizefourThevalueisassembledaccordingtoURLencoding._sign:w1RBM6cG8q2xj5JzBPPa65QKs9w=,thisstringseemstobeobtainedaftersomekindofencryption,oritmaybethevalueinthesourcecodeofthewebpage.user:15555555555,usernameincleartext.hash:FCEA920F7412B5DA7BE0CF42B8C93759,加密后的密码。参数逆向基本参数我们先来看serviceParam等基本参数。大意是直接搜索,看能不能直接找到这个值。搜索发现serviceParam关键字在一个302重定向请求中:我们注意到当只进入登录首页aHR0cHM6Ly9hY2NvdW50LnhpYW9taS5jb20v时,会连续出现两次302重定向,下面重点分析这两个重定向。对于第一次重定向,新的URL中有followup、callback、sign、sid参数,我们将在后续的登录请求中使用这些参数。第二次重定向,新的URL还有followup、callback、sign、sid参数,以及serviceParam、qs参数,后续登录请求也需要这些参数。找到参数的来源,直接从第二次重定向的链接中提取参数。这里使用response.history[1].headers['Location']提取页面Address第二次重定向返回的header中的target,urllib.parse.urlparse解析重定向链接urllib的URL结构。parse.parse_qs提取参数返回字典,代码示例:importrequestsimporturllib.parseheaders={'Host':'脱敏处理,全代码关注GitHub:https://github.com/kgepachong/crawler','User-Agent':'Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/91.0.4472.124Safari/537.36'}index_url='脱敏处理,完整代码关注GitHub:https:///github.com/kgepachong/crawler'response=requests.get(url=index_url,headers=headers)location_url=response.history[1]。headers['Location']urlparse=urllib.parse.urlparse(location_url)query_dict=urllib.parse.parse_qs(urlparse.query)print(query_dict)need_theme=query_dict['needTheme'][0]show_active_x=query_dict['showActiveX'][0]service_param=query_dict['serviceParam'][0]callback=query_dict['callback'][0]qs=query_dict['qs'][0]sid=query_dict['sid'][0]_sign=query_dict['_sign'][0]print(need_theme,show_active_x,service_param,callback,qs,sid,_sign)hash等参数齐全,现在还有一个加密的密码hash,一般来说,这个是用JS加密的,老方法,全局搜索hash或者hash:,在78.4da22c55.chunk.js文件中可以看到一句话:hash:S()(r.password).toUpperCase(),很明显明文密码加密后全部转为大写:的关键点是这个S()。当你移动鼠标时,你会发现它实际上调用了78.4da22c55.chunk.js的一个匿名函数。我们在匿名函数的返回位置打断点调试:e.exports=function(e,n){if(void0===e||null===e)thrownewError("Illegalargument"+e);varr=t.wordsToBytes(u(e,n));返回n&&n.asBytes?r:n&&n.asString?s.bytesToString(r):t.bytesToHex(r)}可以看到传入的e是明文密码,最后一个return语句是三元运算符,因为n没有定义,所以最后一个return其实是t。bytesToHex(r),它的值就是加密后的密码,但是所有的字母都是小写的。按照正常的思路,我们要开始扣JS了,这里传入参数r指定,varr=t.wordsToBytes(u(e,n));,先跟进u函数看:可以看到u函数其实用到了567的对象方法,在这个对象方法中,还用到了129、211、22等很多方法。如果一一扣除,到猴年才扣除,而且容易出错。代码太多,不容易定位错误的地方,所以这里需要换个思路。我们先看看t.bytesToHex(r)是什么,接着这个函数:bytesToHex:function(e){for(vart=[],n=0;n>>4).toString(16)),t.push((15&e[n]).toString(16));returnt.join("")}解读这段代码,传入的e是一个16位的Array对象,定义了一个t的空数组,经过一个循环,依次取Array对象中的值,经过第一次无符号右移操作(>>>)后,转换为十六进制字符串,结果添加到t数组的末尾。经过第二位运算(&)后,同样转为十六进制字符串Base字符串,将结果添加到t数组的末尾。也就是说传入的原始16位Array对象的每个值都经过了两次运算,所以最终结果t数组中会有32个值,最后将t数组转换成字符串返回.结合调用的函数名,我们来回顾一下整个过程。首先,调用wordsToBytes()方法将明文密码字符串转换为字节数组。不管密码的长度,最终的字节数组都是16位的,然后调用bytesToHex()方法,循环遍历生成的字节类型数组,让它生成一个32位的字符串。无论密码长度如何,最终的密文都是32位长,由字母和数字组成。这些特点很容易想到MD5加密。将明文转换为字节数组后,进行随机哈希,对字节数组进行随机哈希。Summary,获取汇总字节数组,循环遍历字节数组,生成固定位数的字符串。这不就是MD5的加密过程吗?直接取密码进行MD5加密,与网站加密结果对比。可以发现确实是一样的,这就验证了我们的猜想是正确的:在这种情况下,直接使用Python的hashlib模块就可以了。不用上代码了,代码示例:importhashlibpassword="1234567"encrypted_pa??ssword=hashlib.md5(password.encode(encoding='utf-8')).hexdigest().upper()print(encrypted_pa??ssword)#FCEA920F7412B5DA7BE0CF42B8C93759总结有时候我们需要换个思路,不一定每次都死守着JS代码。相对简单的站点只有几种加密方式,有的稍微重写了一些,并且隐藏了一些密钥和偏移量等参数,有些给你混淆了加密解密的过程,让你难以理解。如果你熟悉常见的加密方式和原理,有时候你只需要弄清楚他用的是什么加密方式,或者拿到密钥,偏移量,更改数据量等关键参数就可以完全自己还原整个加密过程!完整代码GitHub关注K哥的爬虫,持续分享爬虫相关代码!欢迎加星!https://github.com/kgepachong/下面只演示部分关键代码,完整代码仓库地址:https://github.com/kgepachong...Python登录关键代码#!/usr/bin/envpython3#-*-coding:utf-8-*-importjsonimporthashlibimporturllib.parseimportrequestsindex_url='脱敏处理,完整代码关注github:https://github.com/kgepachong/crawler'login_url='脱敏处理,关注GitHub获取完整代码:https://github.com/kgepachong/crawler'headers={'Host':'脱敏处理,完整代码关注GitHub:https://github.com/kgepachong/crawler','Origin':'脱敏处理,关注GitHub完整代码:https://github.com/kgepachong/crawler','Referer':'脱敏处理,完整代码关注GitHub:https://github.com/kgepachong/crawler','User-Agent':'Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/91.0.4472.124Safari/537.36'}session=requests.session()defget_encrypted_pa??ssword(password):encrypted_lib.password=hashmd5(password.encode(encoding='utf-8')).hexdigest().upper()返回encrypted_pa??ssworddefget_parameter():response=requests.get(url=index_url,headers=headers)location_url=response.history[1].headers['Location']urlparse=urllib.parse.urlparse(location_url)query_dict=urllib.parse.parse_qs(urlparse.query)#print(query_dict)returnquery_dictdeflogin(username,encrypted_pa??ssw)ord,query_dict):data={'bizDeviceType':'','needTheme':query_dict['needTheme'][0],'theme':'','showActiveX':query_dict['showActiveX'][0],'serviceParam':query_dict['serviceParam'][0],'callback':query_dict['callback'][0],'qs':query_dict['qs'][0],'sid':query_dict['sid'][0],'_sign':query_dict['_sign'][0],'user':username,'cc':'+86','hash':encrypted_pa??ssword,'_json':True}response=session.post(url=login_url,data=data,headers=headers)response_json=json.loads(response.text.replace('&&&START&&&',''))print(response_json)returnresponse_jsondefmain():username=input('请输入登录账号:')password=input('请输入登录密码:')encrypted_pa??ssword=get_encrypted_pa??ssword(password)parameter=get_parameter()login(username,encrypted_pa??ssword,parameter)if__name__=='__main__':main()