灵感来源:白嫖
某文理的一次答题竞赛,前一百名有奖品正好缺个蓝牙耳机索性就刷个时间白嫖一波吧.咳咳,正式开始分享咯.
准备工作:
谷歌浏览器以及自带开发者工具
页面分析:
由于此次白嫖活动已经结束,就采用其他竞赛URL进行分析,原理相同.
URL:
https://saishi.cnki.net/MatchIndex/hd6343c8ff-adcf-47c3-aa16-efea48477ddf
请求得到如上界面,打开开发者工具进行抓包(根据经验,极有可能是ajax请求),如下:
经过分析,返回的数据没有什么价值.
继续点击 开始答题个人信息随便填一下,观察抓到的包:
这个请求返回了这个竞赛的全部题目以及选项等详细信息,格式为JSON.
看他携带了哪些参数:
ExamineePaperGUID:不详
_:明显是一个时间戳,经过后续测试,这个参数可以直接写死也可以用time库获取当前时间戳
接下来尝试答题,看会请求到什么:
注意UserAnswer,就是我们刚才提交的答案,多次请求观察参数变化可得到:
ExamineePaperGUID:变化的,不详
ExamineeQuetionGUID:变化的,不详
SectionGUID:变化的,不详
SequenceNumber:代表了题目的序号,从1开始
QuestionType:发现一直是3,其实他代表了题目类型,1是选择,3是填空
QuestionScore:代表了题目的分值
其他的参数不变
这会想起来去刚才请求到的JSON数据里看看有啥有价值的信息吗
其实JSON数据里面还有QuestionType以及QuestionScore的值,可以在代码里修改成自动获取
json里的这部分代表每个题目的ID值
到此所有的参数分析结束
点击提交,发现请求到的返回值为空,携带的参数一个是ExamineePaperGUID另一个是固定参数(多提交几次就可以发现)
验证码绕过
在答题过程中,频率太高会跳出验证码,导致刷题失败.如图:
这个不是ajax请求,
可以看到只携带了一个随机浮点数,可直接写死
因为采用ddddocr库识别验证码有可能失败所以抓到故意输错时的返回值如下:
正确的返回值以及请求链接如下:
至此,仍然存疑的就是ExamineePaperGUID这个参数,虽然JSON数据里有他,可是请求时也携带了他,通过抓包以及全局搜索并未找到这个参数来自何处,亦或是加密形成,所以无法做到输入账号密码,竞赛链接就全自动答题的功能.
登录时password采用了rsa加密算法,需要js逆向,闲了再探索.
脚本编写:
可以采用第三方题库api形式的,也可以自己观察答案以及题目的变化(所以本脚本只适用于题目固定,答案随机的竞赛,其他的需要自己修改,至于账户登录问题我们可以用cookies直接绕过)
使用时,采用抓包工具抓到ExamineePaperGUID参数输入就行.cookie替换成自己的,data列表存放的是题目答案
完整代码
# -*- coding:utf-8 -*-
import random
import time
import ddddocr
import requests
data = ["第一个答案", "第二个答案"]
ExamineePaperGUID = input("请输入:")
headers = {
"Accept": "application/json, text/javascript, */*; q=0.01",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en-GB;q=0.7,en;q=0.6",
"Connection": "keep-alive",
"Cookie": "你自己的cookie",
"Host": "saishi.cnki.net",
"Referer": "https://saishi.cnki.net/exam/ExamRd/Answer/{0}".format(ExamineePaperGUID),
"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/106.0.0.0 Safari/537.36",
"X-Requested-With": "XMLHttpRequest"
}
def getInfo():
url = "https://saishi.cnki.net/api/ExamineRd/GetExamineePaperForTest"
k = 0
params = {
"examineepaperguid": ExamineePaperGUID,
"_": str(int(time.time() * 1000))
}
text = requests.get(url=url, headers=headers, params=params).json()
print(text)
SectionGUID = text["data"]["Sections"][0]["SectionGUID"]
question_list = []
option_list = []
for i in text["data"]["Questions"]:
question_list.append(i["ExamineeQuetionGUID"])
option_list.append(i["Option"])
result = []
for i in option_list:
for dic in i:
if data[k] in str(dic):
result.append(list(dic.values())[0])
k = k + 1
return SectionGUID, question_list, result
def start():
sec, qu_list, result = getInfo()
post_url = 'https://saishi.cnki.net/api/ExamineRd/SubmitUserAnswer'
for i in range(len(qu_list)):
data = {
"ExamineeQueID": "0",
"ExamineeQuetionGUID": qu_list[i],
"ExamineePaperGUID": ExamineePaperGUID,
"SectionNumber": "0",
"SectionGUID": sec,
"SequenceNumber": str(i + 1),
"QuestionType": "1",
"QuestionScore": "2",
"Question": "",
"Option": "",
"IsAnswered": "1",
"IsHasSign": "0",
"TiankongAnswerCount": "1",
"UserAnswer": result[i],
"Tiankong_Answers_Separator": "#$$#"
}
print((qu_list[i], str(i + 1)))
time.sleep(0.2)
resopnse = requests.post(url=post_url, data=data, headers=headers).json()
if resopnse['state'] == 'captcha':
cap()
else:
print(resopnse)
def cap():
for i in range(5):
url = "https://saishi.cnki.net/api/ExamCaptchaRd/Get/{0}".format(ExamineePaperGUID)
params = {
"_": "0.5594454608679078"
}
img_data = requests.get(url=url, headers=headers, params=params).content
with open('./code.jpg', 'wb') as fp:
fp.write(img_data)
ocr = ddddocr.DdddOcr(old=True)
with open("code.jpg", 'rb') as f:
image = f.read()
res = ocr.classification(image)
v_url = "https://saishi.cnki.net/api/ExamCaptchaRd/Verify/{0}".format(ExamineePaperGUID)
params1 = {
"captcha": str(res)
}
response1 = requests.get(url=v_url, headers=headers, params=params1).json()
if response1['state'] == 'success':
print('验证成功')
break
def submit(ExamineePaperGUID):
re_url = "https://saishi.cnki.net/api/ExamineRd/SubmitExaminee"
data1 = {
"ExamineePaperGUID": ExamineePaperGUID,
"SubmitMode": "2"
}
requests.post(url=re_url, headers=headers, data=data1)
if __name__ == '__main__':
start()
submit(ExamineePaperGUID)
print("提交结束!!")
标签:作答,headers,Python,list,ExamineePaperGUID,url,赛事,net,data
From: https://www.cnblogs.com/xiaotuo/p/17733263.html