From 1c81b2baae0289f93c503cdf5835e083a3574b27 Mon Sep 17 00:00:00 2001
From: moloch-- <875022+moloch--@users.noreply.github.com>
Date: Sat, 3 Jul 2021 12:33:44 -0500
Subject: [PATCH] Refactored jobs
---
client/command/README.md | 1 +
client/command/env.go | 111 -------------
client/command/environment/README.md | 4 +
client/command/environment/get.go | 49 ++++++
client/command/environment/set.go | 59 +++++++
client/command/environment/unset.go | 56 +++++++
client/command/jobs/README.md | 4 +
client/command/jobs/dns.go | 36 +++++
client/command/jobs/http.go | 28 ++++
client/command/jobs/https.go | 56 +++++++
client/command/jobs/job.go | 231 ---------------------------
client/command/jobs/jobs-kill.go | 32 ++++
client/command/jobs/jobs.go | 80 ++++++++++
client/command/jobs/mtls.go | 27 ++++
client/command/jobs/wg.go | 28 ++++
15 files changed, 460 insertions(+), 342 deletions(-)
delete mode 100644 client/command/env.go
create mode 100644 client/command/environment/README.md
create mode 100644 client/command/environment/get.go
create mode 100644 client/command/environment/set.go
create mode 100644 client/command/environment/unset.go
create mode 100644 client/command/jobs/README.md
create mode 100644 client/command/jobs/dns.go
create mode 100644 client/command/jobs/http.go
create mode 100644 client/command/jobs/https.go
delete mode 100644 client/command/jobs/job.go
create mode 100644 client/command/jobs/jobs-kill.go
create mode 100644 client/command/jobs/jobs.go
create mode 100644 client/command/jobs/mtls.go
create mode 100644 client/command/jobs/wg.go
diff --git a/client/command/README.md b/client/command/README.md
index e2bfba0e7d..f2e17d866b 100644
--- a/client/command/README.md
+++ b/client/command/README.md
@@ -10,4 +10,5 @@ General guidance on the structure of this package:
* The root command, and reused code should go into the file named after the command
* For example, code shared between the `generate` and the `regenerate` command should go in `generate.go`, and any `regenerate` specific code should go in `regenerate.go`
* Command entrypoint functions should have the suffix `Cmd` e.g., `GenerateCmd` is the entrypoint for `generate`
+ * Command entrypoints should always a function signature of `func (ctx *grumble.Context, con *console.SliverConsoleClient)`
* Functions that are only ever exported for other commands to use should go in a `helpers.go`, if the function is used internally and exported follow the guidance above on shared code.
diff --git a/client/command/env.go b/client/command/env.go
deleted file mode 100644
index 947ea32363..0000000000
--- a/client/command/env.go
+++ /dev/null
@@ -1,111 +0,0 @@
-package command
-
-// /*
-// 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 .
-// */
-
-// import (
-// "context"
-// "fmt"
-
-// "github.com/bishopfox/sliver/protobuf/commonpb"
-// "github.com/bishopfox/sliver/protobuf/rpcpb"
-// "github.com/bishopfox/sliver/protobuf/sliverpb"
-// "github.com/desertbit/grumble"
-// )
-
-// func getEnv(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
-// session := ActiveSession.Get()
-// if session == nil {
-// return
-// }
-
-// name := ctx.Args.String("name")
-// envInfo, err := rpc.GetEnv(context.Background(), &sliverpb.EnvReq{
-// Name: name,
-// Request: ActiveSession.Request(ctx),
-// })
-
-// if err != nil {
-// fmt.Printf(Warn+"Error: %v", err)
-// return
-// }
-
-// for _, envVar := range envInfo.Variables {
-// fmt.Printf("%s=%s\n", envVar.Key, envVar.Value)
-// }
-// }
-
-// func setEnv(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
-// session := ActiveSession.Get()
-// if session == nil {
-// return
-// }
-
-// name := ctx.Args.String("name")
-// value := ctx.Args.String("value")
-// if name == "" || value == "" {
-// fmt.Printf(Warn + "Usage: setenv KEY VALUE\n")
-// return
-// }
-
-// envInfo, err := rpc.SetEnv(context.Background(), &sliverpb.SetEnvReq{
-// Variable: &commonpb.EnvVar{
-// Key: name,
-// Value: value,
-// },
-// Request: ActiveSession.Request(ctx),
-// })
-// if err != nil {
-// fmt.Printf(Warn+"Error: %v", err)
-// return
-// }
-// if envInfo.Response != nil && envInfo.Response.Err != "" {
-// fmt.Printf(Warn+"Error: %s", envInfo.Response.Err)
-// return
-// }
-// fmt.Printf(Info+"set %s to %s\n", name, value)
-// }
-
-// func unsetEnv(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
-// session := ActiveSession.Get()
-// if session == nil {
-// return
-// }
-
-// name := ctx.Args.String("name")
-// if name == "" {
-// fmt.Printf(Warn + "Usage: setenv NAME\n")
-// return
-// }
-
-// unsetResp, err := rpc.UnsetEnv(context.Background(), &sliverpb.UnsetEnvReq{
-// Name: name,
-// Request: ActiveSession.Request(ctx),
-// })
-
-// if err != nil {
-// fmt.Printf(Warn+"Error: %v", err)
-// return
-// }
-
-// if unsetResp.Response != nil && unsetResp.Response.Err != "" {
-// fmt.Printf(Warn+"Error: %s\n", unsetResp.Response.Err)
-// return
-// }
-// fmt.Printf(Info+"Successfully unset %s\n", name)
-// }
diff --git a/client/command/environment/README.md b/client/command/environment/README.md
new file mode 100644
index 0000000000..20dd1fa8e3
--- /dev/null
+++ b/client/command/environment/README.md
@@ -0,0 +1,4 @@
+Environment
+===========
+
+Contains command implementations for manipulating remote environment variables.
diff --git a/client/command/environment/get.go b/client/command/environment/get.go
new file mode 100644
index 0000000000..b85ae451b1
--- /dev/null
+++ b/client/command/environment/get.go
@@ -0,0 +1,49 @@
+package environment
+
+/*
+ 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 .
+*/
+
+import (
+ "context"
+
+ "github.com/bishopfox/sliver/client/console"
+ "github.com/bishopfox/sliver/protobuf/sliverpb"
+ "github.com/desertbit/grumble"
+)
+
+func EnvGetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
+ session := con.ActiveSession.Get()
+ if session == nil {
+ return
+ }
+
+ name := ctx.Args.String("name")
+ envInfo, err := con.Rpc.GetEnv(context.Background(), &sliverpb.EnvReq{
+ Name: name,
+ Request: con.ActiveSession.Request(ctx),
+ })
+
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ return
+ }
+
+ for _, envVar := range envInfo.Variables {
+ con.Printf("%s=%s\n", envVar.Key, envVar.Value)
+ }
+}
diff --git a/client/command/environment/set.go b/client/command/environment/set.go
new file mode 100644
index 0000000000..5f58484761
--- /dev/null
+++ b/client/command/environment/set.go
@@ -0,0 +1,59 @@
+package environment
+
+/*
+ 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 .
+*/
+
+import (
+ "context"
+
+ "github.com/bishopfox/sliver/client/console"
+ "github.com/bishopfox/sliver/protobuf/commonpb"
+ "github.com/bishopfox/sliver/protobuf/sliverpb"
+ "github.com/desertbit/grumble"
+)
+
+func EnvSetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
+ session := con.ActiveSession.Get()
+ if session == nil {
+ return
+ }
+
+ name := ctx.Args.String("name")
+ value := ctx.Args.String("value")
+ if name == "" || value == "" {
+ con.PrintErrorf("Usage: setenv KEY VALUE\n")
+ return
+ }
+
+ envInfo, err := con.Rpc.SetEnv(context.Background(), &sliverpb.SetEnvReq{
+ Variable: &commonpb.EnvVar{
+ Key: name,
+ Value: value,
+ },
+ Request: con.ActiveSession.Request(ctx),
+ })
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ return
+ }
+ if envInfo.Response != nil && envInfo.Response.Err != "" {
+ con.PrintErrorf("%s\n", envInfo.Response.Err)
+ return
+ }
+ con.PrintInfof("Set %s to %s\n", name, value)
+}
diff --git a/client/command/environment/unset.go b/client/command/environment/unset.go
new file mode 100644
index 0000000000..c9fc023cb0
--- /dev/null
+++ b/client/command/environment/unset.go
@@ -0,0 +1,56 @@
+package environment
+
+/*
+ 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 .
+*/
+
+import (
+ "context"
+
+ "github.com/bishopfox/sliver/client/console"
+ "github.com/bishopfox/sliver/protobuf/sliverpb"
+ "github.com/desertbit/grumble"
+)
+
+func EnvUnsetCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
+ session := con.ActiveSession.Get()
+ if session == nil {
+ return
+ }
+
+ name := ctx.Args.String("name")
+ if name == "" {
+ con.PrintErrorf("Usage: setenv NAME\n")
+ return
+ }
+
+ unsetResp, err := con.Rpc.UnsetEnv(context.Background(), &sliverpb.UnsetEnvReq{
+ Name: name,
+ Request: con.ActiveSession.Request(ctx),
+ })
+
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ return
+ }
+
+ if unsetResp.Response != nil && unsetResp.Response.Err != "" {
+ con.PrintErrorf("%s\n", unsetResp.Response.Err)
+ return
+ }
+ con.PrintInfof("Successfully unset %s\n", name)
+}
diff --git a/client/command/jobs/README.md b/client/command/jobs/README.md
new file mode 100644
index 0000000000..3921833db9
--- /dev/null
+++ b/client/command/jobs/README.md
@@ -0,0 +1,4 @@
+Jobs
+=====
+
+Implements commands related to starting/killing jobs like `jobs` and starting C2 listeners (`mtls`, `http`, etc.)
diff --git a/client/command/jobs/dns.go b/client/command/jobs/dns.go
new file mode 100644
index 0000000000..5e22c0028a
--- /dev/null
+++ b/client/command/jobs/dns.go
@@ -0,0 +1,36 @@
+package jobs
+
+import (
+ "context"
+ "strings"
+
+ "github.com/bishopfox/sliver/client/console"
+ "github.com/bishopfox/sliver/protobuf/clientpb"
+ "github.com/desertbit/grumble"
+)
+
+func DNSListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
+
+ domains := strings.Split(ctx.Flags.String("domains"), ",")
+ for _, domain := range domains {
+ if !strings.HasSuffix(domain, ".") {
+ domain += "."
+ }
+ }
+
+ lport := uint16(ctx.Flags.Int("lport"))
+
+ con.PrintInfof("Starting DNS listener with parent domain(s) %v ...\n", domains)
+ dns, err := con.Rpc.StartDNSListener(context.Background(), &clientpb.DNSListenerReq{
+ Domains: domains,
+ Port: uint32(lport),
+ Canaries: !ctx.Flags.Bool("no-canaries"),
+ Persistent: ctx.Flags.Bool("persistent"),
+ })
+ con.Println()
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ } else {
+ con.PrintInfof("Successfully started job #%d\n", dns.JobID)
+ }
+}
diff --git a/client/command/jobs/http.go b/client/command/jobs/http.go
new file mode 100644
index 0000000000..f0881e8899
--- /dev/null
+++ b/client/command/jobs/http.go
@@ -0,0 +1,28 @@
+package jobs
+
+import (
+ "context"
+
+ "github.com/bishopfox/sliver/client/console"
+ "github.com/bishopfox/sliver/protobuf/clientpb"
+ "github.com/desertbit/grumble"
+)
+
+func HTTPListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
+ domain := ctx.Flags.String("domain")
+ lport := uint16(ctx.Flags.Int("lport"))
+
+ con.PrintInfof("Starting HTTP %s:%d listener ...\n", domain, lport)
+ http, err := con.Rpc.StartHTTPListener(context.Background(), &clientpb.HTTPListenerReq{
+ Domain: domain,
+ Website: ctx.Flags.String("website"),
+ Port: uint32(lport),
+ Secure: false,
+ Persistent: ctx.Flags.Bool("persistent"),
+ })
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ } else {
+ con.PrintInfof("Successfully started job #%d\n", http.JobID)
+ }
+}
diff --git a/client/command/jobs/https.go b/client/command/jobs/https.go
new file mode 100644
index 0000000000..57928d2572
--- /dev/null
+++ b/client/command/jobs/https.go
@@ -0,0 +1,56 @@
+package jobs
+
+import (
+ "context"
+ "io/ioutil"
+
+ "github.com/bishopfox/sliver/client/console"
+ "github.com/bishopfox/sliver/protobuf/clientpb"
+ "github.com/desertbit/grumble"
+)
+
+func HTTPSListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
+ domain := ctx.Flags.String("domain")
+ website := ctx.Flags.String("website")
+ lport := uint16(ctx.Flags.Int("lport"))
+
+ cert, key, err := getLocalCertificatePair(ctx)
+ if err != nil {
+ con.Println()
+ con.PrintErrorf("Failed to load local certificate %s\n", err)
+ return
+ }
+
+ con.PrintInfof("Starting HTTPS %s:%d listener ...\n", domain, lport)
+ https, err := con.Rpc.StartHTTPSListener(context.Background(), &clientpb.HTTPListenerReq{
+ Domain: domain,
+ Website: website,
+ Port: uint32(lport),
+ Secure: true,
+ Cert: cert,
+ Key: key,
+ ACME: ctx.Flags.Bool("lets-encrypt"),
+ Persistent: ctx.Flags.Bool("persistent"),
+ })
+ con.Println()
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ } else {
+ con.PrintInfof("Successfully started job #%d\n", https.JobID)
+ }
+}
+
+func getLocalCertificatePair(ctx *grumble.Context) ([]byte, []byte, error) {
+ if ctx.Flags.String("cert") == "" && ctx.Flags.String("key") == "" {
+ return nil, nil, nil
+ }
+ cert, err := ioutil.ReadFile(ctx.Flags.String("cert"))
+ if err != nil {
+ return nil, nil, err
+ }
+ key, err := ioutil.ReadFile(ctx.Flags.String("key"))
+ if err != nil {
+ return nil, nil, err
+ }
+ return cert, key, nil
+}
diff --git a/client/command/jobs/job.go b/client/command/jobs/job.go
deleted file mode 100644
index 610bad0525..0000000000
--- a/client/command/jobs/job.go
+++ /dev/null
@@ -1,231 +0,0 @@
-package command
-
-// /*
-// 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 .
-// */
-
-// import (
-// "context"
-// "fmt"
-// "io/ioutil"
-// "os"
-// "sort"
-// "strings"
-// "text/tabwriter"
-
-// "github.com/bishopfox/sliver/protobuf/clientpb"
-// "github.com/bishopfox/sliver/protobuf/commonpb"
-// "github.com/bishopfox/sliver/protobuf/rpcpb"
-
-// // "github.com/bishopfox/sliver/protobuf/sliverpb"
-
-// "github.com/desertbit/grumble"
-// // "github.com/golang/protobuf/proto"
-// )
-
-// func jobs(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
-// if ctx.Flags.Int("kill") != -1 {
-// killJob(uint32(ctx.Flags.Int("kill")), rpc)
-// } else if ctx.Flags.Bool("kill-all") {
-// killAllJobs(rpc)
-// } else {
-// jobs, err := rpc.GetJobs(context.Background(), &commonpb.Empty{})
-// if err != nil {
-// fmt.Printf(Warn+"%s", err)
-// return
-// }
-// // Convert to a map
-// activeJobs := map[uint32]*clientpb.Job{}
-// for _, job := range jobs.Active {
-// activeJobs[job.ID] = job
-// }
-// if 0 < len(activeJobs) {
-// printJobs(activeJobs)
-// } else {
-// fmt.Printf(Info + "No active jobs\n")
-// }
-// }
-// }
-
-// func killAllJobs(rpc rpcpb.SliverRPCClient) {
-// jobs, err := rpc.GetJobs(context.Background(), &commonpb.Empty{})
-// if err != nil {
-// fmt.Printf(Warn+"%s\n", err)
-// return
-// }
-// for _, job := range jobs.Active {
-// killJob(job.ID, rpc)
-// }
-// }
-
-// func killJob(jobID uint32, rpc rpcpb.SliverRPCClient) {
-// fmt.Printf(Info+"Killing job #%d ...\n", jobID)
-// jobKill, err := rpc.KillJob(context.Background(), &clientpb.KillJobReq{
-// ID: jobID,
-// })
-// if err != nil {
-// fmt.Printf(Warn+"%s\n", err)
-// } else {
-// fmt.Printf(Info+"Successfully killed job #%d\n", jobKill.ID)
-// }
-// }
-
-// func printJobs(jobs map[uint32]*clientpb.Job) {
-// table := tabwriter.NewWriter(os.Stdout, 0, 2, 2, ' ', 0)
-// fmt.Fprintf(table, "ID\tName\tProtocol\tPort\t\n")
-// fmt.Fprintf(table, "%s\t%s\t%s\t%s\t\n",
-// strings.Repeat("=", len("ID")),
-// strings.Repeat("=", len("Name")),
-// strings.Repeat("=", len("Protocol")),
-// strings.Repeat("=", len("Port")))
-
-// var keys []int
-// for _, job := range jobs {
-// keys = append(keys, int(job.ID))
-// }
-// sort.Ints(keys) // Fucking Go can't sort int32's, so we convert to/from int's
-
-// for _, k := range keys {
-// job := jobs[uint32(k)]
-// fmt.Fprintf(table, "%d\t%s\t%s\t%d\t\n", job.ID, job.Name, job.Protocol, job.Port)
-// }
-// table.Flush()
-// }
-
-// func startMTLSListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
-// server := ctx.Flags.String("server")
-// lport := uint16(ctx.Flags.Int("lport"))
-
-// fmt.Printf(Info + "Starting mTLS listener ...\n")
-// mtls, err := rpc.StartMTLSListener(context.Background(), &clientpb.MTLSListenerReq{
-// Host: server,
-// Port: uint32(lport),
-// Persistent: ctx.Flags.Bool("persistent"),
-// })
-// if err != nil {
-// fmt.Printf("\n"+Warn+"%s\n", err)
-// } else {
-// fmt.Printf("\n"+Info+"Successfully started job #%d\n", mtls.JobID)
-// }
-// }
-
-// func startWGListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
-// lport := uint16(ctx.Flags.Int("lport"))
-// nport := uint16(ctx.Flags.Int("nport"))
-// keyExchangePort := uint16(ctx.Flags.Int("key-port"))
-
-// fmt.Printf(Info + "Starting Wireguard listener ...\n")
-// wg, err := rpc.StartWGListener(context.Background(), &clientpb.WGListenerReq{
-// Port: uint32(lport),
-// NPort: uint32(nport),
-// KeyPort: uint32(keyExchangePort),
-// Persistent: ctx.Flags.Bool("persistent"),
-// })
-// if err != nil {
-// fmt.Printf("\n"+Warn+"%s\n", err)
-// } else {
-// fmt.Printf("\n"+Info+"Successfully started job #%d\n", wg.JobID)
-// }
-// }
-
-// func startDNSListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
-
-// domains := strings.Split(ctx.Flags.String("domains"), ",")
-// for _, domain := range domains {
-// if !strings.HasSuffix(domain, ".") {
-// domain += "."
-// }
-// }
-
-// lport := uint16(ctx.Flags.Int("lport"))
-
-// fmt.Printf(Info+"Starting DNS listener with parent domain(s) %v ...\n", domains)
-// dns, err := rpc.StartDNSListener(context.Background(), &clientpb.DNSListenerReq{
-// Domains: domains,
-// Port: uint32(lport),
-// Canaries: !ctx.Flags.Bool("no-canaries"),
-// Persistent: ctx.Flags.Bool("persistent"),
-// })
-// if err != nil {
-// fmt.Printf("\n"+Warn+"%s\n", err)
-// } else {
-// fmt.Printf("\n"+Info+"Successfully started job #%d\n", dns.JobID)
-// }
-// }
-
-// func startHTTPSListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
-// domain := ctx.Flags.String("domain")
-// website := ctx.Flags.String("website")
-// lport := uint16(ctx.Flags.Int("lport"))
-
-// cert, key, err := getLocalCertificatePair(ctx)
-// if err != nil {
-// fmt.Printf("\n"+Warn+"Failed to load local certificate %v", err)
-// return
-// }
-
-// fmt.Printf(Info+"Starting HTTPS %s:%d listener ...\n", domain, lport)
-// https, err := rpc.StartHTTPSListener(context.Background(), &clientpb.HTTPListenerReq{
-// Domain: domain,
-// Website: website,
-// Port: uint32(lport),
-// Secure: true,
-// Cert: cert,
-// Key: key,
-// ACME: ctx.Flags.Bool("lets-encrypt"),
-// Persistent: ctx.Flags.Bool("persistent"),
-// })
-// if err != nil {
-// fmt.Printf("\n"+Warn+"%s\n", err)
-// } else {
-// fmt.Printf("\n"+Info+"Successfully started job #%d\n", https.JobID)
-// }
-// }
-
-// func getLocalCertificatePair(ctx *grumble.Context) ([]byte, []byte, error) {
-// if ctx.Flags.String("cert") == "" && ctx.Flags.String("key") == "" {
-// return nil, nil, nil
-// }
-// cert, err := ioutil.ReadFile(ctx.Flags.String("cert"))
-// if err != nil {
-// return nil, nil, err
-// }
-// key, err := ioutil.ReadFile(ctx.Flags.String("key"))
-// if err != nil {
-// return nil, nil, err
-// }
-// return cert, key, nil
-// }
-
-// func startHTTPListener(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
-// domain := ctx.Flags.String("domain")
-// lport := uint16(ctx.Flags.Int("lport"))
-
-// fmt.Printf(Info+"Starting HTTP %s:%d listener ...\n", domain, lport)
-// http, err := rpc.StartHTTPListener(context.Background(), &clientpb.HTTPListenerReq{
-// Domain: domain,
-// Website: ctx.Flags.String("website"),
-// Port: uint32(lport),
-// Secure: false,
-// Persistent: ctx.Flags.Bool("persistent"),
-// })
-// if err != nil {
-// fmt.Printf(Warn+"%s\n", err)
-// } else {
-// fmt.Printf(Info+"Successfully started job #%d\n", http.JobID)
-// }
-// }
diff --git a/client/command/jobs/jobs-kill.go b/client/command/jobs/jobs-kill.go
new file mode 100644
index 0000000000..a0f7e789ea
--- /dev/null
+++ b/client/command/jobs/jobs-kill.go
@@ -0,0 +1,32 @@
+package jobs
+
+import (
+ "context"
+
+ "github.com/bishopfox/sliver/client/console"
+ "github.com/bishopfox/sliver/protobuf/clientpb"
+ "github.com/bishopfox/sliver/protobuf/commonpb"
+)
+
+func JobKillCmd(jobID uint32, con *console.SliverConsoleClient) {
+ con.PrintInfof("Killing job #%d ...\n", jobID)
+ jobKill, err := con.Rpc.KillJob(context.Background(), &clientpb.KillJobReq{
+ ID: jobID,
+ })
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ } else {
+ con.PrintInfof("Successfully killed job #%d\n", jobKill.ID)
+ }
+}
+
+func killAllJobs(con *console.SliverConsoleClient) {
+ jobs, err := con.Rpc.GetJobs(context.Background(), &commonpb.Empty{})
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ return
+ }
+ for _, job := range jobs.Active {
+ JobKillCmd(job.ID, con)
+ }
+}
diff --git a/client/command/jobs/jobs.go b/client/command/jobs/jobs.go
new file mode 100644
index 0000000000..6880069df1
--- /dev/null
+++ b/client/command/jobs/jobs.go
@@ -0,0 +1,80 @@
+package jobs
+
+/*
+ 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 .
+*/
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "sort"
+ "strings"
+ "text/tabwriter"
+
+ "github.com/bishopfox/sliver/client/console"
+ "github.com/bishopfox/sliver/protobuf/clientpb"
+ "github.com/bishopfox/sliver/protobuf/commonpb"
+
+ "github.com/desertbit/grumble"
+)
+
+func JobsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
+ if ctx.Flags.Int("kill") != -1 {
+ JobKillCmd(uint32(ctx.Flags.Int("kill")), con)
+ } else if ctx.Flags.Bool("kill-all") {
+ killAllJobs(con)
+ } else {
+ jobs, err := con.Rpc.GetJobs(context.Background(), &commonpb.Empty{})
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ return
+ }
+ // Convert to a map
+ activeJobs := map[uint32]*clientpb.Job{}
+ for _, job := range jobs.Active {
+ activeJobs[job.ID] = job
+ }
+ if 0 < len(activeJobs) {
+ printJobs(activeJobs)
+ } else {
+ con.PrintInfof("No active jobs\n")
+ }
+ }
+}
+
+func printJobs(jobs map[uint32]*clientpb.Job) {
+ table := tabwriter.NewWriter(os.Stdout, 0, 2, 2, ' ', 0)
+ fmt.Fprintf(table, "ID\tName\tProtocol\tPort\t\n")
+ fmt.Fprintf(table, "%s\t%s\t%s\t%s\t\n",
+ strings.Repeat("=", len("ID")),
+ strings.Repeat("=", len("Name")),
+ strings.Repeat("=", len("Protocol")),
+ strings.Repeat("=", len("Port")))
+
+ var keys []int
+ for _, job := range jobs {
+ keys = append(keys, int(job.ID))
+ }
+ sort.Ints(keys) // Fucking Go can't sort int32's, so we convert to/from int's
+
+ for _, k := range keys {
+ job := jobs[uint32(k)]
+ fmt.Fprintf(table, "%d\t%s\t%s\t%d\t\n", job.ID, job.Name, job.Protocol, job.Port)
+ }
+ table.Flush()
+}
diff --git a/client/command/jobs/mtls.go b/client/command/jobs/mtls.go
new file mode 100644
index 0000000000..6eb31e5a73
--- /dev/null
+++ b/client/command/jobs/mtls.go
@@ -0,0 +1,27 @@
+package jobs
+
+import (
+ "context"
+
+ "github.com/bishopfox/sliver/client/console"
+ "github.com/bishopfox/sliver/protobuf/clientpb"
+ "github.com/desertbit/grumble"
+)
+
+func MTLSListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
+ server := ctx.Flags.String("server")
+ lport := uint16(ctx.Flags.Int("lport"))
+
+ con.PrintInfof("Starting mTLS listener ...\n")
+ mtls, err := con.Rpc.StartMTLSListener(context.Background(), &clientpb.MTLSListenerReq{
+ Host: server,
+ Port: uint32(lport),
+ Persistent: ctx.Flags.Bool("persistent"),
+ })
+ con.Println()
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ } else {
+ con.PrintInfof("Successfully started job #%d\n", mtls.JobID)
+ }
+}
diff --git a/client/command/jobs/wg.go b/client/command/jobs/wg.go
new file mode 100644
index 0000000000..8dae3458c3
--- /dev/null
+++ b/client/command/jobs/wg.go
@@ -0,0 +1,28 @@
+package jobs
+
+import (
+ "context"
+
+ "github.com/bishopfox/sliver/client/console"
+ "github.com/bishopfox/sliver/protobuf/clientpb"
+ "github.com/desertbit/grumble"
+)
+
+func WGListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
+ lport := uint16(ctx.Flags.Int("lport"))
+ nport := uint16(ctx.Flags.Int("nport"))
+ keyExchangePort := uint16(ctx.Flags.Int("key-port"))
+
+ con.PrintInfof("Starting Wireguard listener ...\n")
+ wg, err := con.Rpc.StartWGListener(context.Background(), &clientpb.WGListenerReq{
+ Port: uint32(lport),
+ NPort: uint32(nport),
+ KeyPort: uint32(keyExchangePort),
+ Persistent: ctx.Flags.Bool("persistent"),
+ })
+ if err != nil {
+ con.PrintErrorf("%s\n", err)
+ } else {
+ con.PrintInfof("Successfully started job #%d\n", wg.JobID)
+ }
+}