Partition LwVM table

The iBoot exploit discussed in this writeup is relying on an insecure implementation of the HFS+ file system parser on iBoot versions older than iOS 5.x (included). It does not parse the HFS+ header securely, leading to a heap buffer overflow if some values are set to big numbers. This corrupted file system header might be still readable by a fixed HFS+ parser code, but the one compiled within iOS 5.x iBoot (and older versions) won't be able to and will trigger a heap buffer overflow.

Such kind of iBoot exploits that are triggered from file system have some important considerations when implemented. If the corrupted HFS+ file system is used as System partition for iOS, a vulnerable iBoot version will not be able to mount that file system to search for the kernelcache or upgrade routine images (in case of an OTA update). The corrupted HFS+ file system can only be used to trigger the exploit, not to be mounted.

To get around of this issue, we are going to create a third partition and set it as the boot one. Then, iBoot will try mount the corrupted HFS+ file system of that third partition instead of mounting the one of the System partition by default. We will also be able to use this third partition to dry-run our implementation of the exploit before attacking the main bootchain.

Before you attempt to re-partition the disk of your iOS device, I recommand you read the partition LwVM table guide I wrote for my iOS multiboot writeup here to give you a basic idea of what you will have to do.

It contains most of the information you will need to succeed without ending up with a bootlooped device. However, there are some important differences in this process between an iBoot exploit like that one and an iOS multiboot setup.

We will do re-partitionning in four steps.

Let's begin by calculating the size of the current Data partition, according to the left space we will still have after increasing the size of the System partition and creating a new small partition for exploitation.

Execute gptfdisk with the disk volume rdisk0s1 as argument.

iPad-k94ap#gptfdisk /dev/rdisk0s1

To obtain the current list of partitions :

gptfdisk>p

This will print the current partition configuration. On the second line, we can see that /dev/rdisk0s1 has a total capacity of 7815175 sectors. The third line tells us that our logical sector size is 8192, so each sectors have a size of 8192 bytes. We can calculate the size in bytes of /dev/rdisk0s1 by multiplicating the number of sectors by the logical sector size.

7815175 * 8192 = 64021913600 bytes

/dev/rdisk0s1 : 64021913600 bytes

Now, let's calculate the System partition size. There's something important to consider, we must calculate that according to the size we plan to set for the partition.

The new size you will give to the System partition depends of your post-exploitation plans. If you think about installing different iOS versions, I suggest you set a size of 3.2 GB. This will allow you to flash most root filesystem .dmg images including iOS 9 ones and having some space for jailbreaking if you plan to.

1 GB = 1024 * 1024 * 1024 = 1073741824 bytes

3.2 GB = 3.2 * 1073741824 = 3435973836,8

Divide it by [block size] value :

3435973836,8 / 8192 = 419430,4 logical sectors

Remove decimal part, to keep an integer logical sectors number :

419430,4 -> 419430

Convert it back to bytes :

419430 * 8192 = 3435970560 bytes

/dev/rdisk0s1s1 (System) : 3435970560 bytes

Calculate the exploitation partition size. A third partition which contains an invalid HFS+ filesystem is used to trigger the exploit once iBoot tries to mount it. There must be some available space for it right after the Data partition. To define the size of that third partition, we must consider the amount of RAM memory our device has, then add 128 MB to that value.

The iPad 2nd has 512 MB of RAM, so the ideal size of this partition would be around 512 MB + 128 MB = 640 MB.

1 MB = 1024 * 1024 = 1048576 bytes

640 MB = 1048576 * 640 = 671088640bytes

/dev/rdisk0s1s3 (Exploit) : 671088640

Finally, calculate the size in bytes of the Data partition. Our Data partition will fit into the remaining space of the whole disk minus System and Exploit partition.

64021913600 (/dev/rdisk0s1) - 3435970560 (/dev/rdisk0s1s1) - 671088640 (/dev/rdisk0s1s3) = 59914854400 bytes (/dev/rdisk0s1s2)

/dev/rdisk0s1s2 (Data) : 59914854400 bytes (55.8 GB)

