比大小王比赛

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


查看页面源代码:

关键词"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 函数 *** ** * ** *** ![](https://img-blog.csdnimg.cn/img_convert/e3612b18069855a0a9d1a9109edeb0bb.png) 当然,执行代码必须要在比赛开始后,否则会出现如上情况 *** ** * ** *** ![](https://img-blog.csdnimg.cn/img_convert/0d525d4d1354194e3e815dac54e89456.png) 成功得到flag

相关推荐
Doris Liu.3 小时前
如何检测代码注入(Part 2)
windows·python·安全·网络安全·网络攻击模型
iOS技术狂热者4 小时前
使用抓包大师(sniff master)进行手机端iOS抓包的配置步骤
websocket·网络协议·tcp/ip·http·网络安全·https·udp
68岁扶墙肾透5 小时前
Java安全-FastJson反序列化分析
java·安全·web安全·网络安全·网络攻击模型·安全架构·fastjson
梧六柒6 小时前
1.1-站点差异\源码差异\数据存储差异\MVC模型
网络安全
神经毒素12 小时前
WEB安全--SQL注入--无列名注入
sql·安全·web安全
网络安全宇哥12 小时前
零基础被迫参加CTF比赛?CTF高频解题技巧与经验分享
经验分享·安全·web安全·安全架构·waf
金丝猴也是猿12 小时前
如何抓取手机与服务器通信包?三种方法详解
websocket·网络协议·tcp/ip·http·网络安全·https·udp
久违 °12 小时前
【安全运营】关于攻击面管理相关概念的梳理(一)
安全·web安全·网络安全
2501_9110676613 小时前
智慧路灯网络安全入侵监测
网络·安全·web安全
Geek极安网络安全16 小时前
2025年浙江省中等职业学校职业能力大赛(学生技术技能类)“移动应用与开发”赛项技术文件
运维·网络·python·安全·web安全·eclipse·php