Ejemplo n.º 1
0
def main():
    global __exitcode__
    usage = "usage: %prog [options] target\r\n"
    usage += "examples:\r\n"
    usage += "%prog -e100-999 udp://10.0.0.1:5080\r\n"
    usage += "%prog -d dictionary.txt 10.0.0.2\r\n"
    parser = ArgumentParser(usage,
                            version="%prog v" + str(__version__) + __GPL__)
    parser.add_option("-p",
                      "--port",
                      dest="port",
                      default="5060",
                      help="Destination port of the SIP device - eg -p 5060",
                      metavar="PORT")
    parser = standardoptions(parser)
    parser = standardscanneroptions(parser)
    parser.add_option(
        "-d",
        "--dictionary",
        dest="dictionary",
        type="string",
        metavar="DICTIONARY",
        help=
        "specify a dictionary file with possible extension names or - for stdin"
    )
    parser.add_option(
        "-m",
        "--method",
        dest="method",
        type="string",
        help=
        "specify a request method. The default is REGISTER. Other possible methods are OPTIONS and INVITE",
        default="REGISTER",
        metavar="OPTIONS")
    parser.add_option(
        "-e",
        "--extensions",
        dest="range",
        default='100-999',
        help=
        "specify an extension or extension range\r\nexample: -e 100-999,1000-1500,9999",
        metavar="RANGE")
    parser.add_option("-z", "--zeropadding", dest="zeropadding", type="int",
        help="the number of zeros used to padd the username." \
            "the options \"-e 1-9999 -z 4\" would give 0001 0002 0003 ... 9999",
          default=0, metavar="PADDING")
    parser.add_option('--force',
                      dest="force",
                      action="store_true",
                      default=False,
                      help="Force scan, ignoring initial sanity checks.")
    parser.add_option('--template', '-T', action="store", dest="template",
        help="A format string which allows us to specify a template for the extensions. " \
            "example svwar.py -e 1-999 --template=\"123%#04i999\" would scan between 1230001999 to 1230999999\"")
    parser.add_option('--enabledefaults', '-D', action="store_true", dest="defaults",
        default=False, help="Scan for default / typical extensions such as " \
            "1000,2000,3000 ... 1100, etc. This option is off by default." \
            "Use --enabledefaults to enable this functionality")
    parser.add_option(
        '--maximumtime',
        action='store',
        dest='maximumtime',
        type="int",
        default=10,
        help=
        "Maximum time in seconds to keep sending requests without receiving a response back"
    )
    parser.add_option(
        '--domain',
        dest="domain",
        help=
        "force a specific domain name for the SIP message, eg. -d example.org")
    parser.add_option("--debug",
                      dest="printdebug",
                      help="Print SIP messages received",
                      default=False,
                      action="store_true")
    parser.add_option('-6',
                      dest="ipv6",
                      action="store_true",
                      help="scan an IPv6 address")

    options, args = parser.parse_args()

    exportpath = None
    logging.basicConfig(level=calcloglevel(options))
    logging.debug('started logging')

    if options.force:
        initialcheck = False
    else:
        initialcheck = True

    if options.template is not None:
        try:
            options.template % 1
        except TypeError:
            parser.error(
                "The format string template is not correct. Please provide an appropiate one",
                10)

    if options.resume is not None:
        exportpath = os.path.join(os.path.expanduser('~'), '.sipvicious',
                                  __prog__, options.resume)
        if os.path.exists(os.path.join(exportpath, 'closed')):
            parser.error("Cannot resume a session that is complete", 20)

        if not os.path.exists(exportpath):
            parser.error(
                'A session with the name %s was not found' % options.resume,
                20)

        optionssrc = os.path.join(exportpath, 'options.pkl')
        previousresume = options.resume
        previousverbose = options.verbose
        options, args = pickle.load(open(optionssrc, 'rb'), encoding='bytes')
        options.resume = previousresume
        options.verbose = previousverbose

    elif options.save is not None:
        exportpath = os.path.join(os.path.expanduser('~'), '.sipvicious',
                                  __prog__, options.save)

    if len(args) < 1:
        parser.error("Please provide at least one hostname which talks SIP!",
                     10)
    elif len(args) > 1:
        parser.error("Currently svwar supports exactly one hostname.", 10)

    destport = options.port
    parsed = urlparse(args[0])

    if not parsed.scheme:
        host = args[0]

    else:
        if any(parsed.scheme == i for i in ('tcp', 'tls', 'ws', 'wss')):
            parser.error(
                'Protocol scheme %s is not supported in SIPVicious OSS' %
                parsed.scheme, 20)

        if parsed.scheme != 'udp':
            parser.error('Invalid protocol scheme: %s' % parsed.scheme, 20)

        if ':' not in parsed.netloc:
            parser.error(
                'You have to supply hosts in format of scheme://host:port when using newer convention.',
                10)

        if int(destport) != 5060:
            parser.error(
                'You cannot supply additional -p when already including a port in URI. Please use only one.',
                20)

        host = parsed.netloc.split(':')[0]
        destport = parsed.netloc.split(':')[1]

    if options.dictionary is not None:
        guessmode = 2
        if options.dictionary == "-":
            dictionary = sys.stdin
        else:
            try:
                dictionary = open(options.dictionary,
                                  'r',
                                  encoding='utf-8',
                                  errors='ignore')
            except IOError:
                parser.error("could not open %s" % options.dictionary, 20)

            if options.resume is not None:
                lastextensionsrc = os.path.join(exportpath,
                                                'lastextension.pkl')
                previousposition = pickle.load(open(lastextensionsrc, 'rb'),
                                               encoding='bytes')
                dictionary.seek(previousposition)

        guessargs = dictionary

    else:
        guessmode = 1
        if options.resume is not None:
            lastextensionsrc = os.path.join(exportpath, 'lastextension.pkl')
            try:
                previousextension = pickle.load(open(lastextensionsrc, 'rb'),
                                                encoding='bytes')
            except IOError:
                parser.error('Could not read from %s' % lastextensionsrc, 20)

            logging.debug('Previous range: %s' % options.range)
            options.range = resumeFrom(previousextension, options.range)
            logging.debug('New range: %s' % options.range)
            logging.info('Resuming from %s' % previousextension)

        extensionstotry = getRange(options.range)
        guessargs = (extensionstotry, options.zeropadding, options.template,
                     options.defaults)

    if options.save is not None:
        if options.resume is None:
            exportpath = os.path.join(os.path.expanduser('~'), '.sipvicious',
                                      __prog__, options.save)
            if os.path.exists(exportpath):
                parser.error(
                    'we found a previous scan with the same name. Please choose a new session name',
                    20)

            logging.debug('creating an export location %s' % exportpath)
            try:
                os.makedirs(exportpath, mode=0o700)
            except OSError:
                parser.error(
                    'could not create the export location %s' % exportpath, 20)

            optionsdst = os.path.join(exportpath, 'options.pkl')
            logging.debug('saving options to %s' % optionsdst)
            pickle.dump([options, args], open(optionsdst, 'wb+'))

    if options.autogetip:
        tmpsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        tmpsocket.connect(("msn.com", 80))
        options.externalip = tmpsocket.getsockname()[0]
        tmpsocket.close()

    enableack = False
    if options.method.upper() == 'INVITE':
        enableack = True

    sipvicious = TakeASip(
        host,
        port=destport,
        selecttime=options.selecttime,
        method=options.method,
        compact=options.enablecompact,
        guessmode=guessmode,
        guessargs=guessargs,
        sessionpath=exportpath,
        initialcheck=initialcheck,
        externalip=options.externalip,
        enableack=enableack,
        maxlastrecvtime=options.maximumtime,
        localport=options.localport,
        domain=options.domain,
        printdebug=options.printdebug,
        ipv6=options.ipv6,
    )
    start_time = datetime.now()
    logging.info("scan started at %s" % str(start_time))
    logging.info("start your engines")
    try:
        sipvicious.start()
        if exportpath is not None:
            open(os.path.join(exportpath, 'closed'), 'w').close()

    except KeyboardInterrupt:
        logging.warning('caught your control^c - quiting')

    except Exception as err:
        logging.critical("Got unhandled exception : %s", err.__str__())
        reportBugToAuthor(err)
    if options.save is not None and sipvicious.nextuser is not None:
        lastextensiondst = os.path.join(exportpath, 'lastextension.pkl')
        logging.debug('saving state to %s' % lastextensiondst)
        try:
            if guessmode == 1:
                pickle.dump(
                    sipvicious.nextuser,
                    open(os.path.join(exportpath, 'lastextension.pkl'), 'wb'))
                logging.debug('logged last extension %s' % sipvicious.nextuser)
            elif guessmode == 2:
                pickle.dump(
                    sipvicious.guessargs.tell(),
                    open(os.path.join(exportpath, 'lastextension.pkl'), 'wb'))
                logging.debug('logged last position %s' %
                              sipvicious.guessargs.tell())
        except IOError:
            logging.warning('could not log the last extension scanned')
            __exitcode__ = resolveexitcode(20, __exitcode__)

    # display results
    if not options.quiet:
        lenres = len(sipvicious.resultauth)
        if lenres > 0:
            logging.info("we have %s extensions" % lenres)
            if (lenres < 400
                    and options.save is not None) or options.save is None:
                labels = ('Extension', 'Authentication')
                rows = list()

                try:
                    for k in sipvicious.resultauth.keys():
                        rows.append(
                            (k.decode(), sipvicious.resultauth[k].decode()))
                except AttributeError:
                    for k in sipvicious.resultauth.keys():
                        rows.append((k, sipvicious.resultauth[k]))

                print(to_string(rows, header=labels))

            else:
                logging.warning("too many to print - use svreport for this")

        else:
            logging.warning("found nothing")

    end_time = datetime.now()
    total_time = end_time - start_time
    logging.info("Total time: %s" % total_time)
    sys.exit(__exitcode__)
