CVE-2015-10014: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') (CWE-89)
value: A vulnerability classified as critical has been found in arekk uke. This affects an unknown part of the file lib/uke/finder.rb. The manipulation leads to sql injection. The identifier of the patch is 52fd3b2d0bc16227ef57b7b98a3658bb67c1833f. It is recommended to apply a patch to fix this issue. The identifier VDB-217485 was assigned to this vulnerability.
CWE 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.
CVSS v3 base score: 9.8
Published: 2023-01-05T14:15Z
Repository: https://github.com/arekk/uke
Language: Ruby
Files changed: lib/uke/finder.rb
Commit date: 2015-11-17 14:30:39 +0100
Commit message: SQL injection possibility

Diff: diff --git a/lib/uke/finder.rb b/lib/uke/finder.rb
index 366e6e2..b575f73 100755
--- a/lib/uke/finder.rb
+++ b/lib/uke/finder.rb
@@ -47,16 +47,16 @@ class Uke::Finder
              AND lon BETWEEN :lon_sw AND :lon_ne
         ORDER BY distance ASC
     SQL
     
     sql.gsub!(':uke_import_id', @active_import.id.to_s)
-    sql.gsub!(':lat_ne', conn.quote_string(bounds_ne['lat'].to_s))
-    sql.gsub!(':lat_sw', conn.quote_string(bounds_sw['lat'].to_s))
-    sql.gsub!(':lon_ne', conn.quote_string(bounds_ne['lng'].to_s))
-    sql.gsub!(':lon_sw', conn.quote_string(bounds_sw['lng'].to_s))
-    sql.gsub!(':lat', conn.quote_string(@location.latitude.to_s))
-    sql.gsub!(':lon', conn.quote_string(@location.longitude.to_s))
+    sql.gsub!(':lat_ne', conn.quote(bounds_ne['lat'].to_s))
+    sql.gsub!(':lat_sw', conn.quote(bounds_sw['lat'].to_s))
+    sql.gsub!(':lon_ne', conn.quote(bounds_ne['lng'].to_s))
+    sql.gsub!(':lon_sw', conn.quote(bounds_sw['lng'].to_s))
+    sql.gsub!(':lat', conn.quote(@location.latitude.to_s))
+    sql.gsub!(':lon', conn.quote(@location.longitude.to_s))
     
     result_to_hash select_using_uke_stations_result(sql)
   end
 
   def by_location
@@ -75,16 +75,16 @@ class Uke::Finder
              AND lon BETWEEN :lon_sw AND :lon_ne
        ORDER BY distance ASC
     SQL
 
     sql.gsub!(':uke_import_id', @active_import.id.to_s)
-    sql.gsub!(':lat_ne', conn.quote_string(bounds_ne['lat'].to_s))
-    sql.gsub!(':lat_sw', conn.quote_string(bounds_sw['lat'].to_s))
-    sql.gsub!(':lon_ne', conn.quote_string(bounds_ne['lng'].to_s))
-    sql.gsub!(':lon_sw', conn.quote_string(bounds_sw['lng'].to_s))
-    sql.gsub!(':lat', conn.quote_string(@location.latitude.to_s))
-    sql.gsub!(':lon', conn.quote_string(@location.longitude.to_s))
+    sql.gsub!(':lat_ne', conn.quote(bounds_ne['lat'].to_s))
+    sql.gsub!(':lat_sw', conn.quote(bounds_sw['lat'].to_s))
+    sql.gsub!(':lon_ne', conn.quote(bounds_ne['lng'].to_s))
+    sql.gsub!(':lon_sw', conn.quote(bounds_sw['lng'].to_s))
+    sql.gsub!(':lat', conn.quote(@location.latitude.to_s))
+    sql.gsub!(':lon', conn.quote(@location.longitude.to_s))
 
     result_to_hash select_using_uke_stations_result(sql)
   end
 
   def by_frq_range
