Skip to content

UAF on iconv filter failure #17047

Closed
Closed
@chongwick

Description

@chongwick

Description

The following code:

<?php
define('FILTER_LENGTH', 0x10000000);
require "template.inc";

function reference() {
    static $x = PHP_INT_MAX;
    return $x;
}

function echo_fatal_error() {
    echo PHP_INT_MIN ^ PHP_INT_MAX ^ PHP_FLOAT_MAX ^ PHP_FLOAT_MIN;
    throw new Exception("Fatal error");
}

function __f_1() {
    $foo = function() use (&$x) {
        return $x;
    };
    $x = reference();
    $stream = fopen('php://temp', 'w+');
    stream_filter_append($stream,'string.toupper');
    stream_filter_append($stream,'string.rot13');
    stream_filter_append($stream, 'convert.iconv.UTF-8.UTF-16BE');
    stream_filter_append($stream, 'convert.iconv.UTF-16BE.UTF-16LE');
    stream_filter_append($stream, 'convert.iconv.UTF-16LE.UTF-8');
    stream_filter_append($stream, 'convert.iconv.UTF-8.UTF-16BE', FILTER_LENGTH);
    stream_filter_append($stream, 'convert.iconv.UTF-16LE.UTF-16BE', FILTER_LENGTH);
    stream_filter_append($stream, 'convert.iconv.UTF-16LE.UTF-8', FILTER_LENGTH);
    stream_filter_append($stream, 'convert.iconv.UTF-16BE.UTF-8', FILTER_LENGTH);
    stream_filter_append($stream, 'convert.iconv.UTF-16LE.UTF-16LE', FILTER_LENGTH);
    stream_filter_append($stream, 'convert.iconv.UTF-16BE.UTF-16BE', FILTER_LENGTH);
    fputs($stream, 'test');
    rewind($stream);
    echo stream_get_contents($stream);
    fclose($stream);
    try {
        echo_fatal_error();
    } catch (Exception $e) {
        echo $foo();
    }
}

__f_1();

Resulted in this output:

==2335352==ERROR: AddressSanitizer: heap-use-after-free on address 0x60400004bc7c at pc 0x562810c4ee1c bp 0x7ffe6277e460 sp 0x7ffe6277e450
READ of size 4 at 0x60400004bc7c thread T0
    #0 0x562810c4ee1b in php_stream_bucket_delref /home/dan/php-src/main/streams/filter.c:152
    #1 0x5628108535a7 in php_iconv_stream_filter_do_filter /home/dan/php-src/ext/iconv/iconv.c:2560
    #2 0x562810c5c5ec in _php_stream_fill_read_buffer /home/dan/php-src/main/streams/streams.c:583
    #3 0x562810c5d2a7 in _php_stream_read /home/dan/php-src/main/streams/streams.c:747
    #4 0x562810c60d87 in _php_stream_copy_to_mem /home/dan/php-src/main/streams/streams.c:1580
    #5 0x562810b45bc5 in zif_stream_get_contents /home/dan/php-src/ext/standard/streamsfuncs.c:485
    #6 0x562810fb87e9 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER /home/dan/php-src/Zend/zend_vm_execute.h:1351
    #7 0x562810fb87e9 in execute_ex /home/dan/php-src/Zend/zend_vm_execute.h:58779
    #8 0x562810fd9490 in zend_execute /home/dan/php-src/Zend/zend_vm_execute.h:64206
    #9 0x5628110f3645 in zend_execute_script /home/dan/php-src/Zend/zend.c:1934
    #10 0x562810c1c4e6 in php_execute_script_ex /home/dan/php-src/main/main.c:2574
    #11 0x5628110f7e36 in do_cli /home/dan/php-src/sapi/cli/php_cli.c:935
    #12 0x5628104633c2 in main /home/dan/php-src/sapi/cli/php_cli.c:1310
    #13 0x15421782dd8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f)
    #14 0x15421782de3f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e3f)
    #15 0x562810464634 in _start (/home/w023dtc/php_engines/san_php+0x4c8634)

