Skip to content

Commit 3fc5ce0

Browse files
author
‘niuerzhuang’
committed
fix: BlackUrl collect bypass.
1 parent e12f6cd commit 3fc5ce0

File tree

8 files changed

+214
-18
lines changed

8 files changed

+214
-18
lines changed

dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/asm/AsmMethods.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,20 @@ static Method getAsmMethod(final Class<?> clazz,
255255
boolean.class
256256
);
257257

258+
Method SPY$skipCollect = InnerHelper.getAsmMethod(
259+
SpyDispatcher.class,
260+
"skipCollect",
261+
Object.class,
262+
Object[].class,
263+
Object.class,
264+
String.class,
265+
String.class,
266+
String.class,
267+
String.class,
268+
String.class,
269+
boolean.class
270+
);
271+
258272
Method SPY$traceFeignInvoke = InnerHelper.getAsmMethod(
259273
SpyDispatcher.class,
260274
"traceFeignInvoke",

dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/AbstractAdviceAdapter.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,32 @@ public void captureMethodState(
174174
pop();
175175
}
176176

177+
public void skipCollect(
178+
final int opcode,
179+
final PolicyNode policyNode,
180+
final boolean captureRet
181+
) {
182+
newLocal(ASM_TYPE_OBJECT);
183+
if (captureRet && !isThrow(opcode)) {
184+
loadReturn(opcode);
185+
} else {
186+
pushNull();
187+
}
188+
storeLocal(this.nextLocal - 1);
189+
invokeStatic(ASM_TYPE_SPY_HANDLER, SPY_HANDLER$getDispatcher);
190+
loadThisOrPushNullIfIsStatic();
191+
loadArgArray();
192+
loadLocal(this.nextLocal - 1);
193+
push(policyNode.toString());
194+
push(this.context.getClassName());
195+
push(this.context.getMatchedClassName());
196+
push(this.name);
197+
push(this.signature);
198+
push(Modifier.isStatic(this.access));
199+
invokeInterface(ASM_TYPE_SPY_DISPATCHER, SPY$skipCollect);
200+
pop();
201+
}
202+
177203
/**
178204
* 是否抛出异常返回(通过字节码判断)
179205
*

dongtai-core/src/main/java/io/dongtai/iast/core/bytecode/enhance/plugin/core/adapter/SinkAdapter.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ public void onMethodEnter(MethodAdviceAdapter adapter, MethodVisitor mv, MethodC
1515
if (!(policyNode instanceof SinkNode)) {
1616
continue;
1717
}
18+
if ("ssrf".equals(((SinkNode) policyNode).getVulType())){
19+
adapter.skipCollect(-1, policyNode, false);
20+
}
1821

1922
enterScope(adapter, policyNode);
2023

dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/SpyDispatcherImpl.java

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,15 @@
88
import io.dongtai.iast.core.EngineManager;
99
import io.dongtai.iast.core.bytecode.enhance.plugin.spring.SpringApplicationImpl;
1010
import io.dongtai.iast.core.handler.bypass.BlackUrlBypass;
11-
import io.dongtai.iast.core.handler.context.ContextManager;
1211
import io.dongtai.iast.core.handler.hookpoint.controller.HookType;
1312
import io.dongtai.iast.core.handler.hookpoint.controller.impl.*;
1413
import io.dongtai.iast.core.handler.hookpoint.graphy.GraphBuilder;
1514
import io.dongtai.iast.core.handler.hookpoint.models.MethodEvent;
1615
import io.dongtai.iast.core.handler.hookpoint.models.policy.*;
1716
import io.dongtai.iast.core.handler.hookpoint.service.trace.DubboService;
1817
import io.dongtai.iast.core.handler.hookpoint.service.trace.FeignService;
18+
import io.dongtai.iast.core.handler.hookpoint.service.trace.HttpService;
1919
import io.dongtai.iast.core.utils.StringUtils;
20-
import io.dongtai.iast.core.utils.TaintPoolUtils;
2120
import io.dongtai.iast.core.utils.matcher.ConfigMatcher;
2221
import io.dongtai.log.DongTaiLog;
2322
import io.dongtai.log.ErrorCode;
@@ -192,7 +191,7 @@ public void collectHttpRequest(Object obj, Object req, Object resp, StringBuffer
192191
BlackUrlBypass.setIsBlackUrl(true);
193192
return;
194193
}
195-
if (null != headers.get(BlackUrlBypass.getHeaderKey()) && headers.get(BlackUrlBypass.getHeaderKey()).equals("true")){
194+
if (null != headers.get(BlackUrlBypass.getHeaderKey()) && headers.get(BlackUrlBypass.getHeaderKey()).equals("true")) {
196195
BlackUrlBypass.setIsBlackUrl(true);
197196
return;
198197
}
@@ -607,6 +606,7 @@ public boolean isNotReplayRequest() {
607606

608607
/**
609608
* mark for enter Source Entry Point
609+
*
610610
* @since 1.3.1
611611
*/
612612
@Override
@@ -714,7 +714,7 @@ public boolean traceDubboInvoke(Object instance, String url, Object invocation,
714714

715715
@Override
716716
public boolean isSkipCollectDubbo(Object invocation) {
717-
if (BlackUrlBypass.isBlackUrl()){
717+
if (BlackUrlBypass.isBlackUrl()) {
718718
Method setAttachmentMethod = null;
719719
try {
720720
setAttachmentMethod = invocation.getClass().getMethod("setAttachment", String.class, String.class);
@@ -729,20 +729,42 @@ public boolean isSkipCollectDubbo(Object invocation) {
729729

730730
@Override
731731
public boolean isSkipCollectFeign(Object instance) {
732-
Field metadataField = null;
733-
try {
734-
metadataField = instance.getClass().getDeclaredField("metadata");
735-
metadataField.setAccessible(true);
736-
Object metadata = metadataField.get(instance);
737-
Method templateMethod = metadata.getClass().getMethod("template");
738-
Object template = templateMethod.invoke(metadata);
739-
740-
Method addHeaderMethod = template.getClass().getDeclaredMethod("header", String.class, String[].class);
741-
addHeaderMethod.setAccessible(true);
742-
addHeaderMethod.invoke(template, BlackUrlBypass.getHeaderKey(), new String[]{});
743-
addHeaderMethod.invoke(template, BlackUrlBypass.getHeaderKey(), new String[]{BlackUrlBypass.isBlackUrl().toString()});
744-
} catch (NoSuchFieldException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
745-
DongTaiLog.error(ErrorCode.get("BYPASS_FAILED_FEIGN"), e);
732+
if (BlackUrlBypass.isBlackUrl()) {
733+
Field metadataField = null;
734+
try {
735+
metadataField = instance.getClass().getDeclaredField("metadata");
736+
metadataField.setAccessible(true);
737+
Object metadata = metadataField.get(instance);
738+
Method templateMethod = metadata.getClass().getMethod("template");
739+
Object template = templateMethod.invoke(metadata);
740+
741+
Method addHeaderMethod = template.getClass().getDeclaredMethod("header", String.class, String[].class);
742+
addHeaderMethod.setAccessible(true);
743+
addHeaderMethod.invoke(template, BlackUrlBypass.getHeaderKey(), new String[]{});
744+
addHeaderMethod.invoke(template, BlackUrlBypass.getHeaderKey(), new String[]{BlackUrlBypass.isBlackUrl().toString()});
745+
} catch (NoSuchFieldException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
746+
DongTaiLog.error(ErrorCode.get("BYPASS_FAILED_FEIGN"), e);
747+
}
748+
}
749+
return false;
750+
}
751+
752+
@Override
753+
public boolean skipCollect(Object instance, Object[] parameters, Object retObject, String policyKey,
754+
String className, String matchedClassName, String methodName, String signature,
755+
boolean isStatic) {
756+
if (BlackUrlBypass.isBlackUrl()) {
757+
MethodEvent event = new MethodEvent(className, matchedClassName, methodName,
758+
signature, instance, parameters, retObject);
759+
PolicyNode policyNode = getPolicyNode(policyKey);
760+
if (policyNode == null) {
761+
return false;
762+
}
763+
HttpService httpService = new HttpService();
764+
if (httpService.match(event, policyNode)) {
765+
httpService.addBypass(event);
766+
return true;
767+
}
746768
}
747769
return false;
748770
}

dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/controller/impl/HttpImpl.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.dongtai.iast.common.config.*;
44
import io.dongtai.iast.common.constants.AgentConstant;
55
import io.dongtai.iast.core.EngineManager;
6+
import io.dongtai.iast.core.handler.bypass.BlackUrlBypass;
67
import io.dongtai.iast.core.handler.hookpoint.IastClassLoader;
78
import io.dongtai.iast.core.utils.*;
89
import io.dongtai.iast.core.utils.matcher.ConfigMatcher;
@@ -60,6 +61,7 @@ public static void solveHttpRequest(Object obj, Object req, Object resp, Map<Str
6061
String requestURL = ((StringBuffer) requestMeta.get("requestURL")).toString();
6162
Map<String, String> headers = (Map<String, String>) requestMeta.get("headers");
6263
if (requestDenyList.match(requestURL, headers)) {
64+
BlackUrlBypass.setIsBlackUrl(true);
6365
DongTaiLog.trace("HTTP Request {} deny to collect", requestURL);
6466
return;
6567
}

dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/service/trace/HttpService.java

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.dongtai.iast.core.handler.hookpoint.service.trace;
22

33
import io.dongtai.iast.core.EngineManager;
4+
import io.dongtai.iast.core.handler.bypass.BlackUrlBypass;
45
import io.dongtai.iast.core.handler.context.ContextManager;
56
import io.dongtai.iast.core.handler.hookpoint.models.MethodEvent;
67
import io.dongtai.iast.core.handler.hookpoint.models.policy.PolicyNode;
@@ -12,6 +13,8 @@
1213
import java.lang.reflect.Field;
1314
import java.lang.reflect.Method;
1415
import java.net.HttpURLConnection;
16+
import java.util.HashMap;
17+
import java.util.Map;
1518

1619
public class HttpService implements ServiceTrace {
1720
private String matchedSignature;
@@ -44,6 +47,21 @@ public void addTrace(MethodEvent event, PolicyNode policyNode) {
4447
}
4548
}
4649

50+
public void addBypass(MethodEvent event) {
51+
HashMap<String, String> blackUrlHeaders = new HashMap<>();
52+
blackUrlHeaders.put(BlackUrlBypass.getHeaderKey(), String.valueOf(BlackUrlBypass.isBlackUrl()));
53+
if (HttpClient.matchJavaNetUrl(this.matchedSignature)) {
54+
addHeaderToJavaNetURL(event, blackUrlHeaders);
55+
} else if (HttpClient.matchApacheHttp4(this.matchedSignature)
56+
|| HttpClient.matchApacheHttp5(this.matchedSignature)) {
57+
addHeaderToApacheHttpClient(event, blackUrlHeaders);
58+
} else if (HttpClient.matchApacheHttp3(this.matchedSignature)) {
59+
addHeaderToApacheHttpClientLegacy(event, blackUrlHeaders);
60+
} else if (HttpClient.matchOkhttp(this.matchedSignature)) {
61+
addHeaderToOkhttp(event, blackUrlHeaders);
62+
}
63+
}
64+
4765
private String addTraceToJavaNetURL(MethodEvent event) {
4866
if (event.objectInstance == null) {
4967
return null;
@@ -65,6 +83,24 @@ private String addTraceToJavaNetURL(MethodEvent event) {
6583
return null;
6684
}
6785

86+
private void addHeaderToJavaNetURL(MethodEvent event, Map<String, String> headers) {
87+
if (event.objectInstance == null) {
88+
return;
89+
}
90+
try {
91+
if (event.objectInstance instanceof HttpURLConnection) {
92+
final HttpURLConnection connection = (HttpURLConnection) event.objectInstance;
93+
for (Map.Entry<String, String> header : headers.entrySet()) {
94+
connection.setRequestProperty(header.getKey(), header.getValue());
95+
}
96+
}
97+
} catch (IllegalStateException ignore) {
98+
} catch (Throwable e) {
99+
DongTaiLog.debug("add header to okhttp client failed: {}, {}",
100+
e.getMessage(), e.getCause() != null ? e.getCause().getMessage() : "");
101+
}
102+
}
103+
68104
private String addTraceToApacheHttpClient(MethodEvent event) {
69105
if (event.parameterInstances.length < 2) {
70106
return null;
@@ -96,6 +132,38 @@ private String addTraceToApacheHttpClient(MethodEvent event) {
96132
return null;
97133
}
98134

135+
private void addHeaderToApacheHttpClient(MethodEvent event, Map<String, String> headers) {
136+
if (headers == null) {
137+
return;
138+
}
139+
if (event.parameterInstances.length < 2) {
140+
return;
141+
}
142+
Object obj = event.parameterInstances[1];
143+
if (obj == null) {
144+
return;
145+
}
146+
try {
147+
Method method;
148+
if (HttpClient.matchApacheHttp5(this.matchedSignature)) {
149+
method = ReflectUtils.getDeclaredMethodFromSuperClass(obj.getClass(),
150+
"addHeader", new Class[]{String.class, Object.class});
151+
} else {
152+
method = ReflectUtils.getDeclaredMethodFromSuperClass(obj.getClass(),
153+
"addHeader", new Class[]{String.class, String.class});
154+
}
155+
if (method == null) {
156+
return;
157+
}
158+
for (Map.Entry<String, String> header : headers.entrySet()) {
159+
method.invoke(obj, header.getKey(), header.getValue());
160+
}
161+
} catch (Throwable e) {
162+
DongTaiLog.debug("add header to okhttp client failed: {}, {}",
163+
e.getMessage(), e.getCause() != null ? e.getCause().getMessage() : "");
164+
}
165+
}
166+
99167
private String addTraceToApacheHttpClientLegacy(MethodEvent event) {
100168
Object obj = event.objectInstance;
101169
if (obj == null) {
@@ -118,6 +186,26 @@ private String addTraceToApacheHttpClientLegacy(MethodEvent event) {
118186
return null;
119187
}
120188

189+
private void addHeaderToApacheHttpClientLegacy(MethodEvent event, Map<String, String> headers) {
190+
Object obj = event.objectInstance;
191+
if (obj == null) {
192+
return;
193+
}
194+
try {
195+
Method method = ReflectUtils.getDeclaredMethodFromSuperClass(obj.getClass(),
196+
"setRequestHeader", new Class[]{String.class, String.class});
197+
if (method == null) {
198+
return;
199+
}
200+
for (Map.Entry<String, String> header : headers.entrySet()) {
201+
method.invoke(obj, header.getKey(), header.getValue());
202+
}
203+
} catch (Throwable e) {
204+
DongTaiLog.debug("add header to okhttp client failed: {}, {}"
205+
, e.getMessage(), e.getCause() != null ? e.getCause().getMessage() : "");
206+
}
207+
}
208+
121209
private String addTraceToOkhttp(MethodEvent event) {
122210
Object obj = event.objectInstance;
123211
if (obj == null) {
@@ -153,6 +241,38 @@ private String addTraceToOkhttp(MethodEvent event) {
153241
return null;
154242
}
155243

244+
private void addHeaderToOkhttp(MethodEvent event, Map<String, String> headers) {
245+
Object obj = event.objectInstance;
246+
if (obj == null) {
247+
return;
248+
}
249+
try {
250+
String className = obj.getClass().getName();
251+
if (!HttpClient.matchAllOkhttpCallClass(className)) {
252+
return;
253+
}
254+
255+
Field reqField = obj.getClass().getDeclaredField("originalRequest");
256+
boolean accessible = reqField.isAccessible();
257+
reqField.setAccessible(true);
258+
Object req = reqField.get(obj);
259+
260+
Method methodNewBuilder = req.getClass().getMethod("newBuilder");
261+
Object reqBuilder = methodNewBuilder.invoke(req);
262+
Method methodAddHeader = reqBuilder.getClass().getMethod("addHeader", String.class, String.class);
263+
for (Map.Entry<String, String> header : headers.entrySet()) {
264+
methodAddHeader.invoke(reqBuilder, header.getKey(), header.getValue());
265+
}
266+
Method methodBuild = reqBuilder.getClass().getMethod("build");
267+
Object newReq = methodBuild.invoke(reqBuilder);
268+
reqField.set(obj, newReq);
269+
reqField.setAccessible(accessible);
270+
} catch (Throwable e) {
271+
DongTaiLog.debug("add header to okhttp client failed: {}, {}",
272+
e.getMessage(), e.getCause() != null ? e.getCause().getMessage() : "");
273+
}
274+
}
275+
156276
public static boolean validate(MethodEvent event) {
157277
if (HttpClient.matchJavaNetUrl(event.signature)) {
158278
return validateURLConnection(event);

dongtai-spy/src/main/java/java/lang/dongtai/NopSpy.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,4 +272,9 @@ public boolean isSkipCollectFeign(Object instance) {
272272
return false;
273273
}
274274

275+
@Override
276+
public boolean skipCollect(Object instance, Object[] parameters, Object retObject, String methodMatcher, String className, String matchedClassName, String methodName, String signature, boolean isStatic) {
277+
return false;
278+
}
279+
275280
}

dongtai-spy/src/main/java/java/lang/dongtai/SpyDispatcher.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,4 +174,8 @@ boolean traceDubboInvoke(Object instance, String url, Object invocation, Object[
174174
boolean isSkipCollectDubbo(Object invocation);
175175

176176
boolean isSkipCollectFeign(Object instance);
177+
178+
boolean skipCollect(Object instance, Object[] parameters, Object retObject, String methodMatcher,
179+
String className, String matchedClassName, String methodName, String signature,
180+
boolean isStatic);
177181
}

0 commit comments

Comments
 (0)