对某登录站点的JS前端逆向思路

打印 上一主题 下一主题

主题 819|帖子 819|积分 2457

前言

js逆向一直没有相关了解,虽然目前渗透遇见的不是很多,大多数遇见的要么不加密,要么无法实现其加密流程,不过最近看到了一个较为简单的站点正好能够逆向出来,就做了简单记录。本文旨在介绍js逆向的一些基础思路,希望能对初学js前端逆向的师傅有所帮助。
JS定位

在我们寻找JS源代码时,如果直接翻看全部的js文件以来寻找自己想要的一部分,无疑是复杂繁琐的,且工作量巨大,有点类似大海捞针,因此这里我们需要借助一些巧妙的办法来快速定位某标签的js语句,具体方法如下。
元素审查定位

当我们不确定某处的js文件位置时,可以使用F12,点击元素审查,然后点击登录处,观察事件监听器
[img=720,291.20935330654]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311290018848.png[/img]
此时可以观察到login.js文件出现,接下来就可以去对应文件下继续深入。
[img=720,109.29577464788733]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311290018614.png[/img]
发现check函数,寻找check函数
[img=720,376.59107534747625]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311282348858.png[/img]
此时发现加密是secret函数,再继续跟secert函数就可以了解其整体流程。
全局搜索法

像我们常见的登录框,他们要提交的加密参数一般名为password,或者加密为Crypto加密,因此我们可以全局搜索此类关键字,进而寻找我们需要找的关键加密js语句,进而实现js逆向。
具体操作也很简单,这里简单举个例子。
首先打开F12,随便点击一个元素,而后ctrl+shift+f,接下来全局搜索关键词即可
[img=720,295.0562613430127]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311290019817.png[/img]
此时含关键词的语句映入眼帘,像一些css文件中的直接略过即可,而后即可找到真正生成密码的地方
[img=720,316.86002084056963]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311290019619.png[/img]
接下来便可以深入secret,了解加密方法。
Onclick定位

像一些登录点是存在着onclick属性的,如若该属性值是js函数,那么就极有可能是我们要寻找的js加密函数,而后进行寻找相关函数即可。
注:图参考自cony1大师傅。
以cony1大师傅的图为例进行简单讲解
[img=720,391.24315871774826]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311290019503.png[/img]
这里发现ssologin函数,接下来寻找该函数
[img=720,468.5496183206107]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311282359129.png[/img]
此时即可发现相关js语句。
【----帮助网安学习,以下所有学习资料免费领!加vx:yj009991,备注 “博客园” 获取!】
 ① 网安学习成长路径思维导图
 ② 60+网安经典常用工具包
 ③ 100+SRC漏洞分析报告
 ④ 150+网安攻防实战技术电子书
 ⑤ 最权威CISSP 认证考试指南+题库
 ⑥ 超1800页CTF实战技巧手册
 ⑦ 最新网安大厂面试题合集(含答案)
 ⑧ APP客户端安全检测指南(安卓+IOS)
实战

某登录站点js逆向

找到一个登录站点,随意输入
[img=720,376.79566003616634]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311290019339.png[/img]
发现用户名和密码均被加密,接下来ctrl+shift+f,全局搜索password字段,寻找加密点
[img=720,218.20485744456178]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311280054381.png[/img]
第一个这里明显是输入框的password,且是注释,肯定不是这里,接着寻找,后来到
[img=720,227.48887476160203]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311280056672.png[/img]
整体代码如下
  1.        function check() {
  2.            //这里将用户名,密码加密
  3.            var code = 'letu@levle';
  4.            var yname = $("#yname").val();
  5.            if (yname == '') {
  6.                alert("用户名不能为空");
  7.                return false;
  8.            } else {
  9.                var newName = secret(yname, code, false);
  10.                $("#xname").val(newName);
  11.            }
  12.            var ypassword = $("#ypassword").val();
  13.            if (ypassword == '') {
  14.                alert("密码不能为空");
  15.                return false;
  16.            } else {
  17.                var newPassword = secret(ypassword, code, false);
  18.                $("#xpassword").val(newPassword);
  19.            }
  20.        }
