kxploit 660 revisit
Note from Wololo, a bit of context on this article: if you’re running a CFW on your 6.60 PSP such as Pro CFW, you are regularly using the 6.60 kxploit without knowing it. The vulnerability was exploited and released by developers Davee and some1, about a year ago, and pro CFW relies on it. Today jigsaw gives a full explanation of the inner working of this exploit.
660 kxploit is within ifhandle.pfx, which is the PSP port of mbuf[1]. mbuf is the basic unit of memory management for network packets and socket buffers. It’s originated from BSD, and is widely adopted by commercial products due to BSD license. ifhandle is obviously ported from FreeBSD 4 release with slight changes. Some routines of ifhandle are 100% duplication of original mbuf code[2].
Before we inspect the kxploit, let’s understand what we want to achieve from a kxploit. The answer is straightforward: to be able to run our own routine with kernel privilege. With kernel privilege we are able to patch kernel so as to run unsigned homebrew, to skip version check, so on and so forth.
The answer is not complete, however, since the next question is how to gain kernel privilege. Remember that by issuing a syscall we can execute the kernel routines[3]. If we could somehow redirect the kernel routines to our own routine, our own routine instanly becomes a kernel level routine. We will see how we could redirect a kernel routine. It’s different from case to case. In most cases it requires modification to kernel space, where the kernel routines locate.
It sounds like a dilemma: to gain kernel privilege we have to modify kernel space, which again requires kernel privilege. This is why we need a kxploit. A kxploit, in most cases, is a bug in kernel that allows us to write values to kernel space.
Usually kxploits have this and that limiations. For instance 639 kxploit allows writing value 0xFFFFFFFF to anywhere; 620 allows writing value 0x0 to anywhere. In these 2 cases we have control over the address, but we can’t control the value that is to be written. This is fine, however, coz we need no more than that. We are able to redirect kernel routines by modifying only one word, which is either the check for kernel privilege, or loading offset of a routine. By masking the vital checkpoint, we manage to ask kernel to load the address of our own routine and call it.
Normally we want to write value zero to kernel space. This is because zero in MIPS stands for NOP, a.k.a. no-operation, which is a good candidate for masking other MIPS instructions.
As a conclusion let me put it this way: We need to find out a way to write value zero to an arbitrary address in kernel space.[4]
Now we are ready to check kxploit 660 in detail.
Note this line in sceNetMCopydata:
0x00001DDC: 0x0C000C8C '....' - jal memcpy
We are interested in the first and second arguments of memcpy, which are
destination and source of the data, respectively.
So we search above for $a0 which is the first argument of routines by
convention[5].
... ... 0x00001D18: 0x00E09021 '!...' - addu $s2, $a3, $zr ... ... 0x00001D98: 0x02402021 '! @.' - addu $a0, $s2, $zr
The 4th argument ($a3) of sceNetMCopydata is the destination of memcpy, and the argument is not checked at all. So if we could set this argument to be an address in kernel space…
But sceNetMCopydata is not exported to user space, which means we are not able to call it directly. Fortunetly sceNetMCopydata is called by other syscalls which can be easily accessed from user space. sceNetMPulldown is our target in this case.
We are going to reverse major part of sceNetMPulldown to find the way to sceNetMCopydata. There are two calls to sceNetMCopydata within sceNetMPulldown, and we are interested in the call at 0x00003018. The reason is that the call at 0x00002E9C copies data to a mbuf which is allocated by sceNetMallocInternal, which is not in our hand.
As I mentioned that ifhandle is based on mubf implementation, so we can grab the original FreeBSD code as a reference. You’ll notice a line-to-line mapping in ifhandle. The implemetation of m_pulldown is at http://fxr.watson.org/fxr/source/kern/uipc_mbuf2.c?v=FREEBSD4
Be prepared for a deep dive to MIPS asm. The code is heavily commented so as to be understood easily.
struct m_hdr { struct mbuf *mh_next; /* next buffer in chain */ struct mbuf *mh_nextpkt; /* next chain in queue/record */ caddr_t mh_data; /* location of data */ int mh_len; /* amount of data in this mbuf */ short mh_type; /* type of data in this mbuf */ short mh_flags; /* flags; see below */ }; struct mbuf { struct m_hdr m_hdr; union { struct { struct pkthdr MH_pkthdr; /* M_PKTHDR set */ union { struct m_ext MH_ext; /* M_EXT set */ char MH_databuf[MHLEN]; } MH_dat; } MH; char M_databuf[MLEN]; /* !M_PKTHDR, !M_EXT */ } M_dat; }; #define mtod(m, t) ((t)((m)->m_data)) #define m_next m_hdr.mh_next // 0 #define m_len m_hdr.mh_len // c #define m_data m_hdr.mh_data // 8 #define m_type m_hdr.mh_type // 10 #define m_flags m_hdr.mh_flags // 12 struct mbuf *sceNetMPulldown(struct mbuf *m, int off, int len, int *offp) { struct mbuf *n, *o; int hlen, tlen, olen; // fp = offp // s6 = len // s4 = m // s2 = off // s1 = n //0x00002C10 if (m == NULL) return NULL; //0x00002C18 if (m 0x800) { sceNetMFreem(m); return NULL; } //0x00002C4C n = m; // s1 = n //0x00002C50 while (n != NULL && off > 0) { if (n->m_len > off) break; off -= n->m_len; n = n->m_next; } //0x00002C84 while (n != NULL && n->m_len == 0) { n = n->m_next; if (n < 0) //kernel space pointer? return NULL; } //0x00002CB8 if (n == NULL) { sceNetMFreem(m); return NULL; } //0x00002CBC if ((off == 0 || offp) && len m_len - off) goto out; //0x00002CE0 if (len m_len - off) { goto loc_00003050; //not interested } //0x00002CEC hlen = n->m_len - off; // s3 = hlen tlen = len - hlen; // s7 = tlen olen = 0; // v1 = olen // s0 = o //0x00002D00 for (o = n->m_next; o != NULL; o = o->m_next) olen += o->m_len; //0x00002D18 if (hlen + olen m_flags & 1)) { //0x00002D3C if (_lw(n + 0x34) != 0) { // we can't go now goto loc_00002D50; } //0x00002D4C a2 = (_lw(n + 0x44) == n); // a2 MUST equal to 0 } //loc_00002D50 if ((off == 0 || offp)) { //0x00002D60 if ((m->m_flags & 1) == 0) { // we have to stay here goto loc_00003040; } //0x00002D7C x = (_lw(n + 0x30) + _lw(n + 0x3c)) - (n->m_data + n->m_len); // x is the macro M_TRAILINGSPACE if (x >= tlen && a2 == 0) { // finally... //0x00003018 m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len); } } }
As you can see, the code is almost duplicated from mbuf.
To reach sceNetMCopydata at 0x00003018 we have to dodge several traps.
For instance we have to set m_flags, m_len, m_next etc. properly. Besides, we will need 2 mbufs linked together to make this trip. I’m not going to show you how to activate this kxploit, coz you can either work it out yourself, or you can check how procfw does this job.
The idea is to demostrate what does a kxploit look like, and how to find a kxploit. Almost all kxploits that have been published so far fall into this category: a missing check against memory address.
In theory, any pointer (memory address) given from user space to kernel space should be validated. In practice, however, after PSP has been announced nearly ten years, there are still such kind of kxploit unleashed. Of course it has been farely difficult to spot a kxploit like this; even worse, a kxploit is not always useful due to syscall limitations[6].
On the other hand, there are other types of kxploits, such as stack overflow, which enalbes user code to be called directly without modifying kernel memory. We will see an example in the next blog of the series.
BTW, heap overflow is another type of kxploit, which is quite usual in mainstream OS such as Windows and Linux. But it has never been found/published in PSP. Hopefully someday I can show you the beauty of heap overflow.
Stay tuned.
[1] http://people.freebsd.org/~hmp/documentation/manpages/mbuf.pdf
[2] http://fxr.watson.org/fxr/source/kern/?v=FREEBSD4
[3] https://wololo.net/2012/05/30/syscalls-nids-imports/
[4] This is one of various possibilities. We will see other alternatives in this series.
[5] http://www.cygwin.com/ml/binutils/2003-06/msg00436.html
[6] https://wololo.net/2012/06/07/syscall-internals/
What lol….
if you dont understand or do not wish to learn then GTFO from a post that tries to do just that
there’s no need to be that agressive man! I read it and I’m kind of feeling the same 🙂 (not everyone here is a programmer, btw)
its not that he does not understand that bugs me, its the fact he just made a useless comment that makes no attempt at even trying to learn or understand
heck even a simple
“dont know what any of this means but goodpostisgood”
would have been fine
Fate,Why are you so Autistic with a god complex?All of your posts you are just trying to be better than somebody.How about instead of “Hurr Durr,You do not wish to learn,Hurr GTFO.” You give an explanation if you are some super genius.
Great post!
Thank you for the consideration, jigsaw, amazing reading!
I enjoyed the info. 🙂
The Vita’s psp emulator runs on 6.60, so can we use this kxploit in the same way we use in the psp?
no as there is no way to say in example run a modified eboot on the Vita
We’ve all considered this question, and Sony is not as lazy as we’d expect. The Firmware on the Vita *is* 6.60, but with a fix for this exploit, as far as I could tell.
Makes me wonder what is stopping Sony from patching the PSP already?
PSP is abandoned, evidently. Sony can’t afford two teams working parallely, I guess.
Lol, lets post about all previous psp hacks and exploits.
It’s so interesting.
It’s to teach you how it’s done, so you’ll be less dumb when you go to bed tonight.
“Give a man a fish and you feed him for a day. Teach a man to fish and you feed him for a lifetime”. Ever heard that?
Edit: Hmm, I automatically assumed you were being sarcastic, but maybe you’re not?
How can you teach a man how to fish if he has no hands? 😮
Actually I wasn’t sarcastic,since psp vulnerabilities are very interesting.
F/e gta save exploit
Apologies then, I did reply quite aggressively for no reason
lol
btw, I think it’s Davee (instead of some1) who found this kxploit – according to the note of the release:
“To Davee for making the original 6.35/6.31 downgrader, and for finding this exploit.”
Hmm, thanks, I will contact them for confirmation on how I should credit them properly
OMG Great Post ever…! Learning is the best…
Thanks jigsaw 🙂
The best explanation of a kxploit i’ve ever seen 🙂 i’ll take a deeper look on this post tomorrow (since it’s 00.36 am here in Germany ^^)
Great job jigsaw!!!
Very informative. 😀
I not too long ago thankx to a wololo post got curious looked up c and c++, even though the guy spoke klingon for the most part, because this is upper level programming it was like playing FF X and decyphering al bhed language. I caught the meanings to a degree and will learn more sooner or later. I like to juggle my interests, so I don’t get bored with them and quit. Great stuff man!
Upper level programming is like Java, than a little lower that that you would find C/C++, and even lower than that you would find MIPS/ASM, which is extremely low level coding, I think you got them mixed up
Nice read!
This is a great example of developers copying and pasting code and it causing vulnerabilities in their systems.
Which is so common in other areas then just gaming, it’s so ridiculous it shows they don’t have proper auditing teams to go through the software before it goes out onto the market to be honest.
Irresponsible,
Yet anti-virus, and other companies do things like this every day and leave consumer systems open to the flaws.
OMG… I don´t understand nothing… But wololo you are a genius i love you!! and im not *** xD
The article is not by me but by jigsaw. I myself am majorly lost when it comes to kernel exploits 🙂
Thanks for the tech articles! Keep them coming (dumbing down is appreciated when possible)!