According to the partition sizes we have calculated previously, resize the data partition LwVM container. The iOS device I'm working on for this writeup is an iPad 2nd (K48AP) 64 GB.

Initial size of data partition for iOS 5.0.1 on this device is 58.1 GB.



We will use hfs_resize to shrink the LwVM container of the data partition. This will free up some space for a tiny additional partition that we will use to trigger the exploit.

iPad-k48ap#hfs_resize [mount point] [capacity in bytes]

The mount point is the folder where your disk device is mounted. For iOS, the data partition is always mounted in /private/var of the root filesystem. We already have calculated the new size of our Data partition, 59914854400 bytes. Our command to reduce the data partition would be like this.

iPad-k48ap#hfs_resize /private/var/ 59914854400

If you look into your device settings, you should see that capacity has been reduced to 55.8 GB.



We are now ready to adjust the size of partitions within the GPT. To partition an iOS device disk which uses LwVM + GPT, we will use gptfdisk. This tool will allows us to edit the GPT partition table stored on /dev/rdisk0s1, then changes will be written back to the LwVM partition table stored on /dev/rdisk0.

Execute gptfdisk with the disk volume rdisk0s1 as argument.

iPad-k94ap#gptfdisk /dev/rdisk0s1

Partitionning on iOS is very limited compared to most other systems. To resize a partition, you have to delete it first, then recreate it. The issue with that is when the partition is deleted, properties and attributes are lost as well. If you simply recreate the partitions without original properties and attributes, you will get a bootloop.

In order to recreate the partitions with the same properties and attributes they had before deleting them, we can display informations about our current partitions with the following command.

gptfdisk>i [enter]

1 [enter]

gptfdisk>i [enter]

2 [enter]

Write down in a text file the following information. Before delete existing partitions, we must see which attributes flags are set. We currently know that for System partition we have attribute flags value 0000000000000000 set and for Data we have 0001000000000000 value set, but this not really significative.

Go into gptfdisk expert mode, then show attributes for partition 1.

gptfdisk>x [enter]

a [enter]

1 [enter]

[CTRL+C]

You see that there is no attributes fields set for iOS 5.0.1 System partition. Do the same for partition 2.

a [enter]

2 [enter]

[CTRL+C]

There is only bit 48 set as attribute field or the Data partition, remember this value. Go back to gptfdisk basic mode.

gptfdisk>m [enter]

Delete the Data partition :

gptfdisk>d [enter]

2 [enter]

Delete the System partition :

gptfdisk>d [enter]

1 [enter]

Note that the partition aren't officially deleted until you write changes.



Re-create the System partition with the new size you want it to be. I will set it to 3.2 GB, as mentioned before in this writeup.

gptfdisk>n [enter]

The first sector should be keep as default.

[enter]

The last sector is where the partition must ends on the logical disk. We already know how much logical sectors our resized System partition will use, we calculated it previously. Our number of logical sectors for System partition is 419430.

Add the default first sector value (this number is the currently allocated number of blocks) : 419430 + 4 = 419434 and give this value to GPTfdisk.

[enter]

Keep the default Hex code.

[enter]

Eventually, we will resize the LwVM container of the System partition using hfs_resize to fit the size set on the GPT.

Set System as partition name :

gptfdisk>c [enter]

1 [enter]

System [enter]

The original System partition had no attribute fields set, so we have no changes to do there as they are all set to 0 by default. We now have to restore the original System partition GUID.

Go to gptfdisk expert mode.

gptfdisk>x [enter]

Enter the following commands to restore the partition GUID.

c [enter]

1 [enter]

[GUID] [enter]

Go back to gptfdisk basic mode.

gptfdisk>m [enter]

Re-create the data partition with the same size that you set previously using hfs_resize. It was 59914854400 bytes (55.8 GB) for my 64 GB iPad 2nd.

gptfdisk>n [enter]

The first sector should be keep as default.

[enter]

Take the size you have previously set in hfs_resize, then do the following maths.

Divide it by [block size] value :

59914854400 / 8192 = 7313825 blocks

Add the default first sector value (this number is the currently allocated number of blocks) : 419436 + 7313825 = 7733261