Ejemplo n.º 2
0
    def start(self):
        global __exitcode__
        if self.bindingip == '':
            bindingip = 'any'
        else:
            bindingip = self.bindingip
        self.log.debug("binding to %s:%s" % (bindingip, self.localport))

        while 1:
            if self.localport > 65535:
                self.log.critical("Could not bind to any port")
                __exitcode__ = resolveexitcode(30, __exitcode__)
                return
            try:
                self.sock.bind((self.bindingip, self.localport))
                break
            except socket.error:
                self.log.debug("could not bind to %s" % self.localport)
                self.localport += 1

        if self.originallocalport != self.localport:
            self.log.warning(
                "could not bind to %s:%s - some process might already be listening on this port. Listening on port %s instead"
                % (self.bindingip, self.originallocalport, self.localport))
            self.log.info(
                "Make use of the -P option to specify a port to bind to yourself"
            )

        # perform a test 1st .. we want to see if we get a 404
        # some other error for unknown users
        self.nextuser = random.getrandbits(32)
        data = self.createRequest(self.method, self.nextuser)
        try:
            mysendto(self.sock, data, (self.dsthost, self.dstport))
            # self.sock.sendto(data,(self.dsthost,self.dstport))
        except socket.error as err:
            self.log.error("socket error: %s" % err)
            __exitcode__ = resolveexitcode(30, __exitcode__)
            return

        # first we identify the assumed reply for an unknown extension
        gotbadresponse = False
        try:
            while 1:
                try:
                    buff, srcaddr = self.sock.recvfrom(8192)
                    if self.printdebug:
                        print(srcaddr)
                        print(buff)
                except socket.error as err:
                    self.log.error("socket error: %s" % err)
                    __exitcode__ = resolveexitcode(30, __exitcode__)
                    return

                buff = buff.decode('utf-8', 'ignore')
                if buff.startswith(self.TRYING) \
                        or buff.startswith(self.RINGING) \
                        or buff.startswith(self.UNAVAILABLE):
                    gotbadresponse = True

                elif (buff.startswith(self.PROXYAUTHREQ)
                      or buff.startswith(self.INVALIDPASS)
                      or buff.startswith(self.AUTHREQ)) \
                        and self.initialcheck:
                    self.log.error(
                        "SIP server replied with an authentication request for an unknown extension. Set --force to force a scan."
                    )
                    return

                else:
                    self.BADUSER = buff.splitlines()[0]
                    self.log.debug("Bad user = %s" % self.BADUSER)
                    gotbadresponse = False
                    break

        except socket.timeout:
            if gotbadresponse:
                self.log.error("The response we got was not good: %s" %
                               buff.__repr__())
            else:
                self.log.error(
                    "No server response - are you sure that this PBX is listening? run svmap against it to find out"
                )
                __exitcode__ = resolveexitcode(30, __exitcode__)
            return

        except (AttributeError, ValueError, IndexError):
            self.log.error("bad response .. bailing out")
            return

        except socket.error as err:
            self.log.error("socket error: %s" % err)
            __exitcode__ = resolveexitcode(30, __exitcode__)
            return

        if self.BADUSER.startswith(self.AUTHREQ):
            self.log.warning("Bad user = %s - svwar will probably not work!" %
                             self.AUTHREQ)
        # let the fun commence
        self.log.info('Ok SIP device found')
        while 1:
            if self.nomore:
                while 1:
                    try:
                        self.getResponse()
                    except socket.timeout:
                        return
            r, _, _ = select.select(self.rlist, self.wlist, self.xlist,
                                    self.selecttime)
            if r:
                # we got stuff to read off the socket
                self.getResponse()
                self.lastrecvtime = time.time()
            else:
                # check if its been a while since we had a response to prevent
                # flooding - otherwise stop
                timediff = time.time() - self.lastrecvtime
                if timediff > self.maxlastrecvtime:
                    self.nomore = True
                    self.log.warning(
                        'It has been %s seconds since we last received a response - stopping'
                        % timediff)
                    __exitcode__ = resolveexitcode(30, __exitcode__)
                    continue

                # no stuff to read .. its our turn to send back something
                try:
                    self.nextuser = next(self.usernamegen)
                except StopIteration:
                    self.nomore = True
                    continue
                except TypeError:
                    self.nomore = True
                    self.log.exception('Bad format string')
                    __exitcode__ = resolveexitcode(20, __exitcode__)

                data = self.createRequest(self.method, self.nextuser)
                try:
                    self.log.debug("sending request for %s" % self.nextuser)
                    mysendto(self.sock, data, (self.dsthost, self.dstport))

                    # self.sock.sendto(data,(self.dsthost,self.dstport))
                    if self.sessionpath is not None:
                        if next(self.packetcount):
                            try:
                                if self.guessmode == 1:
                                    pickle.dump(
                                        self.nextuser,
                                        open(
                                            os.path.join(
                                                self.sessionpath,
                                                'lastextension.pkl'), 'wb+'))
                                    self.log.debug('logged last extension %s' %
                                                   self.nextuser)

                                elif self.guessmode == 2:
                                    pickle.dump(
                                        self.guessargs.tell(),
                                        open(
                                            os.path.join(
                                                self.sessionpath,
                                                'lastextension.pkl'), 'wb+'))
                                    self.log.debug('logged last position %s' %
                                                   self.guessargs.tell())

                            except IOError:
                                self.log.warning(
                                    'could not log the last extension scanned')
                                __exitcode__ = resolveexitcode(
                                    20, __exitcode__)

                except socket.error as err:
                    __exitcode__ = resolveexitcode(30, __exitcode__)
                    self.log.error("socket error: %s" % err)
                    break
