环境已经关了,这里主要说下思路
拿到题目,很容易发现一个任意文件读取
读取根目录flag,权限不够,发现根目录有/readflag
那么思路就是要rce或者其他有执行/readflag得操作了
由题目知道是 tomcat java的
读源码
搭建过tomcat的师傅们知道tomcat一般的默认路径
挨个读取文件
/usr/local/tomcat/webapps/ROOT/WEB-INF/classes/util/Secr3t.class
/usr/local/tomcat/webapps/ROOT/WEB-INF/classes/servlet
/usr/local/tomcat/webapps/ROOT/WEB-INF/classes/controller
/usr/local/tomcat/webapps/ROOT/WEB-INF/classes/entity
/usr/local/tomcat/webapps/ROOT/WEB-INF/classes/util
主要是这三个文件
SerAndDe.class
User.class
HelloWorldServlet.class
然后去反编译
@WebServlet(name = "HelloServlet", urlPatterns = {"/evi1"})
/* loaded from: file(5) */
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 void init() throws ServletException {
this.user = new User(this.name, this.age, this.height);
}
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)) {
Response(resp, "no vnctf2022!");
} else if (Secr3t.check(this.name)) {
Response(resp, "The Key is " + Secr3t.getKey());
}
}
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) {
Response(resp, "KeyError");
return;
}
if (this.user.equals((User) SerAndDe.deserialize(Base64.getDecoder().decode(text)))) {
Response(resp, "Deserialize…… Flag is " + Secr3t.getFlag().toString());
}
}
private void Response(HttpServletResponse resp, String outStr) throws IOException {
ServletOutputStream out = resp.getOutputStream();
out.write(outStr.getBytes());
out.flush();
out.close();
}
}
public class SerAndDe {
private SerAndDe() {
}
public static byte[] serialize(Object object) {
ObjectOutputStream oos = null;
ByteArrayOutputStream bos = null;
try {
try {
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(object);
byte[] b = bos.toByteArray();
if (oos != null) {
try {
oos.close();
} catch (IOException ex) {
System.out.println("io could not close:" + ex.toString());
}
}
if (bos != null) {
bos.close();
}
return b;
} catch (IOException e) {
System.out.println("serialize Exception:" + e.toString());
if (oos != null) {
try {
oos.close();
} catch (IOException ex2) {
System.out.println("io could not close:" + ex2.toString());
return null;
}
}
if (bos != null) {
bos.close();
}
return null;
}
} catch (Throwable th) {
if (oos != null) {
try {
oos.close();
} catch (IOException ex3) {
System.out.println("io could not close:" + ex3.toString());
throw th;
}
}
if (bos != null) {
bos.close();
}
throw th;
}
}
public static Object deserialize(byte[] bytes) {
ByteArrayInputStream bais;
try {
bais = null;
try {
bais = new ByteArrayInputStream(bytes);
Object readObject = new ObjectInputStream(bais).readObject();
if (bais != null) {
try {
bais.close();
} catch (IOException ex) {
System.out.println("LogManage Could not serialize:" + ex.toString());
}
}
return readObject;
} catch (IOException | ClassNotFoundException e) {
System.out.println("deserialize Exception:" + e.toString());
if (bais != null) {
try {
bais.close();
} catch (IOException ex2) {
System.out.println("LogManage Could not serialize:" + ex2.toString());
return null;
}
}
return null;
}
} catch (Throwable th) {
if (bais != null) {
try {
bais.close();
} catch (IOException ex3) {
System.out.println("LogManage Could not serialize:" + ex3.toString());
throw th;
}
}
throw th;
}
}
}
public class User implements Serializable {
private String name;
private String age;
private transient String height;
public User(String name, String age, String height) {
this.name = name;
this.age = age;
this.height = height;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return this.age;
}
public void setAge(String age) {
this.age = age;
}
public String getHeight() {
return this.height;
}
public void setHeight(String height) {
this.height = height;
}
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();
this.height = (String) s.readObject();
}
@Override // java.lang.Object
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
if (!(obj instanceof User)) {
return false;
}
User user = (User) obj;
if (!user.getAge().equals(this.age) || !user.getHeight().equals(this.height) || !user.getName().equals(this.name)) {
return false;
}
return true;
}
@Override // java.lang.Object
public String toString() {
return "User{name='" + this.name + "', age='" + this.age + "', height='" + this.height + "'}";
}
}
java代码审计
可以知道得先得到一个key doGet 方法那里得到key
直接读key是行不通得
然后这里要设法绕过
乍一看是决定无法成功得
经过师傅提示 ,跟java线程安全有关系,burpsuite开两个intruder
然后去爆破,等个几分钟 响应包中发现得到key
之后 去 doPost 方法 设法得到flag
这里反序列化必须满足条件
新建一个t3目录
根据原先得目录结构 新建这几个文件
对t3文件夹 直接 右键 idea打开
文件--项目结构设置
模块标记为源
直接把 User和 SerAndDe得代码 拷贝进去
写一个main
然后是漫长得改bug
SerAndDe中bug很多
通过idea提示 等等 终于改完bug
运行之后 发现 还不行
注意到 User中得
private transient String height;
https://blog.csdn.net/qq_42843172/article/details/107193866
transient关键字:游离的,被该关键字修饰的变量不参与序列化
所有这里还得重写 User中得
readObject 和 writeObject 方法
然后再次运行main就成功了
post传入key和 base64即可
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。