nesser 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,127 @@
1
+ # Encoding: ASCII-8BIT
2
+ ##
3
+ # unpacker.rb
4
+ # Created June 20, 2017
5
+ # By Ron Bowes
6
+ #
7
+ # See: LICENSE.md
8
+ #
9
+ # DNS has some unusual properties that we have to handle, which is why I
10
+ # wrote this class. It handles building / parsing DNS packets and keeping
11
+ # track of where in the packet we currently are. The advantage, besides
12
+ # simpler unpacking, is that encoded names (with pointers to other parts
13
+ # of the packet) can be trivially handled.
14
+ ##
15
+
16
+ require 'hexhelper'
17
+
18
+ require 'nesser/dns_exception'
19
+ require 'nesser/packets/constants'
20
+
21
+ module Nesser
22
+ class Unpacker
23
+ attr_accessor :data, :offset
24
+
25
+ public
26
+ def initialize(data)
27
+ @data = data
28
+ @offset = 0
29
+ end
30
+
31
+ private
32
+ def _verify_results(results)
33
+ # If there's at least one nil included in our results, bad stuff happened
34
+ if results.index(nil)
35
+ raise(FormatException, "DNS packet was truncated (or we messed up parsing it)!")
36
+ end
37
+ end
38
+
39
+ # Unpack from the string, exactly like the normal `String#Unpack` method
40
+ # in Ruby, except that an offset into the string is maintained and updated.
41
+ public
42
+ def unpack(format)
43
+ if @offset >= @data.length
44
+ raise(FormatException, "DNS packet was invalid!")
45
+ end
46
+
47
+ results = @data[@offset..-1].unpack(format + "a*")
48
+ remaining = results.pop
49
+ @offset = @data.length - remaining.length
50
+
51
+ _verify_results(results)
52
+
53
+ return *results
54
+ end
55
+
56
+ public
57
+ def unpack_one(format)
58
+ results = unpack(format)
59
+
60
+ _verify_results(results)
61
+ if results.length != 1
62
+ raise(FormatException, "unpack_one() was passed a bad format string")
63
+ end
64
+
65
+ return results.pop()
66
+ end
67
+
68
+ # This temporarily changes the offset that we're reading from, runs the
69
+ # given block, then changes it back. This is used internally while
70
+ # unpacking names.
71
+ private
72
+ def _with_offset(offset)
73
+ old_offset = @offset
74
+ @offset = offset
75
+ yield
76
+ @offset = old_offset
77
+ end
78
+
79
+ # Unpack a name from the packet. Names are special, because they're
80
+ # encoded as:
81
+ # * A series of length-prefixed blocks, each indicating a segment
82
+ # * Blocks with a length the starts with two '1' bits (11xxxxx...), which
83
+ # contains a pointer to another name elsewhere in the packet
84
+ public
85
+ def unpack_name(depth:0)
86
+ segments = []
87
+
88
+ if depth > MAX_RECURSION_DEPTH
89
+ raise(FormatException, "It looks like this packet contains recursive pointers!")
90
+ end
91
+
92
+ loop do
93
+ # If no offset is given, just eat data from the normal source
94
+ len = unpack_one("C")
95
+
96
+ # Stop at the null terminator
97
+ if len == 0
98
+ break
99
+ end
100
+
101
+ # Handle "pointer" records by updating the offset
102
+ if (len & 0xc0) == 0xc0
103
+ # If the first two bits are 1 (ie, 0xC0), the next
104
+ # 10 bits are an offset, so we have to mask out the first two bits
105
+ # with 0x3F (00111111)
106
+ offset = ((len << 8) | unpack_one("C")) & 0x3FFF
107
+
108
+ _with_offset(offset) do
109
+ segments << unpack_name(depth:depth+1).split(/\./)
110
+ end
111
+
112
+ break
113
+ end
114
+
115
+ # It's normal, just unpack what we need to!
116
+ segments << unpack("a#{len}")
117
+ end
118
+
119
+ return segments.join('.')
120
+ end
121
+
122
+ public
123
+ def to_s()
124
+ return HexHelper::to_s(@data, offset: @offset)
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,94 @@
1
+ # Encoding: ASCII-8BIT
2
+ ##
3
+ # transaction.rb
4
+ # Created June 20, 2017
5
+ # By Ron Bowes
6
+ #
7
+ # See: LICENSE.md
8
+ #
9
+ # When a request comes in, a transaction is created and sent to the callback.
10
+ # The transaction can be used to respond to the request at any point in the
11
+ # future.
12
+ #
13
+ # Any methods with a bang ('!') in front will send the response back to the
14
+ # requester. Only one bang method can be called, any subsequent calls will
15
+ # throw an exception.
16
+ ##
17
+ module Nesser
18
+ class Transaction
19
+ attr_reader :request_packet, :response_packet, :sent
20
+
21
+ public
22
+ def initialize(s:, request_packet:, host:, port:)
23
+ @s = s
24
+ @request_packet = request_packet
25
+ @host = host
26
+ @port = port
27
+ @sent = false
28
+
29
+ @response_packet = request_packet.answer()
30
+ end
31
+
32
+ private
33
+ def not_sent!()
34
+ if @sent
35
+ raise ArgumentError("Already sent!")
36
+ end
37
+ end
38
+
39
+ public
40
+ def answer!(answers=[])
41
+ answers.each do |answer|
42
+ @response_packet.add_answer(answer)
43
+ end
44
+
45
+ reply!()
46
+ end
47
+
48
+ public
49
+ def error!(rcode)
50
+ not_sent!()
51
+
52
+ @response_packet.rcode = rcode
53
+ reply!()
54
+ end
55
+
56
+ # public
57
+ # def passthrough!(pt_host, pt_port, callback = nil)
58
+ # not_sent!()
59
+ #
60
+ # Nesser.query(@request.questions[0].name, {
61
+ # :server => pt_host,
62
+ # :port => pt_port,
63
+ # :type => @request.questions[0].type,
64
+ # :cls => @request.questions[0].cls,
65
+ # :timeout => 3,
66
+ # }
67
+ # ) do |response|
68
+ # # If there was a timeout, handle it
69
+ # if(response.nil?)
70
+ # response = @response
71
+ # response.rcode = Nesser::Packet::RCODE_SERVER_FAILURE
72
+ # end
73
+ #
74
+ # response.trn_id = @request.trn_id
75
+ # @s.send(response.serialize(), 0, @host, @port)
76
+ #
77
+ # # Let the callback know if anybody registered one
78
+ # if(callback)
79
+ # callback.call(response)
80
+ # end
81
+ # end
82
+ #
83
+ # @sent = true
84
+ # end
85
+
86
+ private
87
+ def reply!()
88
+ not_sent!()
89
+
90
+ @s.send(@response_packet.to_bytes(), 0, @host, @port)
91
+ @sent = true
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,3 @@
1
+ module Nesser
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'nesser/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "nesser"
8
+ spec.version = Nesser::VERSION
9
+ spec.authors = ["iagox86"]
10
+ spec.email = ["ron-git@skullsecurity.org"]
11
+
12
+ spec.summary = "A simple and straight forward DNS library, created for dnscat2"
13
+ spec.homepage = "https://github.com/iagox86/nesser"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
+ spec.require_paths = ["lib"]
17
+
18
+ spec.add_development_dependency "bundler"
19
+ spec.add_development_dependency "rake"
20
+ spec.add_development_dependency "simplecov"
21
+ spec.add_dependency "hexhelper"
22
+ end
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nesser
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - iagox86
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-06-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: simplecov
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: hexhelper
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description:
70
+ email:
71
+ - ron-git@skullsecurity.org
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".travis.yml"
78
+ - Gemfile
79
+ - README.md
80
+ - Rakefile
81
+ - bin/console
82
+ - bin/setup
83
+ - lib/nesser.rb
84
+ - lib/nesser/dns_exception.rb
85
+ - lib/nesser/packets/answer.rb
86
+ - lib/nesser/packets/constants.rb
87
+ - lib/nesser/packets/packer.rb
88
+ - lib/nesser/packets/packet.rb
89
+ - lib/nesser/packets/question.rb
90
+ - lib/nesser/packets/rr_types.rb
91
+ - lib/nesser/packets/unpacker.rb
92
+ - lib/nesser/transaction.rb
93
+ - lib/nesser/version.rb
94
+ - nesser.gemspec
95
+ homepage: https://github.com/iagox86/nesser
96
+ licenses: []
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.5.1
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: A simple and straight forward DNS library, created for dnscat2
118
+ test_files: []