CVE-2015-10017 (published 2023-01-06T11:15Z)

A vulnerability has been found in HPI-Information-Systems ProLOD and classified as critical. This vulnerability affects unknown code. The manipulation of the argument this leads to sql injection. The name of the patch is 3f710905458d49c77530bd3cbcd8960457566b73. It is recommended to apply a patch to fix this issue. The identifier of this vulnerability is VDB-217552.

CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

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/HPI-Information-Systems/ProLOD
commit_details: repo_url: https://github.com/HPI-Information-Systems/ProLOD
author: Christian Dullweber
author_date: 2015-07-06 12:57:42+02:00
msg: validate dataset name to prevent sql injection from this parameter
repository: repo_url: https://github.com/HPI-Information-Systems/ProLOD
repo_name: HPI-Information-Systems/ProLOD
description: ProLOD++ contains algorithms to perform data profiling on Linked Data.
repo_language: Scala
owner: HPI-Information-Systems
file_changes: filename: DatabaseConnection.scala
change_type: ModificationType.MODIFY
diff: @@ -224,8 +224,14 @@ class DatabaseConnection(config : Configuration) {
 		result                */
 	}
 
-	def getClusters(s: String, ontologyNamespace : String): Seq[Group] = {
-		val table = s
+	def validateDatasetString(table: String) = {
+		if(!table.matches("[A-Za-z]+")) {
+			throw new RuntimeException("illegal table name: " + table)
+		}
+	}
+
+	def getClusters(table: String, ontologyNamespace : String): Seq[Group] = {
+		validateDatasetString(table)
 		val sql = sql"SELECT label, cluster_size FROM #${table}.CLUSTERS WHERE username = 'ontology' ORDER BY label".as[(String, Int)]
 		var id : Int = -1
 		try {
@@ -235,7 +241,7 @@ class DatabaseConnection(config : Configuration) {
 				new Group(id, removeOntologyNamespace(label, ontologyNamespace), cluster_size)
 			})
 		} catch {
-			case e : SqlSyntaxErrorException => println("This dataset has no clusters: " + s)
+			case e : SqlSyntaxErrorException => println("This dataset has no clusters: " + table)
 			Nil
 		}
 	}
