Changes

Jump to navigation Jump to search
Line 1: Line 1: −
Exploits are used to execute unofficial code (homebrew) on the Nintendo Switch. This page is a list of publicly known Switch system flaws.
+
This page is a list of publicly known Switch flaws.
 
  −
For userland applications/applets flaws see [[Switch_Userland_Flaws|here]].  
      
= Hardware =
 
= Hardware =
Line 447: Line 445:  
| February 2019
 
| February 2019
 
| [[User:TuxSH|TuxSH]]
 
| [[User:TuxSH|TuxSH]]
 +
|-
 +
| Kernel RWX identity mapping never unmapped
 +
| During init, the kernel binary is identity-mapped as RWX at 0x80060000; this is necessary to facilitate the transitionary period while the MMU is being enabled but mappings for e.g. KASLR are not yet determined, and also to enable smooth MMU enable transition during wake-from-sleep.
 +
 +
However, the identity mapping was never unmapped, and thus the whole kernel code bin remained permanently mapped as RWX for all kernel threads (any thread which does not have an owner process and thus uses the KSupervisorPageTable TTBR0).
 +
 +
Thus, any theoretical exploit which would give kernel memory corruption or ROP under a kernel thread would allow making use of this mapping to modify kernel text + bypass KASLR.
 +
 +
This was fixed in [[16.0.0]] by unmapping the identity-mapping during init, and re identity-mapping only the very first page of kernel .text as R-X (for use by wake-from-sleep), which fixes the shellcode problem and mostly fixes the ROP problem, since this page mostly lacks interesting gadgets.
 +
| In theory, with another exploitable kernel memory corruption (or ROP under kernel thread) bug: bypassing KASLR + modifying kernel .text.
 +
 +
However, no such bugs are known.
 +
| [[16.0.0]]
 +
| [[16.0.0]]
 +
| Summer 2018
 +
| February 2023
 +
| Everyone
 
|}
 
|}
   −
== FIRM-package System Modules ==
+
== BootImagePackage System Modules ==
 
