Asterisk is "The Opensource PBX", a popular software telephony server. The Asterisk Skinny channel driver for Cisco SCCP phones chan_skinny.so) incorrectly validates a length value in the packet header. An integer wrap-around leads to heap overwrite, and arbitrary remote code execution as root.
Vulnerable Systems:
* Asterisk version 1.2.12.1 and prior
* Asterisk version 1.0.12 and prior
Immune Systems:
* Asterisk version 1.4.0-beta1
* Asterisk version 1.4.0-beta2
* Asterisk version 1.2.13
* Asterisk version 1.0.13
The function 'static int get_input(struct skinnysession *s)' in chan_skinny.c incorrectly validates a user supplied length in the packet header. In the code below, four bytes of data are read from the socket, cast to a signed integer, and assigned to dlen. If dlen is between -1 and -8 then (dlen + 8) will integer wrap to be greater than zero, but less than sizeof(s->inbuf) for the purposes of this comparison.
Next, dlen + 4 is passed to read() as the maximum number of bytes to write to s->inbuf+4. Read() takes an unsigned value, so dlen is interpreted as a very large number. For example, a value of -6 is interpreted as 0xfffffffa bytes. This instructs read() to write beyond the allocated 1000 byte length of the buffer s->inbuf.
Code asterisk-1.2.12.1/channels/chan_skinny.c lines 2860-2870:
res = read(s->fd, s->inbuf, 4); // <- integer read from attacker
if (res != 4) {
ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
return -1;
}
dlen = letohl(*(int *)s->inbuf); // <- input 0xfffffffa
// interpreted as signed
if (dlen+8 > sizeof(s->inbuf)) // <- integer wrap to +2
dlen = sizeof(s->inbuf) - 8; // bypasses this check
}
*(int *)s->inbuf = htolel(dlen); // casting just for amusement
res = read(s->fd, s->inbuf+4, dlen+4); /* <- dlen now unsigned again
* permitting read() to write
* up to 0xfffffffa bytes off
* the end of s->inbuf
*/
Exploitation:
An attacker who can connect to the Asterisk server SCCP "Skinny" port (by default 2000/tcp) can attack the vulnerable function prior to registering as a configured Skinny phone, permitting pre-authentication remote compromise.
Once the initial length header value in the packet performs an integer-wraparound an attacker can overflow off the end of the malloc()ed input buffer, and into heap space above it. Exploitation is possible via standard heap-overflow malloc-unlink-macro technique[1] on glibc versions prior to 2.3.5. On systems with newer glibc, a more sophisticated exploitation method is necessary due to the improved validation of malloc's internal heap management linked lists. Brett Moore's work[2] on bypassing similar restrictions in WinXPSP2 is instructive.
Our proof-of-concept exploit uses vanilla malloc-unlink() to overwrite a GOT entry to point execution back into our buffer, and executes Metasploit port-binding shellcode.
Solutions:
- Disable the chan_skinny module if it is not required.
- Firewall port 2000/tcp from untrusted networks.
- Install the vendor supplied upgrades:
1.0-branch: Upgrade to 1.0.12 or later
1.2-branch: Upgrade to 1.2.13 or later