@@ -95,11 +95,11 @@ class Uke::Finder
            FROM frequencies f
      INNER JOIN frequency_assignments fa ON (fa.frequency_id = f.id AND fa.subject_type = 'UkeStation' AND fa.uke_import_id = :uke_import_id)
           WHERE (f.mhz BETWEEN :mhz_start AND :mhz_end)
     SQL
 
-    result_to_hash select_using_uke_stations_sql(sql.gsub(':uke_import_id', @active_import.id.to_s).gsub(':mhz_start', conn.quote_string(first.to_s)).gsub(':mhz_end', conn.quote_string(last.to_s)))
+    result_to_hash select_using_uke_stations_sql(sql.gsub(':uke_import_id', @active_import.id.to_s).gsub(':mhz_start', conn.quote(first.to_s)).gsub(':mhz_end', conn.quote(last.to_s)))
   end
 
   def by_frq
     return nil if @q.length < 4 || Uke::Unifier::frq_string(@q) < 1
 
@@ -108,25 +108,25 @@ class Uke::Finder
            FROM frequencies f
      INNER JOIN frequency_assignments fa ON (fa.frequency_id = f.id AND fa.subject_type = 'UkeStation' AND fa.uke_import_id = :uke_import_id)
           WHERE f.mhz = :mhz
     SQL
 
-    result_to_hash select_using_uke_stations_sql(sql.gsub(':uke_import_id', @active_import.id.to_s).gsub(':mhz', conn.quote_string(Uke::Unifier::frq_string(@q).to_s)))
+    result_to_hash select_using_uke_stations_sql(sql.gsub(':uke_import_id', @active_import.id.to_s).gsub(':mhz', conn.quote(Uke::Unifier::frq_string(@q).to_s)))
   end
 
   def by_string
     return nil if @q.length < 4
 
     sql = <<-SQL
         SELECT us.id
           FROM uke_stations us
           JOIN uke_operators uo on (uo.id = us.uke_operator_id)
          WHERE us.uke_import_id = :uke_import_id
-           AND (us.location LIKE '%:like%' OR us.name LIKE '%:like%' OR uo.name LIKE '%:like%')
+           AND (us.location LIKE :like OR us.name LIKE :like OR uo.name LIKE :like)
     SQL
 
-    result_to_hash select_using_uke_stations_sql(sql.gsub(':uke_import_id', @active_import.id.to_s).gsub(':like', conn.quote_string(@q)))
+    result_to_hash select_using_uke_stations_sql(sql.gsub(':uke_import_id', @active_import.id.to_s).gsub(':like', conn.quote('%'+@q.to_s+'%')))
   end
 
   def by_frq_order_by_distance
     return nil if @location.nil? || @q.to_f == 0
 
@@ -147,11 +147,11 @@ class Uke::Finder
              AND fa.usage = 'TX'
           HAVING distance <= 100
         ORDER BY distance ASC
     SQL
 
-    result_to_hash(conn.select_all(sql.gsub(':uke_import_id', @active_import.id.to_s).gsub(':lat', conn.quote_string(@location.latitude.to_s)).gsub(':lon', conn.quote_string(@location.longitude.to_s)).gsub(':mhz', conn.quote_string(Uke::Unifier::frq_string(@q).to_s))))
+    result_to_hash(conn.select_all(sql.gsub(':uke_import_id', @active_import.id.to_s).gsub(':lat', conn.quote(@location.latitude.to_s)).gsub(':lon', conn.quote(@location.longitude.to_s)).gsub(':mhz', conn.quote(Uke::Unifier::frq_string(@q).to_s))))
   end
 
   private
 
   def conn

