Class: Brakeman::CheckExecute
- Inherits:
-
BaseCheck
- Object
- SexpProcessor
- BaseCheck
- Brakeman::CheckExecute
- Defined in:
- lib/brakeman/checks/check_execute.rb
Overview
Checks for string interpolation and parameters in calls to Kernel#system, Kernel#exec, Kernel#syscall, and inside backticks.
Examples of command injection vulnerabilities:
system(“rf -rf #:file”) exec(params) ‘unlink #params[:something`
Constant Summary collapse
- SAFE_VALUES =
[s(:const, :RAILS_ROOT), s(:call, s(:const, :Rails), :root), s(:call, s(:const, :Rails), :env)]
- SHELL_ESCAPES =
[:escape, :shellescape, :join]
- SHELLWORDS =
s(:const, :Shellwords)
Constants inherited from BaseCheck
Constants included from Util
Util::ALL_COOKIES, Util::ALL_PARAMETERS, Util::COOKIES, Util::COOKIES_SEXP, Util::PARAMETERS, Util::PARAMS_SEXP, Util::PATH_PARAMETERS, Util::QUERY_PARAMETERS, Util::REQUEST_COOKIES, Util::REQUEST_ENV, Util::REQUEST_PARAMETERS, Util::REQUEST_PARAMS, Util::SESSION, Util::SESSION_SEXP
Constants inherited from SexpProcessor
Instance Attribute Summary
Attributes inherited from BaseCheck
Attributes inherited from SexpProcessor
Instance Method Summary collapse
-
#check_for_backticks(tracker) ⇒ Object
Looks for calls using backticks such as.
- #check_open_calls ⇒ Object
-
#dangerous?(exp) ⇒ Boolean
This method expects a :dstr or :evstr node.
- #dangerous_interp?(exp) ⇒ Boolean
- #dangerous_open_arg?(exp) ⇒ Boolean
-
#process_backticks(result) ⇒ Object
Processes backticks.
-
#process_result(result) ⇒ Object
Processes results from Tracker#find_call.
-
#run_check ⇒ Object
Check models, controllers, and views for command injection.
- #shell_escape?(exp) ⇒ Boolean
Methods inherited from BaseCheck
#add_result, inherited, #initialize, #process_call, #process_cookies, #process_default, #process_dstr, #process_if, #process_params
Methods included from Util
#array?, #block?, #call?, #camelize, #class_name, #constant?, #contains_class?, #context_for, #cookies?, #false?, #file_by_name, #file_for, #github_url, #hash?, #hash_access, #hash_insert, #hash_iterate, #integer?, #make_call, #node_type?, #number?, #params?, #pluralize, #rails_version, #regexp?, #relative_path, #request_env?, #request_value?, #result?, #set_env_defaults, #sexp?, #string?, #string_interp?, #symbol?, #table_to_csv, #template_path_to_name, #true?, #truncate_table, #underscore
Methods included from ProcessorHelper
#current_file_name, #process_all, #process_all!, #process_call_args, #process_call_defn?, #process_class, #process_module
Methods inherited from SexpProcessor
#in_context, #initialize, #process, processors, #scope
Constructor Details
This class inherits a constructor from Brakeman::BaseCheck
Instance Method Details
#check_for_backticks(tracker) ⇒ Object
Looks for calls using backticks such as
‘rm -rf #:file`
105 106 107 108 109 |
# File 'lib/brakeman/checks/check_execute.rb', line 105 def check_for_backticks tracker tracker.find_call(:target => nil, :method => :`).each do |result| process_backticks result end end |
#check_open_calls ⇒ Object
78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/brakeman/checks/check_execute.rb', line 78 def check_open_calls tracker.find_call(:targets => [nil, :Kernel], :method => :open).each do |result| if match = dangerous_open_arg?(result[:call].first_arg) warn :result => result, :warning_type => "Command Injection", :warning_code => :command_injection, :message => "Possible command injection in open()", :user_input => match, :confidence => :high end end end |
#dangerous?(exp) ⇒ Boolean
This method expects a :dstr or :evstr node
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/brakeman/checks/check_execute.rb', line 135 def dangerous? exp exp.each_sexp do |e| if call? e and e.method == :to_s e = e.target end next if node_type? e, :lit, :str next if SAFE_VALUES.include? e next if shell_escape? e if node_type? e, :or, :evstr, :dstr if res = dangerous?(e) return res end else return e end end false end |
#dangerous_interp?(exp) ⇒ Boolean
157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/brakeman/checks/check_execute.rb', line 157 def dangerous_interp? exp match = include_interp? exp return unless match interp = match.match interp.each_sexp do |e| if res = dangerous?(e) return Match.new(:interp, res) end end false end |
#dangerous_open_arg?(exp) ⇒ Boolean
91 92 93 94 95 96 97 98 99 100 |
# File 'lib/brakeman/checks/check_execute.rb', line 91 def dangerous_open_arg? exp if string_interp? exp # Check for input at start of string exp[1] == "" and node_type? exp[2], :evstr and has_immediate_user_input? exp[2] else has_immediate_user_input? exp end end |
#process_backticks(result) ⇒ Object
Processes backticks.
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/brakeman/checks/check_execute.rb', line 112 def process_backticks result return unless original? result exp = result[:call] if input = include_user_input?(exp) confidence = :high elsif input = dangerous?(exp) confidence = :medium else return end warn :result => result, :warning_type => "Command Injection", :warning_code => :command_injection, :message => "Possible command injection", :code => exp, :user_input => input, :confidence => confidence end |
#process_result(result) ⇒ Object
Processes results from Tracker#find_call.
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/brakeman/checks/check_execute.rb', line 44 def process_result result call = result[:call] args = call.arglist first_arg = call.first_arg case call.method when :popen unless array? first_arg failure = include_user_input?(args) || dangerous_interp?(args) end when :system, :exec failure = include_user_input?(first_arg) || dangerous_interp?(first_arg) else failure = include_user_input?(args) || dangerous_interp?(args) end if failure and original? result if failure.type == :interp #Not from user input confidence = :medium else confidence = :high end warn :result => result, :warning_type => "Command Injection", :warning_code => :command_injection, :message => "Possible command injection", :code => call, :user_input => failure, :confidence => confidence end end |
#run_check ⇒ Object
Check models, controllers, and views for command injection.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/brakeman/checks/check_execute.rb', line 25 def run_check Brakeman.debug "Finding system calls using ``" check_for_backticks tracker check_open_calls Brakeman.debug "Finding other system calls" calls = tracker.find_call :targets => [:IO, :Open3, :Kernel, :'POSIX::Spawn', :Process, nil], :methods => [:capture2, :capture2e, :capture3, :exec, :pipeline, :pipeline_r, :pipeline_rw, :pipeline_start, :pipeline_w, :popen, :popen2, :popen2e, :popen3, :spawn, :syscall, :system] Brakeman.debug "Processing system calls" calls.each do |result| process_result result end end |
#shell_escape?(exp) ⇒ Boolean
171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/brakeman/checks/check_execute.rb', line 171 def shell_escape? exp return false unless call? exp if exp.target == SHELLWORDS and SHELL_ESCAPES.include? exp.method true elsif exp.method == :shelljoin true else false end end |