lib/brakeman/checks/check_execute.rb in brakeman-min-2.1.2 vs lib/brakeman/checks/check_execute.rb in brakeman-min-2.2.0
- old
+ new
@@ -11,10 +11,14 @@
class Brakeman::CheckExecute < Brakeman::BaseCheck
Brakeman::Checks.add self
@description = "Finds instances of possible command injection"
+ SAFE_VALUES = [s(:const, :RAILS_ROOT),
+ s(:call, s(:const, :Rails), :root),
+ s(:call, s(:const, :Rails), :env)]
+
#Check models, controllers, and views for command injection.
def run_check
Brakeman.debug "Finding system calls using ``"
check_for_backticks tracker
@@ -36,13 +40,13 @@
args = call.arglist
first_arg = call.first_arg
case call.method
when :system, :exec
- failure = include_user_input?(first_arg) || include_interp?(first_arg)
+ failure = include_user_input?(first_arg) || dangerous_interp?(first_arg)
else
- failure = include_user_input?(args) || include_interp?(args)
+ failure = include_user_input?(args) || dangerous_interp?(args)
end
if failure and not duplicate? result
add_result result
@@ -80,19 +84,56 @@
exp = result[:call]
if input = include_user_input?(exp)
confidence = CONFIDENCE[:high]
user_input = input.match
- else
+ elsif input = dangerous?(exp)
confidence = CONFIDENCE[:med]
- user_input = nil
+ user_input = input
+ else
+ return
end
warn :result => result,
:warning_type => "Command Injection",
:warning_code => :command_injection,
:message => "Possible command injection",
:code => exp,
:user_input => user_input,
:confidence => confidence
+ end
+
+ def dangerous? exp
+ exp.each_sexp do |e|
+ next if node_type? e, :lit, :str
+ next if SAFE_VALUES.include? e
+
+ if call? e and e.method == :to_s
+ e = e.target
+ end
+
+ if node_type? e, :or, :evstr, :string_eval, :string_interp
+ if res = dangerous?(e)
+ return res
+ end
+ else
+ return e
+ end
+ end
+
+ false
+ end
+
+ 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
end