An analysis of iOS 5 OTA updates by @innoying

With iOS 5 Apple added some interesting new technology, over the air updates. Although they are not the first to do this, they happen to have done it very well. Or so it would appear from the outside. Actually, the truth offers a somewhat different story. Here is my attempts at reversing the OTA update process and my explanation of one of the exploits I found as a result.

First, we must find out who, what, and how the iOS devices checks for and downloads OTA updates. Unfortunately, as is becoming alarmingly common, the OTA updates components in iOS ignore the system-wide proxy settings. These settings allow easy access to debug connections made by a device and begin the process of reversing it. It’s seems as though Apple is making it’s system Applications ignore these settings more and more often. If this is intentional or not, it forces us to find another way analyze the internal workings. 

So I turned to DNS Spoofing. DNS Spoofing is a method of returning modified DNS information to devices with the intent to re-direct traffic. In this case I used dnsmasq to redirect all requests to any site to my mac which was acting as a server. I then used a combination of Apache with custom logging enabled and a node.js debugging server to find the protocols and locations of the required resources.

As it turns out, it’s just HTTP requests. The alarm bells should be going off now. So you’re telling me that the part of the O.S. that runs as root and replaces system files is downloaded via unsecured, unauthenticated HTTP? Yup.

So in my reversing of the connections made by the OTA updates software I discovered the internal URLs used for all OTA update files. So lets start with the basics, the “documentation.” The documentation files are what the user is presented with during the course of the OTA update files. This includes the license, description, title, etc. 

The OTA update components get this information from http://mesu.apple.com/assets/com_apple_MobileAsset_SoftwareUpdateDocumentation/com_apple_MobileAsset_SoftwareUpdateDocumentation.xml which contains the list of documentation files linked to firmware versions. The file is a Apple plist served using the xml mime-type (a plist is a type of xml file). The structure of the file is this:

Root (plist)>
	Assets (array)>
		Device (string)
		OSVersion (string)
		_DownloadSize (integer)
		_MasteredVersion (string)
		_Measurement (base 64 encoded data)
		_MeasurementAlgorithm (string)
		_UnarchivedSize (integer)
		__BaseURL (string)
		__RelativePath (string)
	Certificate (base 64 encoded data)
	FormatVersion (integer)
	LastRefreshed (date)
	Signature (base 64 encoded data)
	SigningKey (string)

I have attempted to explain, to the best of my knowledge, each of these keys below:

Device: The device "model" being either "iPad", "iPod" or "iPhone"
OSVersion: The version number of the new OS.
_DownloadSize: The size of the zipped downloaded in bits
_MasteredVersion: Unknown. Probably a internal marker of which revision of some type.
_Measurement: The checksum value of the downloaded zip file. Checksum type is dictated by _MeasurementAlgoritm
_MeasurementAlgorithm: The algorithm used to calculate _Measurement
_UnarchivedSize: The  rough estimate size of the download after un-zipped. This is used to check that enough free-space is available before download.
__BaseURL: The first half of the URL. It is prepended to __RelativePath to create the full download URL.
__RelativePath: The second half of the URL. It is appended to __BaseURL to create the full download URL. It is also used to define the download location on device. 
Certificate: The OTA certificate. I believe it is here to use as a check against the on-device copy to verify that is has not changed.
FormatVersion: The version of the format used in the file.
Signature: The signature of the entire file that is checked using the certificate on-device defined by SigningKey
SigningKey: The name of the certificate used to create the Signature that is used to verify the authenticity of the file

After some more research I concluded it was not possible to modify that file nor to spoof a fake download due to the measurement checksum checks. Next I began to look at the documentation file itself. By combining the __BaseURL and __RelativePath manually one can create the url needed to download a documentation file. After downloading a iPod documentation file, I was pleased to find it was a simple, un-encrypted zip file.

Within the file I found this file tree:

