ruby_smb 0.0.8
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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/.gitignore +21 -0
- data/.rspec +3 -0
- data/.simplecov +42 -0
- data/.travis.yml +5 -0
- data/.yardopts +1 -0
- data/CONTRIBUTING.md +119 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +18 -0
- data/README.md +64 -0
- data/Rakefile +22 -0
- data/examples/authenticate.rb +30 -0
- data/examples/negotiate.rb +25 -0
- data/lib/ruby_smb/client/authentication.rb +236 -0
- data/lib/ruby_smb/client/negotiation.rb +126 -0
- data/lib/ruby_smb/client/signing.rb +48 -0
- data/lib/ruby_smb/client.rb +164 -0
- data/lib/ruby_smb/dispatcher/base.rb +18 -0
- data/lib/ruby_smb/dispatcher/socket.rb +53 -0
- data/lib/ruby_smb/dispatcher.rb +4 -0
- data/lib/ruby_smb/error.rb +17 -0
- data/lib/ruby_smb/field/file_time.rb +62 -0
- data/lib/ruby_smb/field/nt_status.rb +16 -0
- data/lib/ruby_smb/field/stringz16.rb +55 -0
- data/lib/ruby_smb/field.rb +7 -0
- data/lib/ruby_smb/generic_packet.rb +179 -0
- data/lib/ruby_smb/gss.rb +109 -0
- data/lib/ruby_smb/smb1/andx_block.rb +13 -0
- data/lib/ruby_smb/smb1/bit_field/capabilities.rb +39 -0
- data/lib/ruby_smb/smb1/bit_field/header_flags.rb +19 -0
- data/lib/ruby_smb/smb1/bit_field/header_flags2.rb +27 -0
- data/lib/ruby_smb/smb1/bit_field/security_mode.rb +16 -0
- data/lib/ruby_smb/smb1/bit_field.rb +10 -0
- data/lib/ruby_smb/smb1/commands.rb +9 -0
- data/lib/ruby_smb/smb1/data_block.rb +42 -0
- data/lib/ruby_smb/smb1/dialect.rb +11 -0
- data/lib/ruby_smb/smb1/packet/error_packet.rb +14 -0
- data/lib/ruby_smb/smb1/packet/negotiate_request.rb +52 -0
- data/lib/ruby_smb/smb1/packet/negotiate_response.rb +46 -0
- data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +47 -0
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +71 -0
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +48 -0
- data/lib/ruby_smb/smb1/packet.rb +12 -0
- data/lib/ruby_smb/smb1/parameter_block.rb +42 -0
- data/lib/ruby_smb/smb1/smb_header.rb +21 -0
- data/lib/ruby_smb/smb1.rb +16 -0
- data/lib/ruby_smb/smb2/bit_field/session_flags.rb +17 -0
- data/lib/ruby_smb/smb2/bit_field/smb2_capabailities.rb +23 -0
- data/lib/ruby_smb/smb2/bit_field/smb2_header_flags.rb +23 -0
- data/lib/ruby_smb/smb2/bit_field/smb2_security_mode.rb +15 -0
- data/lib/ruby_smb/smb2/bit_field/smb2_security_mode_single.rb +14 -0
- data/lib/ruby_smb/smb2/bit_field.rb +11 -0
- data/lib/ruby_smb/smb2/commands.rb +25 -0
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +50 -0
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +33 -0
- data/lib/ruby_smb/smb2/packet/session_setup_request.rb +53 -0
- data/lib/ruby_smb/smb2/packet/session_setup_response.rb +38 -0
- data/lib/ruby_smb/smb2/packet.rb +10 -0
- data/lib/ruby_smb/smb2/smb2_header.rb +22 -0
- data/lib/ruby_smb/smb2.rb +12 -0
- data/lib/ruby_smb/version.rb +3 -0
- data/lib/ruby_smb.rb +22 -0
- data/ruby_smb.gemspec +38 -0
- data/spec/lib/ruby_smb/client_spec.rb +638 -0
- data/spec/lib/ruby_smb/dispatcher/dispatcher_base_spec.rb +22 -0
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +60 -0
- data/spec/lib/ruby_smb/field/file_time_spec.rb +59 -0
- data/spec/lib/ruby_smb/field/nt_status_spec.rb +19 -0
- data/spec/lib/ruby_smb/field/stringz16_spec.rb +50 -0
- data/spec/lib/ruby_smb/generic_packet_spec.rb +58 -0
- data/spec/lib/ruby_smb/smb1/andx_block_spec.rb +41 -0
- data/spec/lib/ruby_smb/smb1/bit_field/capabilities_spec.rb +245 -0
- data/spec/lib/ruby_smb/smb1/bit_field/header_flags2_spec.rb +146 -0
- data/spec/lib/ruby_smb/smb1/bit_field/header_flags_spec.rb +102 -0
- data/spec/lib/ruby_smb/smb1/bit_field/security_mode_spec.rb +44 -0
- data/spec/lib/ruby_smb/smb1/data_block_spec.rb +26 -0
- data/spec/lib/ruby_smb/smb1/dialect_spec.rb +26 -0
- data/spec/lib/ruby_smb/smb1/packet/error_packet_spec.rb +39 -0
- data/spec/lib/ruby_smb/smb1/packet/negotiate_request_spec.rb +77 -0
- data/spec/lib/ruby_smb/smb1/packet/negotiate_response_extended_spec.rb +149 -0
- data/spec/lib/ruby_smb/smb1/packet/negotiate_response_spec.rb +150 -0
- data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +100 -0
- data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +72 -0
- data/spec/lib/ruby_smb/smb1/parameter_block_spec.rb +26 -0
- data/spec/lib/ruby_smb/smb1/smb_header_spec.rb +96 -0
- data/spec/lib/ruby_smb/smb2/bit_field/header_flags_spec.rb +81 -0
- data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +28 -0
- data/spec/lib/ruby_smb/smb2/bit_field/smb2_capabilities_spec.rb +72 -0
- data/spec/lib/ruby_smb/smb2/bit_field/smb_secruity_mode_spec.rb +22 -0
- data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +122 -0
- data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +147 -0
- data/spec/lib/ruby_smb/smb2/packet/session_setup_request_spec.rb +79 -0
- data/spec/lib/ruby_smb/smb2/packet/session_setup_response_spec.rb +54 -0
- data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +127 -0
- data/spec/lib/ruby_smb_spec.rb +2 -0
- data/spec/spec_helper.rb +100 -0
- data/spec/support/mock_socket_dispatcher.rb +8 -0
- data/spec/support/shared/examples/bit_field_single_flag.rb +14 -0
- data.tar.gz.sig +0 -0
- metadata +384 -0
- metadata.gz.sig +0 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 203527ee7c807b85b3af96aea81bdc9f543b5f16
|
|
4
|
+
data.tar.gz: f80aa766405b6b813a5ac9a65aca3778d24f20a0
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 79add85ae366057d7c77cafa684c6c3d6e842777bbf161d768dd8e206a344f712fc3cf5684a0d625c77162e1a07f8dcb7e43bf92292b9fedd0bfd8169a873375
|
|
7
|
+
data.tar.gz: 5866aa5f7aed28b0dfa8b3c147434ebefe6a6e4964618ba7d4762349f5090e826c1461950ec79a53fc52074f75eb99abc8b6a488d9901f2701b537c28aec5601
|
checksums.yaml.gz.sig
ADDED
|
Binary file
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.simplecov
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# RM_INFO is set when using Rubymine. In Rubymine, starting SimpleCov is
|
|
2
|
+
# controlled by running with coverage, so don't explicitly start coverage (and
|
|
3
|
+
# therefore generate a report) when in Rubymine. This _will_ generate a report
|
|
4
|
+
# whenever `rake spec` is run.
|
|
5
|
+
unless ENV['RM_INFO']
|
|
6
|
+
SimpleCov.start
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
SimpleCov.configure do
|
|
10
|
+
# ignore this file
|
|
11
|
+
add_filter '.simplecov'
|
|
12
|
+
|
|
13
|
+
# Rake tasks aren't tested with rspec
|
|
14
|
+
add_filter 'Rakefile'
|
|
15
|
+
add_filter 'lib/tasks'
|
|
16
|
+
|
|
17
|
+
#
|
|
18
|
+
# Changed Files in Git Group
|
|
19
|
+
# @see http://fredwu.me/post/35625566267/simplecov-test-coverage-for-changed-files-only
|
|
20
|
+
#
|
|
21
|
+
|
|
22
|
+
untracked = `git ls-files --exclude-standard --others`
|
|
23
|
+
unstaged = `git diff --name-only`
|
|
24
|
+
staged = `git diff --name-only --cached`
|
|
25
|
+
all = untracked + unstaged + staged
|
|
26
|
+
changed_filenames = all.split("\n")
|
|
27
|
+
|
|
28
|
+
add_group 'Changed' do |source_file|
|
|
29
|
+
changed_filenames.detect { |changed_filename|
|
|
30
|
+
source_file.filename.end_with?(changed_filename)
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
add_group 'Libraries', 'lib'
|
|
35
|
+
|
|
36
|
+
#
|
|
37
|
+
# Specs are reported on to ensure that all examples are being run and all
|
|
38
|
+
# lets, befores, afters, etc are being used.
|
|
39
|
+
#
|
|
40
|
+
|
|
41
|
+
add_group 'Specs', 'spec'
|
|
42
|
+
end
|
data/.travis.yml
ADDED
data/.yardopts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
-m markdown
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Forking
|
|
4
|
+
|
|
5
|
+
[Fork this repository](https://github.com/rapid7/smb2/fork)
|
|
6
|
+
|
|
7
|
+
## Branching
|
|
8
|
+
|
|
9
|
+
Branch names follow the format `TYPE/ISSUE/SUMMARY`. You can create it with `git checkout -b TYPE/ISSUE/SUMMARY`.
|
|
10
|
+
|
|
11
|
+
### `TYPE`
|
|
12
|
+
|
|
13
|
+
`TYPE` can be `bug`, `chore`, or `feature`.
|
|
14
|
+
|
|
15
|
+
### `ISSUE`
|
|
16
|
+
|
|
17
|
+
`ISSUE` is either a [Github issue](https://github.com/rapid7/smb2/issues) or an issue from some other
|
|
18
|
+
issue tracking software.
|
|
19
|
+
|
|
20
|
+
### `SUMMARY`
|
|
21
|
+
|
|
22
|
+
`SUMMARY` is is short summary of the purpose of the branch composed of lower case words separated by '-' so that it is a valid `PRERELEASE` for the Gem version.
|
|
23
|
+
|
|
24
|
+
## Changes
|
|
25
|
+
|
|
26
|
+
### `PRERELEASE`
|
|
27
|
+
|
|
28
|
+
1. Update `PRERELEASE` to match the `SUMMARY` in the branch name. If you branched from `master`, and [version.rb](lib/ruby_smb/version.rb) does not have `PRERELEASE` defined, then adding the following lines after `PATCH`:
|
|
29
|
+
```
|
|
30
|
+
# The prerelease version, scoped to the {MAJOR}, {MINOR}, and {PATCH} version number.
|
|
31
|
+
PRERELEASE = '<SUMMARY>'
|
|
32
|
+
```
|
|
33
|
+
2. `rake spec`
|
|
34
|
+
3. Verify the specs pass, which indicates that `PRERELEASE` was updated correctly.
|
|
35
|
+
4. Commit the change `git commit -a`
|
|
36
|
+
|
|
37
|
+
### Your changes
|
|
38
|
+
|
|
39
|
+
Make your changes or however many commits you like, committing each with `git commit`.
|
|
40
|
+
|
|
41
|
+
### Pre-Pull Request Testing
|
|
42
|
+
|
|
43
|
+
1. Run specs one last time before opening the Pull Request: `rake spec`
|
|
44
|
+
2. Verify there was no failures.
|
|
45
|
+
|
|
46
|
+
### Push
|
|
47
|
+
|
|
48
|
+
Push your branch to your fork on gitub: `git push TYPE/ISSUE/SUMMARY`
|
|
49
|
+
|
|
50
|
+
### Pull Request
|
|
51
|
+
|
|
52
|
+
* [Create new Pull Request](https://github.com/rapid7/smb2/compare/)
|
|
53
|
+
* Add a Verification Steps to the description comment
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
# Verification Steps
|
|
57
|
+
|
|
58
|
+
- [ ] `bundle install`
|
|
59
|
+
|
|
60
|
+
## `rake spec`
|
|
61
|
+
- [ ] `rake spec`
|
|
62
|
+
- [ ] VERIFY no failures
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
You should also include at least one scenario to manually check the changes outside of specs.
|
|
66
|
+
|
|
67
|
+
* Add a Post-merge Steps comment
|
|
68
|
+
|
|
69
|
+
The 'Post-merge Steps' are a reminder to the reviewer of the Pull Request of how to update the [`PRERELEASE`](lib/windows_error/version.rb) so that [version_spec.rb](spec/lib/windows_error/version.rb_spec.rb) passes on the target branch after the merge.
|
|
70
|
+
|
|
71
|
+
DESTINATION is the name of the destination branch into which the merge is being made. SOURCE_SUMMARY is the SUMMARY from TYPE/ISSUE/SUMMARY branch name for the SOURCE branch that is being made.
|
|
72
|
+
|
|
73
|
+
When merging to `master`:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
# Post-merge Steps
|
|
77
|
+
|
|
78
|
+
Perform these steps prior to pushing to master or the build will be broke on master.
|
|
79
|
+
|
|
80
|
+
## Version
|
|
81
|
+
- [ ] Edit `lib/ruby_smb/version.rb`
|
|
82
|
+
- [ ] Remove `PRERELEASE` and its comment as `PRERELEASE` is not defined on master.
|
|
83
|
+
|
|
84
|
+
## Gem build
|
|
85
|
+
- [ ] gem build *.gemspec
|
|
86
|
+
- [ ] VERIFY the gem has no '.pre' version suffix.
|
|
87
|
+
|
|
88
|
+
## RSpec
|
|
89
|
+
- [ ] `rake spec`
|
|
90
|
+
- [ ] VERIFY version examples pass without failures
|
|
91
|
+
|
|
92
|
+
## Commit & Push
|
|
93
|
+
- [ ] `git commit -a`
|
|
94
|
+
- [ ] `git push origin master`
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
When merging to DESTINATION other than `master`:
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
# Post-merge Steps
|
|
101
|
+
|
|
102
|
+
Perform these steps prior to pushing to DESTINATION or the build will be broke on DESTINATION.
|
|
103
|
+
|
|
104
|
+
## Version
|
|
105
|
+
- [ ] Edit `lib/windows_error/version.rb`
|
|
106
|
+
- [ ] Change `PRERELEASE` from `SOURCE_SUMMARY` to `DESTINATION_SUMMARY` to match the branch (DESTINATION) summary (DESTINATION_SUMMARY)
|
|
107
|
+
|
|
108
|
+
## Gem build
|
|
109
|
+
- [ ] gem build windows_error.gemspec
|
|
110
|
+
- [ ] VERIFY the prerelease suffix has change on the gem.
|
|
111
|
+
|
|
112
|
+
## RSpec
|
|
113
|
+
- [ ] `rake spec`
|
|
114
|
+
- [ ] VERIFY version examples pass without failures
|
|
115
|
+
|
|
116
|
+
## Commit & Push
|
|
117
|
+
- [ ] `git commit -a`
|
|
118
|
+
- [ ] `git push origin DESTINATION`
|
|
119
|
+
```
|
data/Gemfile
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
source 'https://rubygems.org'
|
|
2
|
+
gemspec
|
|
3
|
+
|
|
4
|
+
gem 'pry'
|
|
5
|
+
|
|
6
|
+
group :test do
|
|
7
|
+
# simplecov test formatter and uploader for Coveralls.io
|
|
8
|
+
gem 'coveralls', require: false
|
|
9
|
+
# Testing
|
|
10
|
+
gem 'rspec'
|
|
11
|
+
# Coverage reports
|
|
12
|
+
gem 'simplecov', require: false
|
|
13
|
+
end
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Copyright 2014, Rapid7, Inc.
|
|
2
|
+
|
|
3
|
+
License: BSD-3-clause
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
* Redistributions of source code must retain the above copyright notice,
|
|
9
|
+
this list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
* Redistributions in binary form must reproduce the above copyright
|
|
12
|
+
notice, this list of conditions and the following disclaimer in the
|
|
13
|
+
documentation and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
* Neither the name of the copyright holder nor the names of its contributors
|
|
16
|
+
may be used to endorse or promote products derived from this software
|
|
17
|
+
without specific prior written permission.
|
|
18
|
+
|
data/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# RubySMB
|
|
2
|
+
|
|
3
|
+
[](https://travis-ci.org/rapid7/ruby_smb)
|
|
4
|
+
[](https://codeclimate.com/github/rapid7/ruby_smb)
|
|
5
|
+
[](https://coveralls.io/github/rapid7/ruby_smb?branch=master)
|
|
6
|
+
|
|
7
|
+
A packet parsing and manipulation library for the SMB family of protocols.
|
|
8
|
+
|
|
9
|
+
See Microsoft's [[MS-SMB2]](http://msdn.microsoft.com/en-us/library/cc246482.aspx)
|
|
10
|
+
|
|
11
|
+
It supports authentication via NTLM using the [ruby ntlm gem](https://rubygems.org/gems/rubyntlm)
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
This gem has not yet been released, but when it is, do this:
|
|
16
|
+
|
|
17
|
+
Add this line to your application's Gemfile:
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
gem 'ruby_smb'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
And then execute:
|
|
24
|
+
|
|
25
|
+
$ bundle
|
|
26
|
+
|
|
27
|
+
Or install it yourself as:
|
|
28
|
+
|
|
29
|
+
$ gem install ruby_smb
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
Updated Usage Docs coming soon
|
|
34
|
+
|
|
35
|
+
## Developer tips
|
|
36
|
+
You'll want to have Wireshark and perhaps a tool like Impacket (which provides a small SMB client in one of its examples) installed to help with your work:
|
|
37
|
+
|
|
38
|
+
### Wireshark
|
|
39
|
+
- `sudo apt-get install wireshark`
|
|
40
|
+
- `sudo dpkg-reconfigure wireshark-common`
|
|
41
|
+
- `sudo addgroup wireshark`
|
|
42
|
+
- `sudo usermod -a -G wireshark <USERNAME>`
|
|
43
|
+
|
|
44
|
+
### Impacket
|
|
45
|
+
- `sudo apt-get install python-setuptools`
|
|
46
|
+
- `sudo easy_install pyasn1 pycrypto`
|
|
47
|
+
- Download from GitHub (https://github.com/coresecurity/impacket)
|
|
48
|
+
- `sudo python setup.py install`
|
|
49
|
+
- `cd examples && python smbclient.py <USER>:<PASS>@<WINDOWS HOST IP>`
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
## License
|
|
54
|
+
|
|
55
|
+
`ruby_smb` is released under a 3-clause BSD license. See [LICENSE.txt](LICENSE.txt) for full text.
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
## Contributing
|
|
59
|
+
|
|
60
|
+
1. Fork it ( https://github.com/rapid7/smb2/fork )
|
|
61
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
62
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
63
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
64
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'bundler/gem_tasks'
|
|
2
|
+
|
|
3
|
+
require 'rspec/core/rake_task'
|
|
4
|
+
|
|
5
|
+
require 'yard'
|
|
6
|
+
require 'yard/rake/yardoc_task'
|
|
7
|
+
|
|
8
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
9
|
+
|
|
10
|
+
YARD::Rake::YardocTask.new do |t|
|
|
11
|
+
t.options = [
|
|
12
|
+
'-m', 'markdown'
|
|
13
|
+
]
|
|
14
|
+
t.options += Dir.glob('yard_extensions/*.rb').flat_map { |e| ['-e', e] }
|
|
15
|
+
t.files = [
|
|
16
|
+
'lib/**/*.rb',
|
|
17
|
+
'-',
|
|
18
|
+
'README.md', 'LICENSE.txt'
|
|
19
|
+
]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
task default: :spec
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
|
|
3
|
+
# This script tests a full Authentication/Session Setup cycle
|
|
4
|
+
# including protocol negotiation and authentication.
|
|
5
|
+
|
|
6
|
+
require 'bundler/setup'
|
|
7
|
+
require 'ruby_smb'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def run_authentication(address, smb1, smb2, username, password)
|
|
11
|
+
# Create our socket and add it to the dispatcher
|
|
12
|
+
sock = TCPSocket.new address, 445
|
|
13
|
+
dispatcher = RubySMB::Dispatcher::Socket.new(sock)
|
|
14
|
+
|
|
15
|
+
client = RubySMB::Client.new(dispatcher, smb1: smb1, smb2: smb2, username: username, password: password)
|
|
16
|
+
protocol = client.negotiate
|
|
17
|
+
status = client.authenticate
|
|
18
|
+
puts "#{protocol} : #{status}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
address = ARGV[0]
|
|
22
|
+
username = ARGV[1]
|
|
23
|
+
password = ARGV[2]
|
|
24
|
+
|
|
25
|
+
# Negotiate with both SMB1 and SMB2 enabled on the client
|
|
26
|
+
run_authentication(address, true, true, username, password)
|
|
27
|
+
# Negotiate with only SMB1 enabled
|
|
28
|
+
run_authentication(address, true, false, username, password)
|
|
29
|
+
# Negotiate with only SMB2 enabled
|
|
30
|
+
run_authentication(address, false, true, username, password)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# This script is for testing the Protocol Negotiation in the library
|
|
5
|
+
# without any other parts.
|
|
6
|
+
|
|
7
|
+
require 'bundler/setup'
|
|
8
|
+
require 'ruby_smb'
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def run_negotiation(address, smb1, smb2)
|
|
12
|
+
# Create our socket and add it to the dispatcher
|
|
13
|
+
sock = TCPSocket.new address, 445
|
|
14
|
+
dispatcher = RubySMB::Dispatcher::Socket.new(sock)
|
|
15
|
+
|
|
16
|
+
client = RubySMB::Client.new(dispatcher, smb1: smb1, smb2: smb2, username: 'msfadmin', password: 'msfadmin')
|
|
17
|
+
client.negotiate
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Negotiate with both SMB1 and SMB2 enabled on the client
|
|
21
|
+
run_negotiation(ARGV[0], true, true)
|
|
22
|
+
# Negotiate with only SMB1 enabled
|
|
23
|
+
run_negotiation(ARGV[0], true, false)
|
|
24
|
+
# Negotiate with only SMB2 enabled
|
|
25
|
+
run_negotiation(ARGV[0], false, true)
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
class Client
|
|
3
|
+
# This module holds all the backend client methods for authentication.
|
|
4
|
+
module Authentication
|
|
5
|
+
|
|
6
|
+
# Responsible for handling Authentication and Session Setup for
|
|
7
|
+
# the SMB Client. It returns the final Status code from the authentication
|
|
8
|
+
# exchange.
|
|
9
|
+
#
|
|
10
|
+
# @return [WindowsError::NTStatus] the NTStatus object from the SessionSetup exchange.
|
|
11
|
+
def authenticate
|
|
12
|
+
if self.smb1
|
|
13
|
+
smb1_authenticate
|
|
14
|
+
else
|
|
15
|
+
smb2_authenticate
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
#
|
|
20
|
+
# SMB1 Methods
|
|
21
|
+
#
|
|
22
|
+
|
|
23
|
+
# Handles the SMB1 NTLMSSP 4-way handshake for Authentication
|
|
24
|
+
def smb1_authenticate
|
|
25
|
+
response = smb1_ntlmssp_negotiate
|
|
26
|
+
challenge_packet = smb1_ntlmssp_challenge_packet(response)
|
|
27
|
+
user_id = challenge_packet.smb_header.uid
|
|
28
|
+
challenge_message = smb1_type2_message(challenge_packet)
|
|
29
|
+
raw = smb1_ntlmssp_authenticate(challenge_message, user_id)
|
|
30
|
+
response = smb1_ntlmssp_final_packet(raw)
|
|
31
|
+
response_code = response.status_code
|
|
32
|
+
self.user_id = user_id if response_code.name == "STATUS_SUCCESS"
|
|
33
|
+
response_code
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Sends the {RubySMB::SMB1::Packet::SessionSetupRequest} packet and
|
|
37
|
+
# receives the response.
|
|
38
|
+
#
|
|
39
|
+
# @return [String] the binary string response from the server
|
|
40
|
+
def smb1_ntlmssp_negotiate
|
|
41
|
+
packet = smb1_ntlmssp_negotiate_packet
|
|
42
|
+
send_recv(packet)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Takes the Base64 encoded NTLM Type 2 (Challenge) message
|
|
46
|
+
# and calls the routines to build the Auth packet, sends the packet
|
|
47
|
+
# and receives the raw response
|
|
48
|
+
#
|
|
49
|
+
# @param type2_string [String] the Base64 Encoded NTLM Type 2 message
|
|
50
|
+
# @param user_id [Integer] the temporary user ID from the Type 2 response
|
|
51
|
+
# @return [String] the raw binary response from the server
|
|
52
|
+
def smb1_ntlmssp_authenticate(type2_string,user_id)
|
|
53
|
+
packet = smb1_ntlmssp_auth_packet(type2_string,user_id)
|
|
54
|
+
send_recv(packet)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Generates the {RubySMB::SMB1::Packet::SessionSetupRequest} packet
|
|
58
|
+
# with the NTLM Type 3 (Auth) message in the security_blob field.
|
|
59
|
+
#
|
|
60
|
+
# @param type2_string [String] the Base64 encoded Type2 challenge to respond to
|
|
61
|
+
# @param user_id [Integer] the temporary user ID from the Type 2 response
|
|
62
|
+
# @return [RubySMB::SMB1::Packet::SessionSetupRequest] the second authentication packet to send
|
|
63
|
+
def smb1_ntlmssp_auth_packet(type2_string,user_id)
|
|
64
|
+
type3_message = ntlm_client.init_context(type2_string)
|
|
65
|
+
self.session_key = ntlm_client.session_key
|
|
66
|
+
packet = RubySMB::SMB1::Packet::SessionSetupRequest.new
|
|
67
|
+
packet.smb_header.uid = user_id
|
|
68
|
+
packet.set_type3_blob(type3_message.serialize)
|
|
69
|
+
packet.parameter_block.max_buffer_size = 4356
|
|
70
|
+
packet.parameter_block.max_mpx_count = 50
|
|
71
|
+
packet.smb_header.flags2.extended_security = 1
|
|
72
|
+
packet
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Creates the {RubySMB::SMB1::Packet::SessionSetupRequest} packet
|
|
76
|
+
# for the first part of the NTLMSSP 4-way hnadshake. This packet
|
|
77
|
+
# initializes negotiations for the NTLMSSP authentication
|
|
78
|
+
#
|
|
79
|
+
# @return [RubySMB::SMB1::Packet::SessionSetupRequest] the first authentication packet to send
|
|
80
|
+
def smb1_ntlmssp_negotiate_packet
|
|
81
|
+
type1_message = ntlm_client.init_context
|
|
82
|
+
packet = RubySMB::SMB1::Packet::SessionSetupRequest.new
|
|
83
|
+
packet.set_type1_blob(type1_message.serialize)
|
|
84
|
+
packet.parameter_block.max_buffer_size = 4356
|
|
85
|
+
packet.parameter_block.max_mpx_count = 50
|
|
86
|
+
packet.smb_header.flags2.extended_security = 1
|
|
87
|
+
packet
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Takes the raw binary string and returns a {RubySMB::SMB1::Packet::SessionSetupResponse}
|
|
91
|
+
def smb1_ntlmssp_final_packet(raw_response)
|
|
92
|
+
begin
|
|
93
|
+
packet = RubySMB::SMB1::Packet::SessionSetupResponse.read(raw_response)
|
|
94
|
+
rescue
|
|
95
|
+
packet = RubySMB::SMB1::Packet::ErrorPacket.read(raw_response)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
unless packet.smb_header.command == RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
|
|
99
|
+
raise RubySMB::Error::InvalidPacket, "Command was #{packet.smb_header.command} and not #{RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP}"
|
|
100
|
+
end
|
|
101
|
+
packet
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Takes the raw binary string and returns a {RubySMB::SMB1::Packet::SessionSetupResponse}
|
|
105
|
+
def smb1_ntlmssp_challenge_packet(raw_response)
|
|
106
|
+
packet = RubySMB::SMB1::Packet::SessionSetupResponse.read(raw_response)
|
|
107
|
+
status_code = packet.status_code
|
|
108
|
+
|
|
109
|
+
unless status_code.name == "STATUS_MORE_PROCESSING_REQUIRED"
|
|
110
|
+
raise RubySMB::Error::UnexpectedStatusCode, status_code.to_s
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
unless packet.smb_header.command == RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
|
|
114
|
+
raise RubySMB::Error::InvalidPacket, "Command was #{packet.smb_header.command} and not #{RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP}"
|
|
115
|
+
end
|
|
116
|
+
packet
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Parses out the NTLM Type 2 Message from a {RubySMB::SMB1::Packet::SessionSetupResponse}
|
|
120
|
+
#
|
|
121
|
+
# @param response_packet [RubySMB::SMB1::Packet::SessionSetupResponse] the response packet to get the NTLM challenge from
|
|
122
|
+
# @return [String] the base64 encoded NTLM Challenge (Type2 Message) from the response
|
|
123
|
+
def smb1_type2_message(response_packet)
|
|
124
|
+
sec_blob = response_packet.data_block.security_blob
|
|
125
|
+
ntlmssp_offset = sec_blob.index("NTLMSSP")
|
|
126
|
+
type2_blob = sec_blob.slice(ntlmssp_offset..-1)
|
|
127
|
+
[type2_blob].pack("m")
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
#
|
|
131
|
+
# SMB 2 Methods
|
|
132
|
+
#
|
|
133
|
+
|
|
134
|
+
# Handles the SMB1 NTLMSSP 4-way handshake for Authentication
|
|
135
|
+
def smb2_authenticate
|
|
136
|
+
response = smb2_ntlmssp_negotiate
|
|
137
|
+
challenge_packet = smb2_ntlmssp_challenge_packet(response)
|
|
138
|
+
session_id = challenge_packet.smb2_header.session_id
|
|
139
|
+
challenge_message = smb2_type2_message(challenge_packet)
|
|
140
|
+
raw = smb2_ntlmssp_authenticate(challenge_message, session_id)
|
|
141
|
+
response = smb2_ntlmssp_final_packet(raw)
|
|
142
|
+
response_code = response.status_code
|
|
143
|
+
self.session_id = response.smb2_header.session_id if response_code.name == "STATUS_SUCCESS"
|
|
144
|
+
response_code
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Takes the raw binary string and returns a {RubySMB::SMB2::Packet::SessionSetupResponse}
|
|
148
|
+
def smb2_ntlmssp_final_packet(raw_response)
|
|
149
|
+
packet = RubySMB::SMB2::Packet::SessionSetupResponse.read(raw_response)
|
|
150
|
+
unless packet.smb2_header.command == RubySMB::SMB2::Commands::SESSION_SETUP
|
|
151
|
+
raise RubySMB::Error::InvalidPacket, "Command was #{packet.smb2_header.command} and not #{RubySMB::SMB2::Commands::SESSION_SETUP}"
|
|
152
|
+
end
|
|
153
|
+
packet
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Takes the raw binary string and returns a {RubySMB::SMB2::Packet::SessionSetupResponse}
|
|
157
|
+
def smb2_ntlmssp_challenge_packet(raw_response)
|
|
158
|
+
packet = RubySMB::SMB2::Packet::SessionSetupResponse.read(raw_response)
|
|
159
|
+
status_code = packet.status_code
|
|
160
|
+
unless status_code.name == "STATUS_MORE_PROCESSING_REQUIRED"
|
|
161
|
+
raise RubySMB::Error::UnexpectedStatusCode, status_code.to_s
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
unless packet.smb2_header.command == RubySMB::SMB2::Commands::SESSION_SETUP
|
|
165
|
+
raise RubySMB::Error::InvalidPacket, "Command was #{packet.smb2_header.command} and not #{RubySMB::SMB2::Commands::SESSION_SETUP}"
|
|
166
|
+
end
|
|
167
|
+
packet
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Sends the {RubySMB::SMB2::Packet::SessionSetupRequest} packet and
|
|
171
|
+
# receives the response.
|
|
172
|
+
#
|
|
173
|
+
# @return [String] the binary string response from the server
|
|
174
|
+
def smb2_ntlmssp_negotiate
|
|
175
|
+
packet = smb2_ntlmssp_negotiate_packet
|
|
176
|
+
send_recv(packet)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Creates the {RubySMB::SMB2::Packet::SessionSetupRequest} packet
|
|
180
|
+
# for the first part of the NTLMSSP 4-way handshake. This packet
|
|
181
|
+
# initializes negotiations for the NTLMSSP authentication
|
|
182
|
+
#
|
|
183
|
+
# @return [RubySMB::SMB2::Packet::SessionSetupRequest] the first authentication packet to send
|
|
184
|
+
def smb2_ntlmssp_negotiate_packet
|
|
185
|
+
type1_message = ntlm_client.init_context
|
|
186
|
+
packet = RubySMB::SMB2::Packet::SessionSetupRequest.new
|
|
187
|
+
packet.set_type1_blob(type1_message.serialize)
|
|
188
|
+
packet.smb2_header.message_id = 1 #self.smb2_message_id
|
|
189
|
+
self.smb2_message_id = 2
|
|
190
|
+
packet
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Parses out the NTLM Type 2 Message from a {RubySMB::SMB2::Packet::SessionSetupResponse}
|
|
194
|
+
#
|
|
195
|
+
# @param response_packet [RubySMB::SMB2::Packet::SessionSetupResponse] the response packet to get the NTLM challenge from
|
|
196
|
+
# @return [String] the base64 encoded NTLM Challenge (Type2 Message) from the response
|
|
197
|
+
def smb2_type2_message(response_packet)
|
|
198
|
+
sec_blob = response_packet.buffer
|
|
199
|
+
ntlmssp_offset = sec_blob.index("NTLMSSP")
|
|
200
|
+
type2_blob = sec_blob.slice(ntlmssp_offset..-1)
|
|
201
|
+
[type2_blob].pack("m")
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Takes the Base64 encoded NTLM Type 2 (Challenge) message
|
|
205
|
+
# and calls the routines to build the Auth packet, sends the packet
|
|
206
|
+
# and receives the raw response
|
|
207
|
+
#
|
|
208
|
+
# @param type2_string [String] the Base64 Encoded NTLM Type 2 message
|
|
209
|
+
# @param user_id [Integer] the temporary user ID from the Type 2 response
|
|
210
|
+
# @return [String] the raw binary response from the server
|
|
211
|
+
def smb2_ntlmssp_authenticate(type2_string,user_id)
|
|
212
|
+
packet = smb2_ntlmssp_auth_packet(type2_string,user_id)
|
|
213
|
+
send_recv(packet)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# Generates the {RubySMB::SMB2::Packet::SessionSetupRequest} packet
|
|
217
|
+
# with the NTLM Type 3 (Auth) message in the security_blob field.
|
|
218
|
+
#
|
|
219
|
+
# @param type2_string [String] the Base64 encoded Type2 challenge to respond to
|
|
220
|
+
# @param session_id [Integer] the temporary session id from the Type 2 response
|
|
221
|
+
# @return [RubySMB::SMB2::Packet::SessionSetupRequest] the second authentication packet to send
|
|
222
|
+
def smb2_ntlmssp_auth_packet(type2_string, session_id)
|
|
223
|
+
type3_message = ntlm_client.init_context(type2_string)
|
|
224
|
+
self.session_key = ntlm_client.session_key
|
|
225
|
+
packet = RubySMB::SMB2::Packet::SessionSetupRequest.new
|
|
226
|
+
packet.smb2_header.session_id = session_id
|
|
227
|
+
packet.set_type3_blob(type3_message.serialize)
|
|
228
|
+
packet.smb2_header.message_id = self.smb2_message_id
|
|
229
|
+
self.smb2_message_id += 1
|
|
230
|
+
packet
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end
|