Flaws in this category pertain to any of the [[Package2#Section_1|built-in system modules]].
 
Flaws in this category pertain to any of the [[Package2#Section_1|built-in system modules]].
   Line 896: Line 911:  
| November 9, 2022
 
| November 9, 2022
 
| [[User:Hexkyz|hexkyz]]
 
| [[User:Hexkyz|hexkyz]]
 +
|-
 +
| [[Bluetooth_Driver_services|bluetooth]] WriteGattCharacteristic/WriteGattDescriptor stack buffer overflow regression
 +
| Originally btdrv WriteGattCharacteristic/WriteGattDescriptor (bt service LeClientWriteCharacteristic/LeClientWriteDescriptor are the same) validated the input buffer size. However the size check was removed with [12.0.0+] (which was also when bluetooth was refactored), hence stack buffer overflow. Anything with btdrv/bt services access can trigger it. While this is intended to require a BLE connection, it seems to be possible to trigger the buffer overflow without any BLE connection by passing ConnectionHandle=0xFFFFFFFF (handle not tested on hardware).
 +
| Bluetooth-sysmodule stack buffer overflow on [12.0.0-15.0.1], with data from BLE IPC cmds.
 +
| [[16.0.0]]
 +
| [[16.0.0]]
 +
| December 10, 2021
 +
| February 23, 2023
 +
| [[User:Yellows8|yellows8]]
 +
|-
 +
| [[JIT_services|JIT]] usability issues
 +
| CreateJitEnvironment will enter infinite-loops using nn::jitsrv::detail::AslrAllocator::GetAslrRegion when either of the input CodeMemory sizes are zero. Also the second CodeMemory is useless for the user-process since the second addr returned by GetCodeAddress is a dup of the first one, set during state init by CreateJitEnvironment.
 +
With [14.0.0+] size=0 is now properly handled, and also the state for the second addr from GetCodeAddress is now properly initialized.
 +
| Minor usability issues, not useful for exploitation (size=0 will cause jit-sysmodule to hang in a loop).
 +
| [[14.0.0]]
 +
| [[14.0.0]]
 +
| October 1, 2020
 +
| February 26, 2023
 +
| [[User:Yellows8|yellows8]]
 +
|-
 +
| [[USB_services|usbhs]] uninitialized IClientEpSession
 +
| usbhs IClientIfSession OpenUsbEp creates an IClientEpSession object. The allocated object from ExpHeap is not memset, only select fields are cleared. The rest of initialization is done by PopulateRing - however the user-process could skip using that if wanted (official sw always uses it).
 +
 +
ShareReportRing maps tmem and writes the ring buffer/count field into object state. PopulateRing also eventually initializes these fields, with the buffer being allocated from ExpHeap instead of tmem. These fields are not cleared during object creation from OpenUsbEp.
 +
 +
GetXferReport after validating the cmd input, just uses object state assuming it was initialized. This runs code which is the same as the user-process code handling the tmem ringbuf.
 +
 +
Therefore, by skipping using PopulateRing and then using GetXferReport the sysmodule will use an uninitialized ringbuf ptr, and an uninitialized count field. If one could control these fields by doing ExpHeap allocations prior to OpenUsbEp so that {target fields} would be located at {IClientEpSession ring fields}, then one could read usb-sysmodule memory at the target buffer address.
 +
 +
See [[USB_services#ShareReportRing|here]] for ringbuf format. The sysmodule will Abort if read_index is >= {ring count field from object state}. Otherwise it copies an entry from that index to output, and updates read_index.
 +
 +
This is probably tricky to abuse as the ringbuf ptr has to be valid, and {see above} (likewise for write_index when the report-ringbuf-writing func runs).
 +
 +
PostBufferAsync/BatchBufferAsync also use seperate object ring fields which are left uninitialized from OpenUsbEp. Targeting this would be tricky with the ring restrictions - this would allow writing data to a ring addr however.
 +
 +
Pre-4.0.0 (only 2.0.0 checked) is not affected by these. The ring fields in the object are cleared during object creation (no memset of the entire object however). GetXferReport would null-deref if PopulateRing was skipped. PostBufferAsync/BatchBufferAsync will throw an error if PopulateRing was skipped. Pre-4.0.0 also has different ring handling as well.
 +
 +
[16.0.0+] The IClientEpSession init func now clears the remaining previously uninitialized fields. The cmds using the ring fields still don't check for NULL, so using GetXferReport/PostBufferAsync/BatchBufferAsync without PopulateRing will just trigger null-deref. Even if the ptr were somehow valid but ring-count field was left at 0, this would then Abort due to: <code>if (ring_count <= index_loaded_from_ringptr) <Abort></code>
 +
| [4.0.0-15.0.1] If one can trigger using {target values} as the unintialized fields: memory reads from the target addr with GetXferReport, and memory R/W with PostBufferAsync/BatchBufferAsync. This requires access to usb:hs, and an usb device must be connected which is not being used by {other sessions}. If successful, this might (?) result in usb-sysmodule compromise.
 +
| [[16.0.0]]
 +
| [[16.0.0]]
 +
| January 30, 2023
 +
| February 26, 2023
 +
| [[User:Yellows8|yellows8]]
 +
|-
 +
| [[NS_services|ns]] RequestMoveApplicationEntity/EstimateSizeToMove buffer overflow
 +
| ns RequestMoveApplicationEntity eventually calls a func which: Loops through the input buffer. If any entry has value 6, it will call another func to copy data from state to output safely (uses the max_count param). Otherwise, it copies the input buffer to an outbuf (located on caller's stack) without any size validation (inlined memcpy), even though there is a max_count param.
 +
 +
Additional memwrites are also done to the above outbuf following the initial memcopy. This can be avoided if the buffer doesn't contain bytes with values 3-6 (if using values in that range is really needed, the cmd input StorageId param can be set to the required value so that the specified value doesn't trigger the memwrite). Value 6 shouldn't be used anyway (see above).
 +
 +
ns EstimateSizeToMove first calls the same func which does the copy above (outbuf is also located on stack), then it calls another func. Hence, same vuln here.
 +
 +
By corrupting just the first byte of x29 with EstimateSizeToMove, one can obtain infoleaks. This method with x29 essentially only works with [15.0.0+]. Pre-15.0.0 would require a different method with partial overwrite of retaddr, however it's unknown whether this would actually work for infoleak (would require [12.0.0+] for the stack layout change).
 +
With EstimateSizeToMove where x29 is overwritten, the output u64 is the leaked ptr (can be codebin-region). Note that the cmd has to return Result=0 for this to work. x29 is used to load the value which is copied to the cmdreply rawdata.
 +
 +
As of [17.0.0+] an error is thrown if the input array count is larger than 8 (size of the stack dst-array).
 +
| ns-sysmodule stack buffer overflow, allowing ns infoleak+ROP.
 +
| [[17.0.0]]
 +
| [[17.0.0]]
 +
| January 2, 2023
 +
| October 17, 2023
 +
| [[User:Yellows8|yellows8]]
 +
|-
 +
| [[PSC_services|ovln:snd]] OpenSender unvalidated count
 +
| ovln:snd OpenSender has a count param. This count is used to allocate the specified number of objects in a linked-list for storing the data from Send. If count is 0, the linked-list is left empty, with ptrs to itself within the ISender object.
 +
 +
ISender Send when the above linked-list is empty, runs a switch-statement with <code>(inval>>8)&0xFF</code>. This uses another linked-list where the ptrs are initially {within ISender obj}.
 +
No space is allocated in the ISender obj for the linked-list object-data. Therefore using Send with val 1<<8 or 2<<8 (other values throw error) results in the specified input struct being copied into the ISender obj, which then overwrites heap data OOB.
 +
If for example one used OpenSender again right after the first OpenSender usage, then used Send as described above, this would corrupt the second ISender which includes overwriting the vtable.
 +
If one would use Send twice in a row like this, the second one would use a corrupted linked-list (written from the first Send). If the linked-list ptrs would be valid (no crash triggered) this would allow one to copy the input data to a controlled addr, though it's restricted with the linked-list usage.
 +
 +
Using GetUnreceivedMessageCount afterwards is of no interest.
 +
 +
Besides ovln, the only other allocs on this heap is from IPmModule Initialize. This heap is also used for psc:* services (object allocs).
 +
 +
In theory (untested) it may be possible to also use this to obtain infoleaks, however it would only return the high-u32 of ptrs not the low u32. Essentially, one would trigger object allocations so that ExpHeap has layout: {ISender} -> {RF chunk from freeing an object} -> {module object from IPmModule Initialize}. Then one would use the Send vuln to corrupt the RF chunk, changing the size to a larger value. Then one would trigger an object allocation (probably same object which was previously freed), then another object for overwriting the module object (ISender would work) with ptrs at the target offsets in the module object. Then once IPmModule GetRequest is used, the returned u32s would be the high-u32 from ptrs. Due to alignment requirements with each allocation, it isn't possible to shift the allocations in order to leak ptr low-u32.
 +
 +
[17.0.0+] Now throws an error if the input count for OpenSender is 0.
 +
| [[PSC_services|psc]]-sysmodule heap memory corruption ([[NS_services|ns]]-sysmodule on pre-8.0.0).
 +
| [[17.0.0]]
 +
| [[17.0.0]]
 +
| January 13, 2023
 +
| October 20, 2023
 +
| [[User:Yellows8|yellows8]]
 +
|-
 +
| [[NV_services|nv]] NVGPU_GPU_IOCTL_GET_CHARACTERISTICS Ioctl3 infoleak
 +
| The handler code for NVGPU_GPU_IOCTL_GET_CHARACTERISTICS for Ioctl/Ioctl3 are essentially the same, except for the value used for the max-size clamp: Ioctl uses constant 0xA0, while Ioctl3 uses the outbuf1_size. So if one uses this with Ioctl3 and a large outbuf1, this will memcpy data OOB from the source buffer, hence infoleak.
 +
With [17.0.0+] the second block of csel code which previouly essentially used the clamped size from above, was replaced with code which properly clamps to the max-size constant.
 +
| nvservices-sysmodule infoleak, which allows defeating ASLR.
 +
| [[17.0.0]]
 +
| [[17.0.0]]
 +
| February 25, 2022
 +
| October 24, 2023
 +
| [[User:Yellows8|yellows8]]
 +
|-
 +
| [[Audio_services|audctl]] GetTargetDeviceInfo infoleak
 +
| audctl GetTargetDeviceInfo calls an impl func with a ptr to a stackbuf, then if successful memcpys the 0x100-bytes from that buffer to output. This stackbuf is not memset. This func (after doing various state checks) copies a string to output, other than always writing a NUL-terminator there's no clearing of the buffer.
 +
 +
This will leak audio-sysmodule stack into the output buffer as long as the state/input checks pass (for the remainder of the buffer following the string NUL-terminator).
 +
 +
With [18.0.0+] data is written directly to the outbuf instead of the stack tmpbuf.
 +
| audio-sysmodule infoleak, which allows defeating ASLR.
 +
| [[18.0.0]]
 +
| [[18.0.0]]
 +
| December 24, 2022
 +
| March 26, 2024
 +
| [[User:Yellows8|yellows8]]
 +
|-
 +
| [[Audio_services|audctl]] GetSystemInformationForDebug infoleak / buffer overflow
 +
| audctl GetSystemInformationForDebug calls a func with a 0x1000-byte stack tmpbuf, then afterwards that buffer is memcpy'd into the cmd outbuf. This called func doesn't clear the buffer. This func eventually uses [[BTM_services|btm]] cmd75 with outarray={global ptr} and count=10. Then if the outcount is s32 >=1, it loops through the output using the outcount, without validating it besides the <1 check. Data from that outarray is copied into the array in the func output buffer (tmpbuf above).
 +
 +
With btm comprimised, one could return a large output count and trigger a stack buffer overflow with data following that global array, however exploiting this would be difficult since that data would be uncontrolled (can't directly control it from this cmd at least).
 +
 +
A stack infoleak can be obtained with this as well (assuming the above output array isn't full).
 +
 +
Even though the name has "ForDebug", there's no checks which would trigger an error / return early (this also always returns 0).
 +
 +
[18.0.0+] now clears the output buffer, and also now prints strings into the buffer instead of writing binary data (overflow no longer possible).
 +
| audio-sysmodule infoleak, which allows defeating ASLR. Also audio-sysmodule memory corruption, likely not useful unless there's a way to control the data.
 +
| [[18.0.0]]
 +
| [[18.0.0]]
 +
| December 7, 2022
 +
| March 27, 2024
 +
| [[User:Yellows8|yellows8]]
 
|}
 
|}
   Line 1,009: Line 1,148:  
| [[User:Yellows8|yellows8]]
 
| [[User:Yellows8|yellows8]]
 
|}
 
|}
 +
 +
=== Pia ===
 +
This section documents vulnerabilities for [https://github.com/Kinnay/NintendoClients/wiki/Pia-Overview Pia].
 +
 +
In v5.11.3 (exact starting version unknown) the fixes aren't present for the below vulns which were fixed in v5.9.3, while in v5.18.98 these are present (exact starting version unknown). This probably indicates that the vuln fixes were backported from a newer Pia version to v5.9.3.
 +
 +
The Pia packet handlers are only active when the game is using multiplayer. LanProtocol is only active in the games which are actively using the LAN-mode option (not Ldn) - only certain games support LAN-mode. The LanProtocol Pia packet handler can be reached while in a lobby or searching for one.
 +
 +
Most Pia packets require an active StationProtocol connection to be active with {InetAddr which the packet was received from}, otherwise the packet is filtered out. The only protocols which don't use filtering are the following: NatTraversalProtocol, LanProtocol, StationProtocol, LocalProtocol.
 +
 +
Note that broadcast IP-dest Pia packets are accepted - this can be used to target every device on the network which is using Pia (which is really only useful with {above protocols} due to the filtering mentioned above, unless one also handles StationProtocol).
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Summary
 +
!  Description
 +
!  Successful exploitation result
 +
!  Fixed in Pia version
 +
!  Last Pia version this flaw was checked for
 +
!  Timeframe this was discovered
 +
!  Public disclosure timeframe
 +
!  Discovered by
 +
|-
 +
| nn::pia::session::RelayRouteManageJob::UpdateConnectionReport buffer overflow
 +
| nn::pia::session::RelayRouteManageJob::UpdateConnectionReport() checks that the input size is at least {value}, but there's no max size check. This is used to memcpy from the input to elsewhere - hence buf-overflow if size is too large. The dst buffer is allocated on the pead heap - this buffer is probably small.
 +
Note that there's various requirements before it would actually reach the memcpy, such as <code><nn::pia::session::Mesh::IsHost() const></code> must return true.
 +
 +
In fixed versions immediately after the StationIndex validation it now does: <code>if(statefield+0x10<input_size) return;</code>
 +
 +
This is called from nn::pia::session::MeshProtocol::ParseConnectionReport().
 +
| Heap buffer overflow triggered by a Pia MeshProtocol message sent to a host device.
 +
| v5.9.3, see above.
 +
| v5.9.1/v5.9.2/v5.9.3
 +
| November 11, 2022
 +
| November 15, 2022
 +
| [[User:Yellows8|yellows8]]
 +
|-
 +
| nn::pia::lan::LanProtocol::ParseSessionMessage buffer overflow
 +
| nn::pia::lan::LanProtocol::ParseSessionMessage() calls nn::pia::lan::LanSessionMessage::Deserialize() to deserialize the message payload data buffer into the LanSessionMessage object on stack. LanSessionMessage::Deserialize (among other things) memcpys data from the input buffer to the object, using an u32 from the input buffer - there is no size validation in Deserialize itself.
 +
There is a size check immediately after calling Deserialize() to verify <code>payloadsize=={u32val}+{constant}</code>, returning on fail - but this doesn't matter for too-large-size.
 +
 +
In fixed versions Deserialize now does bounds checking, both for the minimum message size and clamping the memcpy size to a constant. An error is thrown if the clamped memcpy size is larger than the message size. The caller now checks the ret properly, previously it was ignored.
 +
 +
Following the size check in ParseSessionMessage() it calls <code><nn::pia::session::Mesh::IsProcessingLeaveMesh() const></code>, returning if ret is false.
 +
 +
Then it calls nn::pia::lan::LanProtocol::ReceivedFragmentData::Receive(), with the memcpy'd buffer/size from the above LanSessionMessage, and other fields from LanSessionMessage. This eventually memcpys the input buffer to object+{offset}+{chunksize_field}*inputu8, there is no validation for size or inputu8 (except for the above size check). Hence, if the u8 is large enough, this would result in a heap buffer overflow.
 +
 +
In fixed versions ReceivedFragmentData::Receive added a bunch of validation before the memcpy.
 +
| Stack/heap buffer overflow triggered by a Pia LanProtocol message.
 +
| v5.9.3, see above.
 +
| v5.9.1/v5.9.2/v5.9.3
 +
| November 14, 2022
 +
| November 15, 2022
 +
| [[User:Yellows8|yellows8]]
 +
|-
 +
| nn::pia::session::SessionProtocol::ParseLeaveMeshInvitation buffer overflow
 +
| <code><nn::pia::session::SessionProtocol::ParseLeaveMeshInvitation(nn::pia::transport::ReceivedMessageAccessor const&)></code> This immediately returns if *(ReceivedMessageAccessor+16) is 0. Then the input data is deserialized. The input u64 array is deserialized to stack, the u8 arraycount field from input is not validated.
 +
 +
Hence, stack buffer overflow. Note that there's similar loop code in nearby funcs, which do validate the count properly.
 +
 +
In fixed versions the arraycount field is now validated.
 +
 +
SessionProtocol uses ReliableSlidingWindow MessageHeader, with a maximum message size of 0x100. The allocated size used for the above u64 array is also 0x100-bytes. Hence, when triggering a buf overflow the data after the buffer is uncontrolled data from the SessionProtocol object.
 +
| Stack buffer overflow triggered by a Pia SessionProtocol message.
 +
| v5.9.3, see above.
 +
| v5.9.1/v5.9.2/v5.9.3
 +
| November 14, 2022
 +
| November 15, 2022
 +
| [[User:Yellows8|yellows8]]
 +
|-
 +
| Optional Pia packet encryption
 +
| Pia packet encryption is optional. If the encryption flag is disabled, the packet handler will accept it and skip crypto.
 +
In fixed versions immediately after grabbing a packet, it now checks the crypto flag. If it's plaintext the packet is dropped.
 +
 +
This can be used to send a plaintext Pia packet without needing to handle encryption, especially useful if the session-key can't be obtained (online-play matchmaking). This could be combined with other vulns if wanted.
 +
| Sending a plaintext Pia packet without needing to handle encryption.
 +
| v5.9.3, see above.
 +
| v5.9.3 (and later versions)
 +
|
 +
| November 19, 2022
 +
|
 +
|-
 +
| nn::pia::session::{JoinMeshJob/ProcessUpdateMeshJob}::SetStationDataList OOB read/write/vfunc-call
 +
| <code>nn::pia::session::JoinMeshJob::SetStationDataList</code>is called by <code>nn::pia::session::MeshProtocol::ParseJoinResponse(nn::pia::transport::ReceivedMessageAccessor const&)></code> with the ReceivedMessageAccessor buffer.
 +
SetStationDataList will update state and immediately return if the join was denied. It will also validate the num_mesh_stations field against state. ParseJoinResponse also essentially verifies that the message was received from the host device.
 +
 +
The input buffer size is ignored.
 +
 +
The num_fragments field must be value 1 or <=3 otherwise it will return, there's two seperate code blocks handling these.
 +
 +
Other than the checks at the start, there's no validation for the index fields. So large enough values could result in OOB-reads.
 +
 +
When handling multiple fragments, it will loop through the stationinfo list. There is no validation for the u8 count field or the baseindex field. It calls a vfunc from obj baseptr+index*{entrysize} with data from the buffer, where index starts with the above baseindex field. Afterwards, an u8 is copied into an u32 array (with certain versions an u16 is deserialized into an u16 array).
 +
 +
<code>nn::pia::session::ProcessUpdateMeshJob::UpdateStationDataList</code> is (eventually) called from <code>nn::pia::session::MeshProtocol::ParseUpdateMesh</code>, which has similar issues to the above.
 +
 +
Note that ParseJoinResponse/ParseUpdateMesh essentially require the message to be received from the host device.
 +
 +
With fixed versions (v5.18.98, exact version unknown) various validation was added. Additional/updated validation was added in a later version (v5.31.0, exact version unknown).
 +
| OOB read/write / vfunc call where the object is selected by an OOB index, triggered by a Pia MeshProtocol message.
 +
| v5.18.98 and v5.31.0 (exact versions unknown).
 +
| v5.31.0
 +
| November 18, 2022
 +
| November 21, 2022
 +
| [[User:Yellows8|yellows8]]
 +
|-
 +
| Insecure encryption
 +
| Originally Pia packets used AES-ECB encryption. As documented [https://github.com/Kinnay/NintendoClients/wiki/Pia-Overview here] it was later changed with v5.7.0 to AES-GCM. Each 0x10-byte block would have the same encrypted block output where the plaintext 0x10-byte data is the same.
 +
The mechanism for generating the Pia SessionKey for LAN has also changed over time.
 +
 +
The [https://github.com/Kinnay/NintendoClients/wiki/LAN-Protocol LAN] non-Pia-encapsulated packets were also originally sent in plaintext, however at some point it was changed to mostly encrypted.
 +
|
 +
| AES-GCM fix: v5.7.0
 +
|
 +
|
 +
|
 +
|
 +
|-
 +
| nn::pia::transport::UnreliableProtocol::Dispatch buffer overflow
 +
| <code>nn::pia::transport::UnreliableProtocol::Dispatch</code> memcpys data from the message into a list entry, without size validation. If the pia packet is the max size, it will only overwrite the 0xC-bytes which were written to immediately before the memcpy: the u32 size and the 8-byte StationAddress (depending on the version there can also be 4-byte padding after the size for alignment).
 +
However, nn::pia::transport::UnreliableProtocol::Receive will clamp the size from the list entry to the outbuf size when doing the memcpy. So this is probably useless.
 +
 +
It's unknown whether there's a version where more data could be overwritten, and whether that would be useful.
 +
 +
This is fixed in v5.31.0, exact version unknown. The message is dropped if too large in Dispatch.
 +
| Small buffer overflow triggered by a Pia UnreliableProtocol message.
 +
| v5.31.0, exact version unknown.
 +
| v5.18.98/v5.31.0
 +
| November 2022
 +
| November 29, 2022
 +
| [[User:Yellows8|yellows8]]
 +
|-
 +
| Uncleared input structs for [[LDN_services|LDN]]
 +
| The Pia code using ldn CreateNetwork*/ConnectNetwork*/Scan doesn't properly memset the input data for SecurityConfig/ScanFilter (when keysize is less than 0x40 for the former). Hence, infoleak from games is sent to ldn (structs are located on stack, so stack data is leaked). This requires ldn compromise/mitm to obtain the leaked data - these are not sent over the network.
 +
With v6.20.1 (exact version unknown - fix isn't present in v5.32.0), the code using Scan* now clears the input ScanFilter properly. With v6.25.1 (exact version unknown - fix isn't present in v6.23.3), the code using CreateNetwork*/ConnectNetwork* now clears the input SecurityConfig properly.
 +
| Infoleak from games with LDN cmds, requires compromised sysmodule/mitm.
 +
| v6.20.1 and v6.25.1, exact versions unknown.
 +
| v5.32.0/v6.20.1/v6.23.3/v6.25.1
 +
|
 +
| December 7, 2022
 +
|
 +
|}
 +
 +
=== ENL ===
 +
This section documents vulnerabilities for [https://github.com/kinnay/NintendoClients/wiki/ENL-Protocol ENL].
 +
A framework used by Nintendo games including Mario Kart 8 Deluxe, Splatoon 2 / 3, Mario Maker 2, and more.
 +
 +
Fun fact, this library appears to re-use network code and concepts from older Nintendo titles such as Mario Kart 7 and some Wii multiplayer games.
 +
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Summary
 +
!  Description
 +
!  Successful exploitation result
 +
!  Fixed in Enl version
 +
!  Last Enl version this flaw was checked for
 +
!  Timeframe this was discovered
 +
!  Public disclosure timeframe
 +
!  Discovered by
 +
|-
 +
| enl::TransportManager::updateReceiveBuffer_() nullptr deref
 +
| enl::TransportManager::updateReceiveBuffer_() is called when the ENL framework receives a PIA packet from a client, it will fully trust the ENL header which includes a "ContentTransporter" type (ID) and a length.
 +
The function will try to fetch the content transporter by ID using <code>enl::TransportManager::getContentTransporter(unsigned char const &)</code>, it returns NULL if there's no content transporter with the same ID
 +
 +
*NOTE: The function may be inlined
 +
 +
Then it will try to call a virtual method: <code>virtual size_t readyReceiveStream(enl::RamReadStream&, enl::Buffer*, size_t)</code>, dereferencing the pointer to fetch the vtable ptr
 +
 +
[https://gist.github.com/Rambo6Glaz/c088e2ed7a12db08f6322e9f7a3c4911 Pseudocode of the function before it was fixed]
 +
 +
| nullptr dereference triggered by an invalid content transporter type in the ENL header (it will crash the game/process)
 +
| Unknown
 +
| Depends on the game
 +
| Early April 2022
 +
| November 16, 2022
 +
| [[User:Rambo6Glaz|Rambo6Glaz]], Kinnay (massive RE help)
 +
|}
 +
 +
There's another one more interesting but it will have to wait a bit :)

Navigation menu