某招标投标平台滑块逆向
某通信工程建设项目招标投标管理信息平台滑块逆向
地址链接:aHR0cHM6Ly90eHpicXkubWlpdC5nb3YuY24vIy9nYXRld2F5L2xpc3Q=
目前为最简单的逆向滑块,适合初级入门这上手
- 触发条件:如图所示点击下一页或者点击页数触发滑块
- 请求200参数:滑块通过请求列表页参数如图所示
- 如上图所看到的一样,
code
参数是滑块成功通过所返回的值,而token
值是请求滑块图片的接口https://txzbqy.miit.gov.cn/zbtb/captcha/slideCaptcha
所返回的nonceStr
值,而且所返回的值中滑块的缺口图片的值是加密过的,需要逆向解密,如图所示
逆向步骤
- 全局搜索
code
并没有确定出具体的位置,所以code
为动态参数,需要跟栈确定位置,还有技巧方法通过解密关键字搜索AES.encrypt
确定位置,如图我们看到并无没魔改,没混淆AES的JS算法,我们直接断点看传参,如图所示
- 再通过
canvasSrc
关键字看图片的js解密过程,如图所示
整个过程就是:
- 1、首先请求了滑块图片的url接口返回了数据(滑块图片背景图 blockSrc、滑块图片加密值 canvasSrc、nonceStr的值)
- 2、使用AES解密算
u(i.canvasSrc, i.nonceStr)
得到滑块图片 - 3、使用`ocr获取滑块缺口的距离 distance
- 4、再使AES用加密算法
d(distance, nonceStr)
得到code
的值
代码实现
#!/usr/bin/env python
# coding=utf-8
from Crypto.Cipher import AES
import base64
from Crypto.Util.Padding import unpad, pad
import ddddocr
import requests
import json
class TxzbqyMiitSlider:
def __init__(self):
self.det = ddddocr.DdddOcr(det=False, ocr=False, show_ad=False)
self.session = requests.session()
self.headers = {
"Accept": "application/json, text/plain, */*",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "keep-alive",
"Content-Type": "application/json;charset=UTF-8",
"Origin": "https://txzbqy.miit.gov.cn",
"Referer": "https://txzbqy.miit.gov.cn/",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
"sec-ch-ua": "\"Chromium\";v=\"110\", \"Not A(Brand\";v=\"24\", \"Google Chrome\";v=\"110\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\""
}
self.cookies = {
"jsessionid": "rBQxShroZP7e6hCSvAaYpEgHr4JRnH6gNcUA",
"wzws_sessionid": "gjFiM2ZlM4AxMTcuNjEuMjEuMjEwgTJjZTFmZKBk/t7g"
}
@staticmethod
def decrypt_aes(ciphertext, key):
ciphertext = base64.b64decode(ciphertext) # 使用base64解码密文
cipher = AES.new(key.encode(), AES.MODE_ECB) # 创建AES对象并指定使用ECB模式和PKCS7填充
plaintext = cipher.decrypt(ciphertext) # 解密密文
plaintext = unpad(plaintext, AES.block_size) # 去除填充数据
return plaintext.decode('utf-8')
@staticmethod
def encrypt_aes(plaintext, key):
cipher = AES.new(key.encode(), AES.MODE_ECB) # 创建AES对象并指定使用ECB模式和PKCS7填充
padded_plaintext = pad(plaintext.encode(), AES.block_size) # 对明文进行填充
ciphertext = cipher.encrypt(padded_plaintext) # 加密明文
encrypted_text = base64.b64encode(ciphertext).decode() # 使用base64进行编码
return encrypted_text
def captcha_request(self): # 请求图片验证数据接口
url = "https://txzbqy.miit.gov.cn/zbtb/captcha/slideCaptcha"
data = {
"canvasWidth": 320, "canvasHeight": 155, "blockWidth": "65", "blockHeight": "55", "blockRadius": 10
}
data = json.dumps(data, separators=(',', ':'))
response = self.session.post(url, headers=self.headers, cookies=self.cookies, data=data)
res_data = json.loads(response.text)
return res_data
def img_info(self, response_data):
block_img = response_data['data']['blockSrc'] # 保存背景图片
block_img = base64.b64decode(block_img.split(',')[-1])
with open('./block.png', 'wb') as f:
f.write(block_img)
canvas_src = response_data['data']['canvasSrc'] # 加密的滑块文本
nonce_str = response_data['data']['nonceStr']
canvas_img = self.decrypt_aes(canvas_src, nonce_str) # 解密滑块文本
canvas_img = base64.b64decode(canvas_img.split(',')[-1]) # 保存滑块图片
with open('./canvas.png', 'wb') as f:
f.write(canvas_img)
def get_distance(self): # 使用ocr识别滑块距离
with open('./block.png', 'rb') as f:
target_bytes = f.read()
with open('./canvas.png', 'rb') as f:
background_bytes = f.read()
res = self.det.slide_match(target_bytes, background_bytes, simple_target=True) # target 的四个值就是缺口位置的左上角和右下角的左边位置
distance = res['target'][0]
return distance
def get_code(self, distance, nonce_str): # 得到 code
code = self.encrypt_aes(str(distance), nonce_str)
return code
def verify_function(self):
res_data = self.captcha_request()
nonce_str = res_data['data']['nonceStr']
self.img_info(response_data=res_data)
distance = self.get_distance()
code = self.get_code(distance=distance, nonce_str=nonce_str)
return {'token': nonce_str, 'code': code}
if __name__ == '__main__':
TxzbqyMiitSlider().verify_function()
测试代码及结果
from txzbqy_miit_slider import TxzbqyMiitSlider
import requests
import json
headers = {
"Accept": "application/json, text/plain, */*",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "keep-alive",
"Content-Type": "application/json;charset=UTF-8",
"Origin": "https://txzbqy.miit.gov.cn",
"Referer": "https://txzbqy.miit.gov.cn/",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
"sec-ch-ua": "\"Chromium\";v=\"110\", \"Not A(Brand\";v=\"24\", \"Google Chrome\";v=\"110\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\""
}
cookies = {
"jsessionid": "rBQl5RroZQEZ1zVgT0ecpkm3umIwl-AbpQcA",
"wzws_sessionid": "gjFiM2ZlM4AxMTcuNjEuMjEuMjEwgTJjZTFmZKBk/t7g"
}
url = "https://txzbqy.miit.gov.cn/zbtb/gateway/gatewayExpert/getBidInformationList"
verify_data = TxzbqyMiitSlider().verify_function()
print("验证参数:", verify_data)
data = {
"totalSize": 0,
"page": 2,
"limit": 15,
"bidProjectName": "",
"supervisorName": [],
"occupationBeginDate": "",
"occupationEndDate": "",
"nationFlag": None,
"bidType": None,
"bidSubtype": None,
"acceptanceBidder": "",
"unitRestrict": [],
"bidAcceptanceNotificaiton": [],
"flag": 2,
"isPublic": "0",
"code": f"{verify_data['code']}",
"token": f"{verify_data['token']}"
}
data = json.dumps(data, separators=(',', ':'))
response = requests.post(url, headers=headers, cookies=cookies, data=data)
print(response.text)
- 结果如图所示
本文来自博客园,作者:愺様,转载请注明原文链接:https://www.cnblogs.com/wyh0923/p/17699889.html