0x60400004bc7c is located 44 bytes inside of 48-byte region [0x60400004bc50,0x60400004bc80)
freed by thread T0 here:
    #0 0x154217ef7537 in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:127
    #1 0x5628108534ef in php_iconv_stream_filter_do_filter /home/dan/php-src/ext/iconv/iconv.c:2541
    #2 0x562810c5c5ec in _php_stream_fill_read_buffer /home/dan/php-src/main/streams/streams.c:583
    #3 0x562810c5d2a7 in _php_stream_read /home/dan/php-src/main/streams/streams.c:747
    #4 0x562810c60d87 in _php_stream_copy_to_mem /home/dan/php-src/main/streams/streams.c:1580
    #5 0x562810b45bc5 in zif_stream_get_contents /home/dan/php-src/ext/standard/streamsfuncs.c:485
    #6 0x562810fb87e9 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER /home/dan/php-src/Zend/zend_vm_execute.h:1351
    #7 0x562810fb87e9 in execute_ex /home/dan/php-src/Zend/zend_vm_execute.h:58779
    #8 0x562810fd9490 in zend_execute /home/dan/php-src/Zend/zend_vm_execute.h:64206
    #9 0x5628110f3645 in zend_execute_script /home/dan/php-src/Zend/zend.c:1934
    #10 0x562810c1c4e6 in php_execute_script_ex /home/dan/php-src/main/main.c:2574
    #11 0x5628110f7e36 in do_cli /home/dan/php-src/sapi/cli/php_cli.c:935
    #12 0x5628104633c2 in main /home/dan/php-src/sapi/cli/php_cli.c:1310
    #13 0x15421782dd8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f)

previously allocated by thread T0 here:
    #0 0x154217ef7887 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
    #1 0x562810d66644 in __zend_malloc /home/dan/php-src/Zend/zend_alloc.c:3280
    #2 0x562810c4e704 in php_stream_bucket_new /home/dan/php-src/main/streams/filter.c:76
    #3 0x562810853165 in php_iconv_stream_filter_append_bucket /home/dan/php-src/ext/iconv/iconv.c:2502
    #4 0x562810853594 in php_iconv_stream_filter_do_filter /home/dan/php-src/ext/iconv/iconv.c:2535
    #5 0x562810c5c5ec in _php_stream_fill_read_buffer /home/dan/php-src/main/streams/streams.c:583
    #6 0x562810c5d2a7 in _php_stream_read /home/dan/php-src/main/streams/streams.c:747
    #7 0x562810c60d87 in _php_stream_copy_to_mem /home/dan/php-src/main/streams/streams.c:1580
    #8 0x562810b45bc5 in zif_stream_get_contents /home/dan/php-src/ext/standard/streamsfuncs.c:485
    #9 0x562810fb87e9 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER /home/dan/php-src/Zend/zend_vm_execute.h:1351
    #10 0x562810fb87e9 in execute_ex /home/dan/php-src/Zend/zend_vm_execute.h:58779
    #11 0x562810fd9490 in zend_execute /home/dan/php-src/Zend/zend_vm_execute.h:64206
    #12 0x5628110f3645 in zend_execute_script /home/dan/php-src/Zend/zend.c:1934
    #13 0x562810c1c4e6 in php_execute_script_ex /home/dan/php-src/main/main.c:2574
    #14 0x5628110f7e36 in do_cli /home/dan/php-src/sapi/cli/php_cli.c:935
    #15 0x5628104633c2 in main /home/dan/php-src/sapi/cli/php_cli.c:1310
    #16 0x15421782dd8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f)

SUMMARY: AddressSanitizer: heap-use-after-free /home/dan/php-src/main/streams/filter.c:152 in php_stream_bucket_delref
Shadow bytes around the buggy address:
  0x0c0880001730: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
  0x0c0880001740: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
  0x0c0880001750: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
  0x0c0880001760: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
  0x0c0880001770: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
=>0x0c0880001780: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd[fd]
  0x0c0880001790: fa fa 00 00 00 00 00 00 fa fa fa fa fa fa fa fa
  0x0c08800017a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c08800017b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c08800017c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c08800017d0: 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
  Shadow gap:              cc
==2335352==ABORTING

But I expected this output instead:

PHP Version

8.4.1

Operating System

No response

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions