Wednesday, July 8, 2015

Upgrade Node.js to Avoid DoS Attack

TL;DR

If your are running Node.js v0.11.0 to v0.12.5 then you need to upgrade to v0.12.6 ASAP.



That's typically what happens with buffer exploits.

The Exploit

A bug in the way the V8 engine decodes UTF strings has been discovered. This impacts Node at the Buffer to UTF8 String conversion and can cause a process to crash. The security concern comes from the fact that a lot of data from outside of an application is delivered to Node via this mechanism which means that users can potentially deliver specially crafted input data that can cause an application to crash when it goes through this path. We know that most networking and filesystem operations are impacted as would be many user-land uses of Buffer to UTF8 String conversion.

Buffers

Here's some background information on how buffers work in NodeJS.

Buffers are instances of the Buffer class in node, which is designed to handle raw binary data. Each buffer corresponds to some raw memory allocated outside V8. Buffers act somewhat like arrays of integers, but aren’t resizable and have a whole bunch of methods specifically for binary data. In addition, the “integers” in a buffer each represent a byte and so are limited to values from 0 to 255 (2^8 – 1), inclusive.

There are a few ways to create new buffers:


var buffer = new Buffer(8);


This buffer is uninitialized and contains 8 bytes.


var buffer = new Buffer([ 8, 6, 7, 5, 3, 0, 9]);


This initializes the buffer to the contents of this array. Keep in mind that the contents of the array are integers representing bytes.


var buffer = new Buffer("I'm a string!", "utf-8")

Writing to Buffers

Given that there is already a buffer created:


var buffer = new Buffer(16);


We can start writing strings to it:


buffer.write("Hello", "utf-8")


The first argument to buffer.write is the string to write to the buffer, and the second argument is the string encoding. It happens to default to utf-8 so this argument is extraneous.

buffer.write returned 5. This means that we wrote to five bytes of the buffer. The fact that the string “Hello” is also 5 characters long is coincidental, since each character just happened to be 8 bits apiece. This is useful if you want to complete the message:


buffer.write(" world!", 5, "utf-8")


When buffer.write has 3 arguments, the second argument indicates an offset, or the index of the buffer to start writing at.

Reading from Buffers

Probably the most common way to read buffers is to use the toString method, since many buffers contain text:


buffer.toString('utf-8')
'Hello world!u0000�kt'


Again, the first argument is the encoding. In this case, it can be seen that not the entire buffer was used! Luckily, because we know how many bytes we’ve written to the buffer, we can simply add more arguments to “stringify” the slice that’s actually interesting:


buffer.toString("utf-8", 0, 12)
'Hello world!'

Using Buffers in the Browser

The Buffer exploit mainly affects backend server running NodeJS (or old versions of IO.JS), but the use of Buffers is not limited to the backend.

You can work also with buffers in the Browser by using: https://github.com/toots/buffer-browserify.

However, its performance is poor, mainly due to Buffer design decisions.

Equivalent functionality, with better performance metrics, in the browser is provided by TypedArrays or https://github.com/chrisdickinson/bops.

bops

bops presents a JavaScript API for working with binary data that will work exactly the same in supported browsers and in node. due to the way that Buffer is implemented in node it is impossible to take code written against the Buffer API and make it work on top of binary data structures (Array Buffers and Typed Arrays) in the browser.

Instead, you have to fake the API on top of Object, but Object isn't designed for holding raw binary data and will be really slow/memory inefficient for many common binary use cases (parsing files, writing files, etc).

Upgrade NodeJS

If your target operating system is OSX, then you probably have 3 main packages to consider:
  • NodeJS
  • NPM
... and probably these as well:
  • Homebrew
  • NVM

If you're a Homebrew user and you installed node via Homebrew, there are issues with the way Homebrew and NPM work together stemming from the fact that both homebrew and npm are package management solutions.

If you're a Homebrew user and you installed node via Homebrew, there is a major philosophical issue with the way Homebrew and NPM work together.

There are many ways to install these packages.

Read this article for my suggested solution (that does not require you to use sudo permissions): Cleanly Install NVM, NodeJS and NPM.

References

http://lexsheehan.blogspot.com/2015/04/cleanly-install-nvm-node-and-npm.html
http://blog.nodejs.org/2015/07/03/node-v0-12-6-stable/
http://blog.nodejs.org/vulnerability/
https://github.com/toots/buffer-browserify
https://github.com/chrisdickinson/bops
http://www.read.seas.harvard.edu/~kohler/class/05f-osp/notes/lec19.html
http://jsdevs.com/how-to-use-buffers-in-node-js/

This work is licensed under the Creative Commons Attribution 3.0 Unported License.

1 comment:

  1. Image is best to explain the buffer overflow. I easily understand the issue from the above image. Thanks to share the function of how buffers work. iOS Event Application

    ReplyDelete