Ejemplo n.º 3
0
def main():
    global __exitcode__
    usage = "usage: %prog [options] host1 host2 hostrange\r\n"
    usage += 'Scans for SIP devices on a given network\r\n\r\n'
    usage += "examples:\r\n"
    usage += "\t%prog 10.0.0.1-10.0.0.255 "
    usage += "172.16.131.1 sipvicious.org/22 10.0.1.1/24 "
    usage += "1.1.1.1-20 1.1.2-20.* 4.1.*.*\r\n"
    usage += "\t%prog -s session1 --randomize 10.0.0.1/8\r\n"
    usage += "\t%prog --resume session1 -v\r\n"
    usage += "\t%prog -p5060-5062 10.0.0.3-20 -m INVITE\r\n"
    parser = ArgumentParser(usage, version="%prog v" + __version__ + __GPL__)
    parser.add_option("-p", "--port", dest="port", default="5060",
        help="Destination port or port ranges of the SIP device - eg -p5060,5061,8000-8100", metavar="PORT")
    parser = standardoptions(parser)
    parser = standardscanneroptions(parser)
    parser.add_option("--randomscan", dest="randomscan", action="store_true", default=False, help="Scan random IP addresses")
    parser.add_option("-i", "--input", dest="input",
        help="Scan IPs which were found in a previous scan. Pass the session name as the argument", metavar="scan1")
    parser.add_option("-I", "--inputtext", dest="inputtext",
        help="Scan IPs from a text file - use the same syntax as command line but with new lines instead of commas. Pass the file name as the argument", metavar="scan1")
    parser.add_option("-m", "--method", dest="method",  help="Specify the request method - by default this is OPTIONS.",
        default='OPTIONS')
    parser.add_option("-d", "--debug", dest="printdebug",
        help="Print SIP messages received", default=False, action="store_true")
    parser.add_option("--first", dest="first", type="long",
        help="Only send the first given number of messages (i.e. usually used to scan only X IPs)")
    parser.add_option("-e", "--extension", dest="extension", default='100',
        help="Specify an extension - by default this is not set")
    parser.add_option("--randomize", dest="randomize", action="store_true", default=False,
        help="Randomize scanning instead of scanning consecutive ip addresses")
    parser.add_option("--srv", dest="srvscan", action="store_true", default=False,
        help="Scan the SRV records for SIP on the destination domain name. The targets have to be domain names - example.org domain1.com")
    parser.add_option('--fromname',dest="fromname", default="sipvicious",
        help="specify a name for the from header")
    parser.add_option('-6', '--ipv6', dest="ipv6", action='store_true', help="scan an IPv6 address")

    options, args = parser.parse_args()
    exportpath = None
    if options.resume is not None:
        exportpath = os.path.join(os.path.expanduser('~'), '.sipvicious', __prog__, options.resume)

        if os.path.exists(os.path.join(exportpath,'closed')):
            parser.error("Cannot resume a session that is complete", 20)

        if not os.path.exists(exportpath):
            parser.error('A session with the name %s was not found' % options.resume, 20)

        optionssrc = os.path.join(exportpath,'options.pkl')
        previousresume = options.resume
        previousverbose = options.verbose

        options, args = pickle.load(open(optionssrc,'rb'), encoding='bytes')
        options.resume = previousresume
        options.verbose = previousverbose

    elif options.save is not None:
        exportpath = os.path.join(os.path.expanduser('~'), '.sipvicious', __prog__, options.save)

    logging.basicConfig(level=calcloglevel(options))
    logging.debug('started logging')
    scanrandomstore = None

    if options.input is not None:
        db = os.path.join(os.path.expanduser('~'), '.sipvicious',__prog__, options.input,'resultua')
        if dbexists(db):
            scaniter = scanfromdb(db, options.method.split(','))
        else:
            parser.error("the session name does not exist. Please use svreport to list existing scans", 20)

    elif options.randomscan:
        logging.debug('making use of random scan')
        logging.debug('parsing range of ports: %s' % options.port)
        portrange = getRange(options.port)
        internetranges = [
            [16777216, 167772159],
            [184549376, 234881023],
            [251658240, 2130706431],
            [2147549184, 2851995647],
            [2852061184, 2886729727],
            [2886795264, 3221159935],
            [3221226240, 3227017983],
            [3227018240, 3232235519],
            [3232301056, 3323068415],
            [3323199488, 3758096127]
        ]

        scanrandomstore = '.sipviciousrandomtmp'
        resumescan = False
        if options.save is not None:
            scanrandomstore = os.path.join(exportpath,'random')
            resumescan = True
        scaniter = scanrandom(
            internetranges,
            portrange,
            options.method.split(','),
            randomstore=scanrandomstore,
            resume=resumescan
        )

    elif options.inputtext:
        logging.debug('Using IP addresses from input text file')
        try:
            f = open(options.inputtext, 'r')
            args = f.readlines()
            f.close()
        except IOError:
            parser.error('Could not open %s' % options.inputtext, 20)

        args = list(map(lambda x: x.strip(), args))
        args = [x for x in args if len(x) > 0]

        logging.debug('ip addresses %s' % args)
        try:
            iprange = ip4range(*args)
        except ValueError as err:
            parser.error(err, 20)

        portrange = getRange(options.port)
        if options.randomize:
            scanrandomstore = '.sipviciousrandomtmp'
            resumescan = False
            if options.save is not None:
                scanrandomstore = os.path.join(exportpath,'random')
                resumescan = True
            scaniter = scanrandom(list(map(getranges, args)), portrange,
                options.method.split(','), randomstore=scanrandomstore, resume=resumescan)
        else:
            scaniter = scanlist(iprange, portrange, options.method.split(','))

    else:
        if len(args) < 1:
            parser.error('Please provide at least one target', 10)

        logging.debug('parsing range of ports: %s' % options.port)
        portrange = getRange(options.port)
        if options.randomize:
            scanrandomstore = '.sipviciousrandomtmp'
            resumescan = False
            if options.save is not None:
                scanrandomstore = os.path.join(exportpath,'random')
                resumescan = True
            scaniter = scanrandom(list(map(getranges, args)), portrange,
                options.method.split(','), randomstore=scanrandomstore, resume=resumescan)

        elif options.srvscan:
            logging.debug("making use of SRV records")
            scaniter = getTargetFromSRV(args, options.method.split(','))

        else:
            if options.resume is not None:
                lastipsrc = os.path.join(exportpath, 'lastip.pkl')
                try:
                    f = open(lastipsrc, 'rb')
                    previousip = pickle.load(f, encoding='bytes')
                    f.close()
                except IOError:
                    parser.error('Could not read from %s' % lastipsrc, 20)

                logging.debug('Previous args: %s' % args)
                args = resumeFromIP(previousip, args)
                logging.debug('New args: %s' % args)
                logging.info('Resuming from %s' % previousip)

            if options.ipv6:
                scaniter = scanlist(ip6range(*args), portrange, options.method.split(','))
            else:
                # normal consecutive scan
                try:
                    iprange = ip4range(*args)
                except ValueError as err:
                    parser.error(err, 20)

                scaniter = scanlist(iprange, portrange, options.method.split(','))

    if options.save is not None:
        if options.resume is None:
            exportpath = os.path.join(os.path.expanduser('~'), '.sipvicious', __prog__, options.save)
            if os.path.exists(exportpath):
                parser.error('we found a previous scan with the same name. Please choose a new session name', 20)

            logging.debug('creating an export location %s' % exportpath)
            try:
                os.makedirs(exportpath, mode=0o700)
            except OSError:
                parser.error('could not create the export location %s' % exportpath, 20)

            optionsdst = os.path.join(exportpath, 'options.pkl')
            logging.debug('saving options to %s' % optionsdst)
            pickle.dump([options, args], open(optionsdst, 'wb+'))

    try:
        options.extension
    except AttributeError:
        options.extension = None

    if options.autogetip:
        tmpsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        tmpsocket.connect(("msn.com",80))
        options.externalip=tmpsocket.getsockname()[0]
        tmpsocket.close()

    sipvicious = DrinkOrSip(
        scaniter,
        selecttime=options.selecttime,
        compact=options.enablecompact,
        localport=options.localport,
        externalip=options.externalip,
        bindingip=options.bindingip,
        sessionpath=exportpath,
        extension=options.extension,
        printdebug=options.printdebug,
        first=options.first,
        fromname=options.fromname,
        ipv6=options.ipv6,
    )
    start_time = datetime.now()
    logging.info("start your engines")
    try:
        sipvicious.start()
        if exportpath is not None:
            open(os.path.join(exportpath,'closed'),'w').close()

    except KeyboardInterrupt:
        logging.warning( 'caught your control^c - quiting' )

    except Exception as err:
        logging.critical( "Got unhandled exception" )
        reportBugToAuthor(err)
        logging.exception("Exception")
        __exitcode__ = resolveexitcode(20, __exitcode__)

    if options.save is not None and sipvicious.nextip is not None and options.randomize is False and options.randomscan is False:
        lastipdst = os.path.join(exportpath,'lastip.pkl')
        logging.debug('saving state to %s' % lastipdst)
        try:
            f = open(lastipdst,'wb+')
            pickle.dump(sipvicious.nextip, f)
            f.close()
        except OSError:
            logging.warning('Could not save state to %s' % lastipdst)

    elif options.save is None:
        if scanrandomstore is not None:
        #if options.randomize or options.randomscan:
            try:
                    logging.debug('removing %s' % scanrandomstore)
                    os.unlink(scanrandomstore)
            except OSError:
                    logging.warning('could not remove %s' % scanrandomstore)
                    pass
    # display results
    if not options.quiet:
        lenres = len(sipvicious.resultua)
        if lenres > 0:
            logging.info("we have %s devices" % lenres)
            if (lenres < 400 and options.save is not None) or options.save is None:
                labels = ('SIP Device','User Agent')
                rows = list()
                try:
                    for k in sipvicious.resultua.keys():
                        rows.append((k.decode(),sipvicious.resultua[k].decode()))
                except AttributeError:
                    for k in sipvicious.resultua.keys():
                        rows.append((k, sipvicious.resultua[k]))
                print(to_string(rows, header=labels))
            else:
                logging.warning("too many to print - use svreport for this")
        else:
            logging.warning("found nothing")
    end_time = datetime.now()
    total_time = end_time - start_time
    logging.info("Total time: %s" %  total_time)
    exit(__exitcode__)
