应要求更新完整代码,有些地方需要更改
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打开调试界面就发现有反调试,直接两个一律不在此处暂停
首先提交一次预约请求,很明显,以下请求就是这次逆向的主体
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提取断点
当我们断上点了,准备在调用栈一层一层往前找参数来源
看到传递的参数,但还要往前找到来源
很明显这是混淆的一个函数,后面传的参数是所有其他参数字段,大概率enc就是来源于这里
找一下这个函数的来源,点击直接跳转
好家伙,往上一看,专门加密过了,还有个网址,作为一个小白,还真不知道这个加密,去网上仔细搜索了一波,发现还是挺流行的一个免费加密,看了几个解密的文章,看的头昏脑胀,作为一个懒货,自然是不可能直接开始从头解密的
接下来,就请出调试断点大法,当然猜也是必不可少的
由上面就知道_0x6d646b
应该就是主要的加密函数,毕竟调用的就是这个函数,又从网上的解密文章得知,该版本加密特征分几段,最下面一段就是被加密的源代码,那么这里的代码从define
开始就是被加密的源代码了
本人出身是物联网,后来自学web渗透,对js并不是很熟悉,还好最近AI崛起,我直接询问chatgpt,发现define(...
这一句是下面需要引用库,控制台已查询,是md5库,不出意外是MD5
为了节省时间,我尝试能不能直接一站到底,我在_0x6d646b
函数中尝试寻找关键点,如果找不到,就需要一步一步调试了,幸运的是,发现调用md5的地方,果断断了点,重新提交
看着这行字符串,很明显是前面所有url中的参数添加进来进行重新排列拼接,感觉这不就来了
"[captcha=][day=2023-06-03][endTime=19:00][roomId=1901][seatNum=022][startTime=18:30][token=xxx][%sd`~7^/>N4!Q#){'']"
直接往前追溯_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一样
这样某通图书馆预约座位系统被我们扒光了,又可以愉快的抢座预约了,考研党永不为奴