ronin-code-sql 2.0.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.document +4 -0
  3. data/.editorconfig +11 -0
  4. data/.github/workflows/ruby.yml +27 -0
  5. data/.gitignore +11 -0
  6. data/.mailmap +1 -0
  7. data/.rspec +1 -0
  8. data/.ruby-version +1 -0
  9. data/.yardopts +1 -0
  10. data/COPYING.txt +165 -0
  11. data/ChangeLog.md +104 -0
  12. data/Gemfile +28 -0
  13. data/README.md +212 -0
  14. data/Rakefile +30 -0
  15. data/gemspec.yml +25 -0
  16. data/lib/ronin/code/sql/binary_expr.rb +53 -0
  17. data/lib/ronin/code/sql/clause.rb +74 -0
  18. data/lib/ronin/code/sql/clauses.rb +310 -0
  19. data/lib/ronin/code/sql/emittable.rb +88 -0
  20. data/lib/ronin/code/sql/emitter.rb +406 -0
  21. data/lib/ronin/code/sql/field.rb +110 -0
  22. data/lib/ronin/code/sql/fields.rb +82 -0
  23. data/lib/ronin/code/sql/function.rb +53 -0
  24. data/lib/ronin/code/sql/functions.rb +1265 -0
  25. data/lib/ronin/code/sql/injection.rb +168 -0
  26. data/lib/ronin/code/sql/injection_expr.rb +113 -0
  27. data/lib/ronin/code/sql/literal.rb +40 -0
  28. data/lib/ronin/code/sql/literals.rb +83 -0
  29. data/lib/ronin/code/sql/operators.rb +384 -0
  30. data/lib/ronin/code/sql/statement.rb +72 -0
  31. data/lib/ronin/code/sql/statement_list.rb +112 -0
  32. data/lib/ronin/code/sql/statements.rb +117 -0
  33. data/lib/ronin/code/sql/unary_expr.rb +38 -0
  34. data/lib/ronin/code/sql/version.rb +28 -0
  35. data/lib/ronin/code/sql.rb +96 -0
  36. data/ronin-code-sql.gemspec +62 -0
  37. data/spec/spec_helper.rb +3 -0
  38. data/spec/sql/binary_expr_examples.rb +25 -0
  39. data/spec/sql/binary_expr_spec.rb +5 -0
  40. data/spec/sql/clause_examples.rb +43 -0
  41. data/spec/sql/clause_spec.rb +31 -0
  42. data/spec/sql/clauses_spec.rb +47 -0
  43. data/spec/sql/emittable_spec.rb +41 -0
  44. data/spec/sql/emitter_spec.rb +533 -0
  45. data/spec/sql/field_spec.rb +103 -0
  46. data/spec/sql/fields_spec.rb +40 -0
  47. data/spec/sql/function_examples.rb +30 -0
  48. data/spec/sql/function_spec.rb +25 -0
  49. data/spec/sql/functions_spec.rb +113 -0
  50. data/spec/sql/injection_expr_spec.rb +98 -0
  51. data/spec/sql/injection_spec.rb +172 -0
  52. data/spec/sql/literal_spec.rb +5 -0
  53. data/spec/sql/literals_spec.rb +46 -0
  54. data/spec/sql/operators_spec.rb +44 -0
  55. data/spec/sql/statement_examples.rb +39 -0
  56. data/spec/sql/statement_list_spec.rb +48 -0
  57. data/spec/sql/statement_spec.rb +38 -0
  58. data/spec/sql/statements_spec.rb +22 -0
  59. data/spec/sql/unary_expr_examples.rb +20 -0
  60. data/spec/sql/unary_expr_spec.rb +5 -0
  61. data/spec/sql_spec.rb +18 -0
  62. 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
@@ -0,0 +1,3 @@
1
+ require 'rspec'
2
+ require 'simplecov'
3
+ SimpleCov.start
@@ -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,5 @@
1
+ require 'spec_helper'
2
+ require 'ronin/code/sql/binary_expr'
3
+
4
+ describe Ronin::Code::SQL::BinaryExpr do
5
+ 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