|
1 | 1 | # -*- coding: binary -*-
|
2 | 2 |
|
3 | 3 | module Msf
|
| 4 | + module Exploit::Remote::SMB |
| 5 | + # This mixin provides a minimal SMB server |
| 6 | + module Server |
| 7 | + include Msf::Exploit::Remote::TcpServer |
| 8 | + include Msf::Exploit::NTLM |
| 9 | + CONST = ::Rex::Proto::SMB::Constants |
| 10 | + CRYPT = ::Rex::Proto::SMB::Crypt |
| 11 | + UTILS = ::Rex::Proto::SMB::Utils |
| 12 | + XCEPT = ::Rex::Proto::SMB::Exceptions |
| 13 | + EVADE = ::Rex::Proto::SMB::Evasions |
| 14 | + |
| 15 | + def initialize(info = {}) |
| 16 | + super |
| 17 | + |
| 18 | + deregister_options('SSL', 'SSLCert') |
| 19 | + register_options( |
| 20 | + [ |
| 21 | + OptPort.new('SRVPORT', [ true, "The local port to listen on.", 445 ]) |
| 22 | + ], self.class) |
| 23 | + end |
4 | 24 |
|
5 |
| -### |
6 |
| -# |
7 |
| -# This mixin provides a minimal SMB server |
8 |
| -# |
9 |
| -### |
10 |
| - |
11 |
| -module Exploit::Remote::SMB::Server |
12 |
| - include Exploit::Remote::TcpServer |
13 |
| - include Exploit::NTLM |
14 |
| - CONST = ::Rex::Proto::SMB::Constants |
15 |
| - CRYPT = ::Rex::Proto::SMB::Crypt |
16 |
| - UTILS = ::Rex::Proto::SMB::Utils |
17 |
| - XCEPT = ::Rex::Proto::SMB::Exceptions |
18 |
| - EVADE = ::Rex::Proto::SMB::Evasions |
19 |
| - |
20 |
| - def initialize(info = {}) |
21 |
| - super |
22 |
| - |
23 |
| - deregister_options('SSL', 'SSLCert') |
24 |
| - register_options( |
25 |
| - [ |
26 |
| - OptPort.new('SRVPORT', [ true, "The local port to listen on.", 445 ]) |
27 |
| - ], self.class) |
28 |
| - end |
| 25 | + def setup |
| 26 | + super |
| 27 | + @state = {} |
| 28 | + end |
29 | 29 |
|
30 |
| - def setup |
31 |
| - super |
32 |
| - @state = {} |
33 |
| - end |
| 30 | + def on_client_connect(client) |
| 31 | + # print_status("New SMB connection from #{client.peerhost}:#{client.peerport}") |
| 32 | + smb_conn(client) |
| 33 | + end |
34 | 34 |
|
35 |
| - def on_client_connect(client) |
36 |
| - # print_status("New SMB connection from #{client.peerhost}:#{client.peerport}") |
37 |
| - smb_conn(client) |
38 |
| - end |
| 35 | + def on_client_data(client) |
| 36 | + # print_status("New data from #{client.peerhost}:#{client.peerport}") |
| 37 | + smb_recv(client) |
| 38 | + true |
| 39 | + end |
39 | 40 |
|
40 |
| - def on_client_data(client) |
41 |
| - # print_status("New data from #{client.peerhost}:#{client.peerport}") |
42 |
| - smb_recv(client) |
43 |
| - true |
44 |
| - end |
| 41 | + def on_client_close(client) |
| 42 | + smb_stop(client) |
| 43 | + end |
45 | 44 |
|
46 |
| - def on_client_close(client) |
47 |
| - smb_stop(client) |
48 |
| - end |
| 45 | + def smb_conn(c) |
| 46 | + @state[c] = {:name => "#{c.peerhost}:#{c.peerport}", :ip => c.peerhost, :port => c.peerport} |
| 47 | + end |
49 | 48 |
|
50 |
| - def smb_conn(c) |
51 |
| - @state[c] = {:name => "#{c.peerhost}:#{c.peerport}", :ip => c.peerhost, :port => c.peerport} |
52 |
| - end |
| 49 | + def smb_stop(c) |
| 50 | + @state.delete(c) |
| 51 | + end |
53 | 52 |
|
54 |
| - def smb_stop(c) |
55 |
| - @state.delete(c) |
56 |
| - end |
| 53 | + def smb_recv(c) |
| 54 | + smb = @state[c] |
| 55 | + smb[:data] ||= '' |
| 56 | + smb[:data] << c.get_once |
57 | 57 |
|
58 |
| - def smb_recv(c) |
59 |
| - smb = @state[c] |
60 |
| - smb[:data] ||= '' |
61 |
| - smb[:data] << c.get_once |
| 58 | + while(smb[:data].length > 0) |
62 | 59 |
|
63 |
| - while(smb[:data].length > 0) |
| 60 | + return if smb[:data].length < 4 |
64 | 61 |
|
65 |
| - return if smb[:data].length < 4 |
| 62 | + plen = smb[:data][2,2].unpack('n')[0] |
66 | 63 |
|
67 |
| - plen = smb[:data][2,2].unpack('n')[0] |
| 64 | + return if smb[:data].length < plen+4 |
68 | 65 |
|
69 |
| - return if smb[:data].length < plen+4 |
| 66 | + buff = smb[:data].slice!(0, plen+4) |
70 | 67 |
|
71 |
| - buff = smb[:data].slice!(0, plen+4) |
| 68 | + pkt_nbs = CONST::NBRAW_PKT.make_struct |
| 69 | + pkt_nbs.from_s(buff) |
72 | 70 |
|
73 |
| - pkt_nbs = CONST::NBRAW_PKT.make_struct |
74 |
| - pkt_nbs.from_s(buff) |
| 71 | + # print_status("NetBIOS request from #{smb[:name]} #{pkt_nbs.v['Type']} #{pkt_nbs.v['Flags']} #{buff.inspect}") |
75 | 72 |
|
76 |
| - # print_status("NetBIOS request from #{smb[:name]} #{pkt_nbs.v['Type']} #{pkt_nbs.v['Flags']} #{buff.inspect}") |
| 73 | + # Check for a NetBIOS name request |
| 74 | + if (pkt_nbs.v['Type'] == 0x81) |
| 75 | + # Accept any name they happen to send |
77 | 76 |
|
78 |
| - # Check for a NetBIOS name request |
79 |
| - if (pkt_nbs.v['Type'] == 0x81) |
80 |
| - # Accept any name they happen to send |
| 77 | + host_dst = UTILS.nbname_decode(pkt_nbs.v['Payload'][1,32]).gsub(/[\x00\x20]+$/n, '') |
| 78 | + host_src = UTILS.nbname_decode(pkt_nbs.v['Payload'][35,32]).gsub(/[\x00\x20]+$/n, '') |
81 | 79 |
|
82 |
| - host_dst = UTILS.nbname_decode(pkt_nbs.v['Payload'][1,32]).gsub(/[\x00\x20]+$/n, '') |
83 |
| - host_src = UTILS.nbname_decode(pkt_nbs.v['Payload'][35,32]).gsub(/[\x00\x20]+$/n, '') |
| 80 | + smb[:nbdst] = host_dst |
| 81 | + smb[:nbsrc] = host_src |
84 | 82 |
|
85 |
| - smb[:nbdst] = host_dst |
86 |
| - smb[:nbsrc] = host_src |
| 83 | + # print_status("NetBIOS session request from #{smb[:name]} (asking for #{host_dst} from #{host_src})") |
| 84 | + c.write("\x82\x00\x00\x00") |
| 85 | + next |
| 86 | + end |
87 | 87 |
|
88 |
| - # print_status("NetBIOS session request from #{smb[:name]} (asking for #{host_dst} from #{host_src})") |
89 |
| - c.write("\x82\x00\x00\x00") |
90 |
| - next |
91 |
| - end |
92 | 88 |
|
| 89 | + # |
| 90 | + # TODO: Support AndX parameters |
| 91 | + # |
93 | 92 |
|
94 |
| - # |
95 |
| - # TODO: Support AndX parameters |
96 |
| - # |
97 | 93 |
|
| 94 | + # Cast this to a generic SMB structure |
| 95 | + pkt = CONST::SMB_BASE_PKT.make_struct |
| 96 | + pkt.from_s(buff) |
98 | 97 |
|
99 |
| - # Cast this to a generic SMB structure |
100 |
| - pkt = CONST::SMB_BASE_PKT.make_struct |
101 |
| - pkt.from_s(buff) |
| 98 | + # Only response to requests, ignore server replies |
| 99 | + if (pkt['Payload']['SMB'].v['Flags1'] & 128 != 0) |
| 100 | + print_status("Ignoring server response from #{smb[:name]}") |
| 101 | + next |
| 102 | + end |
102 | 103 |
|
103 |
| - # Only response to requests, ignore server replies |
104 |
| - if (pkt['Payload']['SMB'].v['Flags1'] & 128 != 0) |
105 |
| - print_status("Ignoring server response from #{smb[:name]}") |
106 |
| - next |
| 104 | + cmd = pkt['Payload']['SMB'].v['Command'] |
| 105 | + begin |
| 106 | + smb_cmd_dispatch(cmd, c, buff) |
| 107 | + rescue ::Interrupt |
| 108 | + raise $! |
| 109 | + rescue ::Exception => e |
| 110 | + print_status("Error processing request from #{smb[:name]} (#{cmd}): #{e.class} #{e} #{e.backtrace}") |
| 111 | + next |
| 112 | + end |
| 113 | + end |
107 | 114 | end
|
108 | 115 |
|
109 |
| - cmd = pkt['Payload']['SMB'].v['Command'] |
110 |
| - begin |
111 |
| - smb_cmd_dispatch(cmd, c, buff) |
112 |
| - rescue ::Interrupt |
113 |
| - raise $! |
114 |
| - rescue ::Exception => e |
115 |
| - print_status("Error processing request from #{smb[:name]} (#{cmd}): #{e.class} #{e} #{e.backtrace}") |
116 |
| - next |
| 116 | + def smb_cmd_dispatch(cmd, c, buff) |
| 117 | + smb = @state[c] |
| 118 | + print_status("Received command #{cmd} from #{smb[:name]}") |
117 | 119 | end
|
118 |
| - end |
119 |
| - end |
120 |
| - |
121 |
| - def smb_cmd_dispatch(cmd, c, buff) |
122 |
| - smb = @state[c] |
123 |
| - print_status("Received command #{cmd} from #{smb[:name]}") |
124 |
| - end |
125 | 120 |
|
126 |
| - def smb_set_defaults(c, pkt) |
127 |
| - smb = @state[c] |
128 |
| - pkt['Payload']['SMB'].v['ProcessID'] = smb[:process_id].to_i |
129 |
| - pkt['Payload']['SMB'].v['UserID'] = smb[:user_id].to_i |
130 |
| - pkt['Payload']['SMB'].v['TreeID'] = smb[:tree_id].to_i |
131 |
| - pkt['Payload']['SMB'].v['MultiplexID'] = smb[:multiplex_id].to_i |
132 |
| - end |
| 121 | + def smb_set_defaults(c, pkt) |
| 122 | + smb = @state[c] |
| 123 | + pkt['Payload']['SMB'].v['ProcessID'] = smb[:process_id].to_i |
| 124 | + pkt['Payload']['SMB'].v['UserID'] = smb[:user_id].to_i |
| 125 | + pkt['Payload']['SMB'].v['TreeID'] = smb[:tree_id].to_i |
| 126 | + pkt['Payload']['SMB'].v['MultiplexID'] = smb[:multiplex_id].to_i |
| 127 | + end |
133 | 128 |
|
134 |
| - def smb_error(cmd, c, errorclass, esn = false) |
135 |
| - # 0xc0000022 = Deny |
136 |
| - # 0xc000006D = Logon_Failure |
137 |
| - # 0x00000000 = Ignore |
138 |
| - pkt = CONST::SMB_BASE_PKT.make_struct |
139 |
| - smb_set_defaults(c, pkt) |
140 |
| - pkt['Payload']['SMB'].v['Command'] = cmd |
141 |
| - pkt['Payload']['SMB'].v['Flags1'] = 0x88 |
142 |
| - if esn |
143 |
| - pkt['Payload']['SMB'].v['Flags2'] = 0xc801 |
144 |
| - else |
145 |
| - pkt['Payload']['SMB'].v['Flags2'] = 0xc001 |
| 129 | + def smb_error(cmd, c, errorclass, esn = false) |
| 130 | + # 0xc0000022 = Deny |
| 131 | + # 0xc000006D = Logon_Failure |
| 132 | + # 0x00000000 = Ignore |
| 133 | + pkt = CONST::SMB_BASE_PKT.make_struct |
| 134 | + smb_set_defaults(c, pkt) |
| 135 | + pkt['Payload']['SMB'].v['Command'] = cmd |
| 136 | + pkt['Payload']['SMB'].v['Flags1'] = 0x88 |
| 137 | + if esn |
| 138 | + pkt['Payload']['SMB'].v['Flags2'] = 0xc801 |
| 139 | + else |
| 140 | + pkt['Payload']['SMB'].v['Flags2'] = 0xc001 |
| 141 | + end |
| 142 | + pkt['Payload']['SMB'].v['ErrorClass'] = errorclass |
| 143 | + c.put(pkt.to_s) |
| 144 | + end |
146 | 145 | end
|
147 |
| - pkt['Payload']['SMB'].v['ErrorClass'] = errorclass |
148 |
| - c.put(pkt.to_s) |
149 | 146 | end
|
150 | 147 |
|
151 | 148 | end
|
152 | 149 |
|
153 |
| -end |
154 |
| - |
0 commit comments