ronin-code-sql 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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