@@ -271,6 +277,7 @@ class DatabaseConnection(config : Configuration) {
 
 
 	def getStatistics(dataset: String) : mutable.Map[String, String] = {
+		validateDatasetString(dataset)
 		val statistics = mutable.Map[String, String]()
 		val sql = sql"SELECT nodedegreedistribution, averagelinks, edges, connectedcomponents, stronglyconnectedcomponents FROM #$dataset.graphstatistics".as[(String, Float, Int, Int, Int)]
 		try {
@@ -297,7 +304,7 @@ class DatabaseConnection(config : Configuration) {
 				val result2 = execute(sql2) map ((gcnodes) => {
 					statistics += ("gcnodes" -> gcnodes.toString)
 				})
-				println(e.getMessage + System.lineSeparator() + sql.toString)
+				println("error getting stats: " + e.getMessage + System.lineSeparator() + sql.toString)
 			}
 		}
 		statistics
@@ -355,6 +362,7 @@ class DatabaseConnection(config : Configuration) {
 	}
 
 	def getPatternDiameter(dataset: String, patternId: Int) : Int = {
+		validateDatasetString(dataset)
 		var diameter : Int = 0
 		try {
 			val sql = sql"SELECT diameter FROM #${dataset}.patterns WHERE id = #${patternId}".as[(Int)]
@@ -363,12 +371,13 @@ class DatabaseConnection(config : Configuration) {
 				diameter = diameterSql
 			})
 		} catch {
-			case e : SqlSyntaxErrorException => println(e.getMessage)
+			case e : SqlSyntaxErrorException => println("error getting diameter" + e.getMessage)
 		}
 		diameter
 	}
 
 	def getEntityDetails(dataset: String, subjectId: Int): Entity = {
+		validateDatasetString(dataset)
 		var triples : List[Triple] = Nil
 		var label : String = ""
 		var subjectUri = ""
@@ -409,7 +418,7 @@ class DatabaseConnection(config : Configuration) {
 			}
 			statement.close
 		} catch {
-			case e : SqlSyntaxErrorException => println(e.getMessage)
+			case e : SqlSyntaxErrorException => println("error getting entity details" + e.getMessage)
 		}
 
 		val entityDetails = new Entity(subjectId, subjectUri, label, triples)
@@ -434,6 +443,7 @@ class DatabaseConnection(config : Configuration) {
 	}
 
 	def insertPatterns(name: String, patterns: util.HashMap[Integer, util.HashMap[String, Integer]], coloredPatterns: util.HashMap[Integer, util.List[String]], diameter: util.HashMap[Integer, lang.Double]) {
+		validateDatasetString(name)
 		val coloredPatternsMap = coloredPatterns.asScala.toMap
 		val diameterMap = diameter.asScala.toMap
 		val patternsMap = patterns.asScala.toMap
@@ -450,7 +460,7 @@ class DatabaseConnection(config : Configuration) {
 							val resultSet = statement.execute("INSERT INTO " + name + ".PATTERNS (ID, NAME, PATTERN, OCCURENCES, DIAMETER) VALUES (" + id + ", '" + patternName + "',  '" + pattern + "'," + occurences + "," + patternDiameter + ")")
 						} catch {
 							case e: SqlIntegrityConstraintViolationException => println("Pattern already exists")
-							case e: SqlException => println(e.getMessage)
+							case e: SqlException => println("error inserting pattern: " + e.getMessage)
 							case e: SqlSyntaxErrorException => println(e.getMessage + System.lineSeparator() + "INSERT INTO " + name + ".PATTERNS (ID, PATTERN, OCCURENCES, DIAMETER) VALUES (" + id + ", '" + pattern + "'," + occurences + ", " + patternDiameter + ")")
 						}
 						val cPattern = coloredPatternsMap.get(id).get.asScala.toList
@@ -460,7 +470,7 @@ class DatabaseConnection(config : Configuration) {
 								val resultSet = statement.execute("INSERT INTO " + name + ".coloredpatterns (ID, PATTERN) VALUES (" + id + ", '" + coloredpattern + "')")
 							} catch {
 								case e: SqlException => {
-									println(e.getMessage)
+									println("error inserting pattern (2)" + e.getMessage)
 									println(coloredpattern)
 								}
 								case e: SqlSyntaxErrorException => println(e.getMessage + System.lineSeparator() + "INSERT INTO " + name + ".coloredpatterns (ID, PATTERN) VALUES (" + id + ", '" + coloredpattern + "')")
@@ -478,6 +488,7 @@ class DatabaseConnection(config : Configuration) {
 	}
 
 	def performInsert(table: String, names: Seq[Any], values: Seq[Any]): Option[Int] = {
+		validateDatasetString(table)
 		val query = String.format("insert into %s (%s) values (%s)",
 			table,
 			commaize(names.map(n => n.toString).toList),
@@ -513,6 +524,7 @@ class DatabaseConnection(config : Configuration) {
 	}
 
 	def getSubjectId(dataset: String, s: String): Int = {
+		validateDatasetString(dataset)
 		var result : Int = -1
 		val statement = connection.createStatement()
 		try {
@@ -544,6 +556,7 @@ class DatabaseConnection(config : Configuration) {
 	}
 
 	def getObjectId(name: String, s: String): Int = {
+		validateDatasetString(name)
 		var result : Int = -1
 		val statement = connection.createStatement()
 		val resultSet = statement.executeQuery("SELECT tuple_id FROM " + name + ".objecttable WHERE object='" + s.replace("'", "") + "'")
@@ -556,14 +569,14 @@ class DatabaseConnection(config : Configuration) {
 	def getOntologyNamespace(s: String): String = {
 		var namespace :String = null
 		try {
-			val sql = sql"""SELECT ONTOLOGY_NAMESPACE FROM PROLOD_MAIN.SCHEMATA WHERE SCHEMA_NAME = '#${s}'""".as[String]
+			val sql = sql"""SELECT ONTOLOGY_NAMESPACE FROM PROLOD_MAIN.SCHEMATA WHERE SCHEMA_NAME = ${s}""".as[String]
 			val result = execute(sql)
 			result map ((ns) => {
 				namespace = ns
 			})
 		} catch {
-			case e: SqlException => println(e.getMessage + System.lineSeparator())
-			case e: SqlSyntaxErrorException   => println(e.getMessage + System.lineSeparator())
+			case e: SqlException => println("error getting ontology namespace: " + e.getMessage + System.lineSeparator())
+			case e: SqlSyntaxErrorException   => println("syntax in ontology namespace: " + e.getMessage + System.lineSeparator())
 		}
 		namespace
 	}
@@ -571,13 +584,13 @@ class DatabaseConnection(config : Configuration) {
 	def getNamespace(s: String): String = {
 		var namespace :String = null
 		try {
-			val sql = sql"""SELECT NAMESPACE FROM PROLOD_MAIN.SCHEMATA WHERE SCHEMA_NAME = '#${s}'""".as[String]
+			val sql = sql"""SELECT NAMESPACE FROM PROLOD_MAIN.SCHEMATA WHERE SCHEMA_NAME = ${s}""".as[String]
 			val result = execute(sql)
 			result map ((ns) => {
 				namespace = ns
 			})
 		} catch {
-			case e: SqlException => println(e.getMessage + System.lineSeparator())
+			case e: SqlException => println("error getting namespace: " + e.getMessage + System.lineSeparator())
 			case e: SqlSyntaxErrorException   => println(e.getMessage + System.lineSeparator())
 		}
 		namespace
@@ -591,6 +604,7 @@ class DatabaseConnection(config : Configuration) {
 	}
 
 	def getPredicateId(name: String, s: String): Int = {
+		validateDatasetString(name)
 		var result : Int = -1
 		val statement = connection.createStatement()
 		val resultSet = statement.executeQuery("SELECT id FROM " + name + ".predicatetable WHERE predicate='" + s + "'")
@@ -641,9 +655,10 @@ class DatabaseConnection(config : Configuration) {
 	}
 
 	def updateClusterSizes(dataset : String, ontologyNamespace : String) = {
+		validateDatasetString(dataset)
 		for (cluster : Group <- getClusters(dataset, ontologyNamespace)) {
 			try {
-				val sql = sql"""SELECT COUNT(*) FROM #${dataset}.MAINTABLE as m, #${dataset}.predicatetable as p, #${dataset}.objecttable as o WHERE m.predicate_id = p.id  AND o.tuple_id = m.tuple_id  AND p.predicate = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' AND o.object = '#${ontologyNamespace}#${cluster.name}'""".as[(Int)]
+				val sql = sql"""SELECT COUNT(*) FROM #${dataset}.MAINTABLE as m, #${dataset}.predicatetable as p, #${dataset}.objecttable as o WHERE m.predicate_id = p.id  AND o.tuple_id = m.tuple_id  AND p.predicate = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' AND o.object = ${ontologyNamespace + cluster.name}""".as[(Int)]
 				val result = execute(sql)
 				var clusterSize = 0
 				result map ((cluster_size) => {

programming_language: Scala
filename: GraphLod.scala
change_type: ModificationType.MODIFY
diff: @@ -153,8 +153,10 @@ object GraphLod extends Controller {
       data.classDistribution =  classDistribution
     }
 
-    val patternDiameter = db.getPatternDiameter(datasetId, data.patterns.last.id)
-    data.diameter = patternDiameter
+    if(data.patterns.nonEmpty) {
+      val patternDiameter = db.getPatternDiameter(datasetId, data.patterns.last.id)
+      data.diameter = patternDiameter
+    }
 
     val json = Json.obj("statistics" -> data)
     Ok(json)

programming_language: Scala