-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathps4-2.html
1062 lines (809 loc) · 42.7 KB
/
ps4-2.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
<link rel="stylesheet" type="text/css" href="css/core.css" />
<link rel="stylesheet" type="text/css" href="css/prism.css" />
<title>Hacking the PS4, part 2 - Userland code execution</title>
</head>
<body>
<div class="page">
<div class="container">
<div class="header">
<a href="contact.html" class="header-element">
Contact
</a>
<a href="about.html" class="header-element">
About
</a>
<a href="articles.html" class="header-element">
Articles
</a>
<a href="index.html" class="header-element">
Home
</a>
</div>
<h1>Hacking the PS4, part 2</h1>
<h2>Userland code execution</h2>
<span class="date">Initial publication: September 4th, 2015</span>
<hr>
<p>
<b>Note</b>: This article is part of a 3 part series:
</p>
<ul>
<li><a href="ps4.html">Hacking the PS4, part 1 - Introduction to PS4's security, and userland ROP</a></li>
<li><b><a href="ps4-2.html">Hacking the PS4, part 2 - Userland code execution</a></b></li>
<li><a href="ps4-3.html">Hacking the PS4, part 3 - Kernel exploitation</a></li>
</ul>
<p>
See also: <a href="dlclose-overflow.html">Analysis of <code>sys_dynlib_prepare_dlclose</code> PS4 kernel heap overflow</a>
</p>
<br>
<h2>Introduction</h2>
<p>
Since <a href="ps4.html">my first article on the PS4's security</a>, I have made some new discoveries, aided by the fact that I now have code execution within the WebKit process.
</p>
<p>
Whilst I don't want to release my code execution solution yet, I have made my <a href="https://github.com/CTurt/PS4-SDK">PS4-SDK</a> open source, and will try to explain everything I have managed to do with it.
</p>
<p>
This article is less focused on exploitation, and more on what is possible with userland code execution under the WebKit process.
</p>
<br>
<h2>Update</h2>
<p>
After gaining kernel code execution, I've gone back to this article to update some of the uncertainties I had whilst researching with just userland code execution.
</p>
<p>
I've also since posted the method for gaining userland code execution, along with a ROP chain to load binaries sent over TCP; it is explained in <a href="ps4-3.html#code-execution">part 3 of this series</a>.
</p>
<br>
<h2>Code execution</h2>
<p>
As explained in my previous article, ROP is just executing existing code loaded in memory in a smart way; whilst ROP can technically be <a href="https://en.wikipedia.org/wiki/Turing_completeness">Turing-complete</a>, it really isn't practical for anything more complex than some basic tests.
</p>
<p>
With the help of flatz, I've been able to leverage ROP to setup memory in such a way that I can write my own code into it, and execute it.
</p>
<p>
Simply, this means that I can compile C code, such as these <a href="https://github.com/CTurt/PS4-SDK/tree/master/examples">examples included in PS4-SDK</a>, and execute them as native x86_64 code.
</p>
<p>
Whilst this is big progress, we are still running within the Internet Browser, and have the same restrictions as before (like sandboxing).
</p>
<p>
As a little side note; with the recent <a href="http://llvm.org/releases/download.html">release of LLVM 3.7</a>, if we specify <code>-target x86_64-scei-ps4</code> to <code>clang</code>, we can compile code with the exact same options that Sony uses to compile official code for the PS4.
</p>
<br>
<h2>WebKit process limitations</h2>
<p>
As stated in my previous article, the Internet Browser actually consists of 2 separate processes. The one which we hijack for code execution is the core WebKit process (which handles parsing HTML and CSS, decoding images, and executing JavaScript for example).
</p>
<p>
We can use the following code to dump all memory which our process has access to:
</p>
<pre><code class="language-c">struct memoryRegionInfo info;
struct otherMemoryRegionInfo otherInfo;
void *m = NULL;
int i;
// Iterate over first 107 memory mappings
for(i = 0; i < 107; i++) {
// Find base of next mapping
getOtherMemoryInfo(m, 1, &otherInfo);
// Get more info about this mapping
getMemoryInfo(otherInfo.base, &info);
// If readable, dump it
if(info.flags & PROT_CPU_READ) {
sceNetSend(sock, info.base, info.end - info.base, 0);
}
m = info.end;
}</code></pre>
<br>
<p>
Within this dump, you won't be able to find strings used by the other process, such as "Options", "Close Window", "Refresh", or "There is not enough free system memory".
</p>
<br>
<h2>Graphics</h2>
<p>
One of the main implications of this is clear: if the other process handles displaying graphics, we can't easily hijack the active <code>libSceVideoOut</code> handle.
</p>
<p>
I've been working with <a href="https://github.com/xerpi">xerpi</a> to try to reinitialise <code>libSceVideoOut</code>, but even though all functions are returning good values, we can't get the screen to change from the browser view.
</p>
<p>
Just to be certain that our process can't access any existing video handles created by the other process, we tried brute forcing all positive integers to see if any were valid.
</p>
<br>
<h2>Brute forcing with code execution</h2>
<p>
Brute forcing things with the ROP framework was very impractical. I relied on redirecting the page after each test, and since the exploit isn't 100% reliable, the brute forcer would get stuck after left for just a minute or so.
</p>
<p>
With real code execution, we can try to brute force more ambitious things, such as a video handle that the Internet Browser has opened. And we can use sockets to track the progress remotely from a PC.
</p>
<p>
<code>sceVideoOutWaitVblank</code> will return an error if it is given an invalid handle, and 0 if it's given a valid handle:
</p>
<pre><code class="language-c">int i;
for(i = 0; i < 0x7FFFFFFF; i++) {
if(!sceVideoOutWaitVblank(i)) return i;
if(i % 0x10000 == 0) debug(sock, "At %08x\n", i);
}
sceNetSocketClose(sock);
return 0;</code></pre>
<br>
<p>
After running this for several hours it returned 0, confirming that our process has no access to the other process' video handle.
</p>
<br>
<h2>Canvas</h2>
<p>
There is a partial solution to this though. If we create an HTML5 canvas and fill it with a single colour, we can find the address of its framebuffer in RAM, and create a new thread to render to it from native code, leaving the original thread to update the canvas as normal.
</p>
<p>
I've added <a href="https://github.com/CTurt/PS4-SDK/blob/master/examples/canvas/source/main.c">an example of this</a> to the PS4-SDK.
</p>
<p>
If the canvas has too high of a resolution, it is harder to locate its address, and will often have a poor refresh rate. However, we can stretch a low resolution image to be fullscreen, and it will work fine:
</p>
<pre><code>var body = document.getElementsByTagName("body")[0];
// Create canvas
var canvas = document.createElement("canvas");
canvas.id = "canvas";
canvas.width = 160;
canvas.height = 144;
canvas.style.zIndex = 1;
canvas.style.position = "absolute";
canvas.style.border = "1px solid";
// Centered
//canvas.style.left = ((window.screen.width - canvas.width) / 2).toString() + "px";
//canvas.style.top = ((window.screen.height - canvas.height) / 2).toString() + "px";
// Fullscreen
canvas.style.left = "0px";
canvas.style.top = "0px";
canvas.style.width = "100%";
canvas.style.height = "100%";
body.appendChild(canvas);</code></pre>
<br>
<p>
Another thing you may want to do is remove all other elements before creating the canvas, as a slight performance boost, but also to prevent being able to scroll:
</p>
<pre><code>while(body.firstChild) {
body.removeChild(body.firstChild);
}</code></pre>
<br>
<p>
And finally, you will want to hide the cursor:
</p>
<pre><code>document.body.style.cursor = "none";</code></pre>
<br>
<h2>Controller</h2>
<p>
The <code>libScePad</code> module is similar to <code>libSceVideoOut</code> in that it isn't used by our process, and so I wasn't able to get it working.
</p>
<p>
Calling <code>scePadOpen</code> will give an error, unless you call <code>scePadInit</code> beforehand. From this, we can tell that separate processes' modules each have their own internal state, and that our process wasn't using <code>libScePad</code> (since it wasn't already initialised).
</p>
<p>
So, like with graphics, we won't be able to hijack any handles already open, and <a href="https://github.com/CTurt/PS4-SDK/blob/master/examples/pad/source/main.c">trying to create new handles</a> won't work either.
</p>
<p>
Maybe we can't read from the controller because it is already in use, and we would be able to read from a second controller, but unfortunately I can't test this since I only have 1 controller.
</p>
<p>
There are two workarounds for this: use the USB library to receive input from a third party controller, or just use any WiFi compatible device with buttons to send input over a UDP socket. I opted for using a Nintendo DS wirelessly.
</p>
<br>
<h2>USB flash drives</h2>
<p>
When you insert a USB into the PS4, a new device is listed under <code>/dev/</code>; <code>ugen0.4</code> for the first slot, and <code>ugen0.5</code> for the second slot.
</p>
<p>
Unfortunately, we can't mount the device since the <code>mount</code> system call (and variations like <code>nmount</code>) always return 1, <code>EPERM</code>.
</p>
<p>
However, we can access USB flash drives using the <code>libSceUsbd.sprx</code> module; it is very similar to <a href="http://www.freebsd.org/cgi/man.cgi?format=html&query=libusb%283%29"><code>libusb</code></a>, but with the Sony naming convention, and the removal of contexts.
</p>
<p>
For example, the following <code>libusb</code> code:
</p>
<pre><code class="language-c">libusb_context *context;
libusb_init(&context);
libusb_exit(context);</code></pre>
<br>
<p>
Would translate to this <code>libSceUsbd</code> code:
</p>
<pre><code class="language-c">sceUsbdInit();
sceUsbdExit();</code></pre>
<br>
<p>
This is a very low level library for sending direct commands to USB devices, so it isn't really ideal to use, but with the help of xerpi, I was able to port one of the <code>libusb</code> examples to PS4, and <a href="https://github.com/CTurt/PS4-SDK/blob/master/examples/usb/storage/source/main.c">read the raw image of a USB flash drive</a>.
</p>
<p>
Whilst it may be possible in the future to port a full FAT implementation based on direct USB commands, for now I am just writing my data as the raw image of a USB flash drive using <a href="http://sourceforge.net/projects/win32diskimager/">Win32 Disk Imager</a> (similar to <code>dd</code> for Linux).
</p>
<br>
<h2>USB findings with kernel access</h2>
<p>
The PS4 automatically attempts to mount USB flash drives when inserted. Once kernel code execution has been used to enable UART output, the following message is displayed upon insertion of a USB flash drive:
</p>
<pre><code>ugen0.4: <SanDisk> at usbus0
umass1: <SanDisk Cruzer Edge, class 0/0, rev 2.00/1.26, addr 4> on usbus0
umass1: SCSI over Bulk-Only; quirks = 0x0000
umass1:2:1:-1: Attached to scbus2
da1 at umass-sim1 bus 1 scbus2 target 0 lun 0
da1: <SanDisk Cruzer Edge 1.26> Removable Direct Access SCSI-5 device
da1: 40.000MB/s transfers
da1: 3819MB (7821312 512 byte sectors: 255H 63S/T 486C)
[SceAutoMount] /mnt/usb0 is now available. fstype=exfatfs, device=/dev/da1s1
MSG AutomounterMelUtil(void sceAutomounterMelUtil::callbackMountAll(void **) 203):
device(/dev/da1s1): exfat(mediaType=0x1001) is mounted at /mnt/usb0.</code></pre>
<br>
<p>
Only devices formatted as FAT32 will be successfully mounted, and after kernel code execution has been used to escape the filesystem sandbox, they may be accessed from <code>/mnt/usb0</code> and <code>/mnt/usb1</code>.
</p>
<p>
However, without a kernel exploit the <code>libSceUsbd</code> module remains the only way to access USBs, which actually gives more control over the device, but is less convenient to use for just reading and writing files.
</p>
<br>
<h2>Cinoop</h2>
<p>
<a href="cinoop.html">Cinoop</a> is a GameBoy emulator I wrote a while ago. Whilst it isn't one of the best GameBoy emulators out there, I thought it would be a fun project to port to PS4 to show what code execution within the Internet Browser is capable of (using all of the workarounds explained above).
</p>
<div class="center">
<iframe class="youtube" width="560" height="315" src="https://www.youtube.com/embed/94Q91xDJatE" frameborder="0" allowfullscreen></iframe>
</div>
<br>
<h2>More on processes</h2>
<p>
Our environment has been restricted such that there are very few ways to interact with other processes meaningfully; I experimented with potential methods of hijacking another process to gain more access but have had little success:
</p>
<p>
The <code>fork</code> (2) system call is disabled, so we can't create new processes.
</p>
<p>
The <code>chroot</code> (61) system call is disabled.
</p>
<p>
The <code>libc</code> function <code>getprocname</code> returns an empty string.
</p>
<p>
The <code>execve</code> (59) system call is allowed, and there is also a function called <code>sceSystemServiceLoadExec</code> in <code>libSceSystemService.sprx</code>, but we have no way of testing either of these since the filesystem is read only and we can't mount USB flash drives. Executable files on the PS4 have a custom header, and the contents are encrypted anyway.
</p>
<p>
We can copy some of the functions from <a href="http://www.freebsd.org/cgi/man.cgi?query=libprocstat&apropos=0&sektion=3&manpath=FreeBSD+9.0-RELEASE&arch=amd64&format=html"><code>libprocstat</code></a>, but this functionality is mostly useless since we only have permission to target our own process.
</p>
<br>
<h2>Executable files with kernel access</h2>
<p>
The following two kernel functions seem to deal with the majority of integrity checks of executable files: <code>sceSblAuthMgrAuthHeader</code> and <code>sceSblAuthMgrIsLoadable</code>.
</p>
<p>
With kernel code execution, executable files can be directly decrypted on the console, however there isn't much benefit to this over just loading the module and dumping it from userland.
</p>
<br>
<h2>Root confusion</h2>
<p>
I mentioned in my last article that <code>getlogin</code> returns <code>"root"</code>. Whilst the username may be <code>"root"</code>, I'm not convinced that it is the conventional <code>root</code> that one would expect.
</p>
<p>
For example, <code>getuid</code> should always return 0 for the <code>root</code> user, but instead, it returns 1.
</p>
<p>
I've also demonstrated in my last article that our process is running in a FreeBSD jail, which I'm not sure is possible for a process running as <code>root</code>.
</p>
<p>
I don't understand enough about FreeBSD users and jails to really understand what is going on, but I like to think that Sony somehow named a <code>non-root</code> user as <code>"root"</code> just to tease us.
</p>
<br>
<h2>Loading modules from their name</h2>
<p>
We can load modules from their name using <code>sceKernelLoadStartModule</code> from <code>libkernel</code>:
</p>
<pre><code class="language-c">int libPad = sceKernelLoadStartModule("libScePad.sprx", 0, NULL, 0, 0, 0);</pre></code>
<br>
<p>
With the module loaded in memory, we can read its base and size, and dump it like before.
</p>
<p>
This method of loading modules is preferable to the one explained in my last article since it will initialise the imports table, so that you can actually call functions in it, and follow xrefs to other modules like <code>libc</code> and <code>libkernel</code> in your dump.
</p>
<p>
This function also lets us dump a few modules that <a href="http://www.psdevwiki.com/ps4/Libraries#Libraries_on_firmware_1.76">would cause a segmentation fault using the old method</a>.
</p>
<br>
<h2>Finding function offsets from function names</h2>
<p>
FreeBSD uses system call 337, <a href="https://www.freebsd.org/cgi/man.cgi?query=kldsym&sektion=2"><code>kldsym</code></a>, to locate the address of a function in a kernel module from its name.
</p>
<p>
In C, it can be used like this:
</p>
<pre><code class="language-c">struct kld_sym_lookup data;
data.version = sizeof(struct kld_sym_lookup);
data.symname = "sys_getpid";
if(kldsym(libKernel, KLDSYM_LOOKUP, &data) == 0) {
printf("%p\n", data.symvalue);
printf("%d\n", data.symsize);
}</pre></code>
<br>
<p>
In the PS4 kernel, this function has been disabled, and will always return <code>0x4e</code>, <code>ENOSYS</code>.
</p>
<p>
However, Sony implemented a dynamic linker in the PS4 kernel for userland dynamic libraries, and we can use it to resolve userland functions.
</p>
<p>
System call <code>591</code>, <code>sys_dynlib_dlsym</code>, has become the basis of the PS4-SDK; once we've loaded a module and got its handle, we can call any functions which we know the name and parameters of.
</p>
<p>
The following ROP chain will get the offset of the <code>getpid</code> wrapper within <code>libkernel</code>:
</p>
<pre><code>var result = chain.data;
var name = chain.data + 8;
writeString(name, "getpid");
chain.syscall("getFunctionAddressByName", 591, LIBKERNEL, name, result);
chain.execute(function() {
logAdd(readString(name) + " libkernel offset = 0x" + (getU64from(result) - module_infos[LIBKERNEL].image_base).toString(16));
});</code></pre>
<br>
<p>
For firmware 1.76, the result is <code>0xbbb0</code>.
</p>
<p>
We can verify this offset from our <code>libkernel</code> dump (20 is the <code>getpid</code> system call number):
</p>
<pre><code>000000000000BBB0 getpid proc near
000000000000BBB0 mov rax, 20
000000000000BBB7 mov r10, rcx
000000000000BBBA syscall
000000000000BBBC jb short loc_BBBF
000000000000BBBE retn
000000000000BBBF ; ---------------------------------------------------------------------------
000000000000BBBF
000000000000BBBF loc_BBBF:
000000000000BBBF lea rcx, sub_DF60
000000000000BBC6 jmp rcx
000000000000BBC6 getpid endp</code></pre>
<br>
<p>
To get other function names to try, you should use the strings view of your disassembler (or just search for <code>sce</code> in a hex editor); you'll find that Sony left some useful debug messages in many of the modules.
</p>
<p>
For example, <code>libkernel</code> contains the string <code>"verify_header: sceKernelPread failed %x\n"</code>. Now that we've identified a <code>sceKernelPread</code> function, we can guess others that may exist, such as <code>sceKernelPwrite</code>, and so on.
</p>
<p>
Unfortunately, <code>sceKernelPread</code> and <code>sceKernelPwrite</code> aren't very interesting; they are just wrappers for the regular FreeBSD file related system calls.
</p>
<p>
Since Sony has used a fairly consistent naming convention over the years, you can also try using some <a href="http://psp.jim.sh/pspsdk-doc/group__ModuleMgrKern.html">PSP function names</a>; many of them also exist in some of the PS4's modules.
</p>
<br>
<h2>Threads</h2>
<p>
The <code>libkernel</code> module contains an implementation of <a href="http://www.freebsd.org/cgi/man.cgi?query=pthread&apropos=0&sektion=3&manpath=FreeBSD+9.0-RELEASE&arch=amd64&format=html"><code>libpthread</code></a>, but with the Sony naming convention; <a href="https://github.com/CTurt/PS4-SDK/blob/master/examples/threads/source/main.c">an example of using threads</a> has been added to the PS4-SDK.
</p>
<p>
An interesting thing to note is that the threads we create will continue to run in background whilst other applications are active.
</p>
<p>
To demonstrate this, we can create a thread which will launch the Internet Browser after an arbitrary timeout:
</p>
<pre><code class="language-c">int (*sceSystemServiceLaunchWebBrowser)(const char *uri, void *);
void *t(void *n) {
sceKernelSleep(10);
sceSystemServiceLaunchWebBrowser("http://google.com/", NULL);
return NULL;
}
int _main(void) {
initKernel();
initLibc();
initPthread();
int libSceSystemService;
loadModule("libSceSystemService.sprx", &libSceSystemService);
RESOLVE(libSceSystemService, sceSystemServiceLaunchWebBrowser);
ScePthread thread;
scePthreadCreate(&thread, NULL, t, NULL, "t");
return 0;
}</code></pre>
<br>
<div class="center">
<iframe class="youtube" width="560" height="315" src="https://www.youtube.com/embed/tBev5h8vOtg" frameborder="0" allowfullscreen></iframe>
</div>
<br>
<h2>Reading memory protection</h2>
<p>
We can use 2 of Sony's custom system calls, 547 and 572, to read the properties of a memory page (16KB), including its protection:
</p>
<pre><code>function getStackProtection() {
var info = chain.data;
chain.syscall("getMemoryInfo", 547, stack_base, info);
chain.execute(function() {
var base = getU64from(info + 0x0);
var size = getU64from(info + 0x8) - base;
var protection = getU32from(info + 0x10);
logAdd("Stack base: 0x" + base.toString(16));
logAdd("Stack size: 0x" + size.toString(16));
logAdd("Stack protection: 0x" + protection.toString(16));
});
}
function getStackName() {
var info = chain.data;
chain.syscall("getOtherMemoryInfo", 572, stack_base, 0, info, 0x40);
chain.execute(function() {
var base = getU64from(info + 0x0);
var size = getU64from(info + 0x8) - base;
var name = readString(info + 0x20);
logAdd("Stack base: 0x" + base.toString(16));
logAdd("Stack size: 0x" + size.toString(16));
logAdd("Stack name: " + name);
});
}</code></pre>
<br>
<p>
The above code shows us that the stack's name is "main stack" and its protection is 3 (read and write).
</p>
<br>
<h2>Listing all memory pages</h2>
<p>
As you know from my last article, it is difficult to map out all of the PS4's memory due to ASLR (everything is always randomly arranged).
</p>
<p>
Luckily for us, there is something we can do to partially get around this: if the second argument of system call 572 is set to 1 and we specify an address which isn't mapped, the next mapped memory page will be used.
</p>
<p>
This means that we can specify any arbitrary address, and always find a valid memory page. For example, specifying 0 as the address will tell us information about the first mapped memory page:
</p>
<pre><code>var info = chain.data;
chain.syscall("getOtherMemoryInfo", 572, 0, 1, info, 0x40);
chain.execute(function() {
var base = getU64from(info + 0x0);
var size = getU64from(info + 0x8) - base;
var name = readString(info + 0x20);
logAdd("First page base: 0x" + base.toString(16));
logAdd("First page size: 0x" + size.toString(16));
logAdd("First page name: " + name);
});</code></pre>
<br>
<p>
Using this, we can extract a complete list of memory pages accessible from our process:
</p>
<pre><code>Name Address Size Protection
executable 0x65620000 0x4000 0x5
executable 0x65624000 0x4000 0x3
anon:000819401c98 0x200578000 0x4000 0x3
anon:00081baf2243 0x20057c000 0x8000 0x3
anon:00081add693a 0x200584000 0x8000 0x3
anon:00081baf22d6 0x20058c000 0x8000 0x3
anon:00081add739e 0x200594000 0x100000 0x3
anon:00081add6ad2 0x200694000 0x8000 0x3
anon:00081add6ad2 0x20069c000 0x8000 0x3
anon:000815405218 0x2006a4000 0x4000 0x3
anon:00081ac4f19e 0x2006a8000 0x8000 0x3
anon:00081add739e 0x2006b0000 0x100000 0x3
anon:00081ba08107 0x2007b0000 0x4000 0x3
anon:00081ad834f7 0x2007b4000 0x4000 0x1
anon:00081add739e 0x2007b8000 0x300000 0x3
stack guard 0x7ef788000 0x4000 0x0
JavaScriptCore::BlockFree 0x7ef78c000 0x10000 0x3
stack guard 0x7ef79c000 0x4000 0x0
RscHdlMan:Worker 0x7ef7a0000 0x10000 0x3
stack guard 0x7ef7b0000 0x4000 0x0
SceWebReceiveQueue 0x7ef7b4000 0x10000 0x3
stack guard 0x7ef7c4000 0x4000 0x0
SceFastMalloc 0x7ef7c8000 0x10000 0x3
stack guard 0x7ef7d8000 0x4000 0x0
sceVideoCoreServerIFThread 0x7ef7dc000 0x10000 0x3
(NoName)WebProcess.self 0x7ef7ec000 0x4000 0x0
main stack 0x7ef7f0000 0x200000 0x3
0x7ef9f0000 0x4000 0x5
libSceRtc.sprx 0x802ccc000 0x4000 0x5
libSceRtc.sprx 0x802cd0000 0x4000 0x3
libSceSystemService.sprx 0x803468000 0x14000 0x5
libSceSystemService.sprx 0x80347c000 0x4000 0x3
libSceSystemService.sprx 0x803480000 0x8000 0x3
libSceSysmodule.sprx 0x8049bc000 0x4000 0x5
libSceSysmodule.sprx 0x8049c0000 0x4000 0x3
libkernel.sprx 0x808774000 0x34000 0x5
libkernel.sprx 0x8087a8000 0x2c000 0x3
libSceRegMgr.sprx 0x80a520000 0x4000 0x5
libSceRegMgr.sprx 0x80a524000 0x4000 0x3
libSceSsl.sprx 0x80d1c0000 0x48000 0x5
libSceSsl.sprx 0x80d208000 0x8000 0x3
libSceOrbisCompat.sprx 0x80f648000 0x15c000 0x5
libSceOrbisCompat.sprx 0x80f7a4000 0x38000 0x3
libSceOrbisCompat.sprx 0x80f7dc000 0x4000 0x3
libSceLibcInternal.sprx 0x8130dc000 0xd0000 0x5
libSceLibcInternal.sprx 0x8131ac000 0x8000 0x3
libSceLibcInternal.sprx 0x8131b4000 0x18000 0x3
libScePigletv2VSH.sprx 0x815404000 0x74000 0x5
libScePigletv2VSH.sprx 0x815478000 0x2c000 0x3
libSceVideoCoreServerInterface. 0x819400000 0xc000 0x5
libSceVideoCoreServerInterface. 0x81940c000 0x4000 0x3
libSceWebKit2.sprx 0x81ac44000 0x2414000 0x5
libSceWebKit2.sprx 0x81d058000 0x148000 0x3
libSceWebKit2.sprx 0x81d1a0000 0xbc000 0x3
libSceIpmi.sprx 0x81da60000 0x14000 0x5
libSceIpmi.sprx 0x81da74000 0x14000 0x3
libSceMbus.sprx 0x8288a0000 0x8000 0x5
libSceMbus.sprx 0x8288a8000 0x4000 0x3
libSceCompositeExt.sprx 0x829970000 0x8000 0x5
libSceCompositeExt.sprx 0x829978000 0x44000 0x3
libSceNet.sprx 0x82ccdc000 0x1c000 0x5
libSceNet.sprx 0x82ccf8000 0x14000 0x3
libSceNetCtl.sprx 0x833f1c000 0x8000 0x5
libSceNetCtl.sprx 0x833f24000 0x4000 0x3
libScePad.sprx 0x835958000 0x8000 0x5
libScePad.sprx 0x835960000 0x8000 0x3
libSceVideoOut.sprx 0x83afe4000 0xc000 0x5
libSceVideoOut.sprx 0x83aff0000 0x4000 0x3
libSceSysCore.sprx 0x83cdf4000 0x8000 0x5
libSceSysCore.sprx 0x83cdfc000 0x4000 0x3
SceLibcInternalHeap 0x880984000 0x10000 0x3
SceKernelPrimaryTcbTls 0x880994000 0x4000 0x3
SceVideoCoreServerInterface 0x880998000 0x4000 0x3
SceLibcInternalHeap 0x88099c000 0xc0000 0x3
SceLibcInternalHeap 0x880a5c000 0x20000 0x3
SceLibcInternalHeap 0x880a7c000 0x490000 0x3
SceLibcInternalHeap 0x880f0c000 0x470000 0x3
anon:00080f64a807 0x912000000 0x100000 0x3
anon:00080f64a98d 0x912100000 0x10000000 0x3
anon:00080f64aaa5 0x922100000 0x4000000 0x5
CompositorClient 0x1100000000 0x200000 0x33
CompositorClient 0x1100200000 0x200000 0x33
CompositorClient 0x1100400000 0x200000 0x33
CompositorClient 0x1100600000 0x200000 0x33
CompositorClient 0x1180000000 0x200000 0x33
CompositorClient 0x1180200000 0x200000 0x33
CompositorClient 0x1180400000 0x200000 0x33
CompositorClient 0x1180600000 0x200000 0x33
CompositorClient 0x1180800000 0x200000 0x33
CompositorClient 0x1180a00000 0x200000 0x33
CompositorClient 0x1180c00000 0x200000 0x33
CompositorClient 0x1180e00000 0x200000 0x33
CompositorClient 0x1181000000 0x200000 0x33
CompositorClient 0x1181200000 0x200000 0x33
CompositorClient 0x1181400000 0x200000 0x33
CompositorClient 0x1181600000 0x200000 0x33
CompositorClient 0x1181800000 0x200000 0x33
CompositorClient 0x1181a00000 0x200000 0x33
CompositorClient 0x1181c00000 0x200000 0x33
CompositorClient 0x1181e00000 0x200000 0x33
CompositorClient 0x1182000000 0x200000 0x33
CompositorClient 0x1184000000 0x200000 0x33
CompositorClient 0x1186000000 0x200000 0x33
CompositorClient 0x1188000000 0x200000 0x33
CompositorClient 0x118a000000 0x200000 0x33
CompositorClient 0x118c000000 0x200000 0x33
CompositorClient 0x118e000000 0x200000 0x33</code></pre>
<br>
<p>
<code>CompositorClient</code> is always based at <code>0x1100000000</code>, but all other addresses will be different each time.
</p>
<p>
This list is almost exactly what we expected, a bunch of modules each with their own data and code pages, the stack, some stack guards, and some other miscellaneous mappings.
</p>
<p>
There is something peculiar though, <code>CompositorClient</code> is mapped as <code>0x33</code>, which is definitely not a standard FreeBSD memory protection!
</p>
<br>
<h2>GPU</h2>
<p>
Since the CPU and GPU share a unified memory pool, Sony added their own protection flags to control what the GPU can access as well as keeping the standard FreeBSD protections for the CPU.
</p>
<p>
These can be found by either reversing the <code>libSceGnmDriver</code> module, or just by running some tests and thinking logically:
</p>
<ul>
<li>CPU Read - 1</li>
<li>CPU Write - 2</li>
<li>CPU Execute - 4</li>
<li>GPU Execute - 8</li>
<li>GPU Read - 16</li>
<li>GPU Write - 32</li>
</ul>
<p>
<code>CompositorClient</code> is marked as <code>0x33</code> (<code>1 | 2 | 16 | 32</code>), CPU RW and GPU RW.
</p>
<p>
Sony handled the GPU protection system very cleverly; we can only give a processor as much access as the other one has, for example:
</p>
<pre><code>// Give GPU read and write access to stack:
chain.syscall("mprotect", 74, stack_base, 16 * 1024 * 1024, 1 | 2 | 16 | 32);
// Give GPU read and execute access to WebKit2 module:
chain.syscall("mprotect", 74, module_infos[WEBKIT2].image_base, 16 * 1024 * 1024, 1 | 4 | 16 | 8);</code></pre>
<br>
<p>
But trying to bypass DEP will fail:
</p>
<pre><code>// Give GPU read and execute access to stack:
chain.syscall("mprotect", 74, stack_base, 16 * 1024 * 1024, 1 | 2 | 16 | 8);
// Give GPU read and write access to WebKit2 module:
chain.syscall("mprotect", 74, module_infos[WEBKIT2].image_base, 16 * 1024 * 1024, 1 | 4 | 16 | 32);</code></pre>
<br>
<h2>Registry</h2>
<p>
There is a module called <code>libSceRegMgr.sprx</code>, which indicates that Sony added some kind of registry system to the PS4, since FreeBSD doesn't come with one.
</p>
<p>
All functions in this module are wrappers for system call 532, which was previously thought to be <a href="http://fxr.watson.org/fxr/source/kern/syscalls.master?v=FREEBSD9#L952">wait6</a>; the first argument is a command.
</p>
<p>
The fact that <code>wait6</code> has been overwritten with a custom Sony system call suggests that the system call numbers are not as similar to standard FreeBSD 9.0 as I initially believed.
</p>
<p>
Although this module is loaded and used by the Internet Browser, it is restricted from our process; all function calls return <code>0x80020001</code>, the Sony equivalent of <code>EPERM</code>.
</p>
<br>
<h2>More proof of the lack of kernel ASLR</h2>
<p>
System call 617 takes at least 1 argument, and returns a kernel pointer; I don't know anything more about this system call, but since the kernel pointer is always the same, we can use it as further evidence that there is no kernel ASLR on firmware 1.76.
</p>
<br>
<h2>Dumping files</h2>
<p>
Recently, I added a <a href="https://github.com/CTurt/PS4-playground/blob/gh-pages/browser.html">File Browser</a> to PS4-Playground, although I didn't add a way to dump files.
</p>
<p>
With code execution, files can be dumped very easily. I've added <a href="https://github.com/CTurt/PS4-SDK/blob/master/examples/filesystem/files/source/main.c">an example</a> to PS4-SDK which shows how to do it.
</p>
<p>
It is also possible to do using only ROP, but it is a bit more hassle, and must be done in multiple stages.
</p>
<p>
By using PS4 File Browser, you should be able to find some interesting things to dump; I'll be dumping <code>/sandboxDir/common/font/DFHEI5-SONY.ttf</code>.
</p>
<p>
If the path to the file you want to dump starts with 10 random characters (the sandbox directory), you should note that this path will change each time you reboot the PS4. You can use the ROP chain below to find it:
</p>
<pre><code>setU64to(chain.data, 11);
chain.syscall("getSandboxDirectory", 602, 0, chain.data + 8, chain.data);
chain.write_rax_ToVariable(0);
chain.execute(function() {
var name = readString(chain.data + 8);
logAdd(name);
});</pre></code>
<br>
<p>
For me, it was <code>AaQj0xlzjX</code>.
</p>
<p>
For very small files, you can simply read into <code>chain.data</code>, but for larger files, you will need to allocate your own memory.
</p>
<p>
We can do this through the standard <code>mmap</code> system call. Refresh the page, and use this chain:
</p>
<pre><code>chain.syscall("mmap", 477, 0, 0x1000000, 1 | 2, 4096, -1, 0);
chain.write_rax_ToVariable(0);
chain.execute(function() {
chain.logVariable(0);
});
</pre></code>
<br>
<p>
In this example, the address returned was <code>0x200744000</code>.
</p>
<p>
Refresh the page again, and use this chain to read the file and get its size, replace <code>AaQj0xlzjX</code> with your sandbox directory and <code>0x200744000</code> with whatever address the above chain printed:
</p>
<pre><code>writeString(chain.data, "/AaQj0xlzjX/common/font/DFHEI5-SONY.ttf");
chain.syscall("open", 5, chain.data, 0, 0);
chain.write_rax_ToVariable(0);
chain.read_rdi_FromVariable(0);
chain.syscall("read", 3, undefined, 0x200744000, 0x1000000);
chain.syscall("fstat", 189, undefined, chain.data);
chain.execute(function() {
chain.logVariable(0);
logAdd("Size: " + getU32from(chain.data + 0x48).toString());
});</pre></code>
<br>
<p>
The font I am dumping is 8312744 bytes.
</p>
<p>
Now open whatever proxy or network tool you use to intercept traffic on your computer. I created a simple C server called <a href="https://github.com/CTurt/TCP-Dump">TCP-Dump</a> which you can use if you wish.
</p>
<p>
Refresh the page, and use this chain to send the buffer; replace the IP, port, address, and file size with the appropriate values:
</p>
<pre><code>sendBuffer("192.168.0.4", 9023, 0x200744000, 8312744);
chain.execute(function() {
logAdd("Dumped");
});
</pre></code>
<br>
<p>
Using cookies, you can pass information to subsequent stages automatically, but I won't go into it now.
</p>
<p>
You should also note that the filesystem is read only; for example, <a href="https://twitter.com/CTurtE/status/633332237346426880">attempting to overwrite a font will crash your PS4</a> (but it'll be fine afterwards).
</p>
<p>
We can also dump the modules located at <code>/sandboxDir/common/lib/</code>, but they are encrypted.
</p>
<br>
<h2>Encryption</h2>
<p>
The most common questions I am asked pertain to encryption. It is a huge part of the PS4's security which prevents us from analysing firmware updates, games, saves and more.
</p>
<p>
The reason I didn't mention encryption in my last article is because trying to defeat it would be a complete waste of time. The PS4 uses <a href="https://en.wikipedia.org/wiki/Advanced_Encryption_Standard">AES</a> (like the <a href="http://www.ps3devwiki.com/ps3/Keys">PS3</a> and PS Vita), which is the same type of encryption used by the U.S. government.
</p>
<p>
People also don't seem to realise that there are multiple encryption keys used within the PS4; even if we found a way to decrypt save data, we still wouldn't be able to decrypt PUP updates for example.
</p>
<p>
With the current level of access we have to the PS4 there is no way to get any keys: brute forcing them would take longer than the lifetime of the universe even under ideal conditions, and I doubt any of the few engineers at Sony trusted with them would want to lose their job by leaking them.
</p>
<p>
The only exception to this is would be for implementation mistakes such as the PS3's infamous use of the constant 4 instead of what should have been a random number.
</p>
<p>
Whilst it is unlikely that Sony has made another mistake like this in the core of the PS4's encryption, it is not uncommon for other companies to accidentally give us access to unencrypted content. If you snoop around various games' update servers, you might find some debug ELFs for example.
</p>
<p>
Furthermore, encryption on the PS4 is handled by a separate processor, called SAMU, which is very locked down. Even with a kernel exploit, the SAMU processor is one of the few areas which we don't have complete control over. Although we can interact with it to decrypt almost everything, it is impossible to extract any keys so that decryption could be done externally.
</p>
<br>
<h2>Saves</h2>
<p>
Save data is stored at the following location:
</p>
<pre><code>/user/home/[userID]/savedata/[titleID]/</code></pre>
<br>
<p>
For example:
</p>
<pre><code>/user/home/10000000/savedata/CUSA00455/FFXIVSYSTEM.bin</code></pre>
<br>
<p>