Add unsafe-deserialization support for Jabsorb

This is partly extracted from https://github.com/github/codeql/pull/5954
This commit is contained in:
Chris Smowton
2021-08-04 15:35:50 +01:00
parent fe654dc8ee
commit 69549e9ce3
15 changed files with 887 additions and 31 deletions

View 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());
}
}
}

View 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+ "]";
}
}

View 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+ "]";
}
}

View File

@@ -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