PSP and PSP Emulator Kernel Vulnerabilities – An Overview
Chapter 1 – Introduction
This is chapter #1 out of a (2 or 3..? not sure yet) “chapter” tutorial.
Firstly, I’d like to give a big thanks to fate6 from wololo.net/talk forums. It has been a while now since he did this (considering I’ve postponed this tutorial for a loooong time) but he dumped a TON of PSP firmwares for my inspection in order to assist in the documentation of various kernel vulnerabilities and to formulate a concise timeline regarding when each vuln was introduced in the firmware and when it was patched, etc. I did this because as I progress through this tutorial ‘series’, I will pick various kernel vulnerabilities that have been exploited throughout the years (whether privately or publicly), and will use them as examples of exploitable functions. At the time, my friend was borrowing my only PSP 3000, so I was unable to decrypt and dump the modules myself. So once again – thx man!
I’d also like to just clarify what this tutorial series will and won’t be about, to avoid any confusion:
This series is based on kernel vulnerabilities in the original PSP firmware (and thus the PSP emulator as well). This DOES NOT cover kernel vulnerabilities in the native vita firmware. Why? Well, mostly because that’s the way it worked out. When I began writing these tutorials years ago the vita hadn’t even been designed yet. Also, due to other personal projects, school, and work, I will be unable to dive into the vita anytime soon. That being said –this is still a valuable tutorial for those of you who may be interested in investigating the native side of things, as you can apply the theories from this article to other architectures ,exploits, etc as well. In addition, this is not meant to be a “How to find a kernel vulnerability and exploit it for Dummies” guide. If I even promised that, I would be leading you down the wrong path anyway Simply speaking, it is almost impossible to teach someone how to ‘find’ an exploit. Regardless of whether it is usermode, kernel mode – whatever. As you will see as you read though this series, finding vulnerabilities of any kind require logic, patience, and many times, creativity. The purpose is to provide a concrete background regarding PSP kernel vulnerabilities that, if an individual had the necessary programming/computer science skills prior to reading this, could use this tutorial series as a “push” in the right direction to get started looking for vulnerabilities themselves. I will give a very very brief introduction regarding a little kernel vulnerability ‘theory’ for those of you that do already have plenty of programming skills but are new to the PSP. LASTLY, although I will explain some MIPS here and there as it applies to kernel functions I discuss, I will NOT be teaching MIPS. I will also not be teaching C/C++. Sorry… but I want to keep things focused on the topic of vulnerabilities themselves, and if I start teaching about languages… it would just start getting too offtopic and long. If you don’t know MIPS, especially the subset that’s used on the PSP, you should be able to follow along using this as your guide: http://www.mrc.uidaho.edu/mrc/people/jff/digital/MIPSir.htmlHonestly, its one of the easiest assembly languages out there, you should have no problem learning basic concepts on the fly here.
For those of you who don’t have any interest in these kinds of topics — perhaps you will still find this an interesting read and you can gain a larger appreciation for all of the effort that developers put in to enhancing the features of your devices
If you’d like to follow along as I describe each vulnerability, I suggest you grab a few tools: prxtool, a PSP capable of running psardumper, psardumper, and the OFW that contains the vuln you’d like to inspect. You will also need a text editor at your disposal if you wish to open the disassembled output from prxtool. You don’t need anything too fancy, but it does need to handle the large file size of the disassembled file. If you’re using Windows, Wordpad is just fine. Notepad will typically freeze and operates at quite a sluggish speed with large files. I’ve also used Gedit on linux and that works perfectly fine as well.
When disassembling files with prxtool, you simply need to issue the commands: prxtool -w ThePRXofYourChoiceHere.prx > Output.asm
-w essentially just states that you want to disassemble the executable sections of the module. prxtool will just output the asm to the terminal screen, so you will also need to use ‘>’ to route the text to file.
The PSPSDK and prxtool are pretty easy to set up in *nix environments, but this is not always the case for Windows. Getting a full-fledged PSP devlelopment environment up and running on Windows typically involves a great deal of teeth clenching, nail biting, and fits of nausea. OK its not that bad, but you get the point. Nevertheless, if your only purpose is to follow along with me here, the only development related tool you’ll need is prxtool. You can get a prebuilt copy of prxtool for windows that I have uploaded for convenience here: http://n00b81.hack.ee/prxtool.exe
One more quick thing before I get started: I’d also just like to say that when I do list various kernel functions and their corresponding vulnerabilities, I will not be posting a full EBOOT example that you can throw on your memory card and run and have that kernel exploit running on any firmware. In other words, I will explain in detail how certain kernel functions were exploited, but I won’t post Proof of Concept code that will be ready for compiling and running on a PSP – you will need to do this if you’d like to see it in action. However, if you’re a seasoned developer you’ll understand that this is the easy part anyway
Aight – so we got some of the set-up related tasks out of the way. Now I’m going to spend a few moments clearing up some common misconceptions people sometimes have (rightfully so) regarding the differences between PSP usermode and PSP kernel vulnerabilities.
Often times when game exploits are released, individuals will ask if that game exploit is also a kernel exploit – or, they wonder whether with enough work, the game exploit could be ‘transformed’ into a kernel one. The fact is, usermode and kernel exploits both need to be leveraged in order to access the kernel, but they are both a bit different from each other. Let’s take a look at an example. GripShift for example, was exploited by MaTiAz back in 2009. Many members of the scene were frustrated by the fact that a few developers claimed that they had a kernel exploit for GripShift, yet they weren’t releasing it. At the time I remember there were a few individuals on qj.net that basically asked, if the exploit for GripShift was released, and Sony knows that GripShift was exploited, then why can’t anyone just release a HEN for it? There can’t be anything else to hide, can there? Essentially, a usermode exploit (in this case, the GripShift game) is used first to gain any kind of access to the system to execute custom code. Since GripShift is a game, and games execute with usermode privileges, it makes sense to assume that the resources we inherit by exploiting GripShift will also be usermode; and the unsigned code that we execute will also be running with usermode privileges. This leads us to the next step and into our discussion about kernel vulnerabilities – how DO we earn kernel privileges from a usermode exploit?
As many of you might already know, although we cannot read/write kernel memory from usermode programs, we can actually execute kernel functions via the use of syscalls. Without this ability, we could not perform tasks such as playing audio, making adhoc connections, grabbing information about what buttons are pressed on the control pad currently, etc just from usermode functions themselves. Essentially, syscalls allow us to tell the PSP that we would like it to switch to kernel context and execute a certain kernel function for us. Often times, we can pass that kernel function data for that function to compute, and then we wait for that function to return use specialized data. This is the main point though – we can execute a kernel function and pass it data, and get some information back, but we don’t actually get to manipulate that kernel function’s code into doing something useful for us. However, I just said that often times we can pass the kernel function data to process, right? Well, what if the function didn’t handle that data properly and somehow we were able to use that data to manipulate the kernel function into writing or reading to/from arbitrary addresses of kernel memory? And that little loophole right there is the premise of most kernel vulnerabilities.
Before I get any further, let’s make sure we’ve got everything by reviewing what we have so far in this pretend scenario:
- We’ve exploited a game and have executed homebrew machine code (with usermode privaledges). We’ve got a snazzy screen flasher and pong going ( )… nice.
- We’ve built a minimalistic exploit SDK which has all of the addresses already for syscalls that we currently have access to that were imported by the exploited game, like sceIoOpen(), sceIoWrite(), sceIoRead(), etc. We also have access to other syscalls we can leverage to load additional modules (like savegame modules, etc) which in turn we leverage to steal more imports from (possibly).
- We know that we can execute these syscalls and kernel functions will execute, and we may even be able to pass parameters and data to these kernel functions, but we cannot retrieve data back from the kernel just by calling these functions (useful data in this case… that is). Now, the information that I wrote in bold is an important point. We *can* pass data to some kernel functions. A kernel function may accept an integer, two integers, an integer and a pointer to a data structure or 5 pointers to data structures and 5 integers… whatever. The point is, we may not be able to retrieve data from the kernel directly by just calling kernel functions, but we may be able to pass data to them – which ultimately, can be leveraged to partially manipulate the control flow of the function. A PSP kernel function should always validate the data that it accepts from the user and ensure that the data the user passes to it cannot be used to manipulate the kernel function into… basically… doing anything that would allow the user to read from, or write to, kernel memory partitions.
So you’ve put together a little SDK for the game exploit you’re working with, you’ve executed usermode code… and now you’re looking to get a ‘lil kernel mode action. Where do we begin? Let’s start looking for kernel functions in the firmware that we can call with syscalls and allow us to pass parameters to it. Let’s start with functions that have parameters that are pointers (a PSP-independent programming reference… if you don’t know what these are… you should learn at least some C first!).
Initially, let’s begin with a fake ‘golden’ example of an exploitable kernel function. Let’s say with our exploitable game we can call the syscall/function sceKernelCopyMem.
We go to the pspsdk docs (or look at the assembly code) to determine what kind of parameters this function accepts. We find this function definition:
void *sceKernelCopyMem (void *dest, void *src, u32 numBytes)
dest is the pointer to the destination area of memory where we are copying data TO, while src is the pointer to the area of memory where we want to copy the data FROM. numBytes is a 32 bit integer that literally represents the amount of data (in bytes) that we want to copy.
Let’s say we want to copy a chunk of data from one region of user memory to another. We want to copy 512 bytes of data from 0x08800000 to 0x08801000.
We call sceKernelCopyMem with the following parameters:
sceKernelCopyMem( (void *) 0x08801000, (void *) 0x08800000, 512);
But what if we could successfully make a call like this:
sceKernelCopyMem( (void *) 0x88000000, (void *) 0x08000000, 512);
Notice the subtle difference I made to the first parameter (void * dest). Instead of being a user memory address, it is now a kernel memory address (consult https://github.com/uofw/upspd/wiki/Memory-map for various partition info).
Do you think it would make sense for us to be able to copy a chunk of data from anywhere in usermode to anywhere in kernel mode? Definitely *not*. Would this be a vulnerability? Definitely. If we had this ability – we could easily store some useful code somewhere in usermemory that we could then copy anywhere to kernel memory… and then find some way to trigger that code in kernel memory to then call something back in usermemory… thus giving our code in user memory kernel privileges ;P In fact – when it comes to the PSP and PSP emu on the Vita, all you really would need to do is to be able to manipulate a kernel function into writing 4 bytes of arbitrary data to anywhere in kmem (such as overwriting a function pointer)… and you can take over the whole kernel! But anyway, I digress… we’ll discuss exploiting kernel vulnerabilities later ;P
Returning to sceKernelCopyMem, obviously this is a fake function. This function does not actually exist in the official Sony firmware. But I created it and used it as an example of showing what the simplest kernel vulnerability might look like.
How might Sony fix this function to make it non-exploitable?
Well, referring back to the memory map I provided earlier, you’ll notice that kernel addresses (such as 0x80xxxxxx) have the most significant bit (http://en.wikipedia.org/wiki/Most_significant_bit) set. This means that on a 32 bit system such as the PSP, kernel addresses are signed/negative ( < -1 ). User memory addresses are unsigned (positive).
This means that a simple conditional check to see if the dest and src pointers were signed kernel addresses would have easily prevented our pretend attack to work.
In this fake scenario, because the firmware exported sceKernelCopyMem as a syscall that we could call from usermode, we could call it using our game exploit that only has usermode privileges. But sceKernelCopyMem resides in a kernel module (which is in kernel memory), which means that while it is executing, it is executing with kernel privileges. That means that it should be very very careful with the data that it handles that we pass it. But… it doesn’t (this is what we pretended anyway). And because of this, we can copy and thus read/write data to and from basically any valid memory address on the system using this function. And this means that we can manipulate code and other data in kernel memory –not good (for Sony at least ;P).
To wrap things up for this Introduction chapter – This is certainly not the only way kernel vulnerabilities will be found –and in fact, they usually won’t be as easy as this (this kinda of scenario was much more common back in the very early days of the original PSP firmware revisions). However, it does not mean that it’s impossible to find a scenario like this on the recent psp emu firmwares.
Nevertheless, finding kernel vulnerabilities on the PSP will always involve the same concept – finding a kernel function that has kernel privileges that you *DO* have access to (via syscall) that is exploitable and you can “trick” into manipulating kernel memory by leveraging its vulnerability and privileges. This can be as simple as passing arguments that are pointers that the function does not check properly and simply reads/write data to (like above example)… or it may be less obvious (as I will illustrate in later chapters) such as by not checking pointers that are within data structures and such.
As you may have noticed, I also didn’t use prxtool during this chapter at all, or reference MIPS at all. That’s because I wanted this to be an overview of kernel vulnerabilities and keep everything fairly simple and abstract for beginners. I will be referencing both prxtool and MIPS later on when I upload the other chapters at some point… so it would probably be a good idea to start getting accustomed to that stuff if you want to follow along next time!
I also expect that I will be continuously revising this current chapter and fixing grammatical errors, technical wording errors, etc – if you find something yourself please comment here and let me know so I can fix it. And be sure to ask any questions.