非HTTP验证码别乱捅!一不小心就反爬了

一、前言介绍

大家有没有想过,每次在网上注册账号或者登录时,那些不使用滑块验证码,也不依赖HTTP协议的验证码是如何识别我们是人而不是机器的呢?这些验证码可能只需要你简单地进行识别操作,例如输入一些文字或数字。但你可曾想过,这些看似简单的验证背后,蕴含着怎样的科技奥秘?在本文中,我们将揭开非HTTP验证码的神秘面纱,一起探索它的工作原理,了解它是如何巧妙地识别真人身份的。在这个有趣的旅程中,我们将一窥技术背后的精妙,带你进入一个充满挑战和创新的数字世界。快来和我一起探索吧!


二、网站分析

1、从某APP中抓包分析用户登录接口,发现登录接口为webview,将登录接口url使用浏览器打开分析,截图如下:

图片

2、打开浏览器开发者工具,然后输入手机号后,点击发送验证码,请求截图如下所示:

图片

3、浏览器Network中查看请求包,我们并没有发现http请求接口的验证码,只发现了疑似验证码的请求体和响应体,截图如下:

图片

图片

总结:此处我们发现response的返回内容进行了加密,加密参数为encrypt_body。我们再分析下request请求体,结果发现加密参数也是encrypt_body。这里我们初步可以确定,请求入参和response出参使用的是一套加密算法,接下来我们进入逆向分析环节吧。


三、逆向分析

1、通过Initiator进行调试分析,过滤无限debugger模式,进行断点分析截图如下所示:

图片

2、这里我们定位到了请求体加密前参数,先暂时忽略。我们紧接着往下继续分析,截图如下:

图片

3、此处我们查看返回参数s,可以确定是请求体加密后的参数,截图如下:

图片

总结:虽然前面简单分析过,请求体和响应体的encrypt_body使用的是一套加密算法。那么我们先还原请求体加密,再拿请求体加密的对称加密算法进行解密,就可以判断我们前面的猜测是否正确。通过断点分析我们发现请求体加密使用了aes-ecb模式,AES是一种对称加密算法,这意味着加密和解密使用相同的密钥。接下来我们进入算法还原环节,来验证下我们的猜测吧。


四、算法还原

1、使用Python还原JS加密算法,还原后的完整加密算法如下:

# -*- coding: utf-8 -*-
# -------------------------------
# @author : TheWeiJUn
# @time   : 2024.08.04 20:58:33
# -------------------------------

from Crypto.Cipher import AES
import json
import base64

from Crypto.Util.Padding import pad


def encrypt(e, n):
    if e and n:
        if not isinstance(e, str):
            e = json.dumps(e, separators=(",", ":"))

        r = 'utf-8'

        key = n.encode(r)  # Assuming n is a string that needs to be encoded to bytes
        data = e.encode(r)

        cipher = AES.new(key, AES.MODE_ECB)
        padded_data = pad(data, AES.block_size)  # Pad the data to be a multiple of block size
        cipher_text = cipher.encrypt(padded_data)  # Encrypt the padded data

        s = base64.b64encode(cipher_text).decode('utf-8')
        return s


if __name__ == '__main__':
    # Example usage:
    e = {"phone": "xxxx", "countryCode": "CN", "type": "login"}
    n = "1234567890123456"  # Example key (must be 16 bytes for AES-128)
    result = encrypt(e, n)
    print(result)

2、输出Python加密后的参数s同浏览器中生成的加密参数s进行比对,截图如下:

图片

图片

总结:经过对比我们发现,两个参数字符串完全一致。接下来我们使用前面分析的方法对response加密体参数encrypt_body试着进行对称解密还原。截图如下所示:

图片

3、解密还原失败,此处我怀疑response加密参数encrypt_body应该是做了特殊处理,经过断点分析后,果真如我所言,编辑修改后的decrypt解密代码如下:​​​​​​​

# -*- coding: utf-8 -*-
# -------------------------------
# @author : TheWeiJUn
# @time   : 2024.08.04 20:58:33
# -------------------------------

from Crypto.Cipher import AES
import json
import base64

from Crypto.Util.Padding import pad, unpad


def encrypt(e, n):
    if e and n:
        if not isinstance(e, str):
            e = json.dumps(e, separators=(",", ":"))

        r = 'utf-8'

        key = n.encode(r)  # Assuming n is a string that needs to be encoded to bytes
        data = e.encode(r)

        cipher = AES.new(key, AES.MODE_ECB)
        padded_data = pad(data, AES.block_size)  # Pad the data to be a multiple of block size
        cipher_text = cipher.encrypt(padded_data)  # Encrypt the padded data

        s = base64.b64encode(cipher_text).decode('utf-8')
        return s


def decode_base64(t):
    # Add padding to make the length a multiple of 4
    t = t + '=' * (4 - len(t) % 4)

    # Replace URL-safe characters with standard Base64 characters
    t = t.replace('-', '+').replace('_', '/')

    # Decode the Base64 string
    return base64.b64decode(t)


def decrypt(e, n):
    if e and n:
        # Decode the Base64 encoded input
        cipher_text_bytes = decode_base64(e)
        # Define the encoding and decoding formats
        a = 'utf-8'
        key = n.encode(a)  # Convert key to bytes

        # Create the cipher object for decryption
        cipher = AES.new(key, AES.MODE_ECB)
        padded_data = cipher.decrypt(cipher_text_bytes)  # Decrypt the data
        # Remove padding
        data = unpad(padded_data, AES.block_size)
        # Parse the JSON data
        return json.loads(data.decode(a))


if __name__ == '__main__':
    n = "1234567890123456"  # Example key (must be 16 bytes for AES-128)
    e = "encrypt_body"
    result = decrypt(e, n)
    print(result)

4、对加密参数进行padding填充及对特殊符号进行替换处理后,即可进行对称解密操作,解码后的截图如下所示:

图片

5、对还原后的响应体graph参数进行特殊处理后,进行base64decode,相关代码和解码后保存的字节流如下:

图片

图片

6、到这里基本就结束了,接下来进行验证码识别还原,这个相对来说比较简单,我们这里使用ddddocr,编辑代码后还原验证码如下所示:

图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值