Vulnerable code:     sql.gsub!(':lat_ne', conn.quote_string(bounds_ne['lat'].to_s))
    sql.gsub!(':lat_sw', conn.quote_string(bounds_sw['lat'].to_s))
    sql.gsub!(':lon_ne', conn.quote_string(bounds_ne['lng'].to_s))
    sql.gsub!(':lon_sw', conn.quote_string(bounds_sw['lng'].to_s))
    sql.gsub!(':lat', conn.quote_string(@location.latitude.to_s))
    sql.gsub!(':lon', conn.quote_string(@location.longitude.to_s))
    sql.gsub!(':lat_ne', conn.quote_string(bounds_ne['lat'].to_s))
    sql.gsub!(':lat_sw', conn.quote_string(bounds_sw['lat'].to_s))
    sql.gsub!(':lon_ne', conn.quote_string(bounds_ne['lng'].to_s))
    sql.gsub!(':lon_sw', conn.quote_string(bounds_sw['lng'].to_s))
    sql.gsub!(':lat', conn.quote_string(@location.latitude.to_s))
    sql.gsub!(':lon', conn.quote_string(@location.longitude.to_s))
    result_to_hash select_using_uke_stations_sql(sql.gsub(':uke_import_id', @active_import.id.to_s).gsub(':mhz_start', conn.quote_string(first.to_s)).gsub(':mhz_end', conn.quote_string(last.to_s)))
    result_to_hash select_using_uke_stations_sql(sql.gsub(':uke_import_id', @active_import.id.to_s).gsub(':mhz', conn.quote_string(Uke::Unifier::frq_string(@q).to_s)))
           AND (us.location LIKE '%:like%' OR us.name LIKE '%:like%' OR uo.name LIKE '%:like%')
    result_to_hash select_using_uke_stations_sql(sql.gsub(':uke_import_id', @active_import.id.to_s).gsub(':like', conn.quote_string(@q)))
    result_to_hash(conn.select_all(sql.gsub(':uke_import_id', @active_import.id.to_s).gsub(':lat', conn.quote_string(@location.latitude.to_s)).gsub(':lon', conn.quote_string(@location.longitude.to_s)).gsub(':mhz', conn.quote_string(Uke::Unifier::frq_string(@q).to_s))))
Fixed code:     sql.gsub!(':lat_ne', conn.quote(bounds_ne['lat'].to_s))
    sql.gsub!(':lat_sw', conn.quote(bounds_sw['lat'].to_s))
    sql.gsub!(':lon_ne', conn.quote(bounds_ne['lng'].to_s))
    sql.gsub!(':lon_sw', conn.quote(bounds_sw['lng'].to_s))
    sql.gsub!(':lat', conn.quote(@location.latitude.to_s))
    sql.gsub!(':lon', conn.quote(@location.longitude.to_s))
    sql.gsub!(':lat_ne', conn.quote(bounds_ne['lat'].to_s))
    sql.gsub!(':lat_sw', conn.quote(bounds_sw['lat'].to_s))
    sql.gsub!(':lon_ne', conn.quote(bounds_ne['lng'].to_s))
    sql.gsub!(':lon_sw', conn.quote(bounds_sw['lng'].to_s))
    sql.gsub!(':lat', conn.quote(@location.latitude.to_s))
    sql.gsub!(':lon', conn.quote(@location.longitude.to_s))
    result_to_hash select_using_uke_stations_sql(sql.gsub(':uke_import_id', @active_import.id.to_s).gsub(':mhz_start', conn.quote(first.to_s)).gsub(':mhz_end', conn.quote(last.to_s)))
    result_to_hash select_using_uke_stations_sql(sql.gsub(':uke_import_id', @active_import.id.to_s).gsub(':mhz', conn.quote(Uke::Unifier::frq_string(@q).to_s)))
           AND (us.location LIKE :like OR us.name LIKE :like OR uo.name LIKE :like)
    result_to_hash select_using_uke_stations_sql(sql.gsub(':uke_import_id', @active_import.id.to_s).gsub(':like', conn.quote('%'+@q.to_s+'%')))
    result_to_hash(conn.select_all(sql.gsub(':uke_import_id', @active_import.id.to_s).gsub(':lat', conn.quote(@location.latitude.to_s)).gsub(':lon', conn.quote(@location.longitude.to_s)).gsub(':mhz', conn.quote(Uke::Unifier::frq_string(@q).to_s))))