逆向万例| No.00001【滑块篇】喜某拉某web端登录滑块逆

2023-03-04  本文已影响0人  逆向扬

声明:本文仅供学习交流用途,切勿用于非法行为,否则由此产生的一切后果均与作者本人无关。未经授权禁止转载本文。如有侵权,请及时通过本人公众号「逆向扬」联系删除。

0x1 开始之前

网站地址:YUhSMGNITTZMeTkzZDNjdWVHbHRZV3hoZVdFdVkyOXRMdz09(提示:如果解密不成功,可以试着多考虑一步)

本文目标:逆向该网站登录滑块验证

进入网站后,选择密码登录,在输入账号(手机号或邮箱)和密码后,会弹出一个滑块验证:

这个网站的滑块难度属于入门级别,因此很适合逆向新手将这个作为滑块逆向的入门例子。

下面我们来逆向这个滑块。

0x2 抓包分析

2.1 整体流程

首先我们对网站的整个登录请求过程进行分析。打开 chrome 的开发者工具,分析一下网络包。

在点击登录按钮后,会发送请求,用于获取滑块的底图和缺口图片:

滑块后,会发送一个 slider 请求。如果没滑到正确位置,会返回验证失败的响应信息:

若滑到了正确位置,则会返回验证成功的信息和一个 token 值:

这个 token 会被放到 cookie 的 fds_otp 中,并发送一个请求,获取之后请求登录接口所需要用到的 nonce 参数值:

最后,会发起对登录接口的请求,不过在本文中不讲解这一步。关于如何逆向该网站登录接口的参数,将在之后的文章中讲到:

2.2 关键包分析

这里最关键的是滑块验证请求 slider 。

这个包的请求参数分析:

因此,在这里,我们需要弄明白的是captchaText这个参数是如何生成的,只要能逆向这个参数,就能拿下这个网站的滑块。下面我们开始分析。

0x3 验证码底图获取

通过 get 这个请求可以获取到验证码的底图,获取到底图后,需要注意网站会以 0.8 的比例显示滑块验证码图片:

获取底图的代码:

payload = {
    "bpId": "139",
    "sessionId": "xm_leqnng8w237jib"
}

r = requests.get("https://mobile.ximalaya.com/captcha-web/check/slide/get",
                 headers=headers,
                 params=payload,
                 cookies=cookie)

print(r.json())
data = r.json()["data"]

image_url_list = {"fg": data["fgUrl"], "bg": data["bgUrl"]}
for k, v in image_url_list.items():
    rr = requests.get(v, headers=headers)
    with open(f"{k}.png", "wb") as f:
        f.write(rr.content)

拿到底图后,我们就可以用验证码识别库,比如 ddddocr 。可以直接拿着原图识别,而不需要事先将滑块图片和底图缩小为原来的 0.8,然后将通过原图识别出来的距离缩小为原来的 0.8 倍即可。

要注意这里有个小坑,captchaText 的 x 值时,你直接写这个识别出来的距离再乘上 0.8 是不行的,得加上一个偏移量,在 10 像素左右都行,至于偏移量的来源,我目前还没不知道。如果有知道的大佬,欢迎在评论区留言。

0x4 captchaText 参数分析

废话不多说,直接开始调试分析。我们需要定位到这个参数是如何生成的。我个人目前比较习惯直接通过请求的调用栈来做定位。点击 slider 请求,可以找到下图的方法中出现了我们想要分析的参数:

我们可以看到这里的实参 o 是从外部传到方法中的,因此继续往上跟栈,一步步跟,最终可以找到 captchaText 参数的生成位置:

captchaText 的生成规则如下:

其中,c 值就是滑动滑块时鼠标在 y 方向的滑动距离,a 值则是滑动滑块时鼠标在 x 方向的滑动距离。d.ZOOM 则是图像的缩小比例。

按照常规来说,直接传递 a 值和 c 值给网站后台即可通过滑块验证,但是网站前端在 getSliderLeft 方法中还对 a 值进行了一些额外的计算处理。

getSliderLeft 方法如下,其中的计算逻辑复现很简单,因此就不细讲了:

用 python 复现一下 getSliderLeft 方法,供大家参考:

def get_img_left(t):
    return -12 * 0.8 + (t + 10) * (380 - 84.8 + 24 * 0.8) / (380 - 40)

def get_slider_left(t):
    return int(get_img_left(t) / 0.8 + 44)

最后贴上滑块验证的代码:

def verify_slide():
    payload = {
        "bpId": "139",
        "sessionId": "xm_leqnng8w237jib"
    }

    r = requests.get("https://mobile.ximalaya.com/captcha-web/check/slide/get",
                     headers=headers,
                     params=payload,
                     cookies=cookie)

    print(r.json())
    data = r.json()["data"]

    image_url_list = {"fg": data["fgUrl"], "bg": data["bgUrl"]}
    for k, v in image_url_list.items():
        rr = requests.get(v, headers=headers)
        with open(f"{k}.png", "wb") as f:
            f.write(rr.content)

    det = ddddocr.DdddOcr(det=False, ocr=False, show_ad=False)
    with open('fg.png', 'rb') as f:
        fg_bytes = f.read()
    with open('bg.png', 'rb') as f:
        bg_bytes = f.read()
    res = det.slide_match(fg_bytes, bg_bytes, simple_target=True)
    print(res)

    def get_img_left(t):
        return -12 * 0.8 + (t + 10) * (380 - 84.8 + 24 * 0.8) / (380 - 40)

    def get_slider_left(t):
        return int(get_img_left(t) / 0.8 + 44)

    x = int((res["target"][0] + 25) * 0.8) 
    distance = int(get_slider_left(x))
    slide_payload = {
        "bpId": 139,
        "sessionId": "xm_leqnng8w237jib",
        "type": "slider",
        "captchaText": f'{distance},0',
        "startX": 563,
        "startY": 357,
        "startTime": int((time.time() - 2) * 1000)
    }

    print(slide_payload)
    slide_r = requests.post("https://mobile.ximalaya.com/captcha-web/valid/slider",
                            headers=headers,
                            cookies=cookie,
                            json=slide_payload)

    print(slide_r.text)
    print(slide_r.json()["token"])

验证

可以看到滑块验证通过,并且拿到了 token 值:

上一篇下一篇

猜你喜欢

热点阅读