Code-Racing / brickyard

0 stars 0 forks source link

CONTRAST: Unchecked readLine() #31

Open valvolineford opened 4 years ago

valvolineford commented 4 years ago

Vulnerability ID: 01FL-38LU-J1NX-L6Y0

Application Name: AgentMessageGeneratorJava

Vulnerability Link: http://localhost:19080/Contrast/static/ng/index.html#/7c6cfec5-a187-4d5e-984a-d11d96d2ef63/applications/6394f24f-037b-43bb-8ac2-05fa5fb5d862/vulns/01FL-38LU-J1NX-L6Y0

What Happened?

We tracked the following data from "param" Parameter:

GET /grizzly/readline?param=testdata

...which was accessed within the following code:

global#unmakeCookie(), line 69

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

str = reader.readLine()

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:
  global.getCookieValue(/app/vulnerabilities/serialization/index.js:61)
  global.(/app/vulnerabilities/serialization/index.js:36)
  Layer.handle(/app/node_modules/express/lib/router/layer.js:96)
  next(/app/node_modules/express/lib/router/route.js:138)
  Route.dispatch(/app/node_modules/express/lib/router/route.js:113)
  Layer.handle(/app/node_modules/express/lib/router/layer.js:96)
  (/app/node_modules/express/lib/router/index.js:279)
  Function.process_params(/app/node_modules/express/lib/router/index.js:332)
  next(/app/node_modules/express/lib/router/index.js:273)
  Layer.handle(/app/node_modules/express/lib/router/layer.js:96)
  trim_prefix(/app/node_modules/express/lib/router/index.js:314)
  (/app/node_modules/express/lib/router/index.js:282)
  Function.process_params(/app/node_modules/express/lib/router/index.js:332)
  next(/app/node_modules/express/lib/router/index.js:273)
  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:
  global.exports.unserialize(/app/node_modules/node-serialize/lib/serialize.js:76)
  global.unmakeCookie(/app/vulnerabilities/serialization/index.js:69)
  global.getCookieValue(/app/vulnerabilities/serialization/index.js:61)
  global.(/app/vulnerabilities/serialization/index.js:36)
  Layer.handle(/app/node_modules/express/lib/router/layer.js:96)
  next(/app/node_modules/express/lib/router/route.js:138)
  Route.dispatch(/app/node_modules/express/lib/router/route.js:113)
  Layer.handle(/app/node_modules/express/lib/router/layer.js:96)
  (/app/node_modules/express/lib/router/index.js:279)
  Function.process_params(/app/node_modules/express/lib/router/index.js:332)
  next(/app/node_modules/express/lib/router/index.js:273)
  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