mirror of
https://github.com/github/codeql.git
synced 2026-05-01 19:55:15 +02:00
Add unsafe-deserialization support for Jabsorb
This is partly extracted from https://github.com/github/codeql/pull/5954
This commit is contained in:
121
java/ql/test/query-tests/security/CWE-502/JabsorbServlet.java
Normal file
121
java/ql/test/query-tests/security/CWE-502/JabsorbServlet.java
Normal file
@@ -0,0 +1,121 @@
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.jabsorb.JSONSerializer;
|
||||
import org.jabsorb.serializer.SerializerState;
|
||||
import org.jabsorb.serializer.ObjectMatch;
|
||||
|
||||
import com.example.User;
|
||||
import com.thirdparty.Person;
|
||||
|
||||
public class JabsorbServlet extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
// GOOD: final class type specified
|
||||
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
String json = req.getParameter("json");
|
||||
String clazz = req.getParameter("class");
|
||||
|
||||
try {
|
||||
Object jsonObject = new JSONObject(json);
|
||||
|
||||
JSONSerializer serializer = new JSONSerializer();
|
||||
serializer.registerDefaultSerializers();
|
||||
|
||||
serializer.setMarshallClassHints(true);
|
||||
serializer.setMarshallNullAttributes(true);
|
||||
|
||||
SerializerState state = new SerializerState();
|
||||
User user = (User) serializer.unmarshall(state, User.class, jsonObject);
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// GOOD: concrete class type specified even if it has vulnerable subclasses
|
||||
public void doHead(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
String json = req.getParameter("json");
|
||||
String clazz = req.getParameter("class");
|
||||
|
||||
try {
|
||||
Object jsonObject = new JSONObject(json);
|
||||
|
||||
JSONSerializer serializer = new JSONSerializer();
|
||||
serializer.registerDefaultSerializers();
|
||||
|
||||
serializer.setMarshallClassHints(true);
|
||||
serializer.setMarshallNullAttributes(true);
|
||||
|
||||
SerializerState state = new SerializerState();
|
||||
Person person = (Person) serializer.unmarshall(state, Person.class, jsonObject);
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
// GOOD: try unmarshall but doesn't actually marshall the object
|
||||
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
String json = req.getParameter("json");
|
||||
String clazz = req.getParameter("class");
|
||||
|
||||
try {
|
||||
Object jsonObject = new JSONObject(json);
|
||||
|
||||
JSONSerializer serializer = new JSONSerializer();
|
||||
serializer.registerDefaultSerializers();
|
||||
|
||||
serializer.setMarshallClassHints(true);
|
||||
serializer.setMarshallNullAttributes(true);
|
||||
|
||||
SerializerState state = new SerializerState();
|
||||
ObjectMatch objMatch = serializer.tryUnmarshall(state, Class.forName(clazz), jsonObject);
|
||||
User obj = new User();
|
||||
boolean result = objMatch.equals(obj);
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
// BAD: allow class name to be controlled by remote source
|
||||
public void doPut(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
String json = req.getParameter("json");
|
||||
String clazz = req.getParameter("class");
|
||||
|
||||
try {
|
||||
Object jsonObject = new JSONObject(json);
|
||||
|
||||
JSONSerializer serializer = new JSONSerializer();
|
||||
serializer.registerDefaultSerializers();
|
||||
|
||||
serializer.setMarshallClassHints(true);
|
||||
serializer.setMarshallNullAttributes(true);
|
||||
|
||||
SerializerState state = new SerializerState();
|
||||
User user = (User) serializer.unmarshall(state, Class.forName(clazz), jsonObject); // $unsafeDeserialization
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// BAD: allow explicit class type controlled by remote source in the format of "json={\"javaClass\":\"com.thirdparty.Attacker\", ...}"
|
||||
public void doPut2(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
String json = req.getParameter("json");
|
||||
|
||||
try {
|
||||
JSONSerializer serializer = new JSONSerializer();
|
||||
serializer.registerDefaultSerializers();
|
||||
|
||||
User user = (User) serializer.fromJSON(json); // $unsafeDeserialization
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
29
java/ql/test/query-tests/security/CWE-502/Person.java
Normal file
29
java/ql/test/query-tests/security/CWE-502/Person.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package com.thirdparty;
|
||||
|
||||
public class Person {
|
||||
private int snum;
|
||||
private String name;
|
||||
|
||||
public Person() {
|
||||
}
|
||||
|
||||
public int getSnum() {
|
||||
return snum;
|
||||
}
|
||||
|
||||
public void setSnum(int snum) {
|
||||
this.snum = snum;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Person[ name = "+name+", snum: "+snum+ "]";
|
||||
}
|
||||
}
|
||||
29
java/ql/test/query-tests/security/CWE-502/User.java
Normal file
29
java/ql/test/query-tests/security/CWE-502/User.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package com.example;
|
||||
|
||||
public final class User {
|
||||
private String uid;
|
||||
private String name;
|
||||
|
||||
public User() {
|
||||
}
|
||||
|
||||
public String getUid() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
public void setUid(String uid) {
|
||||
this.uid = uid;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "User[ name = "+name+", uid: "+uid+ "]";
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/snakeyaml-1.21:${testdir}/../../../stubs/xstream-1.4.10:${testdir}/../../../stubs/kryo-4.0.2:${testdir}/../../../stubs/jsr311-api-1.1.1:${testdir}/../../../stubs/fastjson-1.2.74:${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/jyaml-1.3:${testdir}/../../../stubs/json-io-4.10.0:${testdir}/../../../stubs/yamlbeans-1.09:${testdir}/../../../stubs/hessian-4.0.38:${testdir}/../../../stubs/castor-1.4.1:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/jackson-core-2.12
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/snakeyaml-1.21:${testdir}/../../../stubs/xstream-1.4.10:${testdir}/../../../stubs/kryo-4.0.2:${testdir}/../../../stubs/jsr311-api-1.1.1:${testdir}/../../../stubs/fastjson-1.2.74:${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/jyaml-1.3:${testdir}/../../../stubs/json-io-4.10.0:${testdir}/../../../stubs/yamlbeans-1.09:${testdir}/../../../stubs/hessian-4.0.38:${testdir}/../../../stubs/castor-1.4.1:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/jackson-core-2.12:${testdir}/../../../stubs/jabsorb-1.3.2:${testdir}/../../../stubs/json-java-20210307
|
||||
|
||||
Reference in New Issue
Block a user