当前位置: 首页 > news >正文

可预测的随机逻辑 -- b01lers CTF when wp

题目信息: the sunk cost fallacy

进去是一个转盘

POST /gamble HTTP/2
Host: when.atreides.b01lersc.tf
Content-Length: 0
Sec-Ch-Ua-Platform: "Windows"
Accept-Language: zh-CN,zh;q=0.9
Sec-Ch-Ua: "Not:A-Brand";v="24", "Chromium";v="134"
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Sec-Ch-Ua-Mobile: ?0
Accept: */*
Origin: https://when.atreides.b01lersc.tf
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://when.atreides.b01lersc.tf/
Accept-Encoding: gzip, deflate, br
Priority: u=1, i
HTTP/2 200 OK
Content-Type: application/json; charset=utf-8
Date: Fri, 18 Apr 2025 23:24:33 GMT
Etag: W/"2c-uk6V5GDhOms+yhdUNsytNwB0L2M"
Ratelimit: limit=60, remaining=56, reset=55
Ratelimit-Policy: 60;w=60
X-Powered-By: Express
Content-Length: 44{"success":true,"result":"1100111100011111"}

可以改为 1111111111111111

服务器似乎会检测请求时间并拒绝,我们得设定burp规则替换

\{\"success\"\:true\,\"result\"\:\".*\"\}
{"success":true,"result":"1111111111111111"}

这似乎没什么作用,观察css

<!DOCTYPE html>
<html><head><!-- 基础元信息 --><meta charset="utf-8" /><title>Let's Go Gambling</title><!-- 移动端视口适配 --><meta name="viewport" content="width=device-width, initial-scale=1" /><!-- 样式表链接 --><link rel="stylesheet" href="/index.css" /></head><body><!-- 音效资源 --><audio id="audio_open" src="assets/open.wav"></audio>  <!-- 开箱音效 --><audio id="audio_win" src="assets/win.wav"></audio>    <!-- 获胜音效 --><audio id="audio_aw" src="assets/aw.wav"></audio>      <!-- 失败音效 --><audio id="audio_click0" src="assets/click.wav"></audio> <!-- 点击音效组 --><audio id="audio_click1" src="assets/click.wav"></audio><audio id="audio_click2" src="assets/click.wav"></audio><!-- 主要游戏容器 --><div id="container"><!-- 角色动画容器 --><div id="men"><img id="neutral" src="assets/neutral.gif">       <!-- 默认状态 --><img id="anger" src="assets/anger.gif" style="display: none">  <!-- 生气状态 --><img id="press" src="assets/press.gif" style="display: none">  <!-- 按压按钮状态 --><img id="jump" src="assets/jump.gif" style="display: none">    <!-- 跳跃状态 --></div><!-- 宝箱图片 --><img id="box" src="assets/box.png"><!-- 老虎机格子(共16个) --><div id="slots"><!-- 初始全部显示失败状态 --><img src="assets/slot_fail.png"> ×16</div></div><!-- 操作提示 --><div id="tip">click anywhere to gamble</div><!-- 结果显示 --><div id="result"></div><script>// DOM 选择快捷方式const $ = (a) => document.getElementById(a)// 游戏状态控制let firstTime = true      // 是否首次游戏let isGambling = false    // 防止重复点击// 预加载图片资源 [失败图, 成功图, 旋转动画]const imgBlobs = new Array(3).fill(null)const assets = ["assets/slot_fail.png", "assets/slot_flag.png", "assets/slot_spin.gif"]for (let i = 0; i < assets.length; i++) {fetch(assets[i]).then(res => res.blob()).then(blob => {imgBlobs[i] = URL.createObjectURL(blob)  // 转换为对象URL})}// 延时函数async function sleep(time) {return new Promise((res) => {setTimeout(() => res(), time)})}// 创建硬币动画效果function createCoin(y, yv) {const coin = document.createElement("img")coin.src = "assets/coin.gif"coin.style.position = "absolute"coin.style.transform = `scale(${Math.random() * 0.5 + 0.5})` // 随机大小// 初始位置和速度let coinY = ylet coinX = Math.random() * (document.body.clientWidth + 400) - 200let xv = (Math.random() - 0.5) * 10  // 水平速度// 位置更新定时器let update = setInterval(() => {coinX += xvcoinY += yvyv += 0.5 * Math.random()  // 模拟重力// 移出屏幕后清除if (coinY > document.body.clientHeight + 500) {coin.remove()clearInterval(update)}}, 30)}// 核心游戏逻辑async function gamble() {if (isGambling) returnisGambling = true// 重置界面状态$("tip").style.transform = "scale(2, 0)"  // 隐藏提示$("neutral").style.display = ""          // 显示默认角色// 发起游戏请求const data = await fetch("/gamble", { method: "POST"}).then(body => body.json()).catch(err => {$("result").innerText = "too much gambling! please wait a bit"isGambling = false})if (!data) return// 显示旋转动画for (let i = 0; i < 16; i++) {$("slots").children[i].src = imgBlobs[2]}// 首次游戏特殊音效if (firstTime) {$("audio_open").play()await sleep(1465)  // 等待音效播放firstTime = false}// 显示按压状态$("press").style.display = ""// 逐个显示结果for (let i = 0; i < 16; i++) {$("audio_click" + i % 3).play()  // 循环播放3个点击音效$("slots").children[i].src = data.result[i] == "1" ? imgBlobs[1] : imgBlobs[0]await sleep(100)  // 每个结果间隔100ms}// 胜利情况处理if (data.flag !== undefined) {document.body.classList.add("win")  // 添加获胜样式$("audio_win").play()$("result").innerText = data.flag// 生成硬币雨效果for (let i = 0; i < 150; i++) {  // 上方硬币createCoin(-200 - Math.random() * document.body.clientHeight, Math.random() * -5)}for (let i = 0; i < 150; i++) {  // 下方硬币createCoin(document.body.clientHeight + 200, -20 + Math.random() * -20)}await sleep(2640)  // 等待音效结束document.body.classList.remove("win")} // 失败情况处理else {$("audio_aw").play()// 播放生气动画序列$("press").style.display = "none"$("anger").style.display = ""await sleep(426)$("anger").style.display = "none"$("jump").style.display = ""await sleep(636)$("jump").style.display = "none"$("neutral").style.display = ""}isGambling = false}// 绑定点击事件document.addEventListener("mousedown", gamble)</script></body>
</html>

当我尝试爆破时发现存在速率限制…

我竟然没没看见有附件。。。。。。。。。

// 导入 express 框架,用于创建 Web 服务器
import express from 'express'
// 导入 express-rate-limit 库中的 rateLimit 函数,用于限制请求频率
import { rateLimit } from 'express-rate-limit'
// 导入 path 模块,用于处理文件路径
import path from "path"/*** 创建一个请求频率限制器实例* 仅对 /gamble 路径的请求进行频率限制*/
const limiter = rateLimit({// 时间窗口,单位为毫秒,这里设置为 1 分钟windowMs: 60 * 1000,// 在时间窗口内允许的最大请求数,这里设置为 60 次limit: 60, // 使用 draft-7 标准的响应头来指示速率限制信息standardHeaders: 'draft-7',// 不使用旧版的速率限制响应头legacyHeaders: false,/*** 跳过不需要进行速率限制的请求* @param req - 请求对象* @param res - 响应对象* @returns 如果请求路径不是 /gamble,则返回 true,跳过速率限制*/skip: (req, res) => {return req.path != "/gamble"}
})// 创建一个 express 应用实例
const app = express()// 应用请求频率限制器到 express 应用
app.use(limiter)
// 静态文件服务,将 __dirname 下的 static 目录作为静态资源目录
app.use(express.static(path.join(__dirname, 'static')))/*** 对输入的数字进行 SHA-256 哈希计算* @param number - 要进行哈希计算的数字* @returns 包含哈希结果的 Promise*/
async function gamble(number: number) {// 使用 crypto.subtle.digest 方法对数字的字符串表示进行 SHA-256 哈希计算return crypto.subtle.digest("SHA-256", Buffer.from(number.toString()))
}/*** 处理 /gamble 路径的 POST 请求* @param req - 请求对象* @param res - 响应对象*/
app.post('/gamble', (req, res) => {// 从请求头中获取日期,如果不存在则使用当前日期const time = req.headers.date ? new Date(req.headers.date) : new Date()// 将时间戳转换为秒级时间戳const number = Math.floor(time.getTime() / 1000)// 检查转换后的时间戳是否为 NaNif (isNaN(number)) {// 如果为 NaN,返回错误响应,状态码为 400res.send({success: false,error: "Bad Date"}).status(400)return}// 调用 gamble 函数进行哈希计算gamble(number).then(data => {// 将哈希结果转换为 Uint8Array 类型const bytes = new Uint8Array(data)// 检查哈希结果的前两个字节是否都为 255if (bytes[0] == 255 && bytes[1] == 255) {// 如果满足条件,返回成功响应,包含 flag 信息res.send({success: true,result: "1111111111111111",flag: "bctf{fake_flag}"})} else {// 如果不满足条件,返回成功响应,包含前两个字节的二进制表示res.send({success: true,result: bytes[0].toString(2).padStart(8, "0") + bytes[1].toString(2).padStart(8, "0")})}})
});// 启动 express 服务器,监听 6060 端口
app.listen(6060, () => {// 服务器启动成功后,在控制台输出提示信息console.log(`Started express server`);
});

