某花顺登录滑块逆向

查看 36|回复 5
作者:zzyzy   
本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!
目标:实现账号登录,滑块验证,python纯算。
网站:aHR0cHM6Ly91cGFzcy4xMGpxa2EuY29tLmNuL2xvZ2luP3JlZGlyPUhUVFBfUkVGRVJFUg==
1.老样子先分析登录过程中需要的所有请求,账号密码登录,触发滑块,先是寻找获得图片的接口,分上下两部分分析整个过程,该网站会禁用f12,所以在请求之前就先打开控制台。
[color=]我们根据验证码图片的url可以找到在getprehandle请求中有我们想要的参数,后面在分析。


image.png (119.98 KB, 下载次数: 0)
下载附件
2025-5-31 12:36 上传

[color=]
2.验证码触发前,主要有两次请求,getGS和dologinreturnjson2,在getGS的请求参数中可以看到是验证账号,得到dsk dsv ssv ,这些后面都会用到。


image.png (36.57 KB, 下载次数: 0)
下载附件
2025-5-31 12:42 上传



image.png (46.05 KB, 下载次数: 0)
下载附件
2025-5-31 12:43 上传

2.2在dologinreturnjson2请求中可以看到参数有点多,结果触发验证码。需要分析的参数就是uname passwd passwdsalt dsk crnd。


image.png (104.52 KB, 下载次数: 0)
下载附件
2025-5-31 12:45 上传



image.png (30.84 KB, 下载次数: 0)
下载附件
2025-5-31 12:46 上传

3.先是定位到参数生成的地方,那我直接根据参数名直接搜索,passwdsalt,这个结果会少很多,可以快速定位。跳转过来之后,在其之上就是所有参数的生成啦,太好了,源码中还有注释,直接都打上断点逐步分析、


image.png (149.67 KB, 下载次数: 0)
下载附件
2025-5-31 12:49 上传

4.登录账号先定到uname,先看uname和passwd这两个参数,加密方式还备注上了,真好,可以看到 ,传入账号-密码,经过thsencrypt中encode方法加密,密码的参数多做了一步处理,经过hex_md5,看名字应该是md5编码,在控制台打印测试一下,找个网站测试一下是标准的md5,这就可以不用分析js源码了,主要进thsencrypt的encode方法里面看看。单步跳进去


image.png (55.11 KB, 下载次数: 0)
下载附件
2025-5-31 12:55 上传



image.png (13.57 KB, 下载次数: 0)
下载附件
2025-5-31 13:00 上传

5.在encode中是传入三个参数直接返回函数encryptencode的结果,其中b是账号,a是密钥,c是公钥指数,返回base64格式字符串。转换成python代码。


image.png (43.96 KB, 下载次数: 0)
下载附件
2025-5-31 13:05 上传

[Python] 纯文本查看 复制代码def encrypt_encode(plaintext: str) -> str:
    modulus_hex = ""  # 这里填入十六进制模数字符串
    exponent_hex = "10001"  # 一般是 65537 的十六进制表示
    if not modulus_hex or not exponent_hex:
        raise ValueError("modulus and publicExponent could not be null")
    modulus = int(modulus_hex, 16)
    exponent = int(exponent_hex, 16)
    key = RSA.construct((modulus, exponent))
    cipher = PKCS1_v1_5.new(key)
    plaintext_bytes = plaintext.encode('utf-8')
    encrypted_bytes = cipher.encrypt(plaintext_bytes)
    if not encrypted_bytes:
        raise ValueError("encrypt failed")
    return b64encode(encrypted_bytes).decode('utf-8')
6.先验证代码是否能用,测试是不是标准rsa,因为加密结果每次都不一样,直接测试请求,在getGS中请求参数是uname rsa_version 和crnd ,现在看一下crnd怎么生成,继续往下走,进入getSaltGs中。


image.png (27.16 KB, 下载次数: 0)
下载附件
2025-5-31 13:19 上传



image.png (61.21 KB, 下载次数: 0)
下载附件
2025-5-31 13:21 上传

7.可以看到随机数转36进制取后八位,重复两边,生成的16位只包含数字和字母的字符串,那我直接从0到9和小写字母中随机取十六位,一样的效果。


image.png (20.47 KB, 下载次数: 0)
下载附件
2025-5-31 13:27 上传

8。用生成的uname和crnd测试getGS,若是uname参数为空,返回参数错误,若加密不对,返回的dsk ssv 等都是空。
测试完接着往下分析,相对dologinreturnjson2里面还有passwdsalt 和 dsk这两个参数没有分析,dsk是getGS中里面返回。
继续往下走, postData.passwdSalt = encodeDataSaltOnce(passwdVal,unameVal);,进入encodeDataSaltOnce中,分析生成过程。


image.png (56.2 KB, 下载次数: 0)
下载附件
2025-5-31 13:46 上传



image.png (43.96 KB, 下载次数: 0)
下载附件
2025-5-31 14:12 上传

9.先到第一生成n的地方,可以看到是拿crnd + dsk,传给r.hex,r在上面定义的有,可以看到是hash 256,往下走是先把ssv进行base64解码,在传入hash后的n,函数getStrXOR中转换。
可以看到是实现两个字符串的字符逐位异或操作(XOR 操作)。转化成python代码。


