吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3870|回复: 16
收起左侧

[Web逆向] 【js逆向】某习通座位预约加密分析(新手向)

[复制链接]
Schwarz 发表于 2023-6-3 22:28
本帖最后由 Schwarz 于 2023-10-20 00:16 编辑

应要求更新完整代码,有些地方需要更改

import requests
import requests.utils
from lxml import etree
import re
from Crypto.Cipher import AES
from Crypto.Hash import MD5
import base64
from datetime import datetime
from fake_useragent import UserAgent
import time

# 登录的加密函数
def encrpytByAES(message, key):
    key = "u2oh6Vu^HWe4_AES"
    iv = key.encode("utf-8")
    message = message.encode("utf-8")

    # 使用PKCS7Padding填充
    BS = AES.block_size
    padding = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS).encode()
    cipher = AES.new(iv, AES.MODE_CBC, iv)
    ciphertext = cipher.encrypt(padding(message))
    return base64.b64encode(ciphertext).decode('utf-8')

# 使用session保存cookies
def getCookies(data, headers):
    url = "https://passport2.chaoxing.com/fanyalogin"
    # proxy = {"http": "http://127.0.0.1:8080"}
    resp = requests.session()
    resp.headers = headers
    resp.post(url, data=data)
    url1 = "https://office.chaoxing.com/front/apps/seatengine/index?seatId=xxx" # 自己的seatId
    resp.get(url=url1)
    return resp

def getToken(session, today):
    # proxy = {"http": "http://127.0.0.1:8080"}
    url = f"http://office.chaoxing.com/front/third/apps/seatengine/select?id=1901&day={today}&backLevel=2&seatId=796"
    resp = session.get(url)
    res = etree.HTML(resp.text)
    script = res.xpath('/html/body/script[3]/text()')[0]
    pattern = re.compile("token = '(?P<token>.*?)'")
    token = pattern.search(script)
    if token:
        token = token.group('token')
        return token
    else:
        return None

def getSeat(sess, roomId, startTime, endTime, day, seatNum, token, enc):
    # proxy = {"http": "http://127.0.0.1:8080"}
    seatNum1 = str(seatNum).rjust(3, '0')
    url = f'http://office.chaoxing.com/data/apps/seatengine/submit?roomId={roomId}&startTime={startTime}&endTime={endTime}&day={day}&captcha=&seatNum={seatNum1}&token={token}&enc={enc}'
    resp = sess.get(url)
    print(resp.text)

def getData(info):
    data = {
        'fid': '-1',
        'uname': encrpytByAES(info[1], 0),
        'password': encrpytByAES(info[2], 0),
        'refer': 'https://office.chaoxing.com/front/apps/seatengine/index?seatId=xxx', # 填写自己的
        't': 'true',
        'forbidotherlogin': '0',
        'validate': '',
        'doubleFactorLogin': '0',
        'independentId': '0'
    }
    return data

def getEnc(today, endTime, seatNum, startTime, token, roomId):
    content = "[captcha=][day={}][endTime={}][roomId={}][seatNum={}][startTime={}][token={}][%sd`~7^/>N4!Q#){kuohao}'']".format(
        today, endTime, roomId, seatNum, startTime, token, kuohao="{")
    result = MD5.new()
    result.update(content.encode('utf-8'))
    return result.hexdigest()

def main():
    ua = UserAgent()
    ua = ua.random
    headers = {
        'user-agent': ua
    }

    info = [['姓名(可写可不写)', '手机号', '密码']] # 登录信息

    # 获取data
    mdata = getData(info[0])

    # 获取session
    msession = getCookies(mdata, headers)

    today = datetime.now().strftime('%Y-%m-%d')

    # 获取必要的token
    mtoken = getToken(msession, today)

    # enc获取
    roomId = "1901"

    ct = [[msession, 14, "08:30", "21:30", mtoken, roomId]]# session,座位号,开始时间,结束时间,token,roomId

    # 添加enc
    for item in ct:
        seatNum = str(item[1]).rjust(3, '0')  # 传入的座位号为0xx
        startTime = item[2]
        endTime = item[3]
        token = item[4]
        roomId = item[5]
        item.append(getEnc(today, endTime, seatNum, startTime, token, roomId))

    while True:
        t = datetime.now().strftime("%H:%M:%S")
        if t:
            print(datetime.now())
            for session, seatNum, startTime, endTime, token, roomId, enc in ct:
                getSeat(session, roomId, startTime, endTime, today, seatNum, token, enc)
            print(datetime.now())
            break
        else:
            time.sleep(0.2)

if __name__ == '__main__':
    try:
        main()
    except Exception as e:
        print(e)
# 44 7 * * * /home/ubuntu/chaoxing.py >> /home/ubuntu/script.log

前言

之前写过图书馆预约抢座,那个时候虽然有加密参数,但是没有校验加密,就放在服务器上自动运行,但是突然有一天开始校验,导致有一天差点没地方学习

作为一个懒货和考研党,怎么可能忍?为了我宿舍里的儿子们不用早起蹲点抢位置,于是乎开始下面的逆向旅途

本人是个新手,虽然以前是web渗透的,但是对js逆向并不熟悉,如果有什么说的不对的地方请各位斧正

目标

学某通图书馆座位预约系统
每个学校不同可能参数也不同,下面是个样例

