Details
-
Bug
-
Status: Open
-
Major
-
Resolution: Unresolved
-
None
-
None
Description
When executing a prepare sql statement, adding too many spaces in front of sql will cause redos.The following is an example.
import groovy.sql.Sql class SqlTest { static void main(String[] args) { def url = 'jdbc:mysql://127.0.0.1:3306/test' def user = 'user' def password = '123456' def driver = 'com.mysql.cj.jdbc.Driver' def conn = Sql.newInstance(url, user, password, driver) def sql = "" for (int i = 0; i < 400; i++) { sql += " " } sql += "select * from users where id=?" def startTime = System.currentTimeMillis() conn.execute(sql, 1) println("exec sql: " + (System.currentTimeMillis() - startTime)) conn.close() } }
The groovy and mysql-connector versions used are as follows
<dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>3.0.7</version> </dependency> <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-sql</artifactId> <version>3.0.7</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.23</version> </dependency>
The output after executing this is as follows
exec sql: 11731
This shows that the conn.execute() operation took about 11 seconds to complete, and the cpu utilization has been high during this period. Modifying 400 in the for loop to 1000 will take longer and eventually lead to exhaustion of computer resources.
The reason for this vuln is that groovy.sql.Sql$CreatePreparedStatementCommand.appearsLikeStoredProc uses improper regular expressions for matching.
private boolean appearsLikeStoredProc(String sql) { return sql.matches("\\s*[{]?\\s*[?]?\\s*[=]?\\s*[cC][aA][lL][lL].*"); }