Airbnb – Ruby on Rails String Interpolation led to Remote Code Execution

airbnb_horizontal_lockup_print

@nahamsec and I discovered a Cross-Site Scripting vulnerability a few months ago related to Rails typecasting request variables into JSON. This caused the output to be JSON formatted and the JSON indexes would avoid XSS encoding. We decided to run with this concept and explore the rest of the website to see if we could identify other vulnerabilities using the same method. Along the way we discovered an interesting output from the /api/v1/listings/[id]/update API request. This led us to finding a Remote Code Execution vulnerability on Airbnb due to Ruby on Rails string interpolation.

This is what the API request typically looks like:

  • https://www.airbnb.com/api/v1/listings/[id]/update
  • POST: {"listing":{"directions":"test"}}

This is what it looks like to turn the listing directions string into an array:

  • https://www.airbnb.com/api/v1/listings/[id]/update
  • POST: {"listing":{"directions":[{"test":"test1"}]}}

After turning it into an array, this is the output it was giving:

"directions":"---\n- !ruby/hash:ActionDispatch::Http::ParamsHashWithIndifferentAccess\n  test: test1\n"

It wasn't the first time we had seen this, as there were other POST requests that resulted in a similar output:

--- !

We were unfamiliar with the YAML format and it wasn't until we discovered the !ruby output and talked to Jobert that we realized this was input inside of a YAML parser. Any attempt at exploiting this as a downstream Rails YAML deserialization attack failed. Any YAML formatted string in the input would be placed inside of quotes or escaped.

During our fuzzing, we were messing with different types of Rails features. We eventually landed on string interpolation and noticed it evaluated.

{"listing":{"directions":[{"test":[{"abc":"#{1+1}"}]}] }}

Result: abc: ! '2'\n

This discovery made us realize that even though we were inside quotes we were able to use #{} to evaluate code. Using the %x arg we were able to execute shell commands.

  • https://www.airbnb.com/api/v1/listings/[id]/update
  • POST: {"listing":{"directions":[{"test":[{"abc":"#{%x['ls']}+foo"}]}] }}

Result:

ls

Thanks:

Timeline:

  • 2/11/2017: Initial discovery of potential flaw (did not report)
  • 2/20/2017: Verified and reported (Holiday)
  • 2/21/2017: Fixed