mirror of
https://github.com/HavocFramework/Havoc
synced 2026-06-08 11:13:29 +00:00
974 lines
25 KiB
Go
974 lines
25 KiB
Go
package server
|
|
|
|
import "C"
|
|
import (
|
|
"Havoc/pkg/agent"
|
|
"Havoc/pkg/common/certs"
|
|
"Havoc/pkg/db"
|
|
"Havoc/pkg/service"
|
|
"Havoc/pkg/webhook"
|
|
"bytes"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/gorilla/websocket"
|
|
"golang.org/x/crypto/sha3"
|
|
|
|
"Havoc/pkg/colors"
|
|
"Havoc/pkg/common"
|
|
"Havoc/pkg/events"
|
|
"Havoc/pkg/handlers"
|
|
"Havoc/pkg/logger"
|
|
"Havoc/pkg/packager"
|
|
"Havoc/pkg/profile"
|
|
"Havoc/pkg/utils"
|
|
)
|
|
|
|
func NewTeamserver(DatabasePath string) *Teamserver {
|
|
if d, err := db.DatabaseNew(DatabasePath); err != nil {
|
|
logger.Error("Failed to create a new db: " + err.Error())
|
|
return nil
|
|
} else {
|
|
return &Teamserver{
|
|
DB: d,
|
|
}
|
|
}
|
|
}
|
|
|
|
func (t *Teamserver) SetServerFlags(flags TeamserverFlags) {
|
|
t.Flags = flags
|
|
}
|
|
|
|
func (t *Teamserver) Start() {
|
|
logger.Debug("Starting teamserver...")
|
|
var (
|
|
ServerFinished chan bool
|
|
TeamserverWs string
|
|
TeamserverPath, err = os.Getwd()
|
|
ListenerCount int
|
|
KillDate int64
|
|
)
|
|
|
|
if err != nil {
|
|
logger.Error("Couldn't get the current directory: " + err.Error())
|
|
return
|
|
}
|
|
|
|
if t.Flags.Server.Host == "" {
|
|
t.Flags.Server.Host = t.Profile.ServerHost()
|
|
}
|
|
|
|
if t.Flags.Server.Port == "" {
|
|
t.Flags.Server.Port = strconv.Itoa(t.Profile.ServerPort())
|
|
}
|
|
|
|
gin.SetMode(gin.ReleaseMode)
|
|
t.Server.Engine = gin.New()
|
|
|
|
t.Server.Engine.GET("/", func(context *gin.Context) {
|
|
context.Redirect(http.StatusMovedPermanently, "home/")
|
|
})
|
|
|
|
// Catch me if you can
|
|
t.Server.Engine.GET("/havoc/", func(context *gin.Context) {
|
|
|
|
var (
|
|
upgrade websocket.Upgrader
|
|
WebSocket *websocket.Conn
|
|
ClientID = utils.GenerateID(6)
|
|
)
|
|
|
|
if WebSocket, err = upgrade.Upgrade(context.Writer, context.Request, nil); err != nil {
|
|
logger.Error("Failed upgrading request: " + err.Error())
|
|
return
|
|
}
|
|
|
|
t.Clients.Store(ClientID,
|
|
&Client{
|
|
Username: "",
|
|
GlobalIP: WebSocket.RemoteAddr().String(),
|
|
Connection: WebSocket,
|
|
ClientVersion: "",
|
|
Packager: packager.NewPackager(),
|
|
Authenticated: false,
|
|
})
|
|
|
|
// Handle connections in a new goroutine.
|
|
go t.handleRequest(ClientID)
|
|
})
|
|
|
|
// TODO: pass this as a profile/command line flag
|
|
t.Server.Engine.Static("/home", "./bin/static")
|
|
|
|
t.Server.Engine.POST("/:endpoint", func(context *gin.Context) {
|
|
var endpoint = context.Request.RequestURI[1:]
|
|
|
|
if len(t.Endpoints) > 0 {
|
|
for i := range t.Endpoints {
|
|
if t.Endpoints[i].Endpoint == endpoint {
|
|
t.Endpoints[i].Function(context)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
// start the teamserver websocket connection
|
|
go func(Host, Port string) {
|
|
var (
|
|
certPath = TeamserverPath + "/data/server.cert"
|
|
keyPath = TeamserverPath + "/data/server.key"
|
|
|
|
Cert []byte
|
|
Key []byte
|
|
)
|
|
|
|
Cert, Key, err = certs.HTTPSGenerateRSACertificate(Host)
|
|
if err != nil {
|
|
logger.Error("Failed to generate server certificates: " + err.Error())
|
|
os.Exit(0)
|
|
}
|
|
|
|
err = os.WriteFile(certPath, Cert, 0644)
|
|
if err != nil {
|
|
logger.Error("Couldn't save server cert file: " + err.Error())
|
|
os.Exit(0)
|
|
}
|
|
|
|
err = os.WriteFile(keyPath, Key, 0644)
|
|
if err != nil {
|
|
logger.Error("Couldn't save server cert file: " + err.Error())
|
|
os.Exit(0)
|
|
}
|
|
|
|
// start the teamserver
|
|
if err = t.Server.Engine.RunTLS(Host+":"+Port, certPath, keyPath); err != nil {
|
|
logger.Error("Failed to start websocket: " + err.Error())
|
|
}
|
|
|
|
ServerFinished <- true
|
|
|
|
os.Exit(0)
|
|
}(t.Flags.Server.Host, t.Flags.Server.Port)
|
|
|
|
t.WebHooks = webhook.NewWebHook()
|
|
t.Listeners = []*Listener{}
|
|
|
|
TeamserverWs = "wss://" + t.Flags.Server.Host + ":" + t.Flags.Server.Port
|
|
|
|
logger.Info("Starting Teamserver on " + colors.BlueUnderline(TeamserverWs))
|
|
|
|
/* if we specified a webhook then lets use it. */
|
|
if t.Profile.Config.WebHook != nil {
|
|
if t.Profile.Config.WebHook.Discord != nil {
|
|
var (
|
|
AvatarUrl string
|
|
UserName string
|
|
)
|
|
|
|
if len(t.Profile.Config.WebHook.Discord.AvatarUrl) > 0 {
|
|
AvatarUrl = t.Profile.Config.WebHook.Discord.AvatarUrl
|
|
}
|
|
|
|
if len(t.Profile.Config.WebHook.Discord.UserName) > 0 {
|
|
UserName = t.Profile.Config.WebHook.Discord.UserName
|
|
}
|
|
|
|
if len(t.Profile.Config.WebHook.Discord.WebHook) > 0 {
|
|
t.WebHooks.SetDiscord(AvatarUrl, UserName, t.Profile.Config.WebHook.Discord.WebHook)
|
|
}
|
|
}
|
|
}
|
|
|
|
// start teamserver service
|
|
if t.Profile.Config.Service != nil {
|
|
|
|
// 3rd Party Agent Support Enabled
|
|
t.Service = service.NewService(t.Server.Engine)
|
|
t.Service.Teamserver = t
|
|
t.Service.Data.ServerAgents = &t.Agents
|
|
t.Service.Config = *t.Profile.Config.Service
|
|
|
|
if len(t.Service.Config.Endpoint) > 0 {
|
|
t.Service.Start()
|
|
logger.Info(fmt.Sprintf("%v starting service handle on %v", "["+colors.BoldWhite("SERVICE")+"]", colors.BlueUnderline(TeamserverWs+"/"+t.Service.Config.Endpoint)))
|
|
} else {
|
|
logger.Error("Teamserver service error: Endpoint not specified")
|
|
}
|
|
}
|
|
|
|
/* now load up our db or start a new one if none exist */
|
|
DBPath := t.DB.Path()
|
|
if t.DB, err = db.DatabaseNew(TeamserverPath + "/" + DBPath); err != nil {
|
|
logger.SetStdOut(os.Stderr)
|
|
logger.Error("Failed to create or open a database: " + err.Error())
|
|
return
|
|
}
|
|
|
|
if t.DB.Existed() {
|
|
logger.Info("Opens existing database: " + colors.Blue(DBPath))
|
|
} else {
|
|
logger.Info("Creates new database: " + colors.Blue(DBPath))
|
|
}
|
|
|
|
ListenerCount = t.DB.ListenerCount()
|
|
|
|
/* start listeners from the specified yaotl profile */
|
|
if t.Profile.Config.Listener != nil {
|
|
|
|
/* Start all HTTP/s listeners */
|
|
for _, listener := range t.Profile.Config.Listener.ListenerHTTP {
|
|
if listener.KillDate != "" {
|
|
t, err := time.Parse("2006-01-02 15:04:05", listener.KillDate)
|
|
if err != nil {
|
|
logger.Error("Failed to parse the kill date: " + err.Error())
|
|
return
|
|
}
|
|
KillDate = common.EpochTimeToSystemTime(t.Unix())
|
|
} else {
|
|
KillDate = 0
|
|
}
|
|
|
|
var HandlerData = handlers.HTTPConfig{
|
|
Name: listener.Name,
|
|
KillDate: KillDate,
|
|
WorkingHours: listener.WorkingHours,
|
|
Hosts: listener.Hosts,
|
|
HostBind: listener.HostBind,
|
|
Methode: listener.Methode,
|
|
HostRotation: listener.HostRotation,
|
|
BehindRedir: t.Profile.Config.Demon.TrustXForwardedFor,
|
|
PortBind: strconv.Itoa(listener.PortBind),
|
|
PortConn: strconv.Itoa(listener.PortConn),
|
|
UserAgent: listener.UserAgent,
|
|
Headers: listener.Headers,
|
|
Uris: listener.Uris,
|
|
Secure: listener.Secure,
|
|
HostHeader: listener.HostHeader,
|
|
Proxy: handlers.ProxyConfig{},
|
|
}
|
|
|
|
// Set proxy settings
|
|
if listener.Proxy != nil {
|
|
if strings.HasPrefix(listener.Proxy.Host, "http://") || strings.HasPrefix(listener.Proxy.Host, "https://") {
|
|
logger.Error("Proxy host should not start with scheme")
|
|
return
|
|
}
|
|
|
|
HandlerData.Proxy = handlers.ProxyConfig{
|
|
Enabled: len(listener.Proxy.Host) > 0,
|
|
Type: listener.Proxy.Type,
|
|
Host: listener.Proxy.Host,
|
|
Port: strconv.Itoa(listener.Proxy.Port),
|
|
Username: listener.Proxy.User,
|
|
Password: listener.Proxy.Pass,
|
|
}
|
|
}
|
|
|
|
if listener.Cert != nil {
|
|
var Found = true
|
|
|
|
if _, err = os.Stat(listener.Cert.Cert); !os.IsNotExist(err) {
|
|
HandlerData.Cert.Cert = listener.Cert.Cert
|
|
} else {
|
|
Found = false
|
|
}
|
|
|
|
if _, err = os.Stat(listener.Cert.Key); !os.IsNotExist(err) {
|
|
HandlerData.Cert.Key = listener.Cert.Key
|
|
} else {
|
|
Found = false
|
|
}
|
|
|
|
if !Found {
|
|
logger.Error("Failed to find Cert/Key Path for listener '" + listener.Name + "'. Using randomly generated certs")
|
|
}
|
|
}
|
|
|
|
if listener.Response != nil {
|
|
HandlerData.Response.Headers = listener.Response.Headers
|
|
}
|
|
|
|
if err := t.ListenerStart(handlers.LISTENER_HTTP, HandlerData); err != nil {
|
|
logger.Error("Failed to start listener from profile: " + err.Error())
|
|
return
|
|
}
|
|
}
|
|
|
|
/* Start all SMB listeners */
|
|
for _, listener := range t.Profile.Config.Listener.ListenerSMB {
|
|
if listener.KillDate != "" {
|
|
t, err := time.Parse("2006-01-02 15:04:05", listener.KillDate)
|
|
if err != nil {
|
|
logger.Error("Failed to parse the kill date: " + err.Error())
|
|
return
|
|
}
|
|
KillDate = common.EpochTimeToSystemTime(t.Unix())
|
|
} else {
|
|
KillDate = 0
|
|
}
|
|
|
|
var HandlerData = handlers.SMBConfig{
|
|
Name: listener.Name,
|
|
PipeName: listener.PipeName,
|
|
KillDate: KillDate,
|
|
WorkingHours: listener.WorkingHours,
|
|
}
|
|
|
|
if err := t.ListenerStart(handlers.LISTENER_PIVOT_SMB, HandlerData); err != nil {
|
|
logger.Error("Failed to start listener from profile: " + err.Error())
|
|
return
|
|
}
|
|
}
|
|
|
|
/* Start all ExternalC2 listeners */
|
|
for _, listener := range t.Profile.Config.Listener.ListenerExternal {
|
|
var HandlerData = handlers.ExternalConfig{
|
|
Name: listener.Name,
|
|
Endpoint: listener.Endpoint,
|
|
}
|
|
|
|
if err := t.ListenerStart(handlers.LISTENER_EXTERNAL, HandlerData); err != nil {
|
|
logger.Error("Failed to start listener from profile: " + err.Error())
|
|
return
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if ListenerCount > 0 {
|
|
var TotalCount = 0
|
|
if DbName := t.DB.ListenerNames(); len(DbName) > 0 {
|
|
TotalCount = ListenerCount
|
|
for _, name := range DbName {
|
|
for _, listener := range t.Listeners {
|
|
if listener.Name == name {
|
|
TotalCount--
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if TotalCount > 0 {
|
|
logger.Info(fmt.Sprintf("Starting %v listeners from last session", colors.Green(TotalCount)))
|
|
}
|
|
}
|
|
|
|
for _, listener := range t.DB.ListenerAll() {
|
|
|
|
switch listener["Protocol"] {
|
|
|
|
case handlers.AGENT_HTTP, handlers.AGENT_HTTPS:
|
|
|
|
var (
|
|
Data = make(map[string]any)
|
|
HandlerData = handlers.HTTPConfig{
|
|
Name: listener["Name"],
|
|
}
|
|
)
|
|
|
|
err = json.Unmarshal([]byte(listener["Config"]), &Data)
|
|
if err != nil {
|
|
logger.Error("Failed to unmarshal json bytes to map: " + err.Error())
|
|
continue
|
|
}
|
|
|
|
/* set config of http listener */
|
|
HandlerData.Hosts = strings.Split(Data["Hosts"].(string), ", ")
|
|
HandlerData.HostBind = Data["HostBind"].(string)
|
|
HandlerData.HostRotation = Data["HostRotation"].(string)
|
|
HandlerData.PortBind = Data["PortBind"].(string)
|
|
HandlerData.UserAgent = Data["UserAgent"].(string)
|
|
HandlerData.Headers = strings.Split(Data["Headers"].(string), "\r\n")
|
|
HandlerData.Uris = strings.Split(Data["Uris"].(string), ", ")
|
|
HandlerData.BehindRedir = t.Profile.Config.Demon.TrustXForwardedFor
|
|
|
|
HandlerData.Secure = false
|
|
if Data["Secure"].(string) == "true" {
|
|
HandlerData.Secure = true
|
|
}
|
|
|
|
if Data["Response Headers"] != nil {
|
|
|
|
switch Data["Response Headers"].(type) {
|
|
|
|
case string:
|
|
HandlerData.Response.Headers = strings.Split(Data["Response Headers"].(string), "\r\n")
|
|
break
|
|
|
|
default:
|
|
for _, s := range Data["Response Headers"].([]interface{}) {
|
|
HandlerData.Response.Headers = append(HandlerData.Response.Headers, s.(string))
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/* also ignore if we already have a listener running */
|
|
if err := t.ListenerStart(handlers.LISTENER_HTTP, HandlerData); err != nil && err.Error() != "listener already exists" {
|
|
logger.SetStdOut(os.Stderr)
|
|
logger.Error("Failed to start listener from db: " + err.Error())
|
|
return
|
|
}
|
|
|
|
break
|
|
|
|
case handlers.AGENT_EXTERNAL:
|
|
|
|
var (
|
|
Data = make(map[string]any)
|
|
HandlerData = handlers.ExternalConfig{
|
|
Name: listener["Name"],
|
|
}
|
|
)
|
|
|
|
err := json.Unmarshal([]byte(listener["Config"]), &Data)
|
|
if err != nil {
|
|
logger.Debug("Failed to unmarshal json bytes to map: " + err.Error())
|
|
continue
|
|
}
|
|
|
|
HandlerData.Endpoint = Data["Endpoint"].(string)
|
|
|
|
if err := t.ListenerStart(handlers.LISTENER_EXTERNAL, HandlerData); err != nil && err.Error() != "listener already exists" {
|
|
logger.SetStdOut(os.Stderr)
|
|
logger.Error("Failed to start listener from db: " + err.Error())
|
|
return
|
|
}
|
|
|
|
break
|
|
|
|
case handlers.AGENT_PIVOT_SMB:
|
|
|
|
var (
|
|
Data = make(map[string]any)
|
|
HandlerData = handlers.SMBConfig{
|
|
Name: listener["Name"],
|
|
}
|
|
)
|
|
|
|
err := json.Unmarshal([]byte(listener["Config"]), &Data)
|
|
if err != nil {
|
|
logger.Debug("Failed to unmarshal json bytes to map: " + err.Error())
|
|
continue
|
|
}
|
|
|
|
HandlerData.PipeName = Data["PipeName"].(string)
|
|
|
|
if err := t.ListenerStart(handlers.LISTENER_PIVOT_SMB, HandlerData); err != nil && err.Error() != "listener already exists" {
|
|
logger.SetStdOut(os.Stderr)
|
|
logger.Error("Failed to start listener from db: " + err.Error())
|
|
return
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// load all existing Agents from the DB
|
|
Agents := t.DB.AgentAll()
|
|
for _, Agent := range Agents {
|
|
t.AgentAdd(Agent)
|
|
}
|
|
|
|
for _, Agent := range Agents {
|
|
// check if the agent has a parent
|
|
parentID, err := t.ParentOf(Agent)
|
|
if err == nil {
|
|
Agent.Pivots.Parent = t.AgentInstance(parentID)
|
|
}
|
|
// check if the agent has any links
|
|
AgentsIDs := t.LinksOf(Agent)
|
|
for _, AgentID := range AgentsIDs {
|
|
Agent.Pivots.Links = append(Agent.Pivots.Links, t.AgentInstance(AgentID))
|
|
}
|
|
}
|
|
|
|
// notify the clients
|
|
for _, Agent := range Agents {
|
|
t.AgentSendNotify(Agent)
|
|
}
|
|
|
|
if len(Agents) > 0 {
|
|
logger.Info(fmt.Sprintf("Restored %v agents from last session", colors.Green(len(Agents))))
|
|
}
|
|
|
|
t.EventAppend(events.SendProfile(t.Profile))
|
|
|
|
// This should hold the Teamserver as long as the WebSocket Server is running
|
|
logger.Debug("Wait til the server shutdown")
|
|
|
|
<-ServerFinished
|
|
}
|
|
|
|
func (t *Teamserver) handleRequest(id string) {
|
|
value, isok := t.Clients.Load(id)
|
|
|
|
if !isok {
|
|
return
|
|
}
|
|
|
|
client := value.(*Client)
|
|
_, NewClient, err := client.Connection.ReadMessage()
|
|
|
|
if err != nil {
|
|
if err != io.EOF {
|
|
logger.Error("Error reading 2:", err.Error())
|
|
if strings.Contains(err.Error(), "connection reset by peer") {
|
|
err := client.Connection.Close()
|
|
if err != nil {
|
|
logger.Error("Error while closing Client connection: " + err.Error())
|
|
}
|
|
}
|
|
}
|
|
t.Clients.Delete(id)
|
|
return
|
|
}
|
|
|
|
pk := client.Packager.CreatePackage(string(NewClient))
|
|
|
|
if t.Profile != nil {
|
|
var found = false
|
|
for _, UserNames := range t.Profile.ListOfUsernames() {
|
|
if UserNames == pk.Head.User {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
err := t.SendEvent(id, events.UserDoNotExists())
|
|
if err != nil {
|
|
logger.Error("Error while sending package to " + colors.Red(id) + "")
|
|
}
|
|
t.RemoveClient(id)
|
|
return
|
|
}
|
|
}
|
|
|
|
isExist := false
|
|
t.Clients.Range(func(key, value any) bool {
|
|
if client.Username == pk.Head.User {
|
|
err := t.SendEvent(id, events.UserAlreadyExits())
|
|
if err != nil {
|
|
logger.Error("couldn't send event to client "+colors.Yellow(id)+":", err)
|
|
}
|
|
t.RemoveClient(id)
|
|
isExist = true
|
|
return false
|
|
}
|
|
return true
|
|
})
|
|
if isExist {
|
|
return
|
|
}
|
|
if !t.ClientAuthenticate(pk) {
|
|
logger.Error("Client [User: " + pk.Body.Info["User"].(string) + "] failed to Authenticate! (" + colors.Red(client.GlobalIP) + ")")
|
|
err := t.SendEvent(id, events.Authenticated(false))
|
|
if err != nil {
|
|
logger.Error("client (" + colors.Red(id) + ") error while sending authenticate message: " + colors.Red(err))
|
|
}
|
|
err = client.Connection.Close()
|
|
if err != nil {
|
|
logger.Error("Failed to close client (" + id + ") socket")
|
|
}
|
|
return
|
|
} else {
|
|
|
|
logger.Good("User <" + colors.Blue(pk.Body.Info["User"].(string)) + "> " + colors.Green("Authenticated"))
|
|
|
|
client.Authenticated = true
|
|
client.ClientID = id
|
|
|
|
err := t.SendEvent(id, events.Authenticated(true))
|
|
if err != nil {
|
|
logger.Error("client (" + colors.Red(id) + ") error while sending authenticate message:" + colors.Red(err))
|
|
}
|
|
}
|
|
|
|
client.Username = pk.Body.Info["User"].(string)
|
|
packageNewUser := events.ChatLog.NewUserConnected(client.Username)
|
|
t.EventAppend(packageNewUser)
|
|
t.EventBroadcast(id, packageNewUser)
|
|
|
|
t.SendAllPackagesToNewClient(id)
|
|
|
|
for {
|
|
value, isok := t.Clients.Load(id)
|
|
if !isok {
|
|
return
|
|
}
|
|
client = value.(*Client)
|
|
_, EventPackage, err := client.Connection.ReadMessage()
|
|
|
|
if err != nil {
|
|
if websocket.IsCloseError(err, websocket.CloseAbnormalClosure) {
|
|
logger.Warn("User <" + colors.Blue(client.Username) + "> " + colors.Red("Disconnected"))
|
|
|
|
t.EventAppend(events.ChatLog.UserDisconnected(client.Username))
|
|
t.RemoveClient(id)
|
|
|
|
return
|
|
} else {
|
|
logger.Error("Error reading :", err.Error())
|
|
}
|
|
|
|
err := client.Connection.Close()
|
|
if err != nil {
|
|
logger.Error("Socket Error:", err.Error())
|
|
}
|
|
|
|
t.EventAppend(events.ChatLog.UserDisconnected(client.Username))
|
|
t.RemoveClient(id)
|
|
|
|
return
|
|
}
|
|
|
|
pk := client.Packager.CreatePackage(string(EventPackage))
|
|
pk.Head.Time = time.Now().Format("02/01/2006 15:04:05")
|
|
|
|
t.EventAppend(pk)
|
|
t.DispatchEvent(pk)
|
|
}
|
|
}
|
|
|
|
func (t *Teamserver) SetProfile(path string) {
|
|
t.Profile = profile.NewProfile()
|
|
logger.LoggerInstance.STDERR = os.Stderr
|
|
err := t.Profile.SetProfile(path, t.Flags.Server.Default)
|
|
if err != nil {
|
|
logger.SetStdOut(os.Stderr)
|
|
logger.Error("Profile error:", colors.Red(err))
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func (t *Teamserver) ClientAuthenticate(pk packager.Package) bool {
|
|
if pk.Head.Event == packager.Type.InitConnection.Type {
|
|
if pk.Body.SubEvent == packager.Type.InitConnection.OAuthRequest {
|
|
if t.Profile != nil {
|
|
if t.Profile.Config.Operators != nil {
|
|
var (
|
|
UserPassword string
|
|
UserName string
|
|
PassHash = sha3.New256()
|
|
UserFound = false
|
|
)
|
|
|
|
// search for operator
|
|
for _, User := range t.Profile.Config.Operators.Users {
|
|
if User.Name == pk.Head.User {
|
|
UserName = User.Name
|
|
UserFound = true
|
|
|
|
PassHash.Write([]byte(User.Password))
|
|
UserPassword = hex.EncodeToString(PassHash.Sum(nil))
|
|
|
|
logger.Debug("Found User: " + User.Name)
|
|
}
|
|
}
|
|
|
|
// check if the operator was even found
|
|
if UserFound {
|
|
if pk.Body.Info["Password"].(string) == UserPassword {
|
|
logger.Debug("User " + colors.Red(UserName) + " is authenticated")
|
|
return true
|
|
}
|
|
} else {
|
|
logger.Debug("User not found")
|
|
}
|
|
|
|
logger.Debug("User not authenticated")
|
|
}
|
|
|
|
return false
|
|
} else {
|
|
return false
|
|
}
|
|
} else {
|
|
logger.Error("Wrong SubEvent :: " + strconv.Itoa(pk.Body.SubEvent))
|
|
}
|
|
} else {
|
|
logger.Error("Not a Authenticate request")
|
|
}
|
|
|
|
logger.Error("Client failed to authenticate with password hash :: " + pk.Body.Info["Password"].(string))
|
|
return false
|
|
}
|
|
|
|
func (t *Teamserver) EventBroadcast(ExceptClient string, pk packager.Package) {
|
|
|
|
// some sanity check
|
|
if pk.Head.Event == 0 {
|
|
return
|
|
}
|
|
|
|
t.Clients.Range(func(key, value any) bool {
|
|
ClientID := key.(string)
|
|
if ExceptClient != ClientID {
|
|
err := t.SendEvent(ClientID, pk)
|
|
if err != nil && !strings.Contains(err.Error(), "use of closed network connection") {
|
|
logger.Error("SendEvent error: ", colors.Red(err))
|
|
}
|
|
}
|
|
return true
|
|
})
|
|
}
|
|
|
|
func (t *Teamserver) EventNewDemon(DemonAgent *agent.Agent) packager.Package {
|
|
return events.Demons.NewDemon(DemonAgent)
|
|
}
|
|
|
|
func (t *Teamserver) EventAgentMark(AgentID, Mark string) {
|
|
var pk = events.Demons.MarkAs(AgentID, Mark)
|
|
|
|
t.EventAppend(pk)
|
|
t.EventBroadcast("", pk)
|
|
}
|
|
|
|
func (t *Teamserver) EventListenerError(ListenerName string, Error error) {
|
|
var pk = events.Listener.ListenerError("", ListenerName, Error)
|
|
|
|
t.EventAppend(pk)
|
|
t.EventBroadcast("", pk)
|
|
|
|
// also remove the listener from the init packages.
|
|
for EventID := range t.EventsList {
|
|
if t.EventsList[EventID].Head.Event == packager.Type.Listener.Type {
|
|
if t.EventsList[EventID].Body.SubEvent == packager.Type.Listener.Add {
|
|
if name, ok := t.EventsList[EventID].Body.Info["Name"]; ok {
|
|
if name == ListenerName {
|
|
t.EventsList[EventID].Body.Info["Status"] = "Offline"
|
|
t.EventsList[EventID].Body.Info["Error"] = Error.Error()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (t *Teamserver) SendEvent(id string, pk packager.Package) error {
|
|
var (
|
|
buffer bytes.Buffer
|
|
err error
|
|
)
|
|
|
|
err = json.NewEncoder(&buffer).Encode(pk)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
value, isOk := t.Clients.Load(id)
|
|
if isOk {
|
|
client := value.(*Client)
|
|
client.Mutex.Lock()
|
|
|
|
err = client.Connection.WriteMessage(websocket.BinaryMessage, buffer.Bytes())
|
|
if err != nil {
|
|
// TODO: comment this line out as it seems to crash the server
|
|
//t.Clients[id].Mutex.Unlock()
|
|
return err
|
|
}
|
|
|
|
client.Mutex.Unlock()
|
|
|
|
} else {
|
|
return errors.New(fmt.Sprintf("client (%v) doesn't exist anymore", colors.Red(id)))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (t *Teamserver) RemoveClient(ClientID string) {
|
|
|
|
value, isOk := t.Clients.Load(ClientID)
|
|
|
|
if isOk {
|
|
client := value.(*Client)
|
|
var (
|
|
userDisconnected = client.Username
|
|
Authenticated = client.Authenticated
|
|
)
|
|
|
|
if Authenticated {
|
|
t.EventBroadcast(ClientID, events.ChatLog.UserDisconnected(userDisconnected))
|
|
for UserID := range t.Users {
|
|
if userDisconnected == t.Users[UserID].Name {
|
|
t.Users[UserID].Online = false
|
|
}
|
|
}
|
|
}
|
|
|
|
t.Clients.Delete(ClientID)
|
|
}
|
|
}
|
|
|
|
func (t *Teamserver) EventAppend(event packager.Package) []packager.Package {
|
|
|
|
// some sanity check
|
|
if event.Head.Event == 0 {
|
|
return t.EventsList
|
|
}
|
|
|
|
if event.Head.OneTime != "true" {
|
|
t.EventsList = append(t.EventsList, event)
|
|
return append(t.EventsList, event)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (t *Teamserver) EventRemove(EventID int) []packager.Package {
|
|
t.EventsList = append(t.EventsList[:EventID], t.EventsList[EventID+1:]...)
|
|
|
|
return append(t.EventsList[:EventID], t.EventsList[EventID+1:]...)
|
|
}
|
|
|
|
func (t *Teamserver) SendAllPackagesToNewClient(ClientID string) {
|
|
for _, Package := range t.EventsList {
|
|
err := t.SendEvent(ClientID, Package)
|
|
if err != nil {
|
|
logger.Error("error while sending info to client("+ClientID+"): ", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
// send all the agents that are alive right now to the new client
|
|
for _, demon := range t.Agents.Agents {
|
|
if demon.Active == false {
|
|
continue
|
|
}
|
|
|
|
pk := t.EventNewDemon(demon)
|
|
err := t.SendEvent(ClientID, pk)
|
|
if err != nil {
|
|
logger.Error("error while sending info to client("+ClientID+"): ", err)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func (t *Teamserver) FindSystemPackages() bool {
|
|
var err error
|
|
|
|
if t.Profile.Config.Server.Build != nil {
|
|
|
|
if len(t.Profile.Config.Server.Build.Compiler64) > 0 {
|
|
if _, err := os.Stat(t.Profile.Config.Server.Build.Compiler64); os.IsNotExist(err) {
|
|
logger.SetStdOut(os.Stderr)
|
|
logger.Error("Compiler x64 path doesn't exist: " + t.Profile.Config.Server.Build.Compiler64)
|
|
return false
|
|
}
|
|
|
|
t.Settings.Compiler64 = t.Profile.Config.Server.Build.Compiler64
|
|
} else {
|
|
t.Settings.Compiler64, err = exec.LookPath("x86_64-w64-mingw32-gcc")
|
|
if err != nil {
|
|
logger.SetStdOut(os.Stderr)
|
|
logger.Error("Couldn't find x64 mingw compiler: " + err.Error())
|
|
return false
|
|
}
|
|
}
|
|
|
|
if len(t.Profile.Config.Server.Build.Compiler86) > 0 {
|
|
if _, err := os.Stat(t.Profile.Config.Server.Build.Compiler86); os.IsNotExist(err) {
|
|
logger.SetStdOut(os.Stderr)
|
|
logger.Error("Compiler x86 path doesn't exist: " + t.Profile.Config.Server.Build.Compiler86)
|
|
return false
|
|
}
|
|
|
|
t.Settings.Compiler32 = t.Profile.Config.Server.Build.Compiler86
|
|
} else {
|
|
t.Settings.Compiler32, err = exec.LookPath("i686-w64-mingw32-gcc")
|
|
if err != nil {
|
|
logger.SetStdOut(os.Stderr)
|
|
logger.Error("Couldn't find x86 mingw compiler: " + err.Error())
|
|
return false
|
|
}
|
|
}
|
|
|
|
if len(t.Profile.Config.Server.Build.Nasm) > 0 {
|
|
if _, err := os.Stat(t.Profile.Config.Server.Build.Nasm); os.IsNotExist(err) {
|
|
logger.SetStdOut(os.Stderr)
|
|
logger.Error("Nasm path doesn't exist: " + t.Profile.Config.Server.Build.Nasm)
|
|
return false
|
|
}
|
|
|
|
t.Settings.Nasm = t.Profile.Config.Server.Build.Nasm
|
|
} else {
|
|
t.Settings.Nasm, err = exec.LookPath("nasm")
|
|
if err != nil {
|
|
logger.Error("Couldn't find nasm: " + err.Error())
|
|
return false
|
|
}
|
|
}
|
|
|
|
} else {
|
|
t.Settings.Compiler64, err = exec.LookPath("x86_64-w64-mingw32-gcc")
|
|
if err != nil {
|
|
logger.SetStdOut(os.Stderr)
|
|
logger.Error("Couldn't find x64 mingw compiler: " + err.Error())
|
|
return false
|
|
}
|
|
|
|
t.Settings.Compiler32, err = exec.LookPath("i686-w64-mingw32-gcc")
|
|
if err != nil {
|
|
logger.SetStdOut(os.Stderr)
|
|
logger.Error("Couldn't find x86 mingw compiler: " + err.Error())
|
|
return false
|
|
}
|
|
|
|
t.Settings.Nasm, err = exec.LookPath("nasm")
|
|
if err != nil {
|
|
logger.SetStdOut(os.Stderr)
|
|
logger.Error("Couldn't find nasm: " + err.Error())
|
|
return false
|
|
}
|
|
}
|
|
|
|
logger.Info(fmt.Sprintf(
|
|
"Build: \n"+
|
|
" - Compiler x64 : %v\n"+
|
|
" - Compiler x86 : %v\n"+
|
|
" - Nasm : %v",
|
|
colors.Blue(t.Settings.Compiler64),
|
|
colors.Blue(t.Settings.Compiler32),
|
|
colors.Blue(t.Settings.Nasm),
|
|
))
|
|
|
|
return true
|
|
}
|
|
|
|
func (t *Teamserver) EndpointAdd(endpoint *Endpoint) bool {
|
|
for _, e := range t.Endpoints {
|
|
if e.Endpoint == endpoint.Endpoint {
|
|
return false
|
|
}
|
|
}
|
|
|
|
t.Endpoints = append(t.Endpoints, endpoint)
|
|
|
|
return true
|
|
}
|
|
|
|
func (t *Teamserver) EndpointRemove(endpoint string) []*Endpoint {
|
|
for i := range t.Endpoints {
|
|
if t.Endpoints[i].Endpoint == endpoint {
|
|
t.Endpoints = append(t.Endpoints[:i], t.Endpoints[i+1:]...)
|
|
return t.Endpoints
|
|
}
|
|
}
|
|
|
|
return t.Endpoints
|
|
}
|