image.png (15.99 KB, 下载次数: 0)
下载附件
2025-5-31 14:16 上传

[Python] 纯文本查看 复制代码def get_str_xor(e: str, t: str) -> str:
    s = len(e)
    r = len(t)
    o = []
    for d in range(s):
        n = d % r
        xor_char = chr(ord(e[d]) ^ ord(t[n]))
        o.append(xor_char)
    return ''.join(o)
10.继续往下走,转换后的结果取等号后面作为n,作为HmacSHA256的key,r.hex_hmac是HmacSHA256,e是密码。


image.png (65.39 KB, 下载次数: 0)
下载附件
2025-5-31 14:20 上传



image.png (34.96 KB, 下载次数: 0)
下载附件
2025-5-31 14:53 上传

11.测试了一下r.hex_hmac,e先md5后在HmacSHA256,结果作为getStrXOR第一个参数,对dsv进行sha256作为第二个参数。经过getStrXOR后n的值在base64编码一下,就到了rsa加密的最终n了,函数encodeDataSaltOnce返回rsa加密的n,python慢慢一步步的还原,这样就的到了passwdSalt。


image.png (19.1 KB, 下载次数: 0)
下载附件
2025-5-31 14:52 上传



image.png (30.06 KB, 下载次数: 0)
下载附件
2025-5-31 15:05 上传



image.png (43.43 KB, 下载次数: 0)
下载附件
2025-5-31 15:06 上传

12.到现在参数都分析完啦,可以测试了,验证一下,接下来开始分析滑块的验证。


image.png (39.47 KB, 下载次数: 0)
下载附件
2025-5-31 15:49 上传

13.滑块验证的请求参数主要查看一下两个,signature是请求图片是返回的sign,可以发现,那phrase这个参数就是主要检验的了,直接搜索。


image.png (64.42 KB, 下载次数: 0)
下载附件
2025-5-31 15:52 上传

14.跳转进去可以看到url的生成规则   后半部分是  (x) + ";" + inity + ";" + opt.width + ";" + opt.height;,其中opt的宽高都是定值,x是动的距离,需要看一下inity的生成,在当前js文件中搜索inity,不多很好定位。


image.png (40.02 KB, 下载次数: 0)
下载附件
2025-5-31 16:06 上传



image.png (30.38 KB, 下载次数: 0)
下载附件
2025-5-31 16:06 上传

15.可以看到inity的赋值   data.data.inity / 195 * opt.height的结果,data是getPreHandle的相应结果,opt.height写死。


image.png (37.75 KB, 下载次数: 0)
下载附件
2025-5-31 16:10 上传



image.png (30.32 KB, 下载次数: 0)
下载附件
2025-5-31 16:14 上传

16.图片的url在getPreHandle请求结果,其中请求参数都可以写死,来获得验证的图片和滑块,滑动距离的识别使用的是ddddocr,以下是python代码。
[Python] 纯文本查看 复制代码def get_distance(bg, tp, save_path=None):
    det = DdddOcr(det=False, ocr=False, show_ad=False)
    res = det.slide_match(tp, bg, simple_target=True)
    if save_path is not None:
        # 将背景图片的二进制数据加载为Pillow Image对象
        left, top, right, bottom = res['target'][0], res['target'][1], res['target'][2], res['target'][3]
        bg_image = Image.open(io.BytesIO(bg))
        draw = ImageDraw.Draw(bg_image)
        draw.rectangle([left, top, right, bottom], outline="red", width=2)
        bg_image.save(save_path)
        logger.info(f"已保存标注后的图片到: {save_path}")
        return res
    return res
[color=]
17.测试滑块验证结果,识别坐标标注的左上角和右下角,当取滑动距离时和浏览器需要的距离有一点偏差,测试一下减去个固定值就行,验证成功就可以拿到ticket了。


image.png (84.6 KB, 下载次数: 0)
下载附件
2025-5-31 16:41 上传



image.png (38.03 KB, 下载次数: 0)
下载附件
2025-5-31 16:53 上传

18.接下来就是最后一步了,来看下半部分,在验证的时候多了一些滑块验证成功后的一些参数,带上这些参数,再去验证登录,就可以啦。


image.png (133.29 KB, 下载次数: 0)
下载附件
2025-5-31 16:48 上传



image.png (44.04 KB, 下载次数: 0)
下载附件
2025-5-31 16:57 上传

验证了以下,至此结束啦,感谢观看哦,祝大家端午节快乐!!(选择甜粽子还是肉粽子呢,犒劳自己)

下载次数, 下载附件

天空宫阙   

暂不支持手机号密码登录[狗头]
zzyzy
OP
  


天空宫阙 发表于 2025-5-31 18:36
暂不支持手机号密码登录[狗头]

啊哈,这我倒是没测试
qqycra   

感谢分享。十几年前开户,那时候要是买茅台我就发了,可惜啊
superzg   

学习了。但没学明白。
massagebox   

学习啦, 最近在学这玩意
您需要登录后才可以回帖 登录 | 立即注册

返回顶部