Class: Rex::Proto::DHCP::Server

Inherits:
Object
  • Object
show all
Includes:
Socket
Defined in:
lib/rex/proto/dhcp/server.rb

Overview

DHCP Server class not completely configurable - written specifically for a PXE server

  • scriptjunkie

extended to support testing/exploiting CVE-2011-0997

Instance Attribute Summary collapse

Attributes included from Socket

#ipv, #localhost, #localport, #peerhost, #peerport

Instance Method Summary collapse

Methods included from Socket

addr_atoc, addr_atoi, addr_aton, addr_ctoa, addr_itoa, addr_iton, addr_ntoa, addr_ntoi, bit2netmask, cidr_crack, create, create_ip, create_param, create_tcp, create_tcp_server, create_udp, dotted_ip?, #fd, from_sockaddr, getaddress, gethostbyname, #getlocalname, #getpeername, #getsockname, #initsock, ipv6_link_address, ipv6_mac, is_internal?, is_ipv4?, is_ipv6?, net2bitmask, portlist_to_portspec, portspec_crack, portspec_to_portlist, resolv_nbo, resolv_nbo_i, resolv_to_dotted, source_address, support_ipv6?, tcp_socket_pair, to_sockaddr, #type?, udp_socket_pair

Constructor Details

#initialize(hash, context = {}) ⇒ Server

Returns a new instance of Server.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/rex/proto/dhcp/server.rb', line 24

def initialize(hash, context = {})
	self.listen_host = '0.0.0.0' # clients don't already have addresses. Needs to be 0.0.0.0
	self.listen_port = 67 # mandatory (bootps)
	self.context = context
	self.sock = nil

	@shutting_down = false

	self.myfilename = hash['FILENAME'] || ""
	self.myfilename << ("\x00" * (128 - self.myfilename.length))

	source = hash['SRVHOST'] || Rex::Socket.source_address
	self.ipstring = Rex::Socket.addr_aton(source)

	ipstart = hash['DHCPIPSTART']
	if ipstart
		self.start_ip = Rex::Socket.addr_atoi(ipstart)
	else
		# Use the first 3 octects of the server's IP to construct the
		# default range of x.x.x.32-254
		self.start_ip = "#{self.ipstring[0..2]}\x20".unpack("N").first
	end
	self.current_ip = start_ip

	ipend = hash['DHCPIPEND']
	if ipend
		self.end_ip = Rex::Socket.addr_atoi(ipend)
	else
		# Use the first 3 octects of the server's IP to construct the
		# default range of x.x.x.32-254
		self.end_ip = "#{self.ipstring[0..2]}\xfe".unpack("N").first
	end

	# netmask
	netmask = hash['NETMASK'] || "255.255.255.0"
	self.netmaskn = Rex::Socket.addr_aton(netmask)

	# router
	router = hash['ROUTER'] || source
	self.router = Rex::Socket.addr_aton(router)

	# dns
	dnsserv = hash['DNSSERVER'] || source
	self.dnsserv = Rex::Socket.addr_aton(dnsserv)

	# broadcast
	if hash['BROADCAST']
		self.broadcasta = Rex::Socket.addr_aton(hash['BROADCAST'])
	else
		self.broadcasta = Rex::Socket.addr_itoa( self.start_ip | (Rex::Socket.addr_ntoi(self.netmaskn) ^ 0xffffffff) )
	end

	self.served = {}
	if (hash['SERVEONCE'])
		self.serveOnce = true
	else
		self.serveOnce = false
	end
	
	if (hash['PXE'])
		self.servePXE = true
	else
		self.servePXE = false
	end

	# Always assume we don't give out hostnames ...
	self.give_hostname = false
	self.served_over = 0
	if (hash['HOSTNAME'])
		self.give_hostname = true
		self.served_hostname = hash['HOSTNAME']
		if ( hash['HOSTSTART'] )
			self.served_over = hash['HOSTSTART'].to_i
		end
	end
	
	self.leasetime = 600
	self.relayip = "\x00\x00\x00\x00" # relay ip - not currently suported
	self.pxeconfigfile = "update2"
	self.pxepathprefix = ""
	self.pxereboottime = 2000
end

Instance Attribute Details

#broadcastaObject

Returns the value of attribute broadcasta.



160
161
162
# File 'lib/rex/proto/dhcp/server.rb', line 160

def broadcasta
  @broadcasta
end

#contextObject

Returns the value of attribute context.



158
159
160
# File 'lib/rex/proto/dhcp/server.rb', line 158

def context
  @context
end

#current_ipObject

Returns the value of attribute current_ip.



160
161
162
# File 'lib/rex/proto/dhcp/server.rb', line 160

def current_ip
  @current_ip
end

#dnsservObject

Returns the value of attribute dnsserv.



158
159
160
# File 'lib/rex/proto/dhcp/server.rb', line 158

def dnsserv
  @dnsserv
end

#end_ipObject

Returns the value of attribute end_ip.



160
161
162
# File 'lib/rex/proto/dhcp/server.rb', line 160

def end_ip
  @end_ip
end

#give_hostnameObject

Returns the value of attribute give_hostname.



162
163
164
# File 'lib/rex/proto/dhcp/server.rb', line 162

