CVE-2012-5648 (published 2014-04-04T14:55Z)

Multiple SQL injection vulnerabilities in Foreman before 1.0.2 allow remote attackers to execute arbitrary SQL commands via unspecified parameters to (1) app/models/hostext/search.rb or (2) app/models/puppetclass.rb, related to the search mechanism.

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)

Weakness information:
cwe_id: CWE-89
cwe_name: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
description: The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data.
extended_description: 
            
            
         
         

Fix information:
repo_url: https://github.com/theforeman/foreman
commit_details: repo_url: https://github.com/theforeman/foreman
author: Amos Benari
author_date: 2012-12-19 12:28:31+02:00
msg: Fix Foreman SQL injection through search mechanism CVE-2012-5648
repository: repo_url: https://github.com/theforeman/foreman
repo_name: theforeman/foreman
description: an application that automates the lifecycle of servers 
repo_language: Ruby
owner: theforeman
file_changes: filename: search.rb
change_type: ModificationType.MODIFY
diff: @@ -51,15 +51,16 @@ module Hostext
 
         def self.search_by_user(key, operator, value)
           key_name = key.sub(/^.*\./,'')
-          users = User.all(:conditions => "#{key_name} #{operator} '#{value_to_sql(operator, value)}'")
+          condition = sanitize_sql_for_conditions(["? #{operator} ?", key_name, value_to_sql(operator, value)])
+          users = User.all(:conditions => condition)
           hosts = users.map(&:hosts).flatten
-          opts  = hosts.empty? ? "= 'nil'" : "IN (#{hosts.map(&:id).join(',')})"
+          opts  = hosts.empty? ? "< 0" : "IN (#{hosts.map(&:id).join(',')})"
 
           return {:conditions => " hosts.id #{opts} " }
         end
 
         def self.search_by_puppetclass(key, operator, value)
-          conditions  = "puppetclasses.name #{operator} '#{value_to_sql(operator, value)}'"
+          conditions  = sanitize_sql_for_conditions(["puppetclasses.name #{operator} ?", value_to_sql(operator, value)])
           hosts       = Host.my_hosts.all(:conditions => conditions, :joins => :puppetclasses, :select => 'DISTINCT hosts.id').map(&:id)
           host_groups = Hostgroup.all(:conditions => conditions, :joins => :puppetclasses, :select => 'DISTINCT hostgroups.id').map(&:id)
 
@@ -73,12 +74,14 @@ module Hostext
 
         def self.search_by_params(key, operator, value)
           key_name = key.sub(/^.*\./,'')
-          opts     = {:conditions => "name = '#{key_name}' and value #{operator} '#{value_to_sql(operator, value)}'", :order => :priority}
+          condition = sanitize_sql_for_conditions(["name = ? and value #{operator} ?", key_name, value_to_sql(operator, value)])
+          opts     = {:conditions => condition, :order => :priority}
           p        = Parameter.all(opts)
           return {:conditions => '1 = 0'} if p.blank?
 
           max         = p.first.priority
-          negate_opts = {:conditions => "name = '#{key_name}' and NOT(value #{operator} '#{value_to_sql(operator, value)}') and priority > #{max}", :order => :priority}
+          condition   = sanitize_sql_for_conditions(["name = ? and NOT(value #{operator} ?) and priority > ?",key_name,value_to_sql(operator, value), max])
+          negate_opts = {:conditions => condition, :order => :priority}
           n           = Parameter.all(negate_opts)
 
           conditions = param_conditions(p)

programming_language: Ruby
filename: puppetclass.rb
change_type: ModificationType.MODIFY
diff: @@ -151,8 +151,8 @@ class Puppetclass < ActiveRecord::Base
   end
 
   def self.search_by_host(key, operator, value)
-    conditions = "hosts.name #{operator} '#{value_to_sql(operator, value)}'"
-    direct     = Puppetclass.all(:conditions => conditions, :joins => :hosts, :select => 'puppetclasses.id').map(&:id).uniq
+    conditions = sanitize_sql_for_conditions(["hosts.name #{operator} ?", value_to_sql(operator, value)])
+    direct     = Puppetclass.joins(:hosts).where(conditions).select('puppetclasses.id').map(&:id).uniq
     hostgroup  = Hostgroup.joins(:hosts).where(conditions).first
     indirect   = HostgroupClass.where(:hostgroup_id => hostgroup.path_ids).pluck(:puppetclass_id).uniq
     return { :conditions => "1=0" } if direct.blank? && indirect.blank?

programming_language: Ruby