declaresthatallcontentinthisarticleisforlearningandcommunicationonly,sensitiveURLsanddatainterfaceshavebeendesensitized,andcommercialandillegalpurposesarestrictlyprohibited,otherwiseallconsequencesarisingtherefromaretheresponsibilityoftheauthorIrrelevant,ifthereisanyinfringement,pleasecontactmetodeleteitimmediately!逆向目标目标:某加速商城登录接口主页:aHR0cDovL3d3dy4xNXl1bm1hbGwuY29tL3BjL2xvZ2luL2luZGV4接口:aHR0cDovL3d3dy4xNXl1bm1hbGwuY29tL3BjL2xvZ2luL2NoZWNr逆向参数:Cookie:PHPSESSID=g9jp7sfpukg99v03gj69nr9r56FormData:u[password]:7aad70a547b016a07f2e20bee7b4936111e650aa5c419fafdfb28322......_csrfToken:4bea63330c5ccdd37588321d027f4c40129687b0逆向过程抓包分析在首页点击登陆,Cometotheloginpage,enteranaccountpasswordtologin,capturethepacketandlocatethelogininterfaceasaHR0cDovL3d3dy4xNXl1bm1hbGwuY29tL3BjL2xvZ2luL2NoZWNr,thePOSTrequest,intheFormData,thepasswordu[password]isencrypted,andthereisanother_csrfTokenthatweneedtosolve.ThereisaPHPSESSIDinthecookie.Aftertesting,ifthisparameterisnotincluded,thefinalrequestwillalsofail.Parameterreversefirstlookat_csrfToken,firsttrytosearchforitsvaluedirectly,youcanfindthatitactuallyexistsinthesourcecodeofthehomepage,justmatchitdirectly:lookatthePHPSESSIDinthecookie,thefirstthingthatcomestomind,itmaybethefirstVisitthepageonce,getitfromtheSet-CookiereturnedbyResponseHeaders,checkthefirstrequest,itisindeed,ifnot,youneedtoclearthecacheandthenvisit(DeveloperTools——>Application——>Storage——>Clearsitedata).最后一个密码参数u[password]必须通过JS加密得到。直接Ctrl+Shift+F全局搜索,在索引首页可以直接找到RSA加密的地方,埋下断点调试,最后res就是加密后的密码:我们将这段关键代码进行修改,封装成一个函数:functiongetEncryptedPassword(password){varpublic_key="00bdf3db924714b9c4ddd144910071c282e235ac51371037cf89fa08f28b9105b6326338ed211280154c645bf81bae4184c2b52e2b02b0953e7aa8b25a8e212a0b";varpublic_length="10001";varrsa=newRSAKey();rsa.setPublic(public_key,public_length);returnrsa.encrypt(password);}此处使用的三个主要函数是RSAKey()、setPublic()和encrypt()。在开发者工具中,将鼠标放在函数上,可以看到这里都是调用rsa.js中的方法。我们直接把整个文件剥离出来进行本地调试:本地调试会发现BigInteger是undefined。将鼠标移到这个函数上,可以发现调用了jsbn.js中的方法。同样,直接把整个jsbn.js文件剥离出来,进行本地调试。这里,rsa.js文件的第一行其实是有注释的://Dependsonjsbn.jsandrng.js,我们可以猜测rsa.js可能依赖jsbn.js和rng.js这两个文件.有了jsbn.js的代码,再debug会发现navigator和SecureRandom是undefined。导航器我们已经非常熟悉了。是浏览器的相关信息。一般可以直接定义为空(navigator={};);将鼠标移到SecureRandom函数上,可以发现调用了rng.js中的方法。同样,直接把整个rng.js文件剥离出来,进行本地调试。这证实了我们之前的猜想,即rsa.js确实依赖于jsbn.js和rng.js。我们注意到rng.js文件的第一行也有注释://Randomnumbergenerator-requiresaPRNGbackend,e.g.prng4.js,表示rng.js是一个随机数生成器,需要一个PRNG后端,比如prng4.js,在密码学中,PRNG的全称是pseudorandomnumbergenerator,即伪随机数生成器,指的是通过特定的算法生成一系列数字,使这一系列数字看似随机,但实际上是确定的,因此称为伪随机数。有兴趣的朋友可以深入研究一下。这里我们知道rng.js可能还依赖prng4.js,这个需要进一步调试才能清楚。rsa.js、jsbn.js和rng.js都是完整的。再次在本地调试时,会发现rng.js中的rng_psize是undefined。把鼠标放到上面,看到rng_psize是一个固定值256,也在右边的Global全局变量中。可以看到这个值为256,尝试搜索rng_psize,可以发现prng4.js中有定义varrng_psize=256;,正如评论所说,rng.js依赖于prng4.js,不过好像直接在这里定义rng_psize就可以了。定义varrng_psize=256;直接在本地代码中,再次调试。这时候会提示rng.js中缺少prng_newstate()对象。再次回到开发者工具,可以看到prng4.js中有prng_newstate(),不出所料,rng.js和prng4.js的关系并不简单。同样,我们直接把整个prng4.js文件剥离出来,进行本地调试。再次调试,运行正确,可以成功得到加密后的密码:逻辑总结加密入口可以在指数首页找到,使用了rsa.js中的三个加密函数RSAKey()、setPublic()、encrypt();rsa.js中的BigInteger()函数依赖于jsbn.js,SecureRandom()函数依赖于rng.js;rng.js中的变量rng_psize在prng4.js中定义,prng_newstate()函数也依赖于prng4.js;RSA。js、jsbn.js、rng.js、prng4.js这四个JS加密文件被完全剥离,还原了整个加密过程。完整代码GitHub关注K哥的爬虫:https://github.com/kuaidadaili,持续分享爬虫相关代码!欢迎加星!下面只演示部分关键代码,完整代码仓库地址:https://github.com/kuaidaili/...参数JS加密关键代码navigator={};//===================prng4.js开始==================//functionArcfour(){}functionARC4init(key){}functionARC4next(){}//此处省略N个函数varrng_psize=256;//====================prng4.jsend===================////==================rng.js开始===================//varrng_state;varrng_pool;varrng_pptr;functionrng_seed_int(x){}functionrng_seed_time(){}//这里省略了N个函数functionSecureRandom(){}SecureRandom.prototype.nextBytes=rng_get_bytes;//===================rng.js结束===================////===================jsbn.js开始==================//vardbits;varcanary=0xdeadbeefcafe;varj_lm=((canary&0xffffff)==0xefcafe);functionBigInteger(a,b,c){}functionnbi(){}//这里省略了N个函数//protectedBigInteger.prototype.copyTo=bnpCopyTo;BigInteger.prototype.fromInt=bnpFromInt;BigInteger.prototype.fromString=bnpFromString;BigInteger.prototype.clamp=bnpClamp;BigInteger.prototype.dlShiftTo=bnpDLShiftTo;BigInteger.prototype.drShiftTo=bnpDRShiftTo;BigInteger.prototype.lShiftTo=bnpLShiftTo;BigInteger.prototype.rShiftTo=bnpRShiftTo.;BigInteger原型.subTo=bnpSubTo;BigInteger.prototype.multiplyTo=bnpMultiplyTo;BigInteger.prototype.squareTo=bnpSquareTo;BigInteger.prototype.divRemTo=bnpDivRemTo;BigInteger.prototype.invDigit=bnpInvDigit;BigInteger.prototype.isEven=bnpBigInteven;exp=bnpExp;//publicBigInteger.prototype.toString=bnToString;BigInteger.prototype.negate=bnNegate;BigInteger.prototype.abs=bnAbs;BigInteger.prototype.compareTo=bnCompareTo;BigInteger.prototype.bitLength=bnBitLength;BigInteger.prototype.mod=bnMod;BigInteger.prototype.modPowInt=bnModPowInt;//"常量"BigInteger.ZERO=nbv(0);BigInteger.ONE=nbv(1);//==================jsbn.js结束==================////==================rsa.js开始==================//functionparseBigInt(str,r){}函数linebrk(s,n){}函数byte2Hex(b){}函数pkcs1pad2(s,n){}函数RSAKey(){}函数RSASetPublic(N,E){}函数RSADoPublic(x){}functionRSAEncrypt(text){}//protectedRSAKey.prototype.doPublic=RSADoPublic;//publicRSAKey.prototype.setPublic=RSASetPublic;RSAKey.prototype.encrypt=RSAEncrypt;//RSAKey.prototype.encrypt_b64=RSAEncryptB64;//==================rsa.js结束==================//functiongetEncryptedPassword(password){varpublic_key=“00bdf3db924714b9c4ddd144910071c282e235ac51371037cf89fa08f28b9105b6326338ed211280154c645bf81bae4184c2b52e2b02b0953e7aa8b25a8e212a0b”;varpublic_length="10001";varrsa=newRSAKey();rsa.setPublic(public_key,public_length);returnrsa.encrypt(password);}//测试样例console.log(getEncryptedPassword("123456"))Python登录关键字#!/usr/bin/envpython3#-*-coding:utf-8-*-进口电子xecjsimportrequestsfromlxmlimportetreefromPILimportImageindex_url='脱敏处理,完整代码参考GitHub:https://github.com/kuaidali/crawler/'login_url='脱敏处理,完整代码参考GitHub:https://github.com/kuaidali/crawler/'code_url='脱敏处理,完整代码参考GitHub:https://github.com/kuaidali/crawler/'headers={'Host':'脱敏处理,完整代码参考GitHub:https://github.com/kuaidali/crawler/','Referer':'脱敏处理,完整代码如下GitHub:https://github.com/kuaidali/crawler/','Origin':'脱敏处理,完整代码如下GitHub:https://github.com/kuaidaili/crawler/','User-Agent':'Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/91.0.4472.114Safari/537.36'}session=requests.session()defget_encrypted_pa??ssword(密码):withopen('encrypt.js','r',encoding='utf-8')asf:yunmall_js=f.read()encrypted_pa??ssword=execjs.compile(yunmall_js).call('getEncryptedPassword',password)返回encrypted_pa??ssworddefget_csrf_token_cookie():response=session.get(url=index_url,headers=headers)tree=etree.HTML(response.text)csrf_token=tree.xpath("//input[@name='_csrfToken']/@value")[0]cookies=response.cookies.get_dict()#print(csrf_token,cookies)返回csrf_token,cookiesdefget_very_code(cookies):response=session.get(url=code_url,cookies=cookies,headers=headers)withopen('code.png','wb')asf:f.write(response.content)image=Image.open('code.png')image.show()very_code=input('请输入验证码:')returnvery_codedeflogin(csrf_token,very_code,cookies,username,encrypted_pa??ssword):data={'u[loginType]':'name','u[phone]':username,'u[password]':encrypted_pa??ssword,'u[veryCode]':very_code,'u[token]':'','_csrfToken':csrf_token}header_info={'X-Requested-With':'XMLHttpRequest',}headers.update(header_info)response=session.post(url=login_url,data=data,cookies=饼干s,headers=headers)response.encoding='utf-8-sig'response_code=response.text#print(response_code)status_code={'31':'恭喜,登录成功','32':'登录失败。','33':'用户名或密码错误。','35':'该用户已被管理员锁定。','311':'该账号已绑定设备,请在绑定设备上登录。','20001':'验证码错误!'}try:print(status_code[response_code])exceptKeyError:print('请求超时!')defmain():username=input('请输入登录账号:')password=input('请输入登录密码:')iflen(password)>32:raiseException('请输入正确的密码!')encrypted_pa??ssword=get_encrypted_pa??ssword(password)csrf_token,cookies=get_csrf_token_cookie()very_code=get_very_code(cookies)login(csrf_token,very_code,cookies,用户名,加密密码)如果__name__=='__main__':main()
