Goal Reached Thanks to every supporter — we hit 100%!

Goal: 1000 CNY · Raised: 1000 CNY

100.0%

CVE-2018-4185 PoC — 多款Apple产品Kernel 信息泄露漏洞

Source
Associated Vulnerability
Title:多款Apple产品Kernel 信息泄露漏洞 (CVE-2018-4185)
Description:Apple iOS、tvOS、watchOS和macOS High Sierra都是美国苹果(Apple)公司的产品。Apple iOS是为移动设备所开发的一套操作系统;tvOS是一套智能电视操作系统;watchOS是一套智能手表操作系统;macOS High Sierra是为Mac计算机所开发的一套专用操作系统。Kernel是其中的一个内核组件。 多款Apple产品中的Kernel组件的程序状态转换存在信息泄露漏洞。攻击者可借助恶意的应用程序利用该漏洞确定内核内存布局。以下产品和版本受到影响:Apple
Description
CVE-2018-4185: iOS 11.2-11.2.6 kernel pointer disclosure introduced by Apple's Meltdown mitigation.
Readme
x18-leak
===================================================================================================

iOS 11.2 introduced a kernel information leak that could be used to determine the kASLR slide. The
issue was the result of a newly added feature, `__ARM_KERNEL_PROTECT__`, that inadvertently caused
the address of the kernel function `Lel0_synchronous_vector_64_long` to appear in register `x18`
when obtaining the values of a thread's registers using `thread_get_state`. The issue was
discovered when kernel pointers started appearing in iOS application crash logs.


The vulnerability
---------------------------------------------------------------------------------------------------

In iOS 11.2, Apple introduced a feature on arm64 called `__ARM_KERNEL_PROTECT__`. According to a
comment in [`osfmk/arm64/proc_reg.h`][proc_reg.h]:

[proc_reg.h]: https://opensource.apple.com/source/xnu/xnu-4570.31.3/osfmk/arm64/proc_reg.h.auto.html

	__ARM_KERNEL_PROTECT__ is a feature intended to guard against potential
	architectural or microarchitectural vulnerabilities that could allow cores to
	read/access EL1-only mappings while in EL0 mode.  This is achieved by
	removing as many mappings as possible when the core transitions to EL0 mode
	from EL1 mode, and restoring those mappings when the core transitions to EL1
	mode from EL0 mode.

That is, when transitioning from EL1 (kernel mode) to EL0 (user mode), as many kernel mappings as
possible will be removed. This should limit the possible attack surface against kernel memory
mappings when exploiting microarchitectural vulnerabilities like Spectre or Meltdown.

If you look through the diff between XNU versions 4570.20.62 and 4570.31.3, you'll find a number of
new references to register `x18` pop up in the file [`osfmk/arm64/locore.s`][XNU 4570.31.3
locore.s] in relation to `__ARM_KERNEL_PROTECT__`. In particular, you'll see that the exception
vector `Lel0_synchronous_vector_64`, which is the exception vector invoked on a system call
(instruction `svc #0`), now looks like this:

[XNU 4570.31.3 locore.s]: https://opensource.apple.com/source/xnu/xnu-4570.31.3/osfmk/arm64/locore.s.auto.html

```assembly
	.text
	.align 7
Lel0_synchronous_vector_64:
	MAP_KERNEL
	BRANCH_TO_KVA_VECTOR Lel0_synchronous_vector_64_long, 8
```

The macro `BRANCH_TO_KVA_VECTOR` is defined as:

```assembly
.macro BRANCH_TO_KVA_VECTOR
#if __ARM_KERNEL_PROTECT__
	/*
	 * Find the kernelcache table for the exception vectors by accessing
	 * the per-CPU data.
	 */
	mrs		x18, TPIDR_EL1
	ldr		x18, [x18, ACT_CPUDATAP]
	ldr		x18, [x18, CPU_EXC_VECTORS]

	/*
	 * Get the handler for this exception and jump to it.
	 */
	ldr		x18, [x18, #($1 << 3)]
	br		x18
#else
	b		$0
#endif /* __ARM_KERNEL_PROTECT__ */
.endmacro
```

This macro performs an indirect branch to the true exception vector implementation,
`Lel0_synchronous_vector_64_long`, by loading a pointer to that function into the register `x18`.
Notice, however, that this clobber of `x18` happens before the userspace registers are saved by the
function `fleh_dispatch64`, which is called by `Lel0_synchronous_vector_64_long`. This means that
when the user registers are saved, `x18` will actually be a pointer to
`Lel0_synchronous_vector_64_long` rather than the original value from userspace.

Even though `x18` is cleared on exception return, storing a kernel pointer in the user register
state is problematic because `thread_get_state` can be used to copy the saved user register state
back to userspace, including the value of register `x18`. All a thread needs to do in order to
obtain the address of the `Lel0_synchronous_vector_64_long` function is call `thread_get_state` on
itself and look at the reported value of `x18`. This makes it trivial to determine the kASLR slide
by subtracting the value of `x18` thus obtained by the static address of
`Lel0_synchronous_vector_64_long`.


Exploitation
---------------------------------------------------------------------------------------------------

As mentioned above, exploitation is trivial: simply call the function `thread_get_state`, look at
the value for register `x18`, and subtract from it the static address of the kernel function
`Lel0_synchronous_vector_64_long`.


Discovery
---------------------------------------------------------------------------------------------------

I discovered this issue on February 26, 2018, after noticing a kernel pointer in register `x18` of
an iOS application crash log. A quick check showed that the same value appeared in register `x18`
of every crash log on the device, which suggested a serious information leak.

I next tried to determine what exactly was going on with register `x18` through experimentation. I
set a breakpoint in an empty iOS app and used lldb to read the value of register `x18`, confirming
that the leak was not restricted to crashing applications. Next I tried to read the value of `x18`
using inline assembly and found that the value obtained did not match the value shown by the
debugger when using a command like `reg read x18`. This suggested that perhaps the leak was really
in `thread_get_state`, and that register `x18` didn't truly contain a kernel pointer while the CPU
was executing in userspace. A quick proof-of-concept that read the value of `x18` using
`thread_get_state` confirmed that this function was indeed the source of the leak.


Timeline
---------------------------------------------------------------------------------------------------

I reported the issue to Apple on February 26, 2018, the same day I discovered it.


---------------------------------------------------------------------------------------------------
By Brandon Azad
File Snapshot

[4.0K] /data/pocs/3355620e25eee19f615d6e546f72487472823259 ├── [5.6K] README.md ├── [4.0K] x18-leak │   ├── [ 281] AppDelegate.h │   ├── [2.1K] AppDelegate.m │   ├── [4.0K] Assets.xcassets │   │   └── [4.0K] AppIcon.appiconset │   │   └── [1.5K] Contents.json │   ├── [4.0K] Base.lproj │   │   ├── [1.6K] LaunchScreen.storyboard │   │   └── [1.6K] Main.storyboard │   ├── [1.4K] Info.plist │   ├── [ 329] main.m │   ├── [ 219] ViewController.h │   ├── [ 488] ViewController.m │   ├── [3.6K] x18_leak.c │   └── [ 309] x18_leak.h └── [4.0K] x18-leak.xcodeproj ├── [ 13K] project.pbxproj └── [4.0K] project.xcworkspace └── [ 153] contents.xcworkspacedata 6 directories, 14 files
Shenlong Bot has cached this for you
Remarks
    1. It is advised to access via the original source first.
    2. If the original source is unavailable, please email f.jinxu#gmail.com for a local snapshot (replace # with @).
    3. Shenlong has snapshotted the POC code for you. To support long-term maintenance, please consider donating. Thank you for your support.