Skip to content

Commit

Permalink
Outlined update cmd
Browse files Browse the repository at this point in the history
  • Loading branch information
moloch-- committed Jul 3, 2021
1 parent b8671cc commit 48dc187
Show file tree
Hide file tree
Showing 10 changed files with 448 additions and 436 deletions.
241 changes: 122 additions & 119 deletions client/command/commands.go

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions client/command/filesystem/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Filesystem
==========

This package implements file system commands such as `ls`, `cd`, `rm`, `download`, `upload`, etc.

19 changes: 9 additions & 10 deletions client/command/filesystem/filesystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import (
"github.com/alecthomas/chroma/lexers"
"github.com/alecthomas/chroma/styles"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/spin"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util"
"github.com/bishopfox/sliver/util/encoders"
Expand All @@ -57,16 +56,16 @@ func Ls(ctx *grumble.Context, con *console.SliverConsoleClient) {
if err != nil {
con.PrintWarnf("%s\n", err)
} else {
PrintDirList(con.App.Stdout(), ls)
PrintLs(con.App.Stdout(), ls)
}
}

func PrintDirList(stdout io.Writer, dirList *sliverpb.Ls) {
fmt.Fprintf(stdout, "%s\n", dirList.Path)
fmt.Fprintf(stdout, "%s\n", strings.Repeat("=", len(dirList.Path)))
func PrintLs(stdout io.Writer, ls *sliverpb.Ls) {
fmt.Fprintf(stdout, "%s\n", ls.Path)
fmt.Fprintf(stdout, "%s\n", strings.Repeat("=", len(ls.Path)))

table := tabwriter.NewWriter(stdout, 0, 2, 2, ' ', 0)
for _, fileInfo := range dirList.Files {
for _, fileInfo := range ls.Files {
if fileInfo.IsDir {
fmt.Fprintf(table, "%s\t<dir>\t\n", fileInfo.Name)
} else {
Expand Down Expand Up @@ -189,10 +188,10 @@ func Cat(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
if ctx.Flags.Bool("colorize-output") {
if err = colorize(download); err != nil {
fmt.Println(string(download.Data))
con.Println(string(download.Data))
}
} else {
fmt.Println(string(download.Data))
con.Println(string(download.Data))
}
// if ctx.Flags.Bool("loot") && 0 < len(download.Data) {
// err = AddLootFile(rpc, fmt.Sprintf("[cat] %s", filepath.Base(filePath)), filePath, download.Data, false)
Expand Down Expand Up @@ -266,7 +265,7 @@ func Download(ctx *grumble.Context, con *console.SliverConsoleClient) {
}

ctrl := make(chan bool)
go spin.Until(fmt.Sprintf("%s -> %s", fileName, dst), ctrl)
con.SpinUntil(fmt.Sprintf("%s -> %s", fileName, dst), ctrl)
download, err := con.Rpc.Download(context.Background(), &sliverpb.DownloadReq{
Request: con.ActiveSession.Request(ctx),
Path: remotePath,
Expand Down Expand Up @@ -339,7 +338,7 @@ func Upload(ctx *grumble.Context, con *console.SliverConsoleClient) {
uploadGzip := new(encoders.Gzip).Encode(fileBuf)

ctrl := make(chan bool)
go spin.Until(fmt.Sprintf("%s -> %s", src, dst), ctrl)
con.SpinUntil(fmt.Sprintf("%s -> %s", src, dst), ctrl)
upload, err := con.Rpc.Upload(context.Background(), &sliverpb.UploadReq{
Request: con.ActiveSession.Request(ctx),
Path: dst,
Expand Down
File renamed without changes.
File renamed without changes.
300 changes: 300 additions & 0 deletions client/command/update/update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
package update

/*
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 (
"context"
"crypto/tls"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"net/url"
"os"
"os/user"
"path"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"

"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/assets"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/version"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/util"
"github.com/cheggaaa/pb/v3"
"github.com/desertbit/grumble"
)

const (
lastCheckFileName = "last_update_check"
)

func UpdateCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
VerboseVersionsCmd(ctx, con)

timeout := time.Duration(ctx.Flags.Int("timeout")) * time.Second

insecure := ctx.Flags.Bool("insecure")
if insecure {
con.Println()
con.Println(console.Warn + "You're trying to update over an insecure connection, this is a really bad idea!")
confirm := false
prompt := &survey.Confirm{Message: "Recklessly update?"}
survey.AskOne(prompt, &confirm)
if !confirm {
return
}
confirm = false
prompt = &survey.Confirm{Message: "Seriously?"}
survey.AskOne(prompt, &confirm)
if !confirm {
return
}
}

proxy := ctx.Flags.String("proxy")
var proxyURL *url.URL = nil
var err error
if proxy != "" {
proxyURL, err = url.Parse(proxy)
if err != nil {
con.PrintErrorf("%s", err)
return
}
}

client := &http.Client{
Timeout: timeout,
Transport: &http.Transport{
Dial: (&net.Dialer{
Timeout: timeout,
}).Dial,
TLSHandshakeTimeout: timeout,
Proxy: http.ProxyURL(proxyURL),
TLSClientConfig: &tls.Config{
InsecureSkipVerify: insecure,
},
},
}

con.Printf("\nChecking for updates ... ")
prereleases := ctx.Flags.Bool("prereleases")
release, err := version.CheckForUpdates(client, prereleases)
con.Printf("done!\n\n")
if err != nil {
con.PrintErrorf("Update check failed %s\n", err)
return
}

if release != nil {
saveTo, err := updateSavePath(ctx)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
updateAvailable(con, client, release, saveTo)
} else {
con.PrintInfof("No new releases.\n")
}
now := time.Now()
lastCheck := []byte(fmt.Sprintf("%d", now.Unix()))
appDir := assets.GetRootAppDir()
lastUpdateCheckPath := path.Join(appDir, lastCheckFileName)
err = ioutil.WriteFile(lastUpdateCheckPath, lastCheck, 0600)
if err != nil {
log.Printf("Failed to save update check time %s", err)
}
}

// GetLastUpdateCheck - Get the timestap of the last update check, nil if none
func GetLastUpdateCheck() *time.Time {
appDir := assets.GetRootAppDir()
lastUpdateCheckPath := path.Join(appDir, lastCheckFileName)
data, err := ioutil.ReadFile(lastUpdateCheckPath)
if err != nil {
log.Printf("Failed to read last update check %s", err)
return nil
}
unixTime, err := strconv.Atoi(string(data))
if err != nil {
log.Printf("Failed to parse last update check %s", err)
return nil
}
lastUpdate := time.Unix(int64(unixTime), 0)
return &lastUpdate
}

func VerboseVersionsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
clientVer := version.FullVersion()
serverVer, err := con.Rpc.GetVersion(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("Failed to check server version %s\n", err)
return
}

con.PrintInfof("Client %s - %s/%s\n", clientVer, runtime.GOOS, runtime.GOARCH)
clientCompiledAt, _ := version.Compiled()
con.Printf(" Compiled at %s\n", clientCompiledAt)
con.Printf(" Compiled with %s\n\n", version.GoVersion)

con.Println()
con.PrintInfof("Server v%d.%d.%d - %s - %s/%s\n",
serverVer.Major, serverVer.Minor, serverVer.Patch, serverVer.Commit,
serverVer.OS, serverVer.Arch)
serverCompiledAt := time.Unix(serverVer.CompiledAt, 0)
con.Printf(" Compiled at %s\n", serverCompiledAt)
}

func updateSavePath(ctx *grumble.Context) (string, error) {
saveTo := ctx.Flags.String("save")
if saveTo != "" {
fi, err := os.Stat(saveTo)
if err != nil {
return "", err
}
if !fi.Mode().IsDir() {
return "", fmt.Errorf("'%s' is not a directory", saveTo)
}
return saveTo, nil
}
user, err := user.Current()
if err != nil {
return os.TempDir(), nil
}
if fi, err := os.Stat(filepath.Join(user.HomeDir, "Downloads")); !os.IsNotExist(err) {
if fi.Mode().IsDir() {
return filepath.Join(user.HomeDir, "Downloads"), nil
}
}
return user.HomeDir, nil
}

func hasAnySuffix(assetFileName string, suffixes []string) bool {
for _, suffix := range suffixes {
if strings.HasSuffix(assetFileName, suffix) {
return true
}
}
return false
}

func findAssetFor(prefix string, suffixes []string, assets []version.Asset) *version.Asset {
for _, asset := range assets {
downloadURL, err := url.Parse(asset.BrowserDownloadURL)
if err != nil {
continue
}
assetFileName := filepath.Base(downloadURL.Path)
if strings.HasPrefix(assetFileName, prefix) && hasAnySuffix(assetFileName, suffixes) {
return &asset
}
}
return nil
}

func serverAssetForGOOS(assets []version.Asset) *version.Asset {
suffixes := []string{fmt.Sprintf("_%s.zip", runtime.GOOS), runtime.GOOS}
if runtime.GOOS == "darwin" {
suffixes = []string{"_macos.zip", "_macos"}
if runtime.GOARCH == "arm64" {
suffixes = []string{"_macos-arm64.zip", "_macos-arm64"}
}
}
prefix := "sliver-server"
return findAssetFor(prefix, suffixes, assets)
}

func clientAssetForGOOS(assets []version.Asset) *version.Asset {
suffixes := []string{fmt.Sprintf("_%s.zip", runtime.GOOS), runtime.GOOS}
if runtime.GOOS == "darwin" {
suffixes = []string{"_macos.zip", "_macos"}
if runtime.GOARCH == "arm64" {
suffixes = []string{"_macos-arm64.zip", "_macos-arm64"}
}
}
prefix := "sliver-client"
return findAssetFor(prefix, suffixes, assets)
}

func updateAvailable(con *console.SliverConsoleClient, client *http.Client, release *version.Release, saveTo string) {

serverAsset := serverAssetForGOOS(release.Assets)
clientAsset := clientAssetForGOOS(release.Assets)

fmt.Printf("New version available %s\n", release.TagName)
if serverAsset != nil {
fmt.Printf(" - Server: %s\n", util.ByteCountBinary(int64(serverAsset.Size)))
}
if clientAsset != nil {
fmt.Printf(" - Client: %s\n", util.ByteCountBinary(int64(clientAsset.Size)))
}
fmt.Println()

confirm := false
prompt := &survey.Confirm{
Message: "Download update?",
}
survey.AskOne(prompt, &confirm)
if confirm {
fmt.Printf("Please wait ...")
err := downloadAsset(client, serverAsset, saveTo)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
err = downloadAsset(client, clientAsset, saveTo)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.Println(console.Clearln)
con.PrintInfof("Saved updates to: %s\n", saveTo)
}
}

func downloadAsset(client *http.Client, asset *version.Asset, saveTo string) error {
downloadURL, err := url.Parse(asset.BrowserDownloadURL)
if err != nil {
return err
}
assetFileName := filepath.Base(downloadURL.Path)

limit := int64(asset.Size)
writer, err := os.Create(filepath.Join(saveTo, assetFileName))
if err != nil {
return err
}

resp, err := client.Get(asset.BrowserDownloadURL)
if err != nil {
return err
}

bar := pb.Full.Start64(limit)
barReader := bar.NewProxyReader(resp.Body)
io.Copy(writer, barReader)
bar.Finish()
return nil
}
Loading

0 comments on commit 48dc187

Please sign in to comment.