AssetData/*.lproj/documentation.strings
AssetData/*.lproj/License.html
AssetData/*.lproj/ReadMe.html
AssetData/*.lproj/ReadMeSummary.html
Info.plist
version.plist

The * represents the different Apple language codes/names. The documents within that folder contain the translations in the language described in the folder title. Now, to analysis the files. I’d like to start with version.plist. It’s structure is the following:

Root (plist)>
	BuildVersion (string)
	CFBundleShortVersionString (string)
	ProjectName (string)
	SourceVersion (string)

From what I can tell this file is unused on-device and appears to be left there for convenience or another purpose. So we move on the Info.plist. It’s structure is the following:

Root (plist)>
	CFBundleIdentifier (string)
	CFBundleName (string)
	CFBundleDevelopmentRegion (string)
	CFBundleInfoDictionaryVersion (string)
	CFBundleShortVersionString (string) 
	MobileAssetProperties (dictionary)>
		OSVersion (string)
		Device (string)

The file would appear to be a standard Info.plist with the addition of the MobileAssetProperties dictionary. This dictionary appears to have the same values containing the new software version number and device. So I looked at AssetsData/*.lproj/documentation.strings next. It is in standard .strings format and contains 1 definition. The file sets the “HumanReadableUpdateName” which is displayed at the header of the OTA settings panel. The remaining files serve a similar purpose and are pretty self-explanatory.

Now here’s a little trick I figured out to help me understand what exactly was happening during OTA update install. Due to filesystem checks (which are explained later) it is difficult to install an OTA update while jailbroken. To get around this annoying check, one can download a OTA update, not install, then jailbreak and examine the files. This was the method used to do a good portion of the research within…

Using the above method one can also modify certain files once jailbroken. As a little experiment you can edit files within /var/mobile/Library/Assets/com_apple_MobileAsset_SoftwareUpdateDocumentation/ to produce OTA updates for iOS 6 or whatever one may desire.

Also using the above method I discovered that the file is initially downloaded /var/mobile/Library/Assets/com_apple_MobileAsset_SoftwareUpdateDocumentation/com_apple_MobileAsset_SoftwareUpdateDocumentation.xml then stripped of all information not pertaining to the current device and re-saved to com_apple_MobileAsset_SoftwareUpdateDocumentation.plist

I then moved on to the OTA updates themselves. They are fetched from http://mesu.apple.com/assets/com_apple_MobileAsset_SoftwareUpdate/com_apple_MobileAsset_SoftwareUpdate.xml for use. The structure is very similar to the documentation file with a few modifications:

Root (plist)>
	Assets (array)>
		Build (string)
		InstallationSize (string)
		MinimumSystemPartition (integer)
		OSVersion (string)
		PrerequisiteBuild (string)
		PrerequisiteOSVersion (string)
		SUProductSystemName (string)
		SUPublisher (string)
		SupportedDevices (array) >
			Device (string)
		SystemPartitionPadding (dictionary) >
			16 (integer)
			32 (integer)
			8 (integer)
		_DownloadSize (integer)
		_Measurement (base 64 encoded data)
		_MeasurementAlgorithm (string)
		_UnarchivedSize (integer)
		__BaseURL (string)
		__RelativePath (string)
	Certificate (base 64 encoded data)
	FormatVersion (integer)
	LastRefreshed (date)
	Signature (base 64 encoded data)
	SigningKey (string)

Unless otherwise stated the definitions are the same as the documentation file:

Build: Build name/id
InstallationSize: Finished installation size
MinimumSystemPartition: The required partition size before continuing.
PrerequisiteBuild: The needed Build for install
PrerequisiteOSVersion: The needed OS version for install
SU*: Standard Apple plist stuff
SupportedDevices: The devices this update supports
SystemPartitionPadding: No clue. Maybe space on flash that root is padded

The rest is self explanatory if not mentioned above. So now the final important part. The actual update. I’ll start with the file. Using the combined __BaseURL and __RelativePath we can construct the URL to download. If we download one of theses files we will find it i a un-uncrypted zip file. Now this is interesting. Apple tends to avoid un-encrypted system stuff as it can make exploiting stuff easier. They must have decided against this to keep files size and processing intensity down.

Once we decrypt this file, which is saved (once unzipped) to /var/mobile/Library/Assets/com_apple_MobileAsset_SoftwareUpdate/*.asset, we can discover how OTA updates work. The unzipped file follows the following structure:

Root>
	AssetData>
		Info.plist
		boot>
			*.dmg
			BuildManifest.plist
			Firmware>
				all_flash>
					(standard ipsw format files)
				dfu>
					(standard ipsw format files)
				usr>
					(standard ipsw format files)
			kernelcache.release.*
		payload>
			patches>
				(actual path on device)/*.patch
			replace>
				(actual path on device)/(actual new replacement file)
			added>
				(actual path on device)/(actual new file)
		payload.bom
		payload.bom.signature
		post.bom
		pre.bom
	Info.plist

The root Info.plist file appears to be the same as the documentation Info.plist in use. The Info.plist file within AssetData contains the information about specifics of the update.

Now the boot folder very closely resembles the folder within ipsw firmware files. It contains applelogo and similar files.

The payload folder contains the filesystem modifications to make. The patches folder contains patches in BSDiff format. The added and replace sub-folders contain the new files instead of BSDiffs.

The authenticity of the payload folder is checked by payload.bom. The file is in the Mac OSX bill of materials format. Using a Mac one can list the contents of this file using the `lsbom` utility. It contains checksums, permissions, etc that are checked. It also checks the authenticity of pre.bom and post.bom.

The authenticity of payload.bom is verified by payload.bom.signature which is the signature of the payload.bom file that is checked against the internal certificates.

The pre.bom and post.bom contain snapshots of how the root filesystem should look before and after installation. This is what prevents users from installing OTA updates with a jailbroken device.

I hope this helps anybody who was or is interested in how OTA updates work. Use this knowledge for good not evil. If you do find any security bugs as a result of this research I would suggest you send those bugs to a jailbreak development team (either chronic-dev or iphone-dev) to help further jailbreaks that make research like this possible.

Notes

  1. innoying posted this