360 Security Guard · 2015/07/24 14:33

Proteas of 360 NirvanTeam

0 x00 preface


Recently, it was found that someone would share a video link in the wechat group. When the user of apple device clicks this video link to play the video, the Apple device will restart. After this problem was discovered, [email protected] analysis was performed on non-jailbroken iPhone devices iOS 8.0.2, iOS 8.4, iOS 8.4.1 Beta 1 and iOS 9 Beta 3. The blue screen of death and the restart of the device were all caused by 0Day. Decided to analyze the causes of iPhone blue screen in detail.

Through the detailed analysis of arm64-bit kernel dump and Panic Log, it was determined that the crash occurred in kernel extension applevXd393. kext. The kernel extension is mainly used to decode video frames, which leads to the exploit of the vulnerability caused by: dereferencing the null pointer without checking the validity of the pointer; In addition, during the analysis, we found another exploit of 0Day in this extension module, which has been submitted to Apple official for confirmation.

In order to facilitate the test, we first wrote a simple App to facilitate the test and trigger the system crash, which will lead to blue screen restart as shown in the following figure (video demonstration: http://v.youku.com/v_show/id_XMTI5MTgzNjc2NA), and in order to locate the module and specific code where the kernel crash occurred, detailed analysis will be made below.

0x01 Vulnerability Impact


  1. This DoS affects non-jailbroken devices and, combined with the test devices and reverse analysis at hand, affects all 64-bit devices above iOS 8: iPhone 5S, iPhone 6, iPhone 6 Plus, iPad Air, iPad Mini, etc.
  2. If you use a website or a platform, you can create a massive denial of service.

0x02 Write programs that aid crashes


Since we may need to cause several kernel crashes in the analysis process, it would be troublesome and unreasonable to trigger the crash from wechat every time, so we need to obtain the video first and then use our own program to play the video.

This program is very simple, run the interface as shown below:

Clicking on “Play Video” will activate the player to Play the corresponding Video, causing the system to crash. So there’s a little bit of a problem here, because we used to play all the videos using MPMoviePlayerController, but the MPMoviePlayerController is still loading the whole time it’s playing the video in question, so instead of playing the video with AVPlayer, In order to facilitate you to build Demo test, give the corresponding code of “Play Video” :

#! Java @implementation ViewController - (void)viewDidLoad {[super viewDidLoad]; self.view.backgroundColor = [UIColor lightGrayColor]; UIButton *playBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect]; Playbtn. frame = CGRectMake(40.0f, 40.0f, 200.0f, 48.0f); playBtn.center = self.view.center; playBtn.backgroundColor = [UIColor darkGrayColor]; [playBtn setTitle:@"Play Video" forState:UIControlStateNormal]; [playBtn setTitle:@"Play Video" forState:UIControlStateHighlighted]; PlayBtn. TitleLabel. The font = [UIFont systemFontOfSize: 32.0 f]; [playBtn addTarget:self action:@selector(onPlayButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:playBtn]; } / / prevent interface screen rotation disorder, affect the mood - (NSUInteger) supportedInterfaceOrientations {return UIInterfaceOrientationMaskPortrait; } // Response button click, (void)onPlayButtonClicked (UIButton *)aSender {NSString *videoPath = [[NSBundle mainBundle] pathForResource:@"crash" ofType:@"mp4"]; self.avPlayer = [AVPlayer playerWithURL:[NSURL fileURLWithPath:videoPath]]; AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer]; self.avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone; playerLayer.frame = self.view.bounds; [self.view.layer addSublayer: playerLayer]; [self.avPlayer play]; } @endCopy the code

0x03 Locate the Crash Point and related modules


First, the video is played. The system crashes. After the device is restarted, the crash log is read from the device.

The important values in the figure above have been circled, where PC and LR are used to locate the crash point. In addition, the kernel slide is also very important, because the register values in the figure above are the values after the slide, and the slide changes every time it starts (KASLR). We need to convert the actual address first:

pc = 0xffffff80020c92e0 = 0xffffff800e2c92e0 - 0x000000000c200000 
lr = 0xffffff8003043a58 = 0xffffff800f243a58 - 0x000000000c200000
Copy the code

After obtaining the actual crash address, we dump the kernel (since there is no arm64 kernel that can be decrypted yet) :

[+] kernel slide: 0x2000000
[+] kernel start: 0xffffff8004002000
[+] vm perm value: 0x9d46a8bdc73a4755
Copy the code

We can see that the value of slide is different from that of the kernel slide when it crashes. Next, we convert the crash address to the kernel currently dumped:

pc = 0xffffff80040c92e0 = 0xffffff80020c92e0 + 0x2000000
lr = 0xffffff8005043a58 = 0xffffff8003043a58 + 0x2000000
Copy the code

Then in IDA Pro, the PC points to the following address:

LR points to the following figure:

From the crash log, it can be seen that x0 = 0x0000000000000000 crashed, and it can be determined that the crash was caused by dereferencing the null pointer, i.e., no validation of the entry parameter.

We know that the iOS kernel (XNU) itself does not contain video processing related functions, video related functions are basically handled by a kernel extension, so we need to find out which kernel extension is the problem.

Fortunately, the address to which LR points contains information about the kernel extension:

If AppleVXD393 is used as a kernel extension, the kernel extension can be used as a kernel extension.

You can see that we have found the relevant kernel extensions.

Since it is now possible to decrypt the newer armV7 kernels, the kernel extension was not found in the relevant kernels, and the kernel did not crash when tested playing video on armV7 devices in iOS 7.x. Given the information, this problem may only affect ARM64 devices.

0x04 Determines the module in user space that calls the AppleVXD393 service


First, we need to determine whether the kernel extension is used in the sandbox. After testing, we find that the kernel extension is not called in the sandbox. Now we need to determine which module is using the service. When calling the kernel extended service, it is necessary to obtain the service according to the service name, so grep the iOS 8.0.2 system library and get the following information:

Grep -r "AppleVXD393 _cached - dyld/v8.0.2 / libraries - arm64 Binary file MediaToolbox. The framework/MediaToolbox matches Binary  file VideoToolbox.framework/VideoToolbox matches Binary file VideoDecoders/MP4VH6.videodecoder matchesCopy the code

Videodecoder is more interesting because of the crash caused by playing MP4VH6. Grep MP4VH6 gets the following information:

Grep -r "MP4VH6 _cached - dyld/v8.0.2 / libraries - arm64 Binary file VideoToolbox. The framework/VideoToolbox matches Binary file  VideoDecoders/MP4VH6.videodecoder matchesCopy the code

Combined with the disassembly analysis of VideoToolBox, we can know that VideoToolBox uses MP4vH6. videodecoder to do MP4 decoding. Drag mp4vH6. videodecoder into IDA Pro and view the exported table:

Can see AppleVXD393 related function, MP4VH6 videodecoder should encapsulate the kernel extensions com. Apple. Driver. AppleVXD393 user space interface.

0x05 Determine video decoding service


Through the above analysis we already know: 1. MP4VH6. Videodecoder encapsulates the user space interface of the video decoding service; 2. Videotoolbox. framework directly calls MP4vh6.videodecoder. Next, we need to know which background process provides video decoding service through XPC, ps + grep:

ps aux |grep media
mobile     214   MusicLibrary.framework/Support/medialibraryd
mobile     119   /usr/sbin/mediaserverd
mobile     117   MediaRemote.framework/Support/mediaremoted
Copy the code

Since all XPC services require checkin, we reverse analyze these three programs and find that Mediaserverd checkin the following two services:

com.apple.mediaserverd
com.apple.audio.SystemSounds
Copy the code

Mediaserverd might be the back-end service we’re looking for. To verify this, I tested mediaserverd. After the breakpoint hit, I got the following message:

(lldb) x/s $x0
0x19368065f: "AppleVXD393"
(lldb) bt
* thread #16: tid = 0x21cb, IOKit`IOServiceMatching
  * frame #0:  IOKit`IOServiceMatching
    frame #1: H264H6.videodecoder`AppleVXD393CheckPlatform + 60
    frame #2: H264H6.videodecoder`H264H6Register + 16
    frame #3: VideoToolbox`VTLoadVideoDecoders + 168
    frame #4: libsystem_pthread.dylib`__pthread_once_handler + 80
    frame #5: libsystem_platform.dylib`_os_once + 56
    frame #6: libsystem_pthread.dylib`pthread_once + 76
    frame #7: VideoToolbox`VTSelectAndCreateVideoDecoderInstanceInternal + 136
    frame #8: VideoToolbox`VTSelectAndCreateVideoDecoderInstance + 44
    frame #9: MediaToolbox`FPSupport_GetDefaultTrackIDForMediaType + 428
    frame #10: MediaToolbox`itemfig_setBasicInspectables + 808
    frame #11: MediaToolbox`itemfig_retrieveAssetBasicsIfReady + 276
    frame #12: MediaToolbox`itemfig_assetPropertyLoaded + 324
Copy the code

So far, it has been confirmed that Mediaserverd is responsible for providing the video decoding service, and we can get a general idea of the architecture of the video decoding function on iOS platform.

0x06 Analyzing controllability


First take a look at the call stack when decoding the video:

(lldb) bt
* thread #19: tid = 0x2020,  IOKit`IOConnectCallMethod
  * frame #0: IOKit`IOConnectCallMethod
    frame #1: IOKit`IOConnectCallStructMethod + 52
    frame #2: MP4VH6.videodecoder`AppleVXD393DecodeFrameInternal + 428
    frame #3: MP4VH6.videodecoder`AppleVXD393DecodeFrame + 1264
    frame #4: MP4VH6.videodecoder`AppleVXD393WrapperMPEG4DecoderDecodeFrame + 728
    frame #5: VideoToolbox`vtDecompressionDuctDecodeSingleFrame + 348
    frame #6: VideoToolbox`VTDecompressionSessionDecodeFrame + 440
    frame #7: MediaToolbox`vmc2DecodeUntilHighWaterMet + 3308
    frame #8: MediaToolbox`activitySchedulerOnThread + 72
    frame #9: CoreMedia`figThreadMain + 248
    frame #10: libsystem_pthread.dylib`_pthread_body + 164
    frame #11: libsystem_pthread.dylib`_pthread_start + 160
Copy the code

In order to determine the controllability, then wrote a Tweak to Hook mediaserverd, and Hook IOConnectCallStructMethod, found that after the video decoding frame number and the cause of the kernel crash video frame number is consistent, the modification to the kernel decoding data, View and compare crash logs to summarize the impact of inputs on register values at crash time. The buffer is filled with the following tests:

Buffer fill test, 0x00 vs. 0x01:

You can see that the PC registers are different, indicating that the code path is not the same. When filling the buffer 0x01, the kernel crashes:

Buffer fill test, 0x01 vs. 0x02:

You can see that some bits of x0 are controllable, x12, x13 are loaded from the address that x1 points to. So far has completed the analysis of the problem, as for the use of each of us.

0 x07 other


1. Processed video containing only a single frame,

Link: http://yunpan.cn/cc5KWG7p368yN

Extraction code: 4E17

MD5: f4260553b0628f2e6bbb88e2c7b124e6

Second, if you have ideas, please follow the weibo exchange: @nirvanteam

In addition, if you are interested in iOS security development, vulnerability analysis and mining, please contact us at [email protected]@360.cn.