比大小王比赛

news/2024/11/15 22:10:10/

对手上来就快速答题,根本没法拼手速赢下比赛


查看页面源代码:

关键词“POST”,找到关键代码段:

前端会调用 loadGame() 函数向后端发送 POST /game 请求,获取 100 道题目的数字和开始时间。这个请求可以通过浏览器的开发者工具看到,其中的信息会被存入 state 变量中


继续往下拉看到updateCountdown()函数:

后端随机生成 100 道题,并按照收到请求的时间加 5 秒作为开始时间。这是为了确保在网络延迟较高的情况下,玩家仍然能看到比赛开始前的倒计时,而不会在收到题目时比赛已经开始。当然这也意味着玩家在比赛开始前已经拿到了题目,可以提前做题和提交,以负数时长完成比赛。后端如果检测到开始时间之前就提交答案,会回复检测到时空穿越,挑战失败!

后端会在回复题目数据的同时,利用 Flask 的 session 机制,将题目数据签名存储在 cookies 中。这样后端无需存储给出过的所有题目数据,等到玩家提交答案时,后端可以从 cookies 中读取题目的数字和开始时间用于验证,并且玩家无法篡改这些信息

加载题目后,updateCountdown() 函数会根据当前时间和开始时间相差的秒数,播放倒计时动画


再看到updateTimer()函数:

比赛开始后,updateTimer() 函数会不断更新显示的时间,以及对手的进度。对手每 100 毫秒完成一道题,10 秒(100 题)后停止,显示挑战失败


再看到chooseAnswer()函数:

玩家每次选择小于或大于后,会调用 chooseAnswer('<') 或 chooseAnswer('>'),这个函数会用绿色或红色指示是否正确,持续 200 毫秒,这期间是不能操作的。200 毫秒之后,如果正确,会显示下一题,如果错误,会显示挑战失败


再看到submit()函数:

玩家正确完成 100 题后,前端会调用 submit(state.inputs) 函数向后端发送 POST /submit 请求,提交玩家的 100 次选择(长度为 100 的数组,每个元素为 '<' 或 '>'),并显示回复


后端会从 cookies 中读取题目的数字,验证签名,验证玩家的 100 次选择是正确的。这个过程中任何错误都会导致回复 检测到异常提交。如果验证通过,取决于当前时间和开始时间的差值,回复 检测到时空穿越,挑战失败! 或 挑战成功!flag{...} 或 对手已完成,挑战失败!


在开始比赛前F12打开控制台执行如下代码:

function f() {// 只要还没到 100 分if (state.score1 < 100) {// 选择正确的答案if (state.value1 < state.value2) {chooseAnswer('<');} else {chooseAnswer('>');}// 1 毫秒后再次调用 f 函数setTimeout(f, 1);}
}f();

发现能自动答题了,但速度上还是比不过对手,仍需要改进代码,必须移除每次 200 毫秒的等待时间,这是在 chooseAnswer() 函数中实现的。要修改一个函数的代码,一般需要使用开发者工具的 override(覆盖)功能,但对于一些简单的情况,例如这道题,直接复制相关函数的代码,修改后粘贴到控制台中运行即可


function f() {// 只要还没到 100 分if (state.score1 < 100) {// 选择正确的答案if (state.value1 < state.value2) {chooseAnswer('<');} else {chooseAnswer('>');}// 1 毫秒后再次调用 f 函数setTimeout(f, 1);}
}f();function chooseAnswer(choice) {if (!state.allowInput) {return;}state.inputs.push(choice);let correct;if (state.value1 < state.value2 && choice === '<' || state.value1 > state.value2 && choice === '>') {correct = true;state.score1++;document.getElementById('answer').style.backgroundColor = '#5e5';} else {correct = false;document.getElementById('answer').style.backgroundColor = '#e55';}document.getElementById('answer').textContent = choice;document.getElementById('score1').textContent = state.score1;document.getElementById('progress1').style.width = `${state.score1}%`;state.allowInput = false;setTimeout(() => {if (state.score1 === 100) {submit(state.inputs);} else if (correct) {state.value1 = state.values[state.score1][0];state.value2 = state.values[state.score1][1];state.allowInput = true;document.getElementById('value1').textContent = state.value1;document.getElementById('value2').textContent = state.value2;document.getElementById('answer').textContent = '?';document.getElementById('answer').style.backgroundColor = '#fff';} else {state.allowInput = false;state.stopUpdate = true;document.getElementById('dialog').textContent = '你选错了,挑战失败!';document.getElementById('dialog').style.display = 'flex';}}, 1);  // 这里的 200 改成了 1
}

