Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 15 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ To run all available modules, call:

Available modules:

c2, dga, imposter, miner, scan, sink, spambot, ssh-exfil, ssh-transfer, tunnel-dns, tunnel-icmp
c2, dga, imposter, miner, scan, sink, spambot, ssh-exfil, ssh-transfer, tor, tunnel-dns, tunnel-icmp

Available flags:
-dry
Expand Down Expand Up @@ -138,16 +138,17 @@ All done!

The modules packaged with the utility are listed in the table below.

| Module | Description |
| ------------- | ----------------------------------------------------------------------------- |
| `c2` | Generates both DNS and IP traffic to a random list of known C2 destinations |
| `dga` | Simulates DGA traffic using random labels and top-level domains |
| `imposter` | Generates DNS traffic to a list of imposter domains |
| `miner` | Generates Stratum mining protocol traffic to known cryptomining pools |
| `scan` | Performs a port scan of random RFC 5737 addresses using common TCP ports |
| `sink` | Connects to known sinkholed destinations run by security researchers |
| `spambot` | Resolves and connects to random Internet SMTP servers to simulate a spam bot |
| `ssh-exfil` | Simulates an SSH file transfer to a service running on a non-standard SSH port|
| `ssh-transfer`| Simulates an SSH file transfer to a service running on an SSH port |
| `tunnel-dns` | Generates DNS tunneling requests to \*.sandbox.alphasoc.xyz |
| `tunnel-icmp` | Generates ICMP tunneling traffic to an Internet service operated by AlphaSOC |
| Module | Description |
| ------------- | ----------------------------------------------------------------------------- |
| `c2` | Generates both DNS and IP traffic to a random list of known C2 destinations |
| `dga` | Simulates DGA traffic using random labels and top-level domains |
| `imposter` | Generates DNS traffic to a list of imposter domains |
| `miner` | Generates Stratum mining protocol traffic to known cryptomining pools |
| `scan` | Performs a port scan of random RFC 5737 addresses using common TCP ports |
| `sink` | Connects to known sinkholed destinations run by security researchers |
| `spambot` | Resolves and connects to random Internet SMTP servers to simulate a spam bot |
| `ssh-exfil` | Simulates an SSH file transfer to a service running on a non-standard SSH port |
| `ssh-transfer` | Simulates an SSH file transfer to a service running on an SSH port |
| `tor` | Simulates Tor relay connections |
| `tunnel-dns` | Generates DNS tunneling requests to \*.sandbox.alphasoc.xyz |
| `tunnel-icmp` | Generates ICMP tunneling traffic to an Internet service operated by AlphaSOC |
17 changes: 7 additions & 10 deletions cmd/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,16 +260,13 @@ var allModules = []Module{
Timeout: 1 * time.Second,
},
Module{
Module: simulator.NewTorSimulator(),
Name: "tor",
Pipeline: PipelineDNS,
Experimental: true,
NumOfHosts: 5,
HeaderMsg: "Preparing Tor connection",
HostMsg: "Connecting to %s",
SuccessMsg: "Tor use is permitted in this environment",
// FailMsg: "Couldn't contact Tor network",
Timeout: 10 * time.Second,
Module: simulator.NewTorSimulator(),
Name: "tor",
Pipeline: PipelineIP,
NumOfHosts: 5,
HeaderMsg: "Preparing Tor relays",
HostMsg: "Connecting to %s",
Timeout: 1 * time.Second,
},
Module{
Module: simulator.NewICMPtunnel(),
Expand Down
122 changes: 55 additions & 67 deletions simulator/tor.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,94 +2,82 @@ package simulator

import (
"context"
"errors"
"encoding/json"
"fmt"
"math/rand"
"net/http"
"os"
"os/exec"

"github.com/cretz/bine/tor"
"time"
)

//Slice containing websites hosted by torproject
var torHosts = []string{"expyuzz4wqqyqhjn.onion", "qrmfuxwgyzk5jdjz.onion", "e4nybovdbcwaqlyt.onion", "52g5y5karruvc7bz.onion", "x3nelbld33llasqv.onion", "vijs2fmpd72nbqok.onion",
"z5tfsnikzulwicxs.onion", "icxe4yp32mq6gm6n.onion", "qigcb4g4xxbh5ho6.onion", "kkvj4mhsttfcrksj.onion", "3gldbgtv5e4god56.onion", "tgnv2pssfumdedyw.onion",
"5bam5t36aombgv76.onion", "sdscoq7snqtznauu.onion", "rqef5a5mebgq46y5.onion", "ruv6ue7d3t22el2a.onion", "zfu7x4fuagirknhb.onion", "klbl4glo2btuwyok.onion",
"ngp5wfw5z6ms3ynx.onion", "tngjm3owsslo3wgo.onion", "dccbbv6cooddgcrq.onion", "jqs44zhtxl2uo6gk.onion", "odz6noxeukaw43e7.onion", "54nujbl4qohb5qdp.onion",
"eibwzyiqgk6vgugg.onion", "f7lqb5oicvsahone.onion", "y7pm6of53hzeb7u2.onion", "n46o4uxsej2icp5l.onion", "rougmnvswfsmd4dq.onion", "l3xrunzkfufzvw2c.onion",
"kzcx36ytbsm5iogs.onion", "ebxqgaz3dwywcoxl.onion", "yz7lpwfhhzcdyc5y.onion", "tgel7v4rpcllsrk2.onion", "llhb3u5h3q66ha62.onion", "rh7jaux2r3tzrqp4.onion",
"sbe5fi5cka5l3fqe.onion", "koz2sqqf4w23qxw2.onion", "hyntj47ow4ermsrh.onion", "yabd3wlpvybdnvzg.onion", "c5qrls2slxqz6vdw.onion", "wcgqzqyfi7a6iu62.onion",
"6m6blys5mwg2jwex.onion", "fhny6b7b6sbslc2b.onion", "s2bweojt5vg52e5i.onion", "xlv5dckljs4vhmhm.onion", "lfdhmyq24uacliu5.onion", "vt5hknv6sblkgf22.onion",
"buqlpzbbcyat2jiy.onion", "bn6kma5cpxill4pe.onion", "4bflp2c4tnynnbes.onion", "2xcd24wfjiqwzwnr.onion", "dgvdmophvhunawds.onion", "fylvgu5r6gcdadeo.onion",
"2iqyjmvrkrq5h5mg.onion", "nraswjtnyrvywxk7.onion", "ea5faa5po25cf7fb.onion", "krkzagd5yo4bvypt.onion", "hzmun3rnnxjhkyhg.onion", "expyuzz4wqqyqhjn.onion",
}

type TorSimulator struct {
tor *tor.Tor
TCPConnectSimulator
}

//NewTorSimulator returns new TorSimulator
func NewTorSimulator() *TorSimulator {
return &TorSimulator{}
}

// Tor creates tor connector;
// There is no way to pass the bind IP to tor, so we ignore it.
func (t *TorSimulator) Init(_ BindAddr) error {
tor, err := tor.Start(nil, &tor.StartConf{
TempDataDirBase: os.TempDir(),
RetainTempDataDir: false,
ExtraArgs: []string{"--quiet"}},
)
if err != nil {
if errors.Is(err, exec.ErrNotFound) {
err = fmt.Errorf("%w (make sure you have tor installed in the system)", err)
}
return err
}
tor.StopProcessOnClose = true
t.tor = tor
return nil
// Init initializes the underlying TCPConnectSimulator.
func (s *TorSimulator) Init(bind BindAddr) error {
return s.TCPConnectSimulator.Init(bind)
}

func (t *TorSimulator) Cleanup() {
if t.tor != nil {
t.tor.Close()
}
func (s *TorSimulator) Cleanup() {}

// DetailsResponse contains the Relays slice we're interested in.
type DetailsResponse struct {
Version string `json:"version"`
BuildRevision string `json:"build_revision"`
RelaysPublished string `json:"relays_published"`
Relays []Relay `json:"relays"`
}

//Hosts returns random hosts from predefined set
func (t TorSimulator) Hosts(scope string, size int) ([]string, error) {
var hosts []string
for _, i := range rand.Perm(len(torHosts)) {
if len(hosts) >= size {
break
}
hosts = append(hosts, torHosts[i])
}
return hosts, nil
// Relays gets us what we need via OrAddresses. There is far more information available
// if future needs expand.
type Relay struct {
Nickname string `json:"nickname"`
Fingerprint string `json:"fingerprint"`
OrAddrs []string `json:"or_addresses"`
}

//Simulate connection to tor network
func (t TorSimulator) Simulate(ctx context.Context, dst string) error {
dialer, err := t.tor.Dialer(ctx, nil)
// Hosts obtains size number of Tor relays using the onionoo.torproject.org API.
func (s *TorSimulator) Hosts(scope string, size int) ([]string, error) {
// Setup the query such that we get size number of running relays, ordered by consensus
// weight from largest to smallest. For details, refer to:
// https://metrics.torproject.org/onionoo.html#parameters
// Note also that the 'details' API is queried in order to get the full (ie. ip:port)
// relay address.
queryURL := fmt.Sprintf(
"https://onionoo.torproject.org/details?limit=%v&running=true&order=-consensus_weight",
size)
// Allow 5 seconds for the query.
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", queryURL, nil)
if err != nil {
return err
return nil, err
}

httpClient := &http.Client{Transport: &http.Transport{DialContext: dialer.DialContext}}
//req, err := http.NewRequestWithContext(ctx, "GET", "http://"+dst, nil) //works in go 1.13
req, err := http.NewRequest("GET", "http://"+dst, nil)
client := http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
// response body closed automatically on error.
return nil, err
}
req = req.WithContext(ctx)
resp, err := httpClient.Do(req)
defer resp.Body.Close()
details := DetailsResponse{}
err = json.NewDecoder(resp.Body).Decode(&details)
if err != nil {
return err
return nil, err
}
defer resp.Body.Close()

return nil
relays := details.Relays
// Setup relayAddrs to be returned. Per
// https://metrics.torproject.org/onionoo.html#details_relay_or_addresses, the first
// addr is the primary onion-routing address used during relay registration.
var relayAddrs []string
for _, r := range relays {
// Paranoia: let's make sure the relay address field has at least 1 address.
if len(r.OrAddrs) > 0 {
relayAddrs = append(relayAddrs, r.OrAddrs[0])
}
}
return relayAddrs, nil
}