选座界面
https://office.xxxx.com/front/third/apps/seatengine/select?id=xxxx&day=2023-06-03&backLevel=2&seatId=xxx

过程

打开选座界面,刚F12打开调试界面就发现有反调试,直接两个一律不在此处暂停

Pasted image 20230603184141.png

首先提交一次预约请求,很明显,以下请求就是这次逆向的主体
Pasted image 20230603183623.png

https://office.xxxx.com/data/apps/seatengine/submit?roomId=1901&startTime=18%3A30&endTime=19%3A00&day=2023-06-03&captcha=&seatNum=022&token=818a0f43a1a64bc98acb3f572fb64336&enc=4e66e0f4a1f3db313ad08288b9c379da

经过小小的测试,token在进入页面就自带,直接爬取网页源代码就可以获得,所以主要的目标是enc
首先通过xhr提取断点
Pasted image 20230603183950.png

当我们断上点了,准备在调用栈一层一层往前找参数来源
Pasted image 20230603185010.png

看到传递的参数,但还要往前找到来源
Pasted image 20230603223631.png

很明显这是混淆的一个函数,后面传的参数是所有其他参数字段,大概率enc就是来源于这里
Pasted image 20230603192628.png

找一下这个函数的来源,点击直接跳转

Pasted image 20230603193622.png

Pasted image 20230603193749.png
好家伙,往上一看,专门加密过了,还有个网址,作为一个小白,还真不知道这个加密,去网上仔细搜索了一波,发现还是挺流行的一个免费加密,看了几个解密的文章,看的头昏脑胀,作为一个懒货,自然是不可能直接开始从头解密的
Pasted image 20230603193825.png

接下来,就请出调试断点大法,当然猜也是必不可少的
由上面就知道_0x6d646b应该就是主要的加密函数,毕竟调用的就是这个函数,又从网上的解密文章得知,该版本加密特征分几段,最下面一段就是被加密的源代码,那么这里的代码从define开始就是被加密的源代码了
Pasted image 20230603195255.png

本人出身是物联网,后来自学web渗透,对js并不是很熟悉,还好最近AI崛起,我直接询问chatgpt,发现define(...这一句是下面需要引用库,控制台已查询,是md5库,不出意外是MD5
Pasted image 20230603200030.png

为了节省时间,我尝试能不能直接一站到底,我在_0x6d646b函数中尝试寻找关键点,如果找不到,就需要一步一步调试了,幸运的是,发现调用md5的地方,果断断了点,重新提交
Pasted image 20230603200843.png

看着这行字符串,很明显是前面所有url中的参数添加进来进行重新排列拼接,感觉这不就来了

"[captcha=][day=2023-06-03][endTime=19:00][roomId=1901][seatNum=022][startTime=18:30][token=xxx][%sd`~7^/>N4!Q#){'']"

Pasted image 20230603201331.png
直接往前追溯_0x4aaee5_中的函数,发现就是个废话函数,直接就是md5加密就行,不过是为了混淆添加了几步
为了确保这里排列的顺序不变,又多试了几次,发现顺序是一样的,那么接下来就毫无悬念了,毕竟虽然混淆十分令人害怕,好几百行代码,但是最后就是个最简单的md5加密,直接进行Python复现

from Crypto.Hash import MD5

def getEnc(today, endTime, seatNum, startTime, token):  
content = "[captcha=][day={}][endTime={}][roomId=1901][seatNum={}][startTime={}][token={}][%sd`~7^/>N4!Q#){'']".format(  
today, endTime, seatNum, startTime, token)  
result = MD5.new()  
result.update(content.encode('utf-8'))  
return result.hexdigest()

传参进去发现,确实和enc一样

这样某通图书馆预约座位系统被我们扒光了,又可以愉快的抢座预约了,考研党永不为奴

免费评分

参与人数 7吾爱币 +11 热心值 +6 收起 理由
na86cjcc46y + 1 我很赞同!大佬可以给源码吗,我抢不到第二天座位
bobocs + 1 + 1 谢谢@Thanks!
passzzh + 1 谢谢@Thanks!
笙若 + 1 + 1 谢谢@Thanks!
catoo1 + 1 谢谢@Thanks!
涛之雨 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
fan37257978 + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

zhongshisan 发表于 2023-8-11 12:12
我学校图书馆预约完,需要到图书馆扫码签到,或者刷脸签到。扫码用的二维码是在网页刷新的,只有图书馆局域网才能打开刷新,所以一直没找到什么方法破解。
libw 发表于 2023-6-5 18:35
jsjiamiv5和v6好像都可以被直接还原了:https://github.com/NXY666/Jsjiemi
minibeetuaman 发表于 2023-6-5 22:02
这种程度的混淆可以用AST还原,目前的攻坚都在jsvm上了
xixicoco 发表于 2023-6-6 00:49
还是不错哈,学以致用
loveu1316 发表于 2023-6-6 07:57
不错,学习学习哈
fan37257978 发表于 2023-6-6 08:24
自己也是前端爱好者,感谢楼主,学习很多
wzyl 发表于 2023-6-6 22:00
感谢楼主分享精神 向楼主学习
bandishui 发表于 2023-6-7 09:32
学习一下, 看的还很晕乎
无言Y 发表于 2023-6-7 11:28
感谢分享
catoo1 发表于 2023-6-7 21:16
感谢分享 学习一下
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 10:39

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表