Skip to content

Instantly share code, notes, and snippets.

@SciresM

SciresM/1.txt Secret

Last active December 29, 2018 19:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SciresM/5b8e8f8d4874e2836df905d424e45191 to your computer and use it in GitHub Desktop.
Save SciresM/5b8e8f8d4874e2836df905d424e45191 to your computer and use it in GitHub Desktop.
Conversation snippets from initial attempts to gain kernel code execution on the Nintendo Switch.
SciresM: so um
SciresM: there are kernel objects in dram.
SciresM: like I am looking at what is very clearly a KHandleTable.
hthh: are we talking 3.0 or 1.0?
SciresM: 1.0
SciresM: 3.0 has nada.
hthh: nice :)
hthh: it's really tricky trying to do these attacks before we have code,
but it's nice that switchbrew documented all this already
hthh: (hmm, just trying to think about options that might be interesting
and/or possible to explore blindly - you could make it a generic KAutoObject UAF,
by copying the type and pointer to a new handle then closing it repeatedly)
hthh: (we'd really like an arbitrary read, so maybe if you can figure out the
different ObjectType you could find an SVC that reads from one of them without
using the vtable, e.g. svcGetProcessId might just cast to KProcess and read from
offset 0x250 - but idk how ObjectType works so just a total guess)
hthh: (svcGetThreadId might be a safer bet because it supports fewer handle
types and it might be easy to create tons of threads to figure out what the type should be)
SciresM: I located the handle table for a specific process.
SciresM: :)
SciresM: :) :) :)
hthh: Haha nice!
SciresM: Yeah, psc heh.
SciresM: hahahaha
SciresM: I caused a kernel fatal error.
SciresM: Error 2001-0114.
SciresM: 1. Replace a KSession's ptr with null
SciresM: 2. Send a message to that session.
hthh: Ahaha that’s awesome!
SciresM: heh
SciresM: just successfully got the kernel to treat an arbitrary DRAM ptr like a handle entry.
SciresM: that's hilarious.
hthh: heh - I don't quite follow - you're pointing it at the physical memory?
SciresM: basically
SciresM: handle tables consist of used entries, free entries.
SciresM: used entries are KHandleEntry or w/e
SciresM: free entries are just a pointer to the next free entry (0x10 later)
hthh: makes sense
SciresM: I modified the first free entry to say the next free one was later.
SciresM: (in arbitrary dram, outside table)
SciresM: then I wrote a fake next pointer in arbitrary dram
SciresM: (pointing back into the table)
SciresM: duplicated session twice -> sure enough...
hthh: hahaha nice!
hthh: oh, uh, this is a bit messy, but if we need we should be able
to get the vtable, I think: find a KProcess, set NextFreeEntry to point
to that, allocate a new handle (corrupting the KProcess) and then read the NextFreeEntry
(with a bit of luck you could repeat that and read whole objects, the big downside
being it corrupts everything it reads, so it can't read read-only memory)
SciresM: ...lol.
SciresM: Yeah actually that might work
SciresM: Oh god that's so stupid
hthh: haha yeah, it'll make things super unstable,
which'd be painful, but hopefully it's enough of a leak
to make your general fake-object technique just about guaranteed to be workable
hthh: I have backup ideas - you might like to weigh in on the 3DS implementations,
but one was using svcGetProcessId on a copied thread (corrupting the KProcess*
within the thread structure). Or trying to see if svcGetInfo can somehow read via a
layer of indirection.
hthh: also I mentioned before: what does the HandleId look like? is there any chance
we could have arbitrary values from 0x00-0xFF in the low byte and then write along
incrementing one byte at a time? with an arbitrary write we could try to write into
the kernel .text via the dram mapping, use a vtable call from a fake object (probably
on svcCloseHandle refcount == 0) to jump there and memcpy the rest of the code out
SciresM: handle ID is just an incrementing u16
SciresM: can't have too many because handle table limits :p
hthh: how limited is the table? and if you open-close-open do you get the same value as before?
SciresM: open close open -> yes
SciresM: nv's table has space for 0x176 more entries.
SciresM: I can try the u8 thing
SciresM: if that works that would be so stupid
hthh: (wow, that's actually plausible - super slow, messy ugly and horrible, but I don't see what
could stop it? LibAppletWeb has Handle Table Size: 512 too, might it be worth trying to find that
table just to avoid the nvcall speed difference? I guess you could implement it with nv ACE,
so either should work.)
SciresM: Easiest way is probably incref or decref?
hthh: yeah, my guess is that incref/decref would be non-virtual, but the destructor would be
virtual, so decref to zero and then it'll jump to offset 0 or 8 in the vtable?
SciresM: On 3ds, decref is virtual
SciresM: and calls destructor on ref == 0
SciresM: I guess if we just point the whole vtable at the shellcode....
SciresM: worth a shot?
hthh: yeah - that's what I'd try
SciresM: fuck this is gonna be dumb
` (...) `
SciresM: okay
SciresM: moment of truth coming in ~60 seconds
SciresM: (I added logging)
hthh: exciting! (is that because kernWriteU8 + nvcall is slow?)
SciresM: SUPER slow.
SciresM: │switch> eval utils.log(utils.paddr(sc.nv.gpuRead(0x83EEB800)))
SciresM: 0xdeadcafecafebabe
SciresM: we have arb write.
hthh: :D
SciresM: Now just need shellcode to copy to physmem 0xC0000000 :)
SciresM: I can do ~14 increments per second....so the worst case to write a byte is 20 seconds
SciresM: So guaranteed < 20 minutes to write it all out.
SciresM: you gonna stay up to see if it works?
hthh: yeah - we could optimise it pretty easily using the nvdrv ACE - I'm happy to wait if you are :)
SciresM: I'm happy to wait :)
SciresM: It's already written 4 dwords!
hthh: haha :D (whether or not this is the time that works, we're insanely close)
SciresM: yeah, no kidding.
(...)
SciresM: about halfway there btw
SciresM: it just wrote out 0xea, 0xff, 0xff, 0xf2, // movk x10, #65535, lsl #48
SciresM: 4 instructions left....
hthh: god, we could really optimise it... how did you implement the nvdrv fast gpu read code?
SciresM: 7 hand written instructions :p
hthh: haha yeah - did you hook it into an IPC service? I mean we really just want
closeHandle(createSharedMemory(0x1000)) N times - pretty comparable complexity
SciresM: eval utils.log(utils.paddr(sc.nv.gpuRead(0xC0000000)))
SciresM: 0xd2a00149d2800008
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment