Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add tracing java net url header for http service #453

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package io.dongtai.iast.core.handler.hookpoint.service;

import java.util.*;

public class HttpClient {
private static final String JAVA_NET_URL_CONN = "sun.net.www.protocol.http.HttpURLConnection.connect()";
private static final String JAVA_NET_URL_CONN_GET_INPUT_STREAM = "sun.net.www.protocol.http.HttpURLConnection.getInputStream()";
private static final String JAVA_NET_URL_CONN_GET_OUTPUT_STREAM = "sun.net.www.protocol.http.HttpURLConnection.getOutputStream()";
private static final String APACHE_LEGACY_HTTP_CLIENT_REQUEST_SET_URI = " org.apache.commons.httpclient.HttpMethodBase.setURI(org.apache.commons.httpclient.URI)".substring(1);
private static final String APACHE_HTTP_CLIENT_REQUEST_SET_URI = " org.apache.http.client.methods.HttpRequestBase.setURI(java.net.URI)".substring(1);
private static final String APACHE_HTTP_CLIENT5_EXECUTE = " org.apache.hc.client5.http.impl.classic.CloseableHttpClient.doExecute(org.apache.hc.core5.http.HttpHost,org.apache.hc.core5.http.ClassicHttpRequest,org.apache.hc.core5.http.protocol.HttpContext)".substring(1);
private static final String OKHTTP_CALL_EXECUTE = "com.squareup.okhttp.Call.execute()";
private static final String OKHTTP_CALL_ENQUEUE = "com.squareup.okhttp.Call.enqueue(com.squareup.okhttp.Callback)";
private static final String OKHTTP3_CALL_EXECUTE = "okhttp3.Call.execute()";
private static final String OKHTTP3_CALL_ENQUEUE = "okhttp3.Call.enqueue(okhttp3.Callback)";

public static final String APACHE_LEGACY_HTTP_CLIENT_URI = " org.apache.commons.httpclient.URI".substring(1);
public static final String APACHE_HTTP_CLIENT5_REQUEST_INTERFACE = " org.apache.hc.core5.http.HttpRequest".substring(1);

private static final String OKHTTP_CALL = "com.squareup.okhttp.Call";
private static final String OKHTTP3_REAL_CALL = "okhttp3.RealCall";
// okhttp v4.x
private static final String OKHTTP3_INTERNAL_REAL_CALL = "okhttp3.internal.connection.RealCall";

private static final Set<String> SIGNATURE = new HashSet<String>(Arrays.asList(
JAVA_NET_URL_CONN,
JAVA_NET_URL_CONN_GET_INPUT_STREAM,
JAVA_NET_URL_CONN_GET_OUTPUT_STREAM,
APACHE_LEGACY_HTTP_CLIENT_REQUEST_SET_URI,
APACHE_HTTP_CLIENT_REQUEST_SET_URI,
APACHE_HTTP_CLIENT5_EXECUTE,
OKHTTP_CALL_EXECUTE,
OKHTTP_CALL_ENQUEUE,
OKHTTP3_CALL_EXECUTE,
OKHTTP3_CALL_ENQUEUE
));

private static final Set<String> JAVA_NET_URL_SIGNATURE = new HashSet<String>(Arrays.asList(
JAVA_NET_URL_CONN,
JAVA_NET_URL_CONN_GET_INPUT_STREAM,
JAVA_NET_URL_CONN_GET_OUTPUT_STREAM
));

private static final Set<String> OKHTTP_SIGNATURE = new HashSet<String>(Arrays.asList(
OKHTTP_CALL_EXECUTE,
OKHTTP_CALL_ENQUEUE,
OKHTTP3_CALL_EXECUTE,
OKHTTP3_CALL_ENQUEUE
));

private static final Set<String> OKHTTP_CALL_CLASS = new HashSet<String>(Arrays.asList(
OKHTTP_CALL,
OKHTTP3_REAL_CALL,
OKHTTP3_INTERNAL_REAL_CALL
));

public static boolean match(String signature) {
return SIGNATURE.contains(signature);
}

public static boolean matchJavaNetUrl(String signature) {
return JAVA_NET_URL_SIGNATURE.contains(signature);
}

public static boolean matchApacheHttp3(String signature) {
return APACHE_LEGACY_HTTP_CLIENT_REQUEST_SET_URI.equals(signature);
}

public static boolean matchApacheHttp4(String signature) {
return APACHE_HTTP_CLIENT_REQUEST_SET_URI.equals(signature);
}

public static boolean matchApacheHttp5(String signature) {
return APACHE_HTTP_CLIENT5_EXECUTE.equals(signature);
}

public static boolean matchOkhttp(String signature) {
return OKHTTP_SIGNATURE.contains(signature);
}

public static boolean matchAllOkhttpCallClass(String className) {
return OKHTTP_CALL_CLASS.contains(className);
}

public static boolean matchLegacyOkhttpCallClass(String className) {
return OKHTTP_CALL.equals(className);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,15 @@
import io.dongtai.iast.core.handler.hookpoint.models.MethodEvent;
import io.dongtai.iast.core.handler.hookpoint.models.policy.PolicyNode;
import io.dongtai.iast.core.handler.hookpoint.models.policy.SignatureMethodMatcher;
import io.dongtai.iast.core.handler.hookpoint.service.HttpClient;
import io.dongtai.iast.core.utils.ReflectUtils;
import io.dongtai.log.DongTaiLog;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.util.*;

public class HttpService implements ServiceTrace {
private static final String JAVA_NET_URL_CONN = "sun.net.www.protocol.http.HttpURLConnection.connect()";
private static final String JAVA_NET_URL_CONN_GET_INPUT_STREAM = "sun.net.www.protocol.http.HttpURLConnection.getInputStream()";
private static final String APACHE_LEGACY_HTTP_CLIENT_REQUEST_SET_URI = " org.apache.commons.httpclient.HttpMethodBase.setURI(org.apache.commons.httpclient.URI)".substring(1);
private static final String APACHE_HTTP_CLIENT_REQUEST_SET_URI = " org.apache.http.client.methods.HttpRequestBase.setURI(java.net.URI)".substring(1);
private static final String APACHE_HTTP_CLIENT5_EXECUTE = " org.apache.hc.client5.http.impl.classic.CloseableHttpClient.doExecute(org.apache.hc.core5.http.HttpHost,org.apache.hc.core5.http.ClassicHttpRequest,org.apache.hc.core5.http.protocol.HttpContext)".substring(1);
private static final String OKHTTP_CALL_EXECUTE = "com.squareup.okhttp.Call.execute()";
private static final String OKHTTP3_CALL_EXECUTE = "okhttp3.Call.execute()";

// okhttp v4.x
private static final String OKHTTP3_INTERNAL_REAL_CALL = "okhttp3.internal.connection.RealCall";
private static final String OKHTTP3_REAL_CALL = "okhttp3.RealCall";
private static final String OKHTTP_CALL = "com.squareup.okhttp.Call";

private static final Set<String> SIGNATURE = new HashSet<String>(Arrays.asList(
JAVA_NET_URL_CONN,
JAVA_NET_URL_CONN_GET_INPUT_STREAM,
APACHE_LEGACY_HTTP_CLIENT_REQUEST_SET_URI,
APACHE_HTTP_CLIENT_REQUEST_SET_URI,
APACHE_HTTP_CLIENT5_EXECUTE,
OKHTTP_CALL_EXECUTE,
OKHTTP3_CALL_EXECUTE
));

private String matchedSignature;

@Override
Expand All @@ -44,22 +21,20 @@ public boolean match(MethodEvent event, PolicyNode policyNode) {
this.matchedSignature = ((SignatureMethodMatcher) policyNode.getMethodMatcher()).getSignature().toString();
}

return SIGNATURE.contains(this.matchedSignature);
return HttpClient.match(this.matchedSignature);
}

@Override
public void addTrace(MethodEvent event, PolicyNode policyNode) {
String traceId = null;
if (JAVA_NET_URL_CONN.equals(this.matchedSignature)
|| JAVA_NET_URL_CONN_GET_INPUT_STREAM.equals(this.matchedSignature)) {
if (HttpClient.matchJavaNetUrl(this.matchedSignature)) {
traceId = addTraceToJavaNetURL(event);
} else if (APACHE_HTTP_CLIENT5_EXECUTE.equals(this.matchedSignature)
|| APACHE_HTTP_CLIENT_REQUEST_SET_URI.equals(this.matchedSignature)) {
} else if (HttpClient.matchApacheHttp4(this.matchedSignature)
|| HttpClient.matchApacheHttp5(this.matchedSignature)) {
traceId = addTraceToApacheHttpClient(event);
} else if (APACHE_LEGACY_HTTP_CLIENT_REQUEST_SET_URI.equals(this.matchedSignature)) {
} else if (HttpClient.matchApacheHttp3(this.matchedSignature)) {
traceId = addTraceToApacheHttpClientLegacy(event);
} else if (OKHTTP_CALL_EXECUTE.equals(this.matchedSignature)
|| OKHTTP3_CALL_EXECUTE.equals(this.matchedSignature)) {
} else if (HttpClient.matchOkhttp(this.matchedSignature)) {
traceId = addTraceToOkhttp(event);
}

Expand Down Expand Up @@ -88,7 +63,7 @@ private String addTraceToJavaNetURL(MethodEvent event) {

private String addTraceToApacheHttpClient(MethodEvent event) {
Object obj;
if (APACHE_HTTP_CLIENT5_EXECUTE.equals(this.matchedSignature)) {
if (HttpClient.matchApacheHttp5(this.matchedSignature)) {
obj = event.parameterInstances[1];
} else {
obj = event.objectInstance;
Expand All @@ -98,7 +73,7 @@ private String addTraceToApacheHttpClient(MethodEvent event) {
}
try {
Method method;
if (APACHE_HTTP_CLIENT5_EXECUTE.equals(this.matchedSignature)) {
if (HttpClient.matchApacheHttp5(this.matchedSignature)) {
method = ReflectUtils.getDeclaredMethodFromSuperClass(obj.getClass(),
"addHeader", new Class[]{String.class, Object.class});
} else {
Expand Down Expand Up @@ -144,8 +119,7 @@ private String addTraceToOkhttp(MethodEvent event) {
}
try {
String className = obj.getClass().getName();
if (!OKHTTP3_REAL_CALL.equals(className) && !OKHTTP3_INTERNAL_REAL_CALL.equals(className)
&& !OKHTTP_CALL.equals(className)) {
if (!HttpClient.matchAllOkhttpCallClass(className)) {
return null;
}

Expand All @@ -171,8 +145,7 @@ private String addTraceToOkhttp(MethodEvent event) {
}

public static boolean validateURLConnection(MethodEvent event) {
if (!JAVA_NET_URL_CONN_GET_INPUT_STREAM.equals(event.signature)
&& !JAVA_NET_URL_CONN.equals(event.signature)) {
if (!HttpClient.matchJavaNetUrl(event.signature)) {
return true;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package io.dongtai.iast.core.handler.hookpoint.vulscan.dynamic;

import io.dongtai.iast.core.handler.context.ContextManager;
import io.dongtai.iast.core.handler.hookpoint.models.MethodEvent;
import io.dongtai.iast.core.handler.hookpoint.models.policy.SignatureMethodMatcher;
import io.dongtai.iast.core.handler.hookpoint.models.policy.SinkNode;
import io.dongtai.iast.core.handler.hookpoint.service.HttpClient;
import io.dongtai.iast.core.utils.*;
import io.dongtai.log.DongTaiLog;
import sun.net.www.MessageHeader;

import java.lang.reflect.*;
import java.net.URI;
Expand All @@ -13,36 +16,6 @@

public class SSRFSourceCheck implements SinkSourceChecker {
public final static String SINK_TYPE = "ssrf";

private static final String JAVA_NET_URL_CONN = "sun.net.www.protocol.http.HttpURLConnection.connect()";
private static final String JAVA_NET_URL_CONN_GET_INPUT_STREAM = "sun.net.www.protocol.http.HttpURLConnection.getInputStream()";
private static final String APACHE_HTTP_CLIENT_REQUEST_SET_URI = " org.apache.http.client.methods.HttpRequestBase.setURI(java.net.URI)".substring(1);
private static final String APACHE_LEGACY_HTTP_CLIENT_REQUEST_SET_URI = " org.apache.commons.httpclient.HttpMethodBase.setURI(org.apache.commons.httpclient.URI)".substring(1);
private static final String APACHE_HTTP_CLIENT5_EXECUTE = " org.apache.hc.client5.http.impl.classic.CloseableHttpClient.doExecute(org.apache.hc.core5.http.HttpHost,org.apache.hc.core5.http.ClassicHttpRequest,org.apache.hc.core5.http.protocol.HttpContext)".substring(1);
private static final String OKHTTP3_CALL_EXECUTE = "okhttp3.Call.execute()";
private static final String OKHTTP3_CALL_ENQUEUE = "okhttp3.Call.enqueue(okhttp3.Callback)";
private static final String OKHTTP_CALL_EXECUTE = "com.squareup.okhttp.Call.execute()";
private static final String OKHTTP_CALL_ENQUEUE = "com.squareup.okhttp.Call.enqueue(com.squareup.okhttp.Callback)";

private static final String APACHE_LEGACY_HTTP_CLIENT_URI = " org.apache.commons.httpclient.URI".substring(1);
private static final String APACHE_HTTP_CLIENT5_REQUEST_INTERFACE = " org.apache.hc.core5.http.HttpRequest".substring(1);
// okhttp v4.x
private static final String OKHTTP3_INTERNAL_REAL_CALL = "okhttp3.internal.connection.RealCall";
private static final String OKHTTP3_REAL_CALL = "okhttp3.RealCall";
private static final String OKHTTP_CALL = "com.squareup.okhttp.Call";

private static final Set<String> SSRF_SINK_METHODS = new HashSet<String>(Arrays.asList(
JAVA_NET_URL_CONN,
JAVA_NET_URL_CONN_GET_INPUT_STREAM,
APACHE_HTTP_CLIENT_REQUEST_SET_URI,
APACHE_LEGACY_HTTP_CLIENT_REQUEST_SET_URI,
APACHE_HTTP_CLIENT5_EXECUTE,
OKHTTP3_CALL_EXECUTE,
OKHTTP3_CALL_ENQUEUE,
OKHTTP_CALL_EXECUTE,
OKHTTP_CALL_ENQUEUE
));

private String policySignature;

@Override
Expand All @@ -51,41 +24,60 @@ public boolean match(MethodEvent event, SinkNode sinkNode) {
this.policySignature = ((SignatureMethodMatcher) sinkNode.getMethodMatcher()).getSignature().toString();
}

return SINK_TYPE.equals(sinkNode.getVulType()) && SSRF_SINK_METHODS.contains(this.policySignature);
return SINK_TYPE.equals(sinkNode.getVulType()) && HttpClient.match(this.policySignature);
}

@Override
public boolean checkSource(MethodEvent event, SinkNode sinkNode) {
boolean hitTaintPool = false;
if (JAVA_NET_URL_CONN.equals(this.policySignature) || JAVA_NET_URL_CONN_GET_INPUT_STREAM.equals(this.policySignature)) {
if (HttpClient.matchJavaNetUrl(this.policySignature)) {
return checkJavaNetURL(event, sinkNode);
} else if (APACHE_HTTP_CLIENT_REQUEST_SET_URI.equals(this.policySignature)
|| APACHE_LEGACY_HTTP_CLIENT_REQUEST_SET_URI.equals(this.policySignature)) {
} else if (HttpClient.matchApacheHttp3(this.policySignature)
|| HttpClient.matchApacheHttp4(this.policySignature)) {
return checkApacheHttpClient(event, sinkNode);
} else if (APACHE_HTTP_CLIENT5_EXECUTE.equals(this.policySignature)) {
} else if (HttpClient.matchApacheHttp5(this.policySignature)) {
return checkApacheHttpClient5(event, sinkNode);
} else if (OKHTTP3_CALL_EXECUTE.equals(this.policySignature)
|| OKHTTP3_CALL_ENQUEUE.equals(this.policySignature)
|| OKHTTP_CALL_EXECUTE.equals(this.policySignature)
|| OKHTTP_CALL_ENQUEUE.equals(this.policySignature)) {
} else if (HttpClient.matchOkhttp(this.policySignature)) {
return CheckOkhttp(event, sinkNode);
}
return hitTaintPool;
}

private boolean processJavaNetUrl(MethodEvent event, Object u) {
private boolean processJavaNetUrl(MethodEvent event, Object conn, Object u) {
try {
if (!(u instanceof URL)) {
return false;
}

List<String> headerList = new ArrayList<String>();
try {
Field userHeadersField = ReflectUtils.getDeclaredFieldFromSuperClassByName(conn.getClass(), "userHeaders");
if (userHeadersField == null) {
return false;
}
userHeadersField.setAccessible(true);
Object userHeaders = userHeadersField.get(conn);
if (userHeaders instanceof MessageHeader) {
Map<String, List<String>> headers = ((MessageHeader) userHeaders).getHeaders();
for (Map.Entry<String, List<String>> header : headers.entrySet()) {
if (header.getKey().equals(ContextManager.getHeaderKey())) {
continue;
}
headerList.add(header.getKey());
headerList.addAll(header.getValue());
}
}
} catch (Throwable ignore) {
}

final URL url = (URL) u;
Map<String, Object> sourceMap = new HashMap<String, Object>() {{
put("PROTOCOL", url.getProtocol());
put("USERINFO", url.getUserInfo());
put("HOST", url.getHost());
put("PATH", url.getPath());
put("QUERY", url.getQuery());
put("HEADER", headerList);
}};

event.setObjectValue(url, true);
Expand Down Expand Up @@ -133,7 +125,7 @@ private boolean checkJavaNetURL(MethodEvent event, SinkNode sinkNode) {

Object u = getURLMethod.invoke(conn);

return processJavaNetUrl(event, u);
return processJavaNetUrl(event, conn, u);
} catch (IllegalAccessException ignore) {
} catch (InvocationTargetException ignore) {
}
Expand All @@ -149,7 +141,7 @@ private boolean checkApacheHttpClient(MethodEvent event, SinkNode sinkNode) {
final Object obj = event.parameterInstances[0];
if (obj instanceof URI) {
return processJavaNetUri(event, obj);
} else if (APACHE_LEGACY_HTTP_CLIENT_URI.equals(obj.getClass().getName())) {
} else if (HttpClient.APACHE_LEGACY_HTTP_CLIENT_URI.equals(obj.getClass().getName())) {
Map<String, Object> sourceMap = new HashMap<String, Object>() {{
put("PROTOCOL", obj.getClass().getMethod("getRawScheme").invoke(obj));
put("USERINFO", obj.getClass().getMethod("getRawUserinfo").invoke(obj));
Expand All @@ -176,7 +168,7 @@ private boolean checkApacheHttpClient5(MethodEvent event, SinkNode sinkNode) {
}

final Object reqObj = event.parameterInstances[1];
if (ReflectUtils.isImplementsInterface(reqObj.getClass(), APACHE_HTTP_CLIENT5_REQUEST_INTERFACE)) {
if (ReflectUtils.isImplementsInterface(reqObj.getClass(), HttpClient.APACHE_HTTP_CLIENT5_REQUEST_INTERFACE)) {
final Object authorityObj = reqObj.getClass().getMethod("getAuthority").invoke(reqObj);
Map<String, Object> sourceMap = new HashMap<String, Object>() {{
put("PROTOCOL", reqObj.getClass().getMethod("getScheme").invoke(reqObj));
Expand All @@ -201,14 +193,13 @@ private boolean checkApacheHttpClient5(MethodEvent event, SinkNode sinkNode) {
private boolean CheckOkhttp(MethodEvent event, SinkNode sinkNode) {
try {
Class<?> cls = event.objectInstance.getClass();
if (OKHTTP3_REAL_CALL.equals(cls.getName()) || OKHTTP3_INTERNAL_REAL_CALL.equals(cls.getName())
|| OKHTTP_CALL.equals(cls.getName())) {
if (HttpClient.matchAllOkhttpCallClass(cls.getName())) {
Object url;

Field reqField = cls.getDeclaredField("originalRequest");
reqField.setAccessible(true);
Object req = reqField.get(event.objectInstance);
if (OKHTTP_CALL.equals(cls.getName())) {
if (HttpClient.matchLegacyOkhttpCallClass(cls.getName())) {
url = req.getClass().getMethod("httpUrl").invoke(req);
} else {
url = req.getClass().getMethod("url").invoke(req);
Expand Down Expand Up @@ -253,7 +244,8 @@ private boolean addSourceType(MethodEvent event, Map<String, Object> sourceMap)
boolean hit = false;
event.sourceTypes = new ArrayList<MethodEvent.MethodEventSourceType>();
for (Map.Entry<String, Object> entry : sourceMap.entrySet()) {
if (entry.getKey().equals("QUERY") && entry.getValue() instanceof List) {
if (("QUERY".equals(entry.getKey()) || "HEADER".equals(entry.getKey()))
&& entry.getValue() != null && entry.getValue() instanceof List) {
for (Object q : (List) entry.getValue()) {
checkTaintPool(event, entry.getKey(), q);
}
Expand Down