2

I am getting SQL-injection url requests such as: ?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=12345.php&vars[1][1]=

which is causing a:

ActionController::BadRequest (Invalid query parameters: expected Hash (got Array) for param `1'):

in my home#index. I believe the error is caught in a middleware or routing as I cannot catch the error in the home#index controller (or application controller either).

This is my development log response to the url:

ActionController::BadRequest (Invalid query parameters: expected Hash (got Array) for param `1'):
  rack (1.6.11) lib/rack/utils.rb:162:in `normalize_params'
  rack (1.6.11) lib/rack/utils.rb:163:in `normalize_params'
  rack (1.6.11) lib/rack/utils.rb:122:in `block in parse_nested_query'
  rack (1.6.11) lib/rack/utils.rb:119:in `each'
  rack (1.6.11) lib/rack/utils.rb:119:in `parse_nested_query'
  rack (1.6.11) lib/rack/request.rb:371:in `parse_query'
  actionpack (4.2.10) lib/action_dispatch/http/request.rb:339:in `parse_query'
  rack (1.6.11) lib/rack/request.rb:191:in `GET'
  actionpack (4.2.10) lib/action_dispatch/http/request.rb:300:in `GET'
  actionpack (4.2.10) lib/action_dispatch/http/parameters.rb:14:in `parameters'
  actionpack (4.2.10) lib/action_dispatch/http/filter_parameters.rb:37:in `filtered_parameters'
  actionpack (4.2.10) lib/action_controller/metal/instrumentation.rb:22:in `process_action'
  actionpack (4.2.10) lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
  activerecord (4.2.10) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
  actionpack (4.2.10) lib/abstract_controller/base.rb:137:in `process'
  actionview (4.2.10) lib/action_view/rendering.rb:30:in `process'
  actionpack (4.2.10) lib/action_controller/metal.rb:196:in `dispatch'
  actionpack (4.2.10) lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
  actionpack (4.2.10) lib/action_controller/metal.rb:237:in `block in action'
  actionpack (4.2.10) lib/action_dispatch/routing/route_set.rb:74:in `dispatch'
  actionpack (4.2.10) lib/action_dispatch/routing/route_set.rb:43:in `serve'
  actionpack (4.2.10) lib/action_dispatch/journey/router.rb:43:in `block in serve'
  actionpack (4.2.10) lib/action_dispatch/journey/router.rb:30:in `each'
  actionpack (4.2.10) lib/action_dispatch/journey/router.rb:30:in `serve'
  actionpack (4.2.10) lib/action_dispatch/routing/route_set.rb:817:in `call'
  bullet (6.0.2) lib/bullet/rack.rb:12:in `call'
  rack (1.6.11) lib/rack/etag.rb:24:in `call'
  rack (1.6.11) lib/rack/conditionalget.rb:25:in `call'
  rack (1.6.11) lib/rack/head.rb:13:in `call'
  actionpack (4.2.10) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
  actionpack (4.2.10) lib/action_dispatch/middleware/flash.rb:260:in `call'
  rack (1.6.11) lib/rack/session/abstract/id.rb:225:in `context'
  rack (1.6.11) lib/rack/session/abstract/id.rb:220:in `call'
  actionpack (4.2.10) lib/action_dispatch/middleware/cookies.rb:560:in `call'
  activerecord (4.2.10) lib/active_record/query_cache.rb:36:in `call'
  airbrake (9.4.3) lib/airbrake/rack/middleware.rb:32:in `call!'
  airbrake (9.4.3) lib/airbrake/rack/middleware.rb:21:in `call'
  activerecord (4.2.10) lib/active_record/connection_adapters/abstract/connection_pool.rb:653:in `call'
  activerecord (4.2.10) lib/active_record/migration.rb:377:in `call'
  actionpack (4.2.10) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
  activesupport (4.2.10) lib/active_support/callbacks.rb:88:in `__run_callbacks__'
  activesupport (4.2.10) lib/active_support/callbacks.rb:778:in `_run_call_callbacks'
  activesupport (4.2.10) lib/active_support/callbacks.rb:81:in `run_callbacks'
  actionpack (4.2.10) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
  actionpack (4.2.10) lib/action_dispatch/middleware/reloader.rb:73:in `call'
  actionpack (4.2.10) lib/action_dispatch/middleware/remote_ip.rb:78:in `call'
  actionpack (4.2.10) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
  web-console (2.3.0) lib/web_console/middleware.rb:28:in `block in call'
  web-console (2.3.0) lib/web_console/middleware.rb:18:in `catch'
  web-console (2.3.0) lib/web_console/middleware.rb:18:in `call'
  actionpack (4.2.10) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
  railties (4.2.10) lib/rails/rack/logger.rb:38:in `call_app'
  railties (4.2.10) lib/rails/rack/logger.rb:20:in `block in call'
  activesupport (4.2.10) lib/active_support/tagged_logging.rb:68:in `block in tagged'
  activesupport (4.2.10) lib/active_support/tagged_logging.rb:26:in `tagged'
  activesupport (4.2.10) lib/active_support/tagged_logging.rb:68:in `tagged'
  railties (4.2.10) lib/rails/rack/logger.rb:20:in `call'
  request_store (1.4.1) lib/request_store/middleware.rb:19:in `call'
  actionpack (4.2.10) lib/action_dispatch/middleware/request_id.rb:21:in `call'
  rack (1.6.11) lib/rack/methodoverride.rb:22:in `call'
  rack (1.6.11) lib/rack/runtime.rb:18:in `call'
  activesupport (4.2.10) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
  rack (1.6.11) lib/rack/lock.rb:17:in `call'
  actionpack (4.2.10) lib/action_dispatch/middleware/static.rb:120:in `call'
  rack (1.6.11) lib/rack/sendfile.rb:113:in `call'
  utf8-cleaner (0.2.5) lib/utf8-cleaner/middleware.rb:21:in `call'
  railties (4.2.10) lib/rails/engine.rb:518:in `call'
  railties (4.2.10) lib/rails/application.rb:165:in `call'
  rack (1.6.11) lib/rack/content_length.rb:15:in `call'
  thin (1.7.2) lib/thin/connection.rb:86:in `block in pre_process'
  thin (1.7.2) lib/thin/connection.rb:84:in `catch'
  thin (1.7.2) lib/thin/connection.rb:84:in `pre_process'
  thin (1.7.2) lib/thin/connection.rb:53:in `process'
  thin (1.7.2) lib/thin/connection.rb:39:in `receive_data'
  eventmachine (1.2.7) lib/eventmachine.rb:195:in `run_machine'
  eventmachine (1.2.7) lib/eventmachine.rb:195:in `run'
  thin (1.7.2) lib/thin/backends/base.rb:73:in `start'
  thin (1.7.2) lib/thin/server.rb:162:in `start'
  rack (1.6.11) lib/rack/handler/thin.rb:19:in `run'
  rack (1.6.11) lib/rack/server.rb:287:in `start'
  railties (4.2.10) lib/rails/commands/server.rb:80:in `start'
  railties (4.2.10) lib/rails/commands/commands_tasks.rb:80:in `block in server'
  railties (4.2.10) lib/rails/commands/commands_tasks.rb:75:in `tap'
  railties (4.2.10) lib/rails/commands/commands_tasks.rb:75:in `server'
  railties (4.2.10) lib/rails/commands/commands_tasks.rb:39:in `run_command!'
  railties (4.2.10) lib/rails/commands.rb:17:in `<top (required)>'
  bin/rails:9:in `require'
  bin/rails:9:in `<top (required)>'
  spring (2.1.0) lib/spring/client/rails.rb:28:in `load'
  spring (2.1.0) lib/spring/client/rails.rb:28:in `call'
  spring (2.1.0) lib/spring/client/command.rb:7:in `call'
  spring (2.1.0) lib/spring/client.rb:30:in `run'
  spring (2.1.0) bin/spring:49:in `<top (required)>'
  spring (2.1.0) lib/spring/binstub.rb:11:in `load'
  spring (2.1.0) lib/spring/binstub.rb:11:in `<top (required)>'
  bin/spring:13:in `require'
  bin/spring:13:in `<top (required)>'
  bin/rails:3:in `load'
  bin/rails:3:in `<main>'

How can I make sure these spam/sql inject-requests are being handled so they don't cause exceptions?

Christoffer
  • 2,271
  • 3
  • 26
  • 57

2 Answers2

2

In Your Application Controller:

rescue_from ActionController::BadRequest, with: :bad_request


def bad_request(exception)
  render status: 400, json: {:error => exception.message}.to_json
end
  • Thanks, I guess this should work normally but as I wrote in my question I cannot catch the error in the Application Controller either. It seems like the error is created before the controllers, and I do not know how to handle it there. – Christoffer Mar 24 '20 at 11:18
1

I came across this same issue this evening. The error is being thrown before ApplicationController begins to handle the request so catching it in ApplicationController won't work because it's too late.

What you need to do is insert a piece of middleware that catches ActionController::BadRequest before the ActionDispatch::ParamsParser middleware which is throwing the error.

Example which catches the error, adds it to the log and then returns a plain text 400 page.

# app/middleware/catch_batch_request_error_mw.rb

class CatchBadRequestErrorMw
  def initialize(app)
    @app = app
  end

  def call(env)
    begin
      @app.call(env)
    rescue ActionController::BadRequest => e
      Rails.logger.error("CatchBadRequestErrorMw: #{e.message}")
      return [
        400,
        {
          'Content-Type': 'text/plain',
        },
        ['Bad Request']
      ]
    end
  end
end

And then in Application.rb

config.middleware.insert_before(ActionDispatch::ParamsParser, CatchBadRequestErrorMw)

I should note that the examples here are from a Rails 4.2 app so if you have any issues I'd start there.

Brent
  • 1,046
  • 11
  • 13
  • Worked great. I had some trouble figuring out how to make the middleware work for me but it was a middleware issue, not an actual issue with the code. Eventually put it in the initializer folder. – Christoffer Apr 06 '20 at 09:13