Ejemplo n.º 4
0
    def getResponse(self):
        # we got stuff to read off the socket
        global __exitcode__
        buff, srcaddr = self.sock.recvfrom(8192)
        if self.printdebug:
            print(srcaddr)
            print(buff)
        buff = buff.decode('utf-8')
        try:
            extension = getTag(buff).decode('utf-8', 'ignore')
        except (TypeError, AttributeError):
            self.log.error('could not decode to tag')
            __exitcode__ = resolveexitcode(20, __exitcode__)
            extension = None
        if extension is None:
            self.nomore = True
            return
        try:
            firstline = buff.splitlines()[0]
        except (ValueError, IndexError, AttributeError):
            self.log.error("could not get the 1st line")
            __exitcode__ = resolveexitcode(20, __exitcode__)
            return
        if self.enableack:
            # send an ack to any responses which match
            _tmp = parseHeader(buff)
            if not (_tmp and 'code' in _tmp):
                return
            if 699 > _tmp['code'] >= 200:
                self.log.debug('will try to send an ACK response')
                if 'headers' not in _tmp:
                    self.log.debug('no headers?')
                    __exitcode__ = resolveexitcode(20, __exitcode__)
                    return
                if 'from' not in _tmp['headers']:
                    self.log.debug('no from?')
                    __exitcode__ = resolveexitcode(20, __exitcode__)
                    return
                if 'cseq' not in _tmp['headers']:
                    self.log.debug('no cseq')
                    __exitcode__ = resolveexitcode(20, __exitcode__)
                    return
                if 'call-id' not in _tmp['headers']:
                    self.log.debug('no caller id')
                    __exitcode__ = resolveexitcode(20, __exitcode__)
                    return

                try:
                    # _tmp['headers']['from'][0].split('"')[1]
                    getTag(buff)
                except IndexError:
                    self.log.warning('could not parse the from address %s' %
                                     _tmp['headers']['from'])
                    __exitcode__ = resolveexitcode(20, __exitcode__)

                cseq = _tmp['headers']['cseq'][0]
                cseqmethod = cseq.split()[1]
                if 'INVITE' == cseqmethod:
                    cid = _tmp['headers']['call-id'][0]
                    fromaddr = _tmp['headers']['from'][0]
                    toaddr = _tmp['headers']['to'][0]
                    ackreq = self.createRequest(
                        'ACK',
                        cid=cid,
                        cseq=cseq.replace(cseqmethod, ''),
                        fromaddr=fromaddr,
                        toaddr=toaddr,
                    )
                    self.log.debug('here is your ack request: %s' % ackreq)
                    mysendto(self.sock, ackreq, (self.dsthost, self.dstport))
                    # self.sock.sendto(ackreq,(self.dsthost,self.dstport))
                    if _tmp['code'] == 200:
                        byemsg = self.createRequest(
                            'BYE',
                            cid=cid,
                            cseq='2',
                            fromaddr=fromaddr,
                            toaddr=toaddr,
                        )
                        self.log.debug(
                            'sending a BYE to the 200 OK for the INVITE')
                        mysendto(self.sock, byemsg,
                                 (self.dsthost, self.dstport))

        if firstline != self.BADUSER:
            __exitcode__ = resolveexitcode(40, __exitcode__)
            if buff.startswith(self.PROXYAUTHREQ) \
                    or buff.startswith(self.INVALIDPASS) \
                    or buff.startswith(self.AUTHREQ):
                if self.realm is None:
                    self.realm = getRealm(buff)
                self.log.info(
                    "extension '%s' exists - requires authentication" %
                    extension)
                self.resultauth[extension] = 'reqauth'
                if self.sessionpath is not None and self.dbsyncs:
                    self.resultauth.sync()
            elif buff.startswith(self.TRYING):
                pass
            elif buff.startswith(self.RINGING):
                pass
            elif buff.startswith(self.OKEY):
                self.log.info(
                    "extension '%s' exists - authentication not required" %
                    extension)
                self.resultauth[extension] = 'noauth'
                if self.sessionpath is not None and self.dbsyncs:
                    self.resultauth.sync()
            else:
                self.log.warning(
                    "extension '%s' probably exists but the response is unexpected"
                    % extension)
                self.log.debug("response: %s" % firstline)
                self.resultauth[extension] = 'weird'
                if self.sessionpath is not None and self.dbsyncs:
                    self.resultauth.sync()

        elif buff.startswith(self.NOTFOUND):
            self.log.debug("User '%s' not found" % extension)

        elif buff.startswith(self.INEXISTENTTRANSACTION):
            pass

        # Prefix not found, lets go to the next one. Should we add a warning
        # here???
        elif buff.startswith(self.SERVICEUN):
            pass

        elif buff.startswith(self.TRYING):
            pass

        elif buff.startswith(self.RINGING):
            pass

        elif buff.startswith(self.OKEY):
            pass

        elif buff.startswith(self.DECLINED):
            pass

        elif buff.startswith(self.NOTALLOWED):
            self.log.warning("method not allowed")
            self.nomore = True

        elif buff.startswith(self.BADREQUEST):
            self.log.error(
                "Protocol / interopability error! The remote side most probably has problems with parsing your SIP messages!"
            )
            self.nomore = True

        else:
            self.log.warning("We got an unknown response")
            self.log.error("Response: %s" % buff.__repr__())
            self.log.debug("1st line: %s" % firstline.__repr__())
            self.log.debug("Bad user: %s" % self.BADUSER.__repr__())
            self.nomore = True
