ratchetphp/RFC6455

Denial of service vulnerability in getPayloadLength()

Closed this issue · 1 comments

It is possible to crash the WS server rather quickly by sending a frame header designating the size to be the maximum (8 x FF bytes).

PHP only has signed int natively, so this large number ends up being "-1" after being parsed by getPayloadLength() of Messaging/Frame.php.

Since that same function uses recursion to compile the length AND uses the special value of "-1" to know it needs to keep calling itself, one simple packet results in the server falling into an endless loop of recursion, eating up all the memory while using max CPU and eventually being killed by the kernel.

Even despite this issue, sending a bunch of nonsense to the server in loop to be picked up will consume a lot of memory without any boundaries and what's even worse, the memory stays reserved even after the client has disconnected. The garbage collector doesn't seem to clean it up even after some time has passed and more flooding from another client after the connection of the first one has closed.

  • There should be a sanity check or a maximum frame size / message size setting (maximum whatever PHP supports so the length never ends up being < 0)

  • Memory should be cleaned up after a message is processed or the client has disconnected

Thanks.

Thanks for the report and suggestions.

After discussing with @mbonneau we're currently proposing:

  • Add a new optional parameter $max_message_length to the MessageBuffer construct
  • If not provided create a sensible default based on max memory allowance
  • As each Frame is received check the current size of a Message, if it exceeds the give max, send a close Frame with code CLOSE_TOO_BIG and release the message