复制代码
可以看出js代码逻辑并不难,首先提取出ypassword标签下的内容,而后验证其是否为空,若不为空,则对其进行secret函数处理,很明显,这个secret函数就是加密函数,所以我们接下来跟进此加密函数
[img=720,182.14387803716056]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311280058423.png[/img]
这里直接给出了iv和key,所以接下来打断点调试就行了,而后打上断点
[img=720,161.5657715065999]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311280058753.png[/img]
接下来开始随便输入密码提交,而后来到调试界面
选中code.substring(16)得到keyf3991777154f4bd0
[img=720,278.8149180899268]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311280100353.png[/img]
选中code.substring(0,16)得到偏移量ace43e65106a77f6
[img=720,273.344911427579]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311280100587.png[/img]
下方也给出了Padding和mode分别是Pkcs7和CBC,所以接下来直接解密即可,在网络中我们可以看到提交后加密的账密
[img=720,259.3015873015873]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311280101557.png[/img]
拿去随便找个AES解密网站
[img=720,419.08329226219814]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311280103919.png[/img]
与所输入的进行比对
[img=720,410.78526754690756]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311280103042.png[/img]
成功得到正确结果
接下来编写脚本即可,直接将字典的内容全部进行加密,而后放入burp进行爆破
  1. import base64
  2. from Crypto.Cipher import AES
  3. from Crypto.Hash import MD5
  4. from Crypto.Util.Padding import pad
  5. #填入AES的key和iv
  6. key = 'f3991777154f4bd0'
  7. iv = 'ace43e65106a77f6'
  8. def AES_Encrypt(data):
  9.    global key
  10.    global iv
  11.    cipher = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
  12.    paddingdata = pad(data.encode('utf-8'),AES.block_size)
  13.    encrypted = cipher.encrypt(paddingdata)
  14.    #print(base64.b64encode(encrypted).decode())
  15.    return base64.b64encode(encrypted).decode()
  16. password = []
  17. with open('password.txt','r',encoding='utf-8') as f:
  18.    for i in f:
  19.        password.append(i.strip())
  20. with open('password_aes.txt','w',encoding='utf-8') as w:
  21.    for i in password:
  22.        data = AES_Encrypt(i)+'\n'
  23.        w.write(data)
复制代码
[img=720,476.0308710033076]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311281556185.png[/img]
数据长度明显与错误时不一致,不过这里也未成功进入后台,有二次验证,Google验证码无从下手,故点到为止。
某道js逆向

[img=720,266.45669291338584]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311282119150.png[/img]
接下来进行抓包
[img=720,723.7663469921534]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311282120198.png[/img]
这里我们首先注意一下每次不同点在哪,以此为入口点来进行下去,因此我们多次刷新界面抓包,同样的参数观察包的参数哪个值是不同的
[img=720,169.21658986175115]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311282132737.png[/img]
从上图可以看出sign和mysticTime是变化的,因此接下来针对这两个变量进行深入,如果我们能够控制这两个变量,那么我们就可以实现直接脚本请求得到翻译对应的语句。
所以接下来首先从sign开始,我们首先进行F12,而后输入ctrl+shift+f全局搜索关键词
[img=720,291.0418904403867]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311282134110.png[/img]
这里可以发现出现了js中含有sign关键字的,但像这个inpage.js他明显不是我们要找的js语句,因此继续往下寻找(输入sign:更容易找到对应函数)。这里我们找到如下语句
[img=720,263.841611670719]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311282137027.png[/img]
相关代码如下
  1. const u = "fanyideskweb"
  2.              , d = "webfanyi"
  3.              , m = "client,mysticTime,product"
  4.              , p = "1.0.0"
  5.              , g = "web"
  6.              , b = "fanyi.web"
  7.              , A = 1
  8.              , h = 1
  9.              , f = 1
  10.              , v = "wifi"
  11.              , O = 0;
  12.            function y(e) {
  13.                return c.a.createHash("md5").update(e).digest()
  14.            }
  15.            function j(e) {
  16.                return c.a.createHash("md5").update(e.toString()).digest("hex")
  17.            }
  18.            function k(e, t) {
  19.                return j(`client=${u}&mysticTime=${e}&product=${d}&key=${t}`)
  20.            }
  21.            function E(e, t) {
  22.                const o = (new Date).getTime();
  23.                return {
  24.                    sign: k(o, e),
  25.                    client: u,
  26.                    product: d,
  27.                    appVersion: p,
  28.                    vendor: g,
  29.                    pointParam: m,
  30.                    mysticTime: o,
  31.                    keyfrom: b,
  32.                    mid: A,
  33.                    screen: h,
  34.                    model: f,
  35.                    network: v,
  36.                    abtest: O,
  37.                    yduuid: t || "abcdefg"
  38.                }
  39.            }