再次在控制台中执行修改后的代码:

成功得到flag


override(覆盖)功能位置如下:


除了上面这种方法还有另一种方法,如果看明白了题目逻辑,可以发现 100 道题目的数字在 state.values 变量中,最终需要调用 submit 函数提交答案,所以可以等待比赛开始后,在控制台执行以下代码:

submit(state.values.map(([v1,v2])=>v1<v2?'<':'>'))

意思如下:

1、state.values 是一个二维数组,每个子数组包含两个值,例如 [[1, 2], [3, 4], [5, 6]]


2、.map(([v1, v2]) => v1 < v2 ? '<' : '>')

.map 方法用于遍历数组中的每个元素,并对每个元素应用一个函数,返回一个新的数组

[v1, v2]是解构赋值,从每个子数组中提取两个值。例如,对于 [1, 2],v1 为 1,v2 为2

v1 < v2 ? '<' : '>' 是一个三元运算符,用于比较 v1 和 v2:

如果 v1 小于 v2,返回 '<'

否则,返回 '>'


3. submit(...)

submit 是一个函数,接受一个参数(在这里是一个数组),并将这个数组作为数据提交


简单来说就是把 state.values 的每一项映射为 '<' 或 '>',得到一个长度为 100 的数组,作为参数调用 submit 函数


当然,执行代码必须要在比赛开始后,否则会出现如上情况


成功得到flag


http://www.ppmy.cn/news/1547290.html

相关文章

pytorch torch.tile用法

指定各维度分别重复多少次 tile 是 PyTorch 中用于重复张量的函数。它可以沿指定的维度重复张量的元素。以下是一个示例代码&#xff0c;展示 tile 的用法&#xff1a; import torch# 创建一个张量 weight_hh torch.tensor([[1, 2], [3, 4]])# 假设批量大小为3 bs 3# 使用 …

Spring挖掘: (事务篇)

谈到事务,我们就绕不开事务的ACID四大特性,我们先来简单介绍一下何为事务 一. 概念 事务是数据库操作的最小工作单元&#xff0c;作为单个逻辑工作单元执行的一系列操作。这些操作作为一个整体一起向系统提交&#xff0c;要么都执行、要么都不执行。事务是一组不可再分割的操作…

ES6 中 Map 和 Set

Map ES6 以前在 js 中实现 key/value 的存储形式都可以使用 Object 来实现&#xff0c;也就是对象的 属性做为键&#xff0c;当需要获取 value 时&#xff0c;必须要通过对应的 key 去访问。 Map 和 Object 的区别 key 上的区别 Object 的 key 类型只能是 number | string |…

H3C ER8300G2-X未授权导致信息泄露漏洞(CVE-2024-32238)

免责声明: 本文旨在提供有关特定漏洞的深入信息,帮助用户充分了解潜在的安全风险。发布此信息的目的在于提升网络安全意识和推动技术进步,未经授权访问系统、网络或应用程序,可能会导致法律责任或严重后果。因此,作者不对读者基于本文内容所采取的任何行为承担责任。读者在…

第02章 CentOS基本操作

2.文件基本操作【文件操作&#xff08;一&#xff09;】 目标 理解Linux下路径的表示方法能够使用命令(mkdir和touch)在指定位置创建目录和文件能够使用命令(rm)删除指定的目录和文件能够使用命令(ls)列出目录里的文件能够使用命令(cat,head,tail,less,more)查看文件内容理解标…

完全二叉树的节点个数

给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面一层的节点都集中在该层最左边的若干位置。若最…

SQL面试题——抖音SQL面试题 主播播出时长

主播播出时长 现有如下数据,主播id、房间号、播出的批次号,每个批次号进出房间的时间戳、分区时间: 每一次直播都有一个上播和下播,每个房间里,同一个批次号会有两条数据,分别记录了上播和下播时间,求每个主播的播出时长? 通过上面的数据,可以清晰的看出,同一个批次…

信息收集—JS框架识别泄露提取API接口泄露FUZZ爬虫插件项目

前言 免杀结束了&#xff0c;我们开个新的篇章——信息收集。为什么我一开始先写信息收集的文章呢&#xff0c;是因为现在我才发现我的信息收集能力其实有点弱的&#xff0c;所以呢开始知不足&#xff0c;而后进。 什么是JS JS就是JavaScript的简称&#xff0c;它和Java是没…