Code-Racing / brickyard

0 stars 0 forks source link

CONTRAST: Unchecked readLine() #115

Open valvolineford opened 4 years ago

valvolineford commented 4 years ago

Vulnerability ID: GM10-HEUV-ZSBO-ZC12

Application Name: JavaThree

Application Code: JAVA3

Vulnerability Link: http://localhost:19080/Contrast/static/ng/index.html#/7c6cfec5-a187-4d5e-984a-d11d96d2ef63/applications/0ef9bd52-f372-4751-a215-cf25f9945c6a/vulns/GM10-HEUV-ZSBO-ZC12

What Happened?

We tracked the following data from "param" Parameter:

GET /grizzly/readline?param=testdata

...which was accessed within the following code:

com.contrastsecurity.bufferedreader.readline.UnsafeReadlineHandler#service(), line 26

...and ended up being consumed (through a reader object) by a method which reads until a newline is encountered:

java.io.BufferedReader@61a627ac

What's the risk?

The application calls the dangerous readLine() method on a stream of data that is controlled by the user. This method reads data until a newline character is encountered. A user can supply a never-ending stream of bytes and never provide a newline, and consume all of the available system memory, eventually taking down the container.

Recommendation

The most obvious way to prevent an unchecked read is to put a control around how many bytes or characters can be read from a given stream before giving up.

Here's an example of a "readLine()" replacement that implements such a control. This was adapted from the ESAPI library (BSD license): public String safeReadLine(InputStream in, int max) { if (max <= 0) { throw new IllegalArgumentException( "Invalid readline. Must read a positive number of bytes from the stream"); } StringBuilder sb = new StringBuilder(); int count = 0; int c; try { while (true) { c = in.read(); if ( c == -1 ) { if (sb.length() == 0) { return null; } break; } if (c == '\n' || c == '\r') { break; } count++; if (count > max) { throw new IllegalArgumentException("Invalid readLine. Read more than maximum characters allowed (" + max + ")"); } sb.append((char) c); } return sb.toString(); } catch (IOException e) { throw new IllegalArgumentException( "Problem reading from input stream", e); } }

First Event


Stack:
  org.glassfish.grizzly.http.server.Request.getParameter(Request.java:1124)
  com.contrastsecurity.bufferedreader.readline.UnsafeReadlineHandler.service(UnsafeReadlineHandler.java:25)
  org.glassfish.grizzly.http.server.HttpHandler$1.run(HttpHandler.java:224)
  org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:593)
  org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:573)
  java.lang.Thread.run(Thread.java:748)

Last Event


Stack:
  java.io.BufferedReader.readLine(BufferedReader.java:389)
  com.contrastsecurity.bufferedreader.readline.UnsafeReadlineHandler.service(UnsafeReadlineHandler.java:26)
  org.glassfish.grizzly.http.server.HttpHandler$1.run(HttpHandler.java:224)
  org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:593)
  org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:573)
  java.lang.Thread.run(Thread.java:748)

HTTP Request

GET http://localhost:32771/grizzly/readline?param=testdata HTTP/1.1 Contrast-Mq-Name: queue-000-BufferedReaderIT.it_tests_unsafe_readline-contrastsecurity-docker.jfrog.io/contrast/buffered-reader:rev1 Host: localhost:32771 Connection: Keep-Alive Accept-Encoding: gzip User-Agent: okhttp/3.9.1