0%

[HarekazeCTF2019]Easy Notes

PHP题,感觉好久没见了,buu上也不说明一下这个题给不给源码,导致我盲测了一个多小时受不了了看wp告诉我是有源码的,然后去GitHub翻源码做。。。害人

卑微盲测

随便登录一下,发现add,delete,view,export几个基本功能,flag功能获取flag但是要求我是admin,登录名改成admin显然无效,不知道是想让我怎么攻击,很令人在意的就是访问时是?page=add这种形式,妥妥的文件包含,开始用filter读源码,被重定向回去,然后访问add.php,报404,那就估计是有一个次级目录专门放包含的文件,尝试跳目录包含自己,不行,简单的跳目录也不行,最后试了试page=/add都不行。放弃包含,估计是已经写死了所有能包含的内容了,后来看源码的确如此。

文件包含不行也有其他的攻击点,这个note添加进去之后会分配一个随机id,还能回显,这种东西可能会通过数据库维护文件系统,note的标题可能存在二次注入,打了一波过去,无果。。。然后查看note的时候get又会多提交一个参数id,也是一波注入,再打一轮,无果。。。心态爆炸

阅读全文 »

[NCTF2019]True XML cookbook

xxe题目,不常见,感觉好像遇到这种题目都是搜一个payload直接打,不过今天看到一个好文章,可以稍微系统的学习一下,起码理解一下之前打XXE的时候遇到的问题是怎么回事

题解

查看源码可以看到一个js函数

function doLogin(){
    var username = $("#username").val();
    var password = $("#password").val();
    if(username == "" || password == ""){
        alert("Please enter the username and password!");
        return;
    }
    
    var data = "<user><username>" + username + "</username><password>" + password + "</password></user>"; 
    $.ajax({
        type: "POST",
        url: "doLogin.php",
        contentType: "application/xml;charset=utf-8",
        data: data,
        dataType: "xml",
        anysc: false,
        success: function (result) {
            var code = result.getElementsByTagName("code")[0].childNodes[0].nodeValue;
            var msg = result.getElementsByTagName("msg")[0].childNodes[0].nodeValue;
            if(code == "0"){
                $(".msg").text(msg + " login fail!");
            }else if(code == "1"){
                $(".msg").text(msg + " login success!");
            }else{
                $(".msg").text("error:" + msg);
            }
        },
        error: function (XMLHttpRequest,textStatus,errorThrown) {
            $(".msg").text(errorThrown + ':' + textStatus);
        }
    }); 
}
阅读全文 »

[GKCTF2020]EzNode

也不ez吧,学习了一下nodeJS的中间件概念和next函数

源码

const express = require('express');
const bodyParser = require('body-parser');

const saferEval = require('safer-eval'); // 2019.7/WORKER1 找到一个很棒的库

const fs = require('fs');

const app = express();


app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

// 2020.1/WORKER2 老板说为了后期方便优化
app.use((req, res, next) => {
  if (req.path === '/eval') {
    let delay = 60 * 1000;
    console.log(delay);
    if (Number.isInteger(parseInt(req.query.delay))) {
      delay = Math.max(delay, parseInt(req.query.delay));
    }
    const t = setTimeout(() => next(), delay);
    // 2020.1/WORKER3 老板说让我优化一下速度,我就直接这样写了,其他人写了啥关我p事
    setTimeout(() => {
      clearTimeout(t);
      console.log('timeout');
      try {
        res.send('Timeout!');
      } catch (e) {

      }
    }, 1000);
  } else {
    next();
  }
});

app.post('/eval', function (req, res) {
  let response = '';
  if (req.body.e) {
    try {
      response = saferEval(req.body.e);
    } catch (e) {
      response = 'Wrong Wrong Wrong!!!!';
    }
  }
  res.send(String(response));
});

// 2019.10/WORKER1 老板娘说她要看到我们的源代码,用行数计算KPI
app.get('/source', function (req, res) {
  res.set('Content-Type', 'text/javascript;charset=utf-8');
  res.send(fs.readFileSync('./index.js'));
});

// 2019.12/WORKER3 为了方便我自己查看版本,加上这个接口
app.get('/version', function (req, res) {
  res.set('Content-Type', 'text/json;charset=utf-8');
  res.send(fs.readFileSync('./package.json'));
});

app.get('/', function (req, res) {
  res.set('Content-Type', 'text/html;charset=utf-8');
  res.send(fs.readFileSync('./index.html'))
})

app.listen(80, '0.0.0.0', () => {
  console.log('Start listening')
});

setTimeout绕过

阅读全文 »

JavaScript原型链污染

大力学习js然后学到原型链把人学傻了,专门理了一下

__proto__和prototype

每个对象都存在一个__proto__属性,而每个类(js并没有很正统的类这个说法)则拥有prototype,由该类构造出来的对象的__proto__就指向该类的prototype,这都是网上可以搜到的内容,不想讲,看这个
https://www.cnblogs.com/shuiyi/p/5305435.html

主题

阅读全文 »

[GYCTF2020]ezExpress

又是一个js题,原型链污染和toUppercase,最后发现居然还有express框架的SSTI
源码在www.zip下
主要逻辑是/route/index.js

源码

var express = require('express');
var router = express.Router();
const isObject = obj => obj && obj.constructor && obj.constructor === Object;
const merge = (a, b) => {
  for (var attr in b) {
    if (isObject(a[attr]) && isObject(b[attr])) {
      merge(a[attr], b[attr]);
    } else {
      a[attr] = b[attr];
    }
  }
  return a
}
const clone = (a) => {
  return merge({}, a);
}
function safeKeyword(keyword) {
  if(keyword.match(/(admin)/is)) {
      return keyword
  }

  return undefined
}

.......

router.post('/login', function (req, res) {
  if(req.body.Submit=="register"){
   if(safeKeyword(req.body.userid)){
    res.end("<script>alert('forbid word');history.go(-1);</script>") 
   }
    req.session.user={
      'user':req.body.userid.toUpperCase(),
      'passwd': req.body.pwd,
      'isLogin':false
    }
    res.redirect('/'); 
  }
  else if(req.body.Submit=="login"){
    if(!req.session.user){res.end("<script>alert('register first');history.go(-1);</script>")}
    if(req.session.user.user==req.body.userid&&req.body.pwd==req.session.user.passwd){
      req.session.user.isLogin=true;
    }
    else{
      res.end("<script>alert('error passwd');history.go(-1);</script>")
    }
  
  }
  res.redirect('/');
});
router.post('/action', function (req, res) {
  if(req.session.user.user!="ADMIN"){res.end("<script>alert('ADMIN is asked');history.go(-1);</script>")} 
  req.session.user.data = clone(req.body);
  res.end("<script>alert('success');history.go(-1);</script>");  
});
router.get('/info', function (req, res) {
  res.render('index',data={'user':res.outputFunctionName});
})
module.exports = router;

上来就自己定义了一个clone函数,怎么看怎么原型链污染,题目意图非常明显,而看到login,首先不允许你是admin,又需要你用admin登录,没找到源码的时候题目有说只支持大写用户名就能猜到是怎么回事了,用一个奇怪的字符绕过一下就好

阅读全文 »