Create basic packet manipulation modules
Create Rex::Proto::DNS::Packet and Packet::Raw to allow common parsing, validation, and raw data operations across both Rex and Msf namespaces. The modules contain class methods and do not need to be mixed in to use their functionality Packet.method is enough, and reduces GC strain since new objects are not constantly being instantiated, and these modules contain no internal state. Clean up UDP socket leak from Rex::Proto::DNS::Server under certain conditions. Create Msf::Exploit::DNS::Common mixin to provide descendants with access to Packet and the hostname Regex. ----- Testing: Tested running the RC provided in the pull request Manual testing in IRB/Pry while porting PoC for CVE-2015-7547
This commit is contained in:
@@ -15,5 +15,6 @@ module Exploit::Remote::DNS
|
||||
end
|
||||
end
|
||||
|
||||
require 'msf/core/exploit/dns/common'
|
||||
require 'msf/core/exploit/dns/client'
|
||||
require 'msf/core/exploit/dns/server'
|
||||
|
||||
@@ -13,6 +13,7 @@ module Msf
|
||||
module Exploit::Remote::DNS
|
||||
module Client
|
||||
|
||||
include Common
|
||||
include Exploit::Remote::Udp
|
||||
include Exploit::Remote::Tcp
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# -*- coding: binary -*-
|
||||
require 'msf/core'
|
||||
require 'rex/proto/dns'
|
||||
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# This module exposes methods for querying a remote DNS service
|
||||
#
|
||||
###
|
||||
module Exploit::Remote::DNS
|
||||
module Common
|
||||
|
||||
MATCH_HOSTNAME = Rex::Proto::DNS::Constants::MATCH_HOSTNAME
|
||||
|
||||
Packet = Rex::Proto::DNS::Packet
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -12,10 +12,9 @@ module Msf
|
||||
###
|
||||
module Exploit::Remote::DNS
|
||||
module Server
|
||||
include Common
|
||||
include Exploit::Remote::SocketServer
|
||||
|
||||
MATCH_HOSTNAME = Rex::Proto::DNS::Constants::MATCH_HOSTNAME
|
||||
|
||||
#
|
||||
# Initializes an exploit module that serves DNS requests
|
||||
#
|
||||
@@ -156,7 +155,10 @@ module Server
|
||||
# @param destroy [TrueClass,FalseClass] Dereference the server object
|
||||
def stop_service(destroy = false)
|
||||
self.service.stop unless self.service.nil?
|
||||
self.service = nil if destroy
|
||||
if destroy
|
||||
@dns_resolver = nil
|
||||
self.service = nil
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
@@ -12,5 +12,6 @@ end
|
||||
end
|
||||
end
|
||||
|
||||
require 'rex/proto/dns/packet'
|
||||
require 'rex/proto/dns/resolver'
|
||||
require 'rex/proto/dns/server'
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
require 'net/dns'
|
||||
require 'resolv'
|
||||
|
||||
module Rex
|
||||
module Proto
|
||||
module DNS
|
||||
|
||||
module Packet
|
||||
|
||||
#
|
||||
# Reconstructs a packet with both standard DNS libraries
|
||||
# Ensures that headers match the payload
|
||||
#
|
||||
# @param packet [String, Net::DNS::Packet] Data to be validated
|
||||
#
|
||||
# @return [Net::DNS::Packet]
|
||||
def self.validate(packet)
|
||||
Net::DNS::Packet.parse(
|
||||
Resolv::DNS::Message.decode(
|
||||
packet.respond_to?(:data) ? packet.data : packet
|
||||
).encode
|
||||
)
|
||||
end
|
||||
|
||||
#
|
||||
# Reads a packet into the Net::DNS::Packet format
|
||||
#
|
||||
# @param data [String, Net::DNS::Packet, Resolv::DNS::Message] Input data
|
||||
#
|
||||
# @return [Net::DNS::Packet]
|
||||
def self.encode_net(packet)
|
||||
return packet if packet.respond_to?(:data)
|
||||
Net::DNS::Packet.parse(
|
||||
packet.respond_to?(:decode) ? packet.encode : packet
|
||||
)
|
||||
end
|
||||
|
||||
# Reads a packet into the Resolv::DNS::Message format
|
||||
#
|
||||
# @param data [String, Net::DNS::Packet, Resolv::DNS::Message] Input data
|
||||
#
|
||||
# @return [Resolv::DNS::Message]
|
||||
def self.encode_res(packet)
|
||||
return packet if packet.respond_to?(:decode)
|
||||
Resolv::DNS::Message.decode(
|
||||
packet.respond_to?(:data) ? packet.data : packet
|
||||
)
|
||||
end
|
||||
|
||||
# Reads a packet into the raw String format
|
||||
#
|
||||
# @param data [String, Net::DNS::Packet, Resolv::DNS::Message] Input data
|
||||
#
|
||||
# @return [Resolv::DNS::Message]
|
||||
def self.encode_raw(packet)
|
||||
return packet unless packet.respond_to?(:decode) or packet.respond_to?(:data)
|
||||
packet.respond_to?(:data) ? packet.data : packet.encode
|
||||
end
|
||||
|
||||
module Raw
|
||||
|
||||
#
|
||||
# Convert data to big endian unsigned short
|
||||
#
|
||||
# @param data [Fixnum, Float, Array] Input for conversion
|
||||
#
|
||||
# @return [String] Raw output
|
||||
def self.to_dw(data)
|
||||
[data].flatten.pack('S>*')
|
||||
end
|
||||
|
||||
#
|
||||
# Convert data from big endian unsigned short
|
||||
#
|
||||
# @param data [String] Input for conversion
|
||||
#
|
||||
# @return [Array] Integer array output
|
||||
def self.from_dw(data)
|
||||
data.unpack('S>*')
|
||||
end
|
||||
|
||||
#
|
||||
# Convert data to big endian unsigned int
|
||||
#
|
||||
# @param data [Fixnum, Float, Array] Input for conversion
|
||||
#
|
||||
# @return [String] Raw output
|
||||
def self.to_dd(data)
|
||||
[data].flatten.pack('I>*')
|
||||
end
|
||||
|
||||
#
|
||||
# Convert data from big endian unsigned int
|
||||
#
|
||||
# @param data [String] Input for conversion
|
||||
#
|
||||
# @return [Array] Integer array output
|
||||
def self.from_dd(data)
|
||||
data.unpack('I>*')
|
||||
end
|
||||
|
||||
#
|
||||
# Convert data to big endian unsigned long
|
||||
#
|
||||
# @param data [Fixnum, Float, Array] Input for conversion
|
||||
#
|
||||
# @return [String] Raw output
|
||||
def self.to_dl(data)
|
||||
[data].flatten.pack('L>*')
|
||||
end
|
||||
|
||||
#
|
||||
# Convert data from big endian unsigned long
|
||||
#
|
||||
# @param data [String] Input for conversion
|
||||
#
|
||||
# @return [Array] Integer array output
|
||||
def self.from_dl(data)
|
||||
data.unpack('L>*')
|
||||
end
|
||||
|
||||
#
|
||||
# Returns request ID from raw packet skipping parsing
|
||||
#
|
||||
# @param data [String] Request data
|
||||
#
|
||||
# @return [Fixnum] Request ID
|
||||
def self.request_id(data)
|
||||
self.from_dw(data[0..1])[0]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -213,18 +213,16 @@ class Server
|
||||
#
|
||||
# @param flush_cache [TrueClass,FalseClass] Flush eDNS cache on stop
|
||||
def stop(flush_cache = false)
|
||||
if self.udp_sock
|
||||
self.listener_thread.kill
|
||||
ensure_close = [self.udp_sock, self.tcp_sock].compact
|
||||
begin
|
||||
self.listener_thread.kill if self.listener_thread.respond_to?(:kill)
|
||||
self.listener_thread = nil
|
||||
@udp_sock = nil
|
||||
ensure
|
||||
while csock = ensure_close.shift
|
||||
csock.stop if csock.respond_to?(:stop)
|
||||
csock.close unless csock.closed?
|
||||
end
|
||||
end
|
||||
|
||||
if self.tcp_sock
|
||||
self.tcp_sock.stop if self.tcp_sock.respond_to?(:stop)
|
||||
self.tcp_sock.close if self.tcp_sock.respond_to?(:close)
|
||||
@tcp_sock = nil
|
||||
end
|
||||
|
||||
self.cache.stop(flush_cache)
|
||||
end
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ class Metasploit3 < Msf::Auxiliary
|
||||
def run
|
||||
begin
|
||||
start_service
|
||||
primer
|
||||
service.wait
|
||||
ensure
|
||||
stop_service(true)
|
||||
@@ -46,7 +45,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||
# Creates Proc to handle incoming requests
|
||||
#
|
||||
def on_dispatch_request(cli,data)
|
||||
req = Net::DNS::Packet.parse(data)
|
||||
req = Packet.encode_net(data)
|
||||
peer = "#{cli.peerhost}:#{cli.peerport}"
|
||||
asked = req.question.map(&:qName).join(', ')
|
||||
vprint_status("Received request for #{asked} from #{peer}")
|
||||
@@ -66,7 +65,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||
end unless service.cache.nil?
|
||||
# Forward remaining requests, cache responses
|
||||
if forward.question.count > 0 and service.fwd_res
|
||||
forwarded = service.fwd_res.send(service.validate_packet(forward))
|
||||
forwarded = service.fwd_res.send(Packet.validate(forward))
|
||||
forwarded.answer.each do |ans|
|
||||
vprint_status("Caching response #{ans.name}:#{ans.address} #{ans.type}")
|
||||
service.cache.cache_record(ans)
|
||||
@@ -76,14 +75,14 @@ class Metasploit3 < Msf::Auxiliary
|
||||
req = forwarded
|
||||
end
|
||||
req.header.qr = 1 # Set response bit
|
||||
service.send_response(cli, service.validate_packet(req).data)
|
||||
service.send_response(cli, Packet.validate(req).data)
|
||||
end
|
||||
|
||||
#
|
||||
# Creates Proc to handle outbound responses
|
||||
#
|
||||
def on_send_response(cli,data)
|
||||
res = Net::DNS::Packet.parse(data)
|
||||
res = Packet.encode_net(data)
|
||||
peer = "#{cli.peerhost}:#{cli.peerport}"
|
||||
asked = res.question.map(&:qName).join(', ')
|
||||
vprint_status("Sending response for #{asked} to #{peer}")
|
||||
|
||||
Reference in New Issue
Block a user