复制代码
这里可以看到sign是由函数k构成的,同时注意到这里也给出了k的参数,k是由client=fanyideskweb&mysticTime=${e}&product=webfanyi&key=${t}所组成的,此时再看函数E,o是时间戳,e这里未知,这时候该怎么办呢,先看看他是不是固定值,当自己不确定在哪下断点调试时,就在附近的几个可疑点都打下断点,观察e的值即可
[img=720,122.02860858257478]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311282324568.png[/img]
经观察,这里的e值是固定的,即fsdsogkndfokasodnaso,此时k(o,e)中的参数我们都了解了,但我们注意到k函数中是有j在外包裹的,因此我们需要对j函数进行相关了解
  1. function j(e) {
  2.                return c.a.createHash("md5").update(e.toString()).digest("hex")
  3.            }
复制代码
明显的md5加密,因此到这里也就都清楚了。
当我们进行请求时,首先获取当前的时间戳,此作为参数之一,同时与client等参数值组合,进行md5加密,就组成了sign的值。对于mysticTime这个参数,我们从k函数也了解到它其实就是时间戳,因此两个变化的参数到目前就都了解其生成过程了。
接下来尝试写python脚本
  1. import hashlib
  2. import time
  3. import requests
  4. requests.packages.urllib3.disable_warnings()
  5. headers = {"Content-Length": "312",
  6. "Pragma": "no-cache",
  7. "Cache-Control": "no-cache",
  8. "Sec-Ch-Ua": ""Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"",
  9. "Accept": "application/json, text/plain, */*",
  10. "Content-Type": "application/x-www-form-urlencoded",
  11. "Sec-Ch-Ua-Mobile":"?0",
  12. "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
  13. "Sec-Ch-Ua-Platform": ""Windows"",
  14. "Origin": "https://fanyi.youdao.com",
  15. "Sec-Fetch-Site": "same-site",
  16. "Sec-Fetch-Mode": "cors",
  17. "Sec-Fetch-Dest": "empty",
  18. "Referer": "https://fanyi.youdao.com/",
  19. "Accept-Encoding": "gzip, deflate",
  20. }
  21. Cookie = {
  22. "OUTFOX_SEARCH_USER_ID":"239978291@10.130.108.41",
  23. "OUTFOX_SEARCH_USER_ID_NCOO":"520521807.43848985"
  24. }
  25. url = ""
  26. word = input("请输入翻译内容:")
  27. localtime = str(int(time.time() * 1000))
  28. canshu = "client=fanyideskweb&mysticTime={}&product=webfanyi&key=fsdsogkndfokasodnaso".format(localtime)
  29. sign = hashlib.md5(canshu.encode(encoding='utf8')).hexdigest()
  30. data = {
  31.    "i": f"{word}",
  32.    "from": "auto",
  33.    "to": "",
  34.    "dictResult": "true",
  35.    "keyid": "webfanyi",
  36.    "sign": sign,
  37.    "client": "fanyideskweb",
  38.    "product": "webfanyi",
  39.    "appVersion": "1.0.0",
  40.    "vendor": "web",
  41.    "pointParam": "client,mysticTime,product",
  42.    "mysticTime": localtime,
  43.    "keyfrom": "fanyi.web"
  44. }
  45. res = requests.post(url=url,headers=headers,cookies=Cookie,data=data,verify=False)
  46. print(res.text)
复制代码
[img=720,46.21011115095016]https://quan9i.oss-cn-beijing.aliyuncs.com/img/202311282325265.png[/img]
此时便得到了加密数据,解密同理,不再阐述。
更多网安技能的在线实操练习,请点击这里>>
  

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

梦见你的名字

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表