def give_hostname
  @give_hostname
end

#ipstringObject

Returns the value of attribute ipstring.



159
160
161
# File 'lib/rex/proto/dhcp/server.rb', line 159

def ipstring
  @ipstring
end

#leasetimeObject

Returns the value of attribute leasetime.



158
159
160
# File 'lib/rex/proto/dhcp/server.rb', line 158

def leasetime
  @leasetime
end

#listen_hostObject

Returns the value of attribute listen_host.



158
159
160
# File 'lib/rex/proto/dhcp/server.rb', line 158

def listen_host
  @listen_host
end

#listen_portObject

Returns the value of attribute listen_port.



158
159
160
# File 'lib/rex/proto/dhcp/server.rb', line 158

def listen_port
  @listen_port
end

#myfilenameObject

Returns the value of attribute myfilename.



159
160
161
# File 'lib/rex/proto/dhcp/server.rb', line 159

def myfilename
  @myfilename
end

#netmasknObject

Returns the value of attribute netmaskn.



160
161
162
# File 'lib/rex/proto/dhcp/server.rb', line 160

def netmaskn
  @netmaskn
end

#pxeconfigfileObject

Returns the value of attribute pxeconfigfile.



161
162
163
# File 'lib/rex/proto/dhcp/server.rb', line 161

def pxeconfigfile
  @pxeconfigfile
end

#pxepathprefixObject

Returns the value of attribute pxepathprefix.



161
162
163
# File 'lib/rex/proto/dhcp/server.rb', line 161

def pxepathprefix
  @pxepathprefix
end

#pxereboottimeObject

Returns the value of attribute pxereboottime.



161
162
163
# File 'lib/rex/proto/dhcp/server.rb', line 161

def pxereboottime
  @pxereboottime
end

#relayipObject

Returns the value of attribute relayip.



158
159
160
# File 'lib/rex/proto/dhcp/server.rb', line 158

def relayip
  @relayip
end

#routerObject

Returns the value of attribute router.



158
159
160
# File 'lib/rex/proto/dhcp/server.rb', line 158

def router
  @router
end

#servedObject

Returns the value of attribute served.



159
160
161
# File 'lib/rex/proto/dhcp/server.rb', line 159

def served
  @served
end

#served_hostnameObject

Returns the value of attribute served_hostname.



162
163
164
# File 'lib/rex/proto/dhcp/server.rb', line 162

def served_hostname
  @served_hostname
end

#served_overObject

Returns the value of attribute served_over.



162
163
164
# File 'lib/rex/proto/dhcp/server.rb', line 162

def served_over
  @served_over
end

#serveOnceObject

Returns the value of attribute serveOnce.



159
160
161
# File 'lib/rex/proto/dhcp/server.rb', line 159

def serveOnce
  @serveOnce
end

#servePXEObject

Returns the value of attribute servePXE.



161
162
163
# File 'lib/rex/proto/dhcp/server.rb', line 161

def servePXE
  @servePXE
end

#sockObject

Returns the value of attribute sock.



159
160
161
# File 'lib/rex/proto/dhcp/server.rb', line 159

def sock
  @sock
end

#start_ipObject

Returns the value of attribute start_ip.



160
161
162
# File 'lib/rex/proto/dhcp/server.rb', line 160

def start_ip
  @start_ip
end

#threadObject

Returns the value of attribute thread.



159
160
161
# File 'lib/rex/proto/dhcp/server.rb', line 159

def thread
  @thread
end

Instance Method Details

#send_packet(ip, pkt) ⇒ Object

Send a single packet to the specified host



147
148
149
150
151
152
153
154
155
156
# File 'lib/rex/proto/dhcp/server.rb', line 147

def send_packet(ip, pkt)
	port = 68 # bootpc
	if ip
		self.sock.sendto( pkt, ip, port )
	else
		if not self.sock.sendto( pkt, '255.255.255.255', port )
			self.sock.sendto( pkt, self.broadcasta, port )
		end
	end
end

#set_option(opts) ⇒ Object

Set an option



130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/rex/proto/dhcp/server.rb', line 130

def set_option(opts)
	allowed_options = [
		:serveOnce, :servePXE, :relayip, :leasetime, :dnsserv,
		:pxeconfigfile, :pxepathprefix, :pxereboottime, :router,
		:give_hostname, :served_hostname, :served_over
	]

	opts.each_pair { |k,v|
		next if not v
		if allowed_options.include?(k)
			self.instance_variable_set("@#{k}", v)
		end
	}
end

#startObject

Start the DHCP server



109
110
111
112
113
114
115
116
117
118
119
# File 'lib/rex/proto/dhcp/server.rb', line 109

def start
	self.sock = Rex::Socket::Udp.create(
		'LocalHost' => listen_host,
		'LocalPort' => listen_port,
		'Context'   => context
	)

	self.thread = Rex::ThreadFactory.spawn("DHCPServerMonitor", false) {
		monitor_socket
	}
end

#stopObject

Stop the DHCP server



122
123
124
125
126
# File 'lib/rex/proto/dhcp/server.rb', line 122

def stop
	@shutting_down = true
	self.thread.kill
	self.sock.close rescue nil
end