module BeEF
module Extension
module ServerClientDnsTunnel
module RubyDNS
class Transaction
def fail!(rcode, domain)
append_question!
@answer.rcode = if rcode.is_a? Symbol
Resolv::DNS::RCode.const_get(rcode)
else
rcode.to_i
end
return unless rcode == :NXDomain
@answer.aa = 1
soa = Resolv::DNS::Resource::IN::SOA.new(Resolv::DNS::Name.create("ns.#{domain}"),
Resolv::DNS::Name.create("hostmaster.#{domain}"),
Time.now.strftime('%Y%m%d%H').to_i, 86_400, 7200, 3_600_000, 172_800)
@answer.add_authority(name, 3600, soa)
end
end
end
class Server < RubyDNS::Server
include Singleton
attr_accessor :messages
def initialize
super()
@lock = Mutex.new
end
def run(options = {})
@lock.synchronize do
Thread.new do
EventMachine.next_tick do
listen = options[:listen] || nil
super(listen: listen)
@selfip = options[:listen][0][1]
@zone = options[:zone]
@messages = {}
end
end
end
end
def process(name, resource, transaction)
@lock.synchronize do
print_debug "Received DNS request (name: #{name} type: #{format_resource(resource)})"
if (format_resource(resource) != 'A') || !name.match(/#{@zone}$/)
transaction.fail!(:Refused, @zone)
return
end
cid = name.split('.')[2].split('-')[2].to_i
bit = name.split('.')[2].split('-')[3].to_i(16)
if @messages[cid].nil?
transaction.fail!(:NXDomain, @zone)
return
else
message = @messages[cid]
end
if message.length <= bit
transaction.fail!(:NXDomain, @zone)
return
end
case message[bit]
when '1'
transaction.respond!(@selfip)
return
when '0'
transaction.fail!(:NXDomain, @zone)
return
end
end
end
private
def format_resource(resource)
/::(\w+)$/.match(resource.name)[1]
end
end
end
end
end