ronin-code-sql 2.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +4 -0
- data/.editorconfig +11 -0
- data/.github/workflows/ruby.yml +27 -0
- data/.gitignore +11 -0
- data/.mailmap +1 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/.yardopts +1 -0
- data/COPYING.txt +165 -0
- data/ChangeLog.md +104 -0
- data/Gemfile +28 -0
- data/README.md +212 -0
- data/Rakefile +30 -0
- data/gemspec.yml +25 -0
- data/lib/ronin/code/sql/binary_expr.rb +53 -0
- data/lib/ronin/code/sql/clause.rb +74 -0
- data/lib/ronin/code/sql/clauses.rb +310 -0
- data/lib/ronin/code/sql/emittable.rb +88 -0
- data/lib/ronin/code/sql/emitter.rb +406 -0
- data/lib/ronin/code/sql/field.rb +110 -0
- data/lib/ronin/code/sql/fields.rb +82 -0
- data/lib/ronin/code/sql/function.rb +53 -0
- data/lib/ronin/code/sql/functions.rb +1265 -0
- data/lib/ronin/code/sql/injection.rb +168 -0
- data/lib/ronin/code/sql/injection_expr.rb +113 -0
- data/lib/ronin/code/sql/literal.rb +40 -0
- data/lib/ronin/code/sql/literals.rb +83 -0
- data/lib/ronin/code/sql/operators.rb +384 -0
- data/lib/ronin/code/sql/statement.rb +72 -0
- data/lib/ronin/code/sql/statement_list.rb +112 -0
- data/lib/ronin/code/sql/statements.rb +117 -0
- data/lib/ronin/code/sql/unary_expr.rb +38 -0
- data/lib/ronin/code/sql/version.rb +28 -0
- data/lib/ronin/code/sql.rb +96 -0
- data/ronin-code-sql.gemspec +62 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/sql/binary_expr_examples.rb +25 -0
- data/spec/sql/binary_expr_spec.rb +5 -0
- data/spec/sql/clause_examples.rb +43 -0
- data/spec/sql/clause_spec.rb +31 -0
- data/spec/sql/clauses_spec.rb +47 -0
- data/spec/sql/emittable_spec.rb +41 -0
- data/spec/sql/emitter_spec.rb +533 -0
- data/spec/sql/field_spec.rb +103 -0
- data/spec/sql/fields_spec.rb +40 -0
- data/spec/sql/function_examples.rb +30 -0
- data/spec/sql/function_spec.rb +25 -0
- data/spec/sql/functions_spec.rb +113 -0
- data/spec/sql/injection_expr_spec.rb +98 -0
- data/spec/sql/injection_spec.rb +172 -0
- data/spec/sql/literal_spec.rb +5 -0
- data/spec/sql/literals_spec.rb +46 -0
- data/spec/sql/operators_spec.rb +44 -0
- data/spec/sql/statement_examples.rb +39 -0
- data/spec/sql/statement_list_spec.rb +48 -0
- data/spec/sql/statement_spec.rb +38 -0
- data/spec/sql/statements_spec.rb +22 -0
- data/spec/sql/unary_expr_examples.rb +20 -0
- data/spec/sql/unary_expr_spec.rb +5 -0
- data/spec/sql_spec.rb +18 -0
- metadata +157 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-code-sql - A Ruby DSL for crafting SQL Injections.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-code-sql is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-code-sql is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with ronin-code-sql. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
module Ronin
|
22
|
+
module Code
|
23
|
+
module SQL
|
24
|
+
# Ronin SQL version
|
25
|
+
VERSION = '2.0.0.beta1'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-code-sql - A Ruby DSL for crafting SQL Injections.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-code-sql is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-code-sql is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with ronin-code-sql. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'ronin/code/sql/statement_list'
|
22
|
+
require 'ronin/code/sql/injection'
|
23
|
+
|
24
|
+
module Ronin
|
25
|
+
module Code
|
26
|
+
#
|
27
|
+
# Provides a Domain Specific Language (DSL) for crafting complex
|
28
|
+
# {StatementList SQL} and SQL {Injection Injections} (SQLi).
|
29
|
+
#
|
30
|
+
# @see http://en.wikipedia.org/wiki/SQL_injection
|
31
|
+
#
|
32
|
+
module SQL
|
33
|
+
|
34
|
+
#
|
35
|
+
# Creates a new SQL statement list.
|
36
|
+
#
|
37
|
+
# @yield [(statements)]
|
38
|
+
# If a block is given, it will be evaluated within the statement list.
|
39
|
+
# If the block accepts an argument, the block will be called with the
|
40
|
+
# new statement list.
|
41
|
+
#
|
42
|
+
# @yieldparam [StatementList] statements
|
43
|
+
# The new statement list.
|
44
|
+
#
|
45
|
+
# @return [StatementList]
|
46
|
+
# The new SQL statement list.
|
47
|
+
#
|
48
|
+
# @example
|
49
|
+
# sql { select(1,2,3,4,id).from(users) }
|
50
|
+
# # => #<Ronin::Code::SQL::StatementList: SELECT (1,2,3,4,id) FROM users>
|
51
|
+
#
|
52
|
+
# @api public
|
53
|
+
#
|
54
|
+
def sql(&block)
|
55
|
+
StatementList.new(&block)
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# Creates a new SQL injection (SQLi)
|
60
|
+
#
|
61
|
+
# @param [Hash{Symbol => Object}] kwargs
|
62
|
+
# Additional keyword arguments for {Injection#initialize}.
|
63
|
+
#
|
64
|
+
# @option kwargs [:integer, :decimal, :string, :column] :escape
|
65
|
+
# The type of element to escape out of.
|
66
|
+
#
|
67
|
+
# @option kwargs [Boolean] :terminate
|
68
|
+
# Specifies whether to terminate the SQLi with a comment.
|
69
|
+
#
|
70
|
+
# @option kwargs [String, Symbol, Integer] :place_holder
|
71
|
+
# Place-holder data.
|
72
|
+
#
|
73
|
+
# @yield [(injection)]
|
74
|
+
# If a block is given, it will be evaluated within the injection.
|
75
|
+
# If the block accepts an argument, the block will be called with the
|
76
|
+
# new injection.
|
77
|
+
#
|
78
|
+
# @yieldparam [Injection] injection
|
79
|
+
# The new injection.
|
80
|
+
#
|
81
|
+
# @return [Injection]
|
82
|
+
# The new SQL injection.
|
83
|
+
#
|
84
|
+
# @example
|
85
|
+
# sqli { self.and { 1 == 1 }.select(1,2,3,4,id).from(users) }
|
86
|
+
# # => #<Ronin::Code::SQL::Injection: 1 AND 1=1; SELECT (1,2,3,4,id) FROM users; SELECT (1,2,3,4,id) FROM users>
|
87
|
+
#
|
88
|
+
# @api public
|
89
|
+
#
|
90
|
+
def sqli(**kwargs,&block)
|
91
|
+
Injection.new(**kwargs,&block)
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gemspec = YAML.load_file('gemspec.yml')
|
7
|
+
|
8
|
+
gem.name = gemspec.fetch('name')
|
9
|
+
gem.version = gemspec.fetch('version') do
|
10
|
+
lib_dir = File.join(File.dirname(__FILE__),'lib')
|
11
|
+
$LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
|
12
|
+
|
13
|
+
require 'ronin/code/sql/version'
|
14
|
+
Ronin::Code::SQL::VERSION
|
15
|
+
end
|
16
|
+
|
17
|
+
gem.summary = gemspec['summary']
|
18
|
+
gem.description = gemspec['description']
|
19
|
+
gem.licenses = Array(gemspec['license'])
|
20
|
+
gem.authors = Array(gemspec['authors'])
|
21
|
+
gem.email = gemspec['email']
|
22
|
+
gem.homepage = gemspec['homepage']
|
23
|
+
gem.metadata = gemspec['metadata'] if gemspec['metadata']
|
24
|
+
|
25
|
+
glob = lambda { |patterns| gem.files & Dir[*patterns] }
|
26
|
+
|
27
|
+
gem.files = `git ls-files`.split($/)
|
28
|
+
gem.files = glob[gemspec['files']] if gemspec['files']
|
29
|
+
gem.files += Array(gemspec['generated_files'])
|
30
|
+
|
31
|
+
gem.executables = gemspec.fetch('executables') do
|
32
|
+
glob['bin/*'].map { |path| File.basename(path) }
|
33
|
+
end
|
34
|
+
gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
|
35
|
+
|
36
|
+
gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
|
37
|
+
gem.test_files = glob[gemspec['test_files'] || 'spec/{**/}*_spec.rb']
|
38
|
+
gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
|
39
|
+
|
40
|
+
gem.require_paths = Array(gemspec.fetch('require_paths') {
|
41
|
+
%w[ext lib].select { |dir| File.directory?(dir) }
|
42
|
+
})
|
43
|
+
|
44
|
+
gem.requirements = gemspec['requirements']
|
45
|
+
gem.required_ruby_version = gemspec['required_ruby_version']
|
46
|
+
gem.required_rubygems_version = gemspec['required_rubygems_version']
|
47
|
+
gem.post_install_message = gemspec['post_install_message']
|
48
|
+
|
49
|
+
split = lambda { |string| string.split(/,\s*/) }
|
50
|
+
|
51
|
+
if gemspec['dependencies']
|
52
|
+
gemspec['dependencies'].each do |name,versions|
|
53
|
+
gem.add_dependency(name,split[versions])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
if gemspec['development_dependencies']
|
58
|
+
gemspec['development_dependencies'].each do |name,versions|
|
59
|
+
gem.add_development_dependency(name,split[versions])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ronin/code/sql/binary_expr'
|
3
|
+
|
4
|
+
shared_examples_for "BinaryExpr" do |method,operator=method|
|
5
|
+
describe "##{method}" do
|
6
|
+
let(:operand) { 1 }
|
7
|
+
let(:expr) { subject.send(method,operand) }
|
8
|
+
|
9
|
+
it "should be a BinaryExpr" do
|
10
|
+
expect(expr).to be_kind_of(Ronin::Code::SQL::BinaryExpr)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should set the left-hand side operand" do
|
14
|
+
expect(expr.left).to eq(subject)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should have a '#{operator}' operator" do
|
18
|
+
expect(expr.operator).to eq(operator)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should set the right-hand side operand" do
|
22
|
+
expect(expr.right).to eq(operand)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples_for "Clause" do |method,keyword,argument_or_block=nil|
|
4
|
+
describe "##{method}" do
|
5
|
+
case argument_or_block
|
6
|
+
when Proc
|
7
|
+
before { subject.send(method,&argument_or_block) }
|
8
|
+
when Array
|
9
|
+
let(:arguments) { argument_or_block }
|
10
|
+
|
11
|
+
before { subject.send(method,*arguments) }
|
12
|
+
when NilClass
|
13
|
+
before { subject.send(method) }
|
14
|
+
else
|
15
|
+
let(:argument) { argument_or_block }
|
16
|
+
|
17
|
+
before { subject.send(method,argument) }
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should add a #{keyword} clause" do
|
21
|
+
expect(clause.keyword).to eq(keyword)
|
22
|
+
end
|
23
|
+
|
24
|
+
case argument_or_block
|
25
|
+
when Proc
|
26
|
+
it "should accept a block" do
|
27
|
+
expect(clause.argument).not_to be_nil
|
28
|
+
end
|
29
|
+
when NilClass
|
30
|
+
it "should not have an argument" do
|
31
|
+
expect(clause.argument).to be_nil
|
32
|
+
end
|
33
|
+
when Array
|
34
|
+
it "should accept an argument" do
|
35
|
+
expect(clause.argument).to eq(arguments)
|
36
|
+
end
|
37
|
+
else
|
38
|
+
it "should accept an argument" do
|
39
|
+
expect(clause.argument).to eq(argument)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ronin/code/sql/clause'
|
3
|
+
|
4
|
+
describe Ronin::Code::SQL::Clause do
|
5
|
+
describe "#initialize" do
|
6
|
+
context "when given an argument" do
|
7
|
+
let(:argument) { 1 }
|
8
|
+
|
9
|
+
subject { described_class.new(:CLAUSE,argument) }
|
10
|
+
|
11
|
+
it "should set the argument" do
|
12
|
+
expect(subject.argument).to eq(argument)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "when given a block" do
|
17
|
+
subject do
|
18
|
+
described_class.new(:CLAUSE) { 1 }
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should use the return value as the argument" do
|
22
|
+
expect(subject.argument).to eq(1)
|
23
|
+
end
|
24
|
+
|
25
|
+
context "that accepts an argument" do
|
26
|
+
it "should yield itself" do
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'sql/clause_examples'
|
3
|
+
require 'ronin/code/sql/clause'
|
4
|
+
require 'ronin/code/sql/clauses'
|
5
|
+
|
6
|
+
describe Ronin::Code::SQL::Clauses do
|
7
|
+
subject { Object.new.extend(described_class) }
|
8
|
+
|
9
|
+
let(:clause) { subject.clauses.last }
|
10
|
+
|
11
|
+
it { expect(subject.clauses).to be_empty }
|
12
|
+
|
13
|
+
describe "#clause" do
|
14
|
+
let(:keyword) { :EXEC }
|
15
|
+
|
16
|
+
before { subject.clause(keyword) }
|
17
|
+
|
18
|
+
it "should add an arbitrary clause" do
|
19
|
+
expect(clause.keyword).to eq(keyword)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
include_examples "Clause", :from, :FROM, :table
|
24
|
+
include_examples "Clause", :into, :INTO, :table
|
25
|
+
include_examples "Clause", :where, :WHERE, proc { id == 1 }
|
26
|
+
include_examples "Clause", :join, :JOIN, :table
|
27
|
+
include_examples "Clause", :inner_join, [:INNER, :JOIN], :table
|
28
|
+
include_examples "Clause", :left_join, [:LEFT, :JOIN], :table
|
29
|
+
include_examples "Clause", :right_join, [:RIGHT, :JOIN], :table
|
30
|
+
include_examples "Clause", :full_join, [:FULL, :JOIN], :table
|
31
|
+
include_examples "Clause", :on, :ON, proc { id == 1 }
|
32
|
+
include_examples "Clause", :union, :UNION, proc { select(:*).from(:table) }
|
33
|
+
include_examples "Clause", :union_all, [:UNION, :ALL], proc {
|
34
|
+
select(:*).from(:table)
|
35
|
+
}
|
36
|
+
include_examples "Clause", :group_by, [:GROUP, :BY], [:column1, :column2]
|
37
|
+
include_examples "Clause", :having, :HAVING, proc { max(priv) > 100 }
|
38
|
+
include_examples "Clause", :limit, :LIMIT, 100
|
39
|
+
include_examples "Clause", :offset, :OFFSET, 20
|
40
|
+
include_examples "Clause", :top, :TOP, 50
|
41
|
+
include_examples "Clause", :into, :INTO, :table
|
42
|
+
include_examples "Clause", :values, :VALUES, [1,2,3,4]
|
43
|
+
include_examples "Clause", :default_values, [:DEFAULT, :VALUES]
|
44
|
+
include_examples "Clause", :set, :SET, {x: 1, y: 2}
|
45
|
+
include_examples "Clause", :indexed_by, [:INDEXED, :BY], :index_name
|
46
|
+
include_examples "Clause", :not_indexed, [:NOT, :INDEXED]
|
47
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ronin/code/sql/emittable'
|
3
|
+
require 'ronin/code/sql/literal'
|
4
|
+
|
5
|
+
describe Ronin::Code::SQL::Emittable do
|
6
|
+
subject { Ronin::Code::SQL::Literal.new('hello') }
|
7
|
+
|
8
|
+
describe "#emitter" do
|
9
|
+
it "should return an Ronin::Code::SQL::Emitter" do
|
10
|
+
expect(subject.emitter).to be_kind_of(Ronin::Code::SQL::Emitter)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should accept Emitter options" do
|
14
|
+
expect(subject.emitter(case: :lower).case).to eq(:lower)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#to_sql" do
|
19
|
+
it "should emit the object" do
|
20
|
+
expect(subject.to_sql).to eq("'hello'")
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when given options" do
|
24
|
+
it "should pass them to #emitter" do
|
25
|
+
expect(subject.to_sql(quotes: :double)).to eq('"hello"')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#to_s" do
|
31
|
+
it "should call #to_sql with no arguments" do
|
32
|
+
expect(subject.to_s).to eq(subject.to_sql)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#inspect" do
|
37
|
+
it "should call #to_sql with no arguments" do
|
38
|
+
expect(subject.inspect).to include(subject.to_sql)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|