Closed springkill closed 2 months ago
When I was analysing the tomcat application, I needed to use the org.apache.catalina.connector.RequestFacade.getParameterMap() method, and the obtained ParameterMap was tainted with taints, and the array obtained by ParameterMap.get() also The array obtained by ParameterMap.get() is also tainted, but when I remove an element from the array, the taint disappears.
I can't clearly understand what you're saying. And there are so many things circled in the chart that I don't know which to focus on. Would you be so kind as to illustrate with examples/current behavior/expected behavior?
The problem I'm trying to solve is, when the return value of the Map.get() method is an array, how do I mark the elements of the returned array with taints? For example, how do I make the elements in the "values" array in the doPost() method carry tags?
package org.owasp.benchmark.testcode;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(value="/cmdi-00/BenchmarkTest00004")
public class BenchmarkTest00004 extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
java.util.Map<String,String[]> map = request.getParameterMap();
String param = "";
if (!map.isEmpty()) {
String[] values = map.get("BenchmarkTest00004");
if (values != null) param = values[0];
}
org.owasp.benchmark.helpers.ThingInterface thing = org.owasp.benchmark.helpers.ThingFactory.createThing();
String bar = thing.doSomething(param);
String cmd = "";
String osName = System.getProperty("os.name");
if (osName.indexOf("Windows") != -1) {
cmd = org.owasp.benchmark.helpers.Utils.getOSCommandString("echo");
}
Runtime r = Runtime.getRuntime();
try {
Process p = r.exec(cmd + bar);
org.owasp.benchmark.helpers.Utils.printOSCommandResults(p, response);
} catch (IOException e) {
System.out.println("Problem executing cmdi - TestCase");
response.getWriter().println(
org.owasp.esapi.ESAPI.encoder().encodeForHTML(e.getMessage())
);
return;
}
}
}
I don't have your test environment and don't know how to reproduce your problem, in addition, you don't provide enough usable information (e.g. points-to-set, analysis options, complete analyzed program and complete taint-config.yml
). All of the above makes it difficult for me to think, validate and answer your question.
Please offer the following infomation (otherwise, I don't know how to proceed.):
org.apache.catalina.connector.RequestFacade
, org.apache.catalina.connector.Request
. (I don't even know what org.apache.catalina.connector.RequestFacade is and I'm not sure if what I searched for online is the same as yours either)pta-results.txt
, tai-e-plan.yml
, tai-e.log
in your output
directory.OK, I will describe my problem in detail. Here's the test code:
package org.owasp.benchmark.testcode;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(value="/cmdi-00/BenchmarkTest00016")
public class BenchmarkTest00016 extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
java.util.Map<String,String[]> map = request.getParameterMap();
String param = "";
if (!map.isEmpty()) {
String[] values = map.get("BenchmarkTest00016");
if (values != null) param = values[0];
}
String bar = doSomething(request, param);
String cmd = "";
String osName = System.getProperty("os.name");
if (osName.indexOf("Windows") != -1) {
cmd = org.owasp.benchmark.helpers.Utils.getOSCommandString("echo");
}
Runtime r = Runtime.getRuntime();
try {
Process p = r.exec(cmd + bar);
org.owasp.benchmark.helpers.Utils.printOSCommandResults(p, response);
} catch (IOException e) {
System.out.println("Problem executing cmdi - TestCase");
response.getWriter().println(
org.owasp.esapi.ESAPI.encoder().encodeForHTML(e.getMessage())
);
return;
}
} // end doPost
private static String doSomething(HttpServletRequest request, String param) throws ServletException, IOException {
String bar = param;
return bar;
}
}
At line 24 of this code, I use getParameterMap()
to get map
, the source method is doPost
and the tain is marked in org.apache.catalina.connector.RequestFacade
which implements HttpServletRequest
.
So if I want to propagate the taint, I need to use RequestFacade.getParameterMap()
as a transfer.
Like this:
- { method: "<org.apache.catalina.connector.RequestFacade: java.util.Map getParameterMap()>", from: base, to: result }
And in line 28 of this test code, I uses the Map.get()
method to get the value of a param, the value obtained is of array type, but since the return value of Map.get() is of type Object, there is no way for me to propagate the taint by using to: "result [*]"
, I can only use to: result
.
Like this:
- { method: "<org.apache.catalina.util.ParameterMap: java.lang.Object get(java.lang.Object)>", from: base, to: result }
After I did this, the taint propagated to the map
object on line 24 and from the map
object to the values
array on line 28, but not to the elements inside thevalues
array.
There is the source code of org.apache.catalina.connector.RequestFacade.getParameterMap()
.
public Map<String,String[]> getParameterMap() {
checkFacade();
if (Globals.IS_SECURITY_ENABLED) {
return AccessController.doPrivileged(new GetParameterMapPrivilegedAction());
} else {
return request.getParameterMap();
}
}
In line 7 of the above code request.getParameterMap()
is used, where request
is a filed of RequestFacade
of type org.apache.catalina.connector.Request
.
There is the source code of org.apache.catalina.connector.Request.getParameterMap()
:
public Map<String,String[]> getParameterMap() {
if (parameterMap.isLocked()) {
return parameterMap;
}
Enumeration<String> enumeration = getParameterNames();
while (enumeration.hasMoreElements()) {
String name = enumeration.nextElement();
String[] values = getParameterValues(name);
parameterMap.put(name, values);
}
parameterMap.setLocked(true);
return parameterMap;
}
I try to usr getParameterValues()
as transfer to tain the array in map, like this :
- { method: "<org.apache.catalina.connector.Request: java.lang.String[] getParameterValues(java.lang.String)>", from: base, to: "result[*]" }
But ultimately the tainflow is still undetectable.
Above is what I mentioned: how to pass taints to elements inside an array when the return value type of Map.get()
is an array?
tai-e.log
tai-e-plan.tml
:
- id: pta
options:
cs: 1-obj
only-app: false
implicit-entries: true
distinguish-string-constants: all
merge-string-objects: false
merge-string-builders: false
merge-exception-objects: false
handle-invokedynamic: false
propagate-types:
- reference
advanced: zipper
dump: false
dump-ci: false
dump-yaml: false
expected-file: null
reflection-inference: solar
reflection-log: null
taint-config: config/common/taint-config.yml
plugins:
- pascal.taie.analysis.pta.plugin.taint.TomcatHandler
time-limit: -1
pascal.taie.analysis.pta.plugin.taint.TomcatHandler
:
package pascal.taie.analysis.pta.plugin.taint;
import pascal.taie.World;
import pascal.taie.analysis.pta.core.cs.context.Context;
import pascal.taie.analysis.pta.core.cs.element.CSMethod;
import pascal.taie.analysis.pta.core.heap.HeapModel;
import pascal.taie.analysis.pta.core.heap.Obj;
import pascal.taie.analysis.pta.core.solver.EntryPoint;
import pascal.taie.analysis.pta.core.solver.Solver;
import pascal.taie.analysis.pta.core.solver.SpecifiedParamProvider;
import pascal.taie.analysis.pta.plugin.Plugin;
import pascal.taie.ir.IR;
import pascal.taie.ir.exp.Var;
import pascal.taie.language.classes.JClass;
import pascal.taie.language.classes.JMethod;
import pascal.taie.language.type.Type;
import java.util.List;
import static pascal.taie.analysis.pta.core.heap.Descriptor.ENTRY_DESC;
public class TomcatHandler implements Plugin {
private Solver solver;
private TaintManager manager;
private boolean isCalled;
final JClass requestFacade = World.get().getClassHierarchy().getClass("org.apache.catalina.connector.RequestFacade");
final JClass responseFacade = World.get().getClassHierarchy().getClass("org.apache.catalina.connector.ResponseFacade");
@Override
public void setSolver(Solver solver) {
this.solver = solver;
manager = new TaintManager(solver.getHeapModel());
}
@Override
public void onStart() {
List<JClass> list = solver.getHierarchy().applicationClasses().toList();
for (JClass jClass : list) {
String a = jClass.getName();
if (a.matches("^(javax\\.servlet\\.ServletRequest).+$")) {
System.out.println("found: " + a);
}
HeapModel heapModel = solver.getHeapModel();
jClass.getAnnotations().forEach(annotation -> {
if (annotation.getType().matches("javax.servlet.annotation.WebServlet")) {
jClass.getDeclaredMethods().forEach(jMethod -> {
if (jMethod.getName().matches("\\b(doGet|doPost|doPut|doDelete)\\b")) {
Type requestFacadeType = jMethod.getParamType(0);
Type responseFacadeType = jMethod.getParamType(1);
String requestFacadeAlloc = "<" + requestFacadeType.toString() + ">";
String responseFacadeAlloc = "<" + responseFacadeType.toString() + ">";
Obj mockRequest = heapModel.getMockObj(ENTRY_DESC, requestFacadeAlloc, requestFacade.getType(), jMethod);
Obj mockResponse = heapModel.getMockObj(ENTRY_DESC, responseFacadeAlloc, responseFacade.getType(), jMethod);
Obj mockServlet = heapModel.getMockObj(ENTRY_DESC, "<http-controller>", jClass.getType());
SpecifiedParamProvider paramProvider = new SpecifiedParamProvider.Builder(jMethod)
.addThisObj(mockServlet)
.addParamObj(0, mockRequest)
.addParamObj(1, mockResponse)
.build();
solver.addEntryPoint(new EntryPoint(jMethod, paramProvider));
}
});
}
}
);
}
}
@Override
public void onNewCSMethod(CSMethod csMethod) {
JMethod method = csMethod.getMethod();
Context context = csMethod.getContext();
boolean isDoMethod = method.getName().matches("\\b(doGet|doPost|doPut|doDelete)\\b");
if (isDoMethod) {
// System.out.println("find"+method.toString());
IR ir = method.getIR();
Var param = ir.getParam(0);
SourcePoint sourcePoint = new ParamSourcePoint(method, new IndexRef(IndexRef.Kind.VAR, 0, null));
Obj taint = manager.makeTaint(sourcePoint, param.getType());
solver.addVarPointsTo(context, param, taint);
}
}
}
You can download the full source code from here: https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-core/9.0.85
Thanks!
Hi, it's been a long time since I received a reply, is this question still being followed?
Sorry for the delay. Could you please share your entire Tai-e project with me, either via file upload or by providing a link to your GitHub repository? This will allow me to reproduce the issue with one-click.
Description
I used the following configuration:
When I use the return value of Map.get() directly as a sink, the taint is captured, but when I use the elements of the returned array, the taint is not added. The reality is that the specific problem is: When I was analysing the tomcat application, I needed to use the org.apache.catalina.connector.RequestFacade.getParameterMap() method, and the obtained ParameterMap was tainted with taints, and the array obtained by ParameterMap.get() also The array obtained by ParameterMap.get() is also tainted, but when I remove an element from the array, the taint disappears. I tried adding TRANSFER to the methods in the two images above, but still not getting the desired results.
Is there any way to fix this?