Class: Msf::Exploit::SMB::ShadowMitmDispatcher

Inherits:
RubySMB::Dispatcher::Base
  • Object
show all
Defined in:
lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb

Overview

This class provides a Man-In-The-Middle packet Dispatcher.

Constant Summary collapse

READ_TIMEOUT =
30
TCP_MSS =

RFC 879

536

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(interface:, mac:, eth_src:, eth_dst:, ip_src:, ip_dst:, tcp_src:, tcp_dst:, tcp_seq:, tcp_ack:, tcp_win:, tcp_mss: TCP_MSS, read_timeout: READ_TIMEOUT) ⇒ ShadowMitmDispatcher

We decide the host based on the first person to connect


86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 86

def initialize(interface: , mac: , eth_src: , eth_dst: , ip_src: , ip_dst: , tcp_src:, tcp_dst: , tcp_seq: , tcp_ack: , tcp_win: , tcp_mss: TCP_MSS, read_timeout: READ_TIMEOUT)
  @interface = interface
  @mac = mac
  @eth_src = eth_src
  @eth_dst = eth_dst
  @ip_src = ip_src
  @ip_dst = ip_dst
  @tcp_src = tcp_src
  @tcp_dst = tcp_dst
  @tcp_seq = tcp_seq
  @tcp_ack = tcp_ack
  @tcp_win = tcp_win
  @tcp_mss = tcp_mss
  @read_timeout = read_timeout
  # Just create something to close
  @stream = Socket.new Socket::AF_INET, Socket::SOCK_STREAM
end

Instance Attribute Details

#ccapPacketFu::Capture

Returns:

  • (PacketFu::Capture)

83
84
85
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 83

def ccap
  @ccap
end

#eth_dstString

Returns:

  • (String)

38
39
40
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 38

def eth_dst
  @eth_dst
end

#eth_srcString

Returns:

  • (String)

33
34
35
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 33

def eth_src
  @eth_src
end

#interfaceString

Returns:

  • (String)

23
24
25
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 23

def interface
  @interface
end

#ip_dstString

Returns:

  • (String)

48
49
50
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 48

def ip_dst
  @ip_dst
end

#ip_srcString

Returns:

  • (String)

43
44
45
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 43

def ip_src
  @ip_src
end

#macString

Returns:

  • (String)

28
29
30
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 28

def mac
  @mac
end

#read_timeoutInteger

Returns:

  • (Integer)

18
19
20
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 18

def read_timeout
  @read_timeout
end

#streamIO Also known as: tcp_socket

Returns:

  • (IO)

11
12
13
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 11

def stream
  @stream
end

#tcp_ackInteger

Returns:

  • (Integer)

58
59
60
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 58

def tcp_ack
  @tcp_ack
end

#tcp_dstInteger

Returns:

  • (Integer)

68
69
70
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 68

def tcp_dst
  @tcp_dst
end

#tcp_mssInteger

Returns:

  • (Integer)

78
79
80
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 78

def tcp_mss
  @tcp_mss
end

#tcp_seqInteger

Returns:

  • (Integer)

53
54
55
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 53

def tcp_seq
  @tcp_seq
end

#tcp_srcInteger

Returns:

  • (Integer)

63
64
65
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 63

def tcp_src
  @tcp_src
end

#tcp_winInteger

Returns:

  • (Integer)

73
74
75
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 73

def tcp_win
  @tcp_win
end

Class Method Details

.connectObject

Parameters:

  • host (String)

    passed to TCPSocket.new

  • port (Fixnum)

    passed to TCPSocket.new


106
107
108
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 106

def self.connect#(host, port: 445, socket: TCPSocket.new(host, port))
  new()
end

Instance Method Details

#recv_packet(full_response: false) ⇒ String

Read a packet off the wire and parse it into a string

Parameters:

  • full_response (Boolean) (defaults to: false)

    whether to include the NetBios Session Service header in the response

Returns:

  • (String)

    the raw response (including the NetBios Session Service header if full_response is true)

