Silverton allows unsigned code execution on a retail Xbox that has been compromised via Collateral Damage & Solstice.
This is performed through the use of the .NET msbuild
command, a custom PE/Dll injector, native API (kernelbase
, advapi32
) interception for LoadLibrary and CreateProcess, and various runtime patches. Through the use of this tool one can invoke a shell (cmd.exe
) that is capable of transparently launching and executing unsigned executables (including unsigned Dlls), allowing for rapid development compared to currently used methods.
This tool is required due to code integrity checks built into the Windows OS running on the Xbox. Attempting to execute unsigned executables on the Xbox will result in the NtCreateUserProcess
syscall (0xD0
) (invoked via ntdll!NtCreateUserProcess
) to return 0xC000003A
(STATUS_OBJECT_PATH_NOT_FOUND
). Attempting to load unsigned Dlls within a signed executable will result in a ERROR_PATH_NOT_FOUND
, ERROR_ACCESS_DENIED
or ERROR_MOD_NOT_FOUND
error.
This library has not been tested extensively. It does not handle every use case in the world, but it should work for research purposes. Additionally, the choice to leverage a .NET in-process PE/Dll injection has plenty of limits (besides just being slow).
Devices tested:
- Xbox One X
- Xbox Series S
- Xbox Series X
Versions supported:
10.0.22621.2864
10.0.25398.4908
10.0.25398.4909
10.0.25398.4478
Scenarios tested:
- Unsigned Visual C++ executable with unsigned Dll imports built using MSBuild
- Unsigned .NET 8.0 executables with unsigned Dll imports loaded using a .NET 8.0 loader runtime
- Powershell version 7.3.12 loaded using a .NET 8.0 loader runtime
- Powershell version 7.4+ loaded using a .NET 8.0 loader runtime with environment variable
CLR_ASSEMBLY_INJECTION
set toSKIP
cmd.exe
,conhost.exe
,sshd.exe
&sftp-server.exe
have all been tested and confirmed to work
Known limitations:
- 32-bit executables or 32-bit Dlls cannot be injected (but can be loaded natively)
- Attempting to run .NET executables using this tool may encounter strange issues. In some scenarios, setting the environment variable
CLR_ASSEMBLY_INJECTION
toFORCE
orSKIP
may allow for the .NET executable to succeed- This is due to the fact that there are essentially two CLRs, as well as P/Invoke callbacks crossing CLR boundaries.
CLRInjector.exe
contains logic to attempt to load CLRs natively when possible, but there can be application-specific issues.
- This is due to the fact that there are essentially two CLRs, as well as P/Invoke callbacks crossing CLR boundaries.
- On your PC, create a directory called
xbox
- Download the .NET 8.0 SDK binaries and extract them to
xbox\dotnet
- Copy the files in this repositories
payloads
directory toxbox\payloads
- Package this repository and copy the output to (
Silverton.dll
, etc) toxbox\payloads\launcher
- Optionally, you may download
Powershell-7.3.12-win-x64.zip
and unzip its contents toxbox\pwsh
- NOTE: Powershell 7.4+ will only work with
CLR_ASSEMBLY_INJECTION=SKIP
- NOTE: Powershell 7.4+ will only work with
- Copy the
xbox
directory to the root of your USB drive - Connect the USB drive to your Xbox
At this point, your Xbox will have access to the D:\xbox
directory on your USB drive.
NOTE: If you'd like to install it to a different location (eg S:\
), see the "Configuration" section for necessary changes.
You will first need to leverage Collateral Damage & Solstice to gain shell access on the Xbox, then you can issue the commands outlined below.
Spawn a new command prompt (cmd.exe
) that allows for unsigned binary execution:
D:\xbox\payloads\cmd.bat
Alternatively, if you opted to download & copy Powershell as per the installation instructions, you can spawn a new Powershell that allows for unsigned binary execution:
D:\xbox\payloads\powershell.bat
Executables launched from within these shells will be intercepted and launched via the custom process launcher or loaded natively based on the configuration in initialize.xml
(see "Configuration")
If you want to invoke an executable directly, without one of the shells listed above, use the following command:
D:\xbox\dotnet\dotnet.exe msbuild "D:\xbox\payloads\initialize.xml" -property:LauncherDirectory="D:\xbox\payloads\launcher" -property:WorkingDirectory="C:\\" -property:Command="C:\windows\system32\cmd.exe /C echo Hello world from the injected cmd.exe" -property:LogLevel="5"
This file is used by init.bat
to initialize environment variables used by the different payloads in the same directory.
Configurations:
DOTNET_DIRECTORY
: The absolute path to the .NET SDK directory containingdotnet.exe
MSBUILD_XML_PATH
: The absolute path to the MSBuild project XML file location (initialize.xml
)LAUNCHER_DIRECTORY
: The absolute path to the directory containing the launcher (Silverton.dll
)LOG_LEVEL
: The log level used by the launcher
This is the MSBuild project file, it is used by the dotnet.exe msbuild
command to invoke the Launcher. It contains configuration that can allow for control over which executables are loaded natively vs injected via Silverton. This is helpful when you do not want to inject signed code in order to ensure things run correctly.
Configurations:
NativeExecutionDirectories
: A semi-colon delimited list of absolute directory paths whose files will be loaded natively (not loaded by this tool)NativeExecutionBlockList
: A semi-colon delimited list of absolute directory/file paths of files that will always be loaded by our tool, regardless of their presence in theNativeExecutionDirectories
directories.
NOTE: All other properties in this file can be ignored when not invoking the MSBuild command directly.
CLR_ASSEMBLY_INJECTION
FORCE
= Force the EXE to be loaded into the current CLR and executed as a native assemblySKIP
= Force the EXE to be loaded outside of the current CLR via normal PE injection and invocation
If you encounter issues using this tool, your best bet is to modify the logging level (see "Configuration") to 5
(TRACE). This will produce verbose logging of the internals of the tool that can aide in debugging. Please include these logs in any issues created.
The dotnet.exe
is a signed executable and thus allowed to be invoked natively on the Xbox. By utilizing it's msbuild
command we gain the ability to load and execute arbitrary .NET Dlls. This is the entry point that allows us to bypass code signing checks.
No real technical limitation here. Opted to work in a less forgiving world while learning about windows internals and I am too lazy to port it to modify a suspended remote process. This can be addressed in the future, leveraging the MSBuild entry point only on the first process invocation. Compatibility and speed gains are possible here.
The actual code being executed is fairly performant, but the underlying .NET and MSBuild code comes with an overhead. This cost can be mitigated if the code is ported to not rely on .NET MSBuild invocation for each new spawned process.
The loader internals and logic are generally well understood, but it's likely this tools implementation is half-hearted, and the reliance on the .NET runtime can cause unintended problems.
Yes, the tool intercepts library loading and will first attempt to load the Dll natively. If that fails due to OS security failures, the Dll be then be injected into the program via the custom PE/Dll loader.
Yes, the tool intercepts process creation and will route all new processes through the custom process launcher, allowing for unsigned executables to be spawned.
Using .NET SDK 8.0+, invoke the following command:
dotnet publish /p:PublishProfile=FolderProfile
Let's wait and see if it works first ...
- https://github.com/exploits-forsale/collateral-damage
- https://github.com/exploits-forsale/solstice
- https://landaire.net/reflective-pe-loader-for-xbox/
- https://xboxoneresearch.github.io
- https://github.com/nettitude/RunPE
- https://github.com/DarthTon/Blackbone
- https://www.mdsec.co.uk/2021/06/bypassing-image-load-kernel-callbacks
- https://elliotonsecurity.com/what-is-loader-lock
- https://github.com/dotnet/msbuild
- https://github.com/dotnet/runtime
- Port the PE/Dll injection part of this library to not rely on a CLR to run (eg C++)
- Invoke the executable in a new thread
- Properly detect when a native exe can be invoked without injection
- Cleanup process pipes
- CLR
LibraryImportAttribute
is not being hijacked