某大学继续教育平台刷课分析
编辑:jimmy
日期: 2024/12/24 浏览:1 次
前言
前两天发小让找一下有没有可以刷课的平台或者软件,找遍论坛和网络也没有找到关于此学院的信息。
无奈,只能自己上手了。
本文应该可能只适用于河南大学继续教育网络平台
QQ五笔截图未命名.png
分析
首先网络平台,最关键的就是有一个向服务器提交数据观看时间的请求,综合此情况,那么就开始抓取请求。
以我当前浏览器搜狗浏览器
为例,在课程页面按F12
键,调出开发者工具,点击NetWork
,勾选住PreserveLog
(持续日志或译为保留日志)。
点击课程平台,在第一次点击之时是不会有请求信息的,这个在稍候解析JS文件的时候说明。
播放之后再次点击一次需要观看的课程,这个时间首先就出现了请求了。
2.png
先来看一下updstatus
中的这个请求。
3.png
请求地址:
[POST]http://henu.cjnep.net/lms/web/timing/updstatus
请求头:
Cookie: _csrf=xxxx; Hm_lvt_fc82d39d0aabdf72237c051c09b9428e=1577847473; PHPFRONTSESSID=xxxxx; contact=%5B%7B%22id%22%3A%221%22%2C%22teacher_name%22%3A%22%5Cu5e73%5Cu53f0%5Cu4f7f%5Cu7528%5Cu54a8%5Cu8be21%22%2C%22qq_number%22%3A%222924134909%22%7D%2C%7B%22id%22%3A%222%22%2C%22teacher_name%22%3A%22%5Cu5e73%5Cu53f0%5Cu4f7f%5Cu7528%5Cu54a8%5Cu8be22%22%2C%22qq_number%22%3A%221283346554%22%7D%5D; noticeNumber=19; Hm_lpvt_fc82d39d0aabdf72237c051c09b9428e=1577848743
其中关键的参数我已经用xxxx为代替。
请求内容:
userId=xxxx&courseId=xxxx&scoId=27463&historyId=272631&addTime=5&totalTime=1149.619955¤tTime=1008.187626&hasCheckOne=false&hasCheckTwo=false&hasCheckThree=true&firstUpdate=false
userId
和courseId
用xxx代替,其中userId
身份证号做为判断依据,scoId
为当前观看地址中的itemid
,historyId
为历史ID,addTime
为增加的时间,totalTime
为总时间,currentTime
为当前播放时间,hasCheckOne
、hasCheckTwo
、hasCheckThree
、firstUpdate
为判断,于本文测试无用,暂不自多说。
Cookie中的信息自不必多说,这个为自己的登陆信息。咱们首先在伪造的请求则是请求中的内容。
相同的请求测试一下。
4.png
状态为-1
,出现了错误。那么说明还是有着验证的,如何寻找到验证呢?
接下来开始寻找关键的JS代码段,来查看JS代码,寻找可能存在的验证。
关键字
关键字为updstatus
,为什么选择updstatus
,可以看上面的请求地址中,他的文件为updstatus
,所以咱们来寻找播放页面所有的JS文件里面,哪个文件包含了updstatus
。
5.png
可以看到在地址中:https://cc9.mynep.com.cn/open/player/jobplayer.js。
存在了updstatus
关键字,下载下来这个文件。
6.jpg
JS代码段:
updateStatus: function(finished) { if (st_updating) return; //if (!finished && Job.conf.lastViewedTime == 0) return; //时间点为0时不提交 st_updating = true; var obj = {}; obj.userId = Job.conf.userId; obj.courseId = Job.conf.courseId; obj.scoId = Job.conf.scoId; obj.historyId = Job.conf.historyId; //obj.addTime = Job.conf.updInterval;//新增学习时间,单位秒 if (Job.conf.updStime) { var stime = (new Date()).getTime(); var diff_time = Math.min((stime - Job.conf.updStime) / 1000, Job.conf.updInterval); if (diff_time < 0) diff_time = 0; Job.conf.updAddTime += diff_time; Job.conf.updStime = stime; } obj.addTime = Math.floor(Job.conf.updAddTime);//新增学习时间,单位秒 Job.conf.updAddTime -= obj.addTime; obj.totalTime = Job.conf.totalTime; if (finished) { obj.finished = 1; obj.currentTime = 0; } else { obj.currentTime = Job.conf.lastViewedTime;//当前时间,可用来更新最后一次访问时间,学习到达最远时间点等 } obj.hasCheckOne = Job.conf.hasCheckOne; obj.hasCheckTwo = Job.conf.hasCheckTwo; obj.hasCheckThree = Job.conf.hasCheckThree; obj.firstUpdate = Job.conf.firstUpdate; //第一次提交时,更新,用于统计学习次数 Job.conf.firstUpdate = false; $.ajax(Job.conf.updStatusUrl, {type: 'POST', data: obj, dataType: 'xml'}).done(function(xml) { console.log('update status'); if (xml) { var status = Number($(xml.documentElement).find('>status').text()); if (status == -1) { Job.player.pause(); } if (!Job.conf.historyId) { var historyId = Number($(xml.documentElement).find('>historyId').text()); if (historyId) Job.conf.historyId = historyId; } window.onUpdstatus && window.onUpdstatus(status); } }).always(function() { st_updating = false; }); }
网站的程序员很贴心啊,还给我备注上了。
基本这个JS代码段看的也是半懂不懂,但大概意思是可以看出来了。
userId=xxxx&courseId=xxxx&scoId=27463&historyId=272631&addTime=5&totalTime=1149.619955¤tTime=1008.187626&hasCheckOne=false&hasCheckTwo=false&hasCheckThree=true&firstUpdate=false
上文所说的这些参数都有涉及。其中最关键的属historyId
、和addTime
。
obj.addTime = Math.floor(Job.conf.updAddTime);//新增学习时间,单位秒
if (!Job.conf.historyId) { var historyId = Number($(xml.documentElement).find('>historyId').text()); if (historyId) Job.conf.historyId = historyId; } window.onUpdstatus && window.onUpdstatus(status); }
addTime
为新增的时间,但如果返回正确的话,那么会根据这个时间来相应的增加时间。
再然后重点的是historyId
参数。
首先
var historyId = Number($(xml.documentElement).find('>historyId').text());
获取historyId
等于XML节点
中的historyId
,在这个时候就需要问了,XML文件是哪一个?
根据所获取的请求往下翻,看到如下请求:
7.png
请求地址
http://henu.cjnep.net/lms/web/course/startupxml?courseid=137&itemid=27463&historyid=272632
首先可以在historyid
处看到最终的historyid
,当然这个地址也可以在播放页面源文件中存在,可以看到。
伪造请求
请求地址:
http://henu.cjnep.net/lms/web/timing/updstatus
请求头:
Cookie: _csrf=xxxx; Hm_lvt_fc82d39d0aabdf72237c051c09b9428e=1577860273; PHPFRONTSESSID=gns54bbucprdtdgarpk2pl2k76; contact=%5B%7B%22id%22%3A%221%22%2C%22teacher_name%22%3A%22%5Cu5e73%5Cu53f0%5Cu4f7f%5Cu7528%5Cu54a8%5Cu8be21%22%2C%22qq_number%22%3A%222924134909%22%7D%2C%7B%22id%22%3A%222%22%2C%22teacher_name%22%3A%22%5Cu5e73%5Cu53f0%5Cu4f7f%5Cu7528%5Cu54a8%5Cu8be22%22%2C%22qq_number%22%3A%221283346554%22%7D%5D; noticeNumber=19; Hm_lpvt_fc82d39d0aabdf72237c051c09b9428e=1577860296
请求内容:
userId=xxxx&courseId=xxxx&scoId=27463&historyId=272632&addTime=60&totalTime=1149.619955¤tTime=1008.187626&hasCheckOne=false&hasCheckTwo=false&hasCheckThree=true&firstUpdate=false
请求时必须historyId
参数必须为XML地址
中的historyId
参数,不然返回的状态是-1
。
8.png
状态返回成功了,那么返回课程页面看一下效果。
注意:设置的addTime
为60
,那么就是请求一次即为六十秒的时间,多次点击可重复增加时间。
9.png
10.png
最后说一下
可以制作成软件成为一个半自动,在软件页输入课程地址,通过源码获取到XML地址,再然后将XML地址中的scoId
、historyId
记录下来,scoId
为课程地址中的itemid
值,historyId
为最后时间的参数。
totalTime
和currentTime
参数这两个随意,不输入也是可以的。
进行伪造请求即可成功。
请求时请务必关闭已经开启的播放界面,避免页面重复进行数据提交造成historyId参数的改变,导致软件请求不成功。这个是最注意的一点,调试的时候难受的要死。