Ejemplo n.º 5
0
    def start(self):
        global __exitcode__
        # bind to 5060 - the reason is to maximize compatability with
        # devices that disregard the source port and send replies back
        # to port 5060
        if self.bindingip == '':
            bindingip = 'any'
        else:
            bindingip = self.bindingip
        self.log.debug("binding to %s:%s" % (bindingip, self.localport))

        while 1:
            if self.localport > 65535:
                self.log.critical("Could not bind to any port")
                __exitcode__ = resolveexitcode(30, __exitcode__)
                return
            try:
                self.sock.bind((self.bindingip, self.localport))
                break
            except socket.error:
                self.log.debug("could not bind to %s" % self.localport)
                self.localport += 1

        if self.originallocalport != self.localport:
            self.log.warning("could not bind to %s:%s - some process might already be listening on this port." \
                "Listening on port %s instead" % (self.bindingip, self.originallocalport, self.localport))
            self.log.info("Make use of the -P option to specify a port to bind to yourself")

        while 1:
            r, _, _ = select.select(
                self.rlist,
                self.wlist,
                self.xlist,
                self.selecttime
            )
            if r:
                # we got stuff to read off the socket
                try:
                    buff, srcaddr = self.sock.recvfrom(8192)
                    host, port, *_ = srcaddr
                    self.log.debug('got data from %s:%s' % (str(host), str(port)))
                    self.log.debug('data: %s' % buff.__repr__())
                    if self.printdebug:
                        print(srcaddr)
                        print(buff)
                except socket.error:
                    __exitcode__ = resolveexitcode(30, __exitcode__)
                    continue
                self.getResponse(buff, srcaddr)

            else:
                # no stuff to read .. its our turn to send back something
                if self.nomoretoscan:
                    try:
                        # having the final sip
                        self.log.debug("Making sure that no packets get lost")
                        self.log.debug("Come to daddy")
                        while 1:
                            buff, srcaddr = self.sock.recvfrom(8192)
                            if self.printdebug:
                                print(srcaddr)
                                print(buff)
                            self.getResponse(buff, srcaddr)
                    except socket.error:
                        break

                try:
                    nextscan = next(self.scaniter)
                except StopIteration:
                    self.log.debug('no more hosts to scan')
                    self.nomoretoscan = True
                    continue

                dstip, dstport, method = nextscan
                self.nextip = dstip
                dsthost = (dstip, dstport)
                domain = dsthost[0]
                branchunique = '%s' % random.getrandbits(32)

                if self.ipv6 and check_ipv6(dsthost[0]):
                    domain = '[' + dsthost[0] + ']'
                    localtag = createTag('%s%s' % (''.join(map(lambda x:
                        '%s' % x, dsthost[0].split(':'))), '%04x' % dsthost[1]))
                else:
                    localtag = createTag('%s%s' % (''.join(map(lambda x:
                        '%02x' % int(x), dsthost[0].split('.'))),'%04x' % dsthost[1]))

                if self.ipv6:
                    fromaddr = '"%s"<sip:100@%s>' % (self.fromname, domain)
                else:
                    fromaddr = '"%s"<%s>' % (self.fromname, self.fromaddr)

                toaddr = fromaddr
                callid = '%s' % random.getrandbits(80)
                contact = None
                if method != 'REGISTER':
                    contact = 'sip:%s@%s:%s' % (self.extension, self.externalip, self.localport)
                data = makeRequest(
                    method,
                    fromaddr,
                    toaddr,
                    domain,
                    dsthost[1],
                    callid,
                    self.externalip,
                    branchunique,
                    compact=self.compact,
                    localtag=localtag,
                    contact=contact,
                    accept='application/sdp',
                    localport=self.localport,
                    extension=self.extension
                )

                try:
                    self.log.debug("sending packet to %s:%s" % dsthost)
                    self.log.debug("packet: %s" % data.__repr__())
                    mysendto(self.sock, data, dsthost)
                    self.sentpackets += 1

                    if self.sessionpath is not None:
                        if next(self.packetcount):
                            try:
                                f = open(os.path.join(self.sessionpath,'lastip.pkl'),'wb+')
                                pickle.dump(self.nextip, f)
                                f.close()
                                self.log.debug('logged last ip %s' % self.nextip)
                            except IOError:
                                self.log.warning('could not log the last ip scanned')
                                __exitcode__ = resolveexitcode(20, __exitcode__)

                    if self.first is not None:
                        if self.sentpackets >= self.first:
                            self.log.info('Reached the limit to scan the first %s packets' % self.first)
                            self.nomoretoscan = True

                except socket.error as err:
                    self.log.error("socket error while sending to %s:%s -> %s" % (dsthost[0], dsthost[1], err))
                    __exitcode__ = resolveexitcode(30, __exitcode__)
                    pass

        # if the number of sentpackets is not equal to the ones we received, then we know that
        # there were packet drops, i.e. network errors :D one hack to rule 'em all ;P
        if self.sentpackets != len(self.resultua):
            __exitcode__ = resolveexitcode(30, __exitcode__)