Give this value to GPTfdisk.

[enter]

Keep the default Hex code.

[enter]

Rename the recreated partition to Data.

gptfdisk>c [enter] 2 [enter] Data [enter]

Verify that everything is right with the recreated partition :

gptfdisk>p [enter]

Seems all good, now let's restore Data partition attributes and properties.

The original Data partition had some attribute flags set to on. In order to make the recreated partition same as it was and avoid disk issues, we will put these flags to on for it.

Be sure you are in gptfdisk expert mode.

a [enter]

2 [enter]

48 [enter][enter]

Enter the following commands to restore the partition GUID.

c [enter]

2 [enter]

[GUID] [enter]

Our data partition is now completely resized, time to verify we did it right before write the stuff to the GPT. Go back to gptfdisk basic mode :

gptfdisk>m [enter]

Verify that the data partition as been properly recreated and that is has the right size :

gptfdisk>p [enter]

Now the most dangerous thing of this writeup ever, write partition changes to disk.

gptfdisk>w [enter]

y [enter]

When new partition configuration is written, synchronize a few times :

iPad-k94ap# sync; iPad-k94ap# sync; iPad-k94ap# sync;

Shortly after the new partition configuration is written, your device might become unstable or completely frozen. Don't worry, a simple reboot (or hard reset if you can't reboot normally) should bring your device back to a working state.



Execute gptfdisk with the disk volume rdisk0s1 as argument.

iPad-k94ap#gptfdisk /dev/rdisk0s1

verify that our current partitions were properly resized.

gptfdisk>p

You should see that System has 3.2 GB size and Data has 55.8 GB size.

Outside gptfdisk, you will notice that our System partition still has 1.6 GB total capacity but we set it to 3.2 GB using gptfdisk. iPad-k94ap#df -h The reason of why some space is still unallocated is that we only have resized the partition within the GPT, not the LwVM container itself. Using hfs_resize, we can grow up the LwVM container according to the unallocated space we have in the GPT partition. Note that the maximum size we can set must be lower or equal than the size we allocated to the partition created using gptfdisk.

We previously set /dev/rdisk0s1s1 (System) to 3435970560 bytes.

iPad-k94ap#hfs_resize / 3435970560

Check using df command that we now have the desired size. Now let's create the exploitation partition. Execute again gptfdisk with the disk volume rdisk0s1 as argument.

iPad-k94ap#gptfdisk /dev/rdisk0s1

Default partition table can only hold two partitions, we will expand it to allow creating more partitions.

gptfdisk>x [enter]

s [enter]

4 [enter]

The partition table should now accepts more than two partitions. We will now create a third partition called Exploit.

gptfdisk>n [enter]

3 [enter]

Keep default first sector [enter]

We calculated previously the size of this new partition, the size we set was 671088640 bytes.

Divide it by [block size] value to obtain how many logical sectors will be required.

671088640 bytes / 8192 = 81920 sectors needed.

Add those sectors to the minimal sector position we can set for the new partition.

7733264 + 81920 = 7815184‬

The last sector number we calculated for our partition at the last position might be greater than the maximum last sector value allowed by gptfdisk for our current partition configuration. This is expected, because we did not include the sectors used for storing partition configuration when we calculated sizes at the beginning. This is also very important to keep at least five unused sectors from the maximum last sector value allowed by gptfdisk for the last partition because gptfdisk or LwVM might not apply the changes.

Give this value to gptfdisk

[enter]

Keep the default Hex code.

[enter]

Rename the recreated partition to "Exploit" :

gptfdisk>c [enter]

3 [enter]

Exploit [enter]

This new partition does not need any special attributes, so we are ready to write it to disk.

gptfdisk>w [enter]

y [enter]

When new partition configuration is written, synchronize a few times :

iPad-k94ap# sync

iPad-k94ap# sync

iPad-k94ap# sync

Verify that new disk devices were properly created :

iPad-k94ap#ls /dev/ | grep rdisk

You should see exactly five disk devices.

> Part 6: Set HFSReadBlock() wrapper