现在写代码找符合的date,直接扔给ai

import hashlib  
import random  
from datetime import datetime, timezone  def find_valid_date():  while True:  # 生成一个随机时间戳(秒级)  t = random.randint(0, 2**32 - 1)  # 转换为字符串并计算SHA-256哈希  s = str(t)  digest = hashlib.sha256(s.encode()).digest()  # 检查前两个字节是否为0xFF  if digest[:2] == b'\xff\xff':  try:  # 转换为UTC时间并格式化Date头  dt = datetime.fromtimestamp(t, tz=timezone.utc)  date_header = dt.strftime('%a, %d %b %Y %H:%M:%S GMT')  return date_header  except:  # 处理无效时间戳,继续循环  continue  # 执行搜索并输出结果  
valid_date = find_valid_date()  
print("Valid Date Header:", valid_date)
POST /gamble HTTP/2
Host: when.atreides.b01lersc.tf
Date: Mon, 29 Jun 1981 00:19:20 GMT

win!!

http://www.xdnf.cn/news/89731.html

相关文章:

  • 关于大数据的基础知识(三)——数据安全与合规
  • 谐振模态图
  • 【OSG学习笔记】Day 6: Day 6: 几何体(Geometry)的创建与自定义
  • IP-Guard加密系统开启不了,说连接失败了,IPG数据库更改为多用户模式修复成功。
  • 【C++】Json-Rpc框架项目介绍(1)
  • 审计平台本地部署遇到的坑
  • 三生原理与现有密码学的核心区别?
  • 龙虎榜——20250422
  • Airbyte - 数据集成平台
  • vue 修改路由动态选择路由 改文件位置
  • 用Qt和deepseek创建自己的问答系统
  • transformer 编码器层
  • 聊天交友APP聊天系统框架搭建
  • 【Linux禁用历史命令】
  • RK3588 Buildroot 新建板级DTS
  • JAVA线程池ThreadPoolExecutor说明
  • 树莓派超全系列教程文档--(40)树莓派config.txt旧版GPIO控制、超频及条件过滤器
  • 【Spring】依赖注入的方式:构造方法、setter注入、字段注入
  • ProxySQL如何支持高并发读写请求
  • ubuntu 安装 redis server
  • 技术能力和关系比较实在没有可比性
  • 【同轴线共焦传感器原理】
  • Tree Shaking 原理
  • [原创](现代Delphi 12指南):[macOS 64bit App开发]:在Mac App Store外创建、部署与公证
  • 【AI面试】分类模型 之 随机森林
  • UWB定位技术在钢铁厂行业中的创新应用与价值实践
  • Linux:简单自定义shell
  • Unity使用反射进行Protobuf(CS/SC)协议,json格式_002
  • Python 常用Web框架对比
  • 乐视系列玩机---乐视2 x620 x628等系列线刷救砖以及刷写第三方twrp 卡刷第三方固件步骤解析