ruby_smb 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://travis-ci.org/rapid7/ruby_smb.svg?branch=master)](https://travis-ci.org/rapid7/ruby_smb)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/rapid7/ruby_smb.png)](https://codeclimate.com/github/rapid7/ruby_smb)
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/github/rapid7/ruby_smb/badge.svg?branch=master)](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
|