Files
2026-04-21 20:51:06 -07:00

177 lines
5.4 KiB
Go

package cli
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"fmt"
"log"
"os"
"path/filepath"
"runtime/debug"
"strings"
"github.com/spf13/cobra"
clientcli "github.com/bishopfox/sliver/client/cli"
"github.com/bishopfox/sliver/server/assets"
"github.com/bishopfox/sliver/server/c2"
"github.com/bishopfox/sliver/server/certs"
"github.com/bishopfox/sliver/server/configs"
"github.com/bishopfox/sliver/server/console"
"github.com/bishopfox/sliver/server/cryptography"
"github.com/bishopfox/sliver/server/daemon"
"github.com/bishopfox/sliver/server/db"
)
const (
// Unpack flags
forceFlagStr = "force"
// Operator flags
nameFlagStr = "name"
lhostFlagStr = "lhost"
lportFlagStr = "lport"
saveFlagStr = "save"
outputFlagStr = "output"
permissionsFlagStr = "permissions"
tailscaleFlagStr = "tailscale"
enableWGFlagStr = "enable-wg"
// Cert flags
caTypeFlagStr = "type"
loadFlagStr = "load"
// console log file name
logFileName = "console.log"
)
// Initialize logging
func initConsoleLogging(appDir string) *os.File {
log.SetFlags(log.LstdFlags | log.Lshortfile)
logFile, err := os.OpenFile(filepath.Join(appDir, "logs", logFileName), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o600)
if err != nil {
log.Fatalf("Error opening file: %v", err)
}
log.SetOutput(logFile)
return logFile
}
func init() {
rootCmd.Flags().String(clientcli.RCFlagName, "", "path to rc script file")
// Unpack
unpackCmd.Flags().BoolP(forceFlagStr, "f", false, "Force unpack and overwrite")
rootCmd.AddCommand(unpackCmd)
// Operator
operatorCmd.Flags().StringP(nameFlagStr, "n", "", "operator name")
operatorCmd.Flags().StringP(lhostFlagStr, "l", "", "multiplayer listener host")
operatorCmd.Flags().Uint16P(lportFlagStr, "p", uint16(31337), "multiplayer listener port")
operatorCmd.Flags().StringP(saveFlagStr, "s", "", "save file to ...")
operatorCmd.Flags().StringP(outputFlagStr, "o", "file", "output format (file, stdout)")
operatorCmd.Flags().StringSliceP(permissionsFlagStr, "P", []string{}, "grant permissions to the operator profile (all, builder, crackstation)")
operatorCmd.Flags().Bool(enableWGFlagStr, false, "include WireGuard tunnel settings in the generated operator config")
rootCmd.AddCommand(operatorCmd)
// Certs
cmdExportCA.Flags().StringP(saveFlagStr, "s", "", "save CA to file ...")
cmdExportCA.Flags().StringP(caTypeFlagStr, "t", "", fmt.Sprintf("ca type (%s)", strings.Join(validCATypes(), ", ")))
rootCmd.AddCommand(cmdExportCA)
cmdImportCA.Flags().StringP(loadFlagStr, "l", "", "load CA from file ...")
cmdImportCA.Flags().StringP(caTypeFlagStr, "t", "", fmt.Sprintf("ca type (%s)", strings.Join(validCATypes(), ", ")))
rootCmd.AddCommand(cmdImportCA)
// Daemon
daemonCmd.Flags().StringP(lhostFlagStr, "l", daemon.BlankHost, "multiplayer listener host")
daemonCmd.Flags().Uint16P(lportFlagStr, "p", daemon.BlankPort, "multiplayer listener port")
daemonCmd.Flags().BoolP(forceFlagStr, "f", false, "force unpack and overwrite static assets")
daemonCmd.Flags().BoolP(tailscaleFlagStr, "t", false, "enable tailscale")
daemonCmd.Flags().Bool(enableWGFlagStr, false, "wrap the multiplayer listener in WireGuard")
rootCmd.AddCommand(daemonCmd)
// Builder
rootCmd.AddCommand(initBuilderCmd())
// Version
rootCmd.AddCommand(versionCmd)
}
var rootCmd = &cobra.Command{
Use: "sliver-server",
Short: "",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
// Root command starts the server normally
appDir := assets.GetRootAppDir()
logFile := initConsoleLogging(appDir)
defer logFile.Close()
defer func() {
if r := recover(); r != nil {
log.Printf("panic:\n%s", debug.Stack())
fmt.Println("stacktrace from panic: \n" + string(debug.Stack()))
os.Exit(99)
}
}()
assets.Setup(false, true)
certs.SetupCAs()
certs.SetupWGKeys()
certs.SetupMultiplayerWGKeys()
cryptography.AgeServerKeyPair()
cryptography.MinisignServerPrivateKey()
c2.SetupDefaultC2Profiles()
_, _ = configs.LoadCrackConfig()
serverConfig := configs.GetServerConfig()
listenerJobs, err := db.ListenerJobs()
if err != nil {
fmt.Printf("[!] Failed to load persistent listener jobs: %s\n", err)
}
err = StartPersistentJobs(listenerJobs)
if err != nil {
fmt.Printf("[!] %s\n", err)
}
if serverConfig.DaemonMode {
daemon.Start(daemon.BlankHost, daemon.BlankPort, serverConfig.DaemonConfig.Tailscale, serverConfig.DaemonConfig.WireGuardEnabled())
} else {
rcScript, err := clientcli.ReadRCScript(cmd)
if err != nil {
fmt.Printf("Failed to read rc script: %s\n", err)
return
}
os.Args = os.Args[:1] // Hide cli from grumble console
console.Start(rcScript)
}
},
}
// Execute - Execute root command
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}