Raises:

  • (RubySMB::Error::NetBiosSessionService)

    if there's an error reading the first 4 bytes, which are assumed to be the NetBiosSessionService header.

  • (RubySMB::Error::CommunicationError)

    if the read timeout expires or an error occurs when reading the packet


166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 166

def recv_packet(full_response: false)
  raise RubySMB::Error::CommunicationError, 'Capture has not been initialized' unless @ccap.class == PacketFu::Capture
  pkt = @stream.each_data do |data|
    pkt = PacketFu::Packet.parse(data)
    break pkt if (pkt.tcp_header.tcp_seq == @tcp_ack) || (@tcp_ack == 0)
  end
  raise Errno::ECONNRESET, 'Recieved a RST packet' if pkt.tcp_header.tcp_flags.rst == 1
  #puts "#{pkt.tcp_header.tcp_seq} == #{@tcp_ack}"
  @tcp_ack = pkt.tcp_header.tcp_seq + pkt.tcp_header.body.size
  @tcp_ack += 1 if pkt.tcp_header.tcp_flags.syn == 1
  @tcp_seq = pkt.tcp_header.tcp_ack
  return pkt.payload[(full_response ? 0 : 4)..-1]
rescue Errno::EINVAL, Errno::ECONNABORTED, Errno::ECONNRESET, TypeError, NoMethodError => e
  raise RubySMB::Error::CommunicationError, "An error occurred reading from the Network #{e.message}"
end

#send_packet(packet, nbss_header: true, tcp_flags: { ack: 1, psh: 1 }, tcp_opts: "") ⇒ Object

Needs: @tcp_src, @tcp_dst, @tcp_seq, @tcp_ack, @tcp-win, @interface, @mac


111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/msf/core/exploit/smb/shadow_mitm_dispatcher.rb', line 111

def send_packet(packet, nbss_header: true, tcp_flags: { ack: 1, psh: 1 }, tcp_opts: "")
  data = nbss_header ? nbss(packet) : ''
  if packet.respond_to?(:to_binary_s)
    data << packet.to_binary_s
  else
    data << packet
  end
  eth_header = PacketFu::EthHeader.new(eth_src: @eth_src, eth_dst: @eth_dst)
  ip_header = PacketFu::IPHeader.new(ip_src: @ip_src, ip_dst: @ip_dst)
  tcp_header = PacketFu::TCPHeader.new(
    tcp_src: @tcp_src,
    tcp_dst: @tcp_dst,
    tcp_seq: @tcp_seq,
    tcp_ack: @tcp_ack,
    tcp_win: @tcp_win,
    tcp_flags: tcp_flags,
    tcp_opts: tcp_opts
  )
  pkt = PacketFu::TCPPacket.new(eth: eth_header, ip: ip_header, tcp: tcp_header)
  pkt.payload = data
  pkt.recalc
  @stream.close if @stream
  @ccap = PacketFu::Capture.new(
    iface: @interface,
    promisc: false,
    start: true,
    filter: "ether dst #{@mac} and not ether src #{@mac} and src port #{@tcp_dst} and dst port #{@tcp_src}"
  )
  @stream = @ccap.stream
  if data.size > @tcp_mss
    ip_body = pkt.ip_header.body.to_s
    ip_id = pkt.ip_header.ip_id
    ip_body.chars.each_slice(@tcp_mss+40).each_with_index do |frag, index|
      fpkt = PacketFu::IPPacket.new(eth: eth_header.to_s, ip: ip_header.to_s)
      fpkt.ip_id = ip_id
      fpkt.ip_header.ip_frag = 0x20*0x100 unless (index+1)*(@tcp_mss+40) >= ip_body.size
      fpkt.ip_header.ip_frag = fpkt.ip_header.ip_frag + ((@tcp_mss+40)/8)*index
      fpkt.payload = frag.join
      fpkt.ip_header.ip_recalc(:ip_len)
      fpkt.ip_header.ip_recalc(:ip_sum)
      fpkt.to_w(@interface)
    end
  else
    pkt.to_w(@interface)
  end
  nil
end