diff --git a/AdaptixServer/core/connector/connector.go b/AdaptixServer/core/connector/connector.go index 0ad64c2f..f9b29888 100644 --- a/AdaptixServer/core/connector/connector.go +++ b/AdaptixServer/core/connector/connector.go @@ -61,6 +61,7 @@ type Teamserver interface { TsTaskDelete(agentId string, taskId string) error TsTaskPostHook(hookData adaptix.TaskData, jobIndex int) error TsTaskSave(hookData adaptix.TaskData) error + TsTaskListCompleted(agentId string, limit int, offset int) (string, error) TsChatSendMessage(username string, message string) @@ -230,6 +231,7 @@ func NewTsConnector(ts Teamserver, tsProfile profile.TsProfile, tsResponse profi api_group.POST("/agent/set/color", connector.TcAgentSetColor) api_group.POST("/agent/set/impersonate", connector.TcAgentSetImpersonate) + api_group.GET("/agent/task/list", connector.TcAgentTaskList) api_group.POST("/agent/task/cancel", connector.TcAgentTaskCancel) api_group.POST("/agent/task/delete", connector.TcAgentTaskDelete) api_group.POST("/agent/task/hook", connector.TcAgentTaskHook) diff --git a/AdaptixServer/core/connector/tc_tasks.go b/AdaptixServer/core/connector/tc_tasks.go index b576d656..a7719f46 100644 --- a/AdaptixServer/core/connector/tc_tasks.go +++ b/AdaptixServer/core/connector/tc_tasks.go @@ -3,11 +3,60 @@ package connector import ( "fmt" "net/http" + "strconv" adaptix "github.com/Adaptix-Framework/axc2" "github.com/gin-gonic/gin" ) +func (tc *TsConnector) TcAgentTaskList(ctx *gin.Context) { + agentId := ctx.Query("agent_id") + if agentId == "" { + ctx.JSON(http.StatusOK, gin.H{"message": "agent_id is required", "ok": false}) + return + } + + limit := 200 + offset := 0 + + if raw := ctx.Query("limit"); raw != "" { + value, err := strconv.Atoi(raw) + if err != nil { + ctx.JSON(http.StatusOK, gin.H{"message": "limit must be an integer", "ok": false}) + return + } + if value < 0 { + ctx.JSON(http.StatusOK, gin.H{"message": "limit must be >= 0", "ok": false}) + return + } + if value > 1000 { + value = 1000 + } + limit = value + } + + if raw := ctx.Query("offset"); raw != "" { + value, err := strconv.Atoi(raw) + if err != nil { + ctx.JSON(http.StatusOK, gin.H{"message": "offset must be an integer", "ok": false}) + return + } + if value < 0 { + ctx.JSON(http.StatusOK, gin.H{"message": "offset must be >= 0", "ok": false}) + return + } + offset = value + } + + jsonTasks, err := tc.teamserver.TsTaskListCompleted(agentId, limit, offset) + if err != nil { + ctx.JSON(http.StatusOK, gin.H{"message": err.Error(), "ok": false}) + return + } + + ctx.Data(http.StatusOK, "application/json; charset=utf-8", []byte(jsonTasks)) +} + type AgentTaskDelete struct { AgentId string `json:"agent_id"` TasksId []string `json:"tasks_array"` diff --git a/AdaptixServer/core/database/db_tasks.go b/AdaptixServer/core/database/db_tasks.go index bfdfb6ed..b91f7f5c 100644 --- a/AdaptixServer/core/database/db_tasks.go +++ b/AdaptixServer/core/database/db_tasks.go @@ -72,6 +72,35 @@ func (dbms *DBMS) DbTaskDelete(taskId string, agentId string) error { return err } +func (dbms *DBMS) DbTasksList(agentId string, limit int, offset int) ([]adaptix.TaskData, error) { + var tasks []adaptix.TaskData + + ok := dbms.DatabaseExists() + if !ok { + return nil, errors.New("database does not exist") + } + + selectQuery := `SELECT TaskId, AgentId, TaskType, Client, User, Computer, StartDate, FinishDate, CommandLine, MessageType, Message, ClearText, Completed FROM Tasks WHERE AgentId = ? AND Completed = 1 ORDER BY StartDate DESC LIMIT ? OFFSET ?;` + query, err := dbms.database.Query(selectQuery, agentId, limit, offset) + if err != nil { + return nil, err + } + defer func(query *sql.Rows) { + _ = query.Close() + }(query) + + for query.Next() { + taskData := adaptix.TaskData{} + err = query.Scan(&taskData.TaskId, &taskData.AgentId, &taskData.Type, &taskData.Client, &taskData.User, &taskData.Computer, &taskData.StartDate, &taskData.FinishDate, &taskData.CommandLine, &taskData.MessageType, &taskData.Message, &taskData.ClearText, &taskData.Completed) + if err != nil { + continue + } + tasks = append(tasks, taskData) + } + + return tasks, nil +} + func (dbms *DBMS) DbTasksAll(agentId string) []adaptix.TaskData { var tasks []adaptix.TaskData diff --git a/AdaptixServer/core/server/ts_tasks.go b/AdaptixServer/core/server/ts_tasks.go index 0402cfc1..09178a49 100644 --- a/AdaptixServer/core/server/ts_tasks.go +++ b/AdaptixServer/core/server/ts_tasks.go @@ -4,6 +4,7 @@ import ( "AdaptixServer/core/utils/krypt" "AdaptixServer/core/utils/logs" "AdaptixServer/core/utils/safe" + "encoding/json" "fmt" "time" @@ -519,6 +520,61 @@ func (ts *Teamserver) TsTaskSave(taskData adaptix.TaskData) error { return nil } +type TaskListItem struct { + TaskType int `json:"a_task_type"` + TaskId string `json:"a_task_id"` + AgentId string `json:"a_id"` + Client string `json:"a_client"` + User string `json:"a_user"` + Computer string `json:"a_computer"` + CmdLine string `json:"a_cmdline"` + StartTime int64 `json:"a_start_time"` + FinishTime int64 `json:"a_finish_time"` + MsgType int `json:"a_msg_type"` + Message string `json:"a_message"` + Text string `json:"a_text"` + Completed bool `json:"a_completed"` +} + +func (ts *Teamserver) TsTaskListCompleted(agentId string, limit int, offset int) (string, error) { + if !ts.TsAgentIsExists(agentId) { + return "", fmt.Errorf("agent %v not found", agentId) + } + + tasks, err := ts.DBMS.DbTasksList(agentId, limit, offset) + if err != nil { + return "", err + } + + items := make([]TaskListItem, 0, len(tasks)) + for _, task := range tasks { + if !task.Completed { + continue + } + items = append(items, TaskListItem{ + TaskType: task.Type, + TaskId: task.TaskId, + AgentId: task.AgentId, + Client: task.Client, + User: task.User, + Computer: task.Computer, + CmdLine: task.CommandLine, + StartTime: task.StartDate, + FinishTime: task.FinishDate, + MsgType: task.MessageType, + Message: task.Message, + Text: task.ClearText, + Completed: true, + }) + } + + blob, err := json.Marshal(items) + if err != nil { + return "", err + } + return string(blob), nil +} + ///// Get Tasks func (ts *Teamserver) TsTaskGetAvailableAll(agentId string, availableSize int) ([]adaptix.TaskData, error) {