Exemplo n.º 1
0
    def __init__(self, proto = None, config=None):
        logger.debug("{!s} __init__".format(self))

        connection.__init__(self, proto)
        self.config = SipConfig(config=config)

        self.personality = self.config.get_personality_by_address(self.local.host)

        logger.info("SIP Session created with personality '{}'".format(self.personality))
        self._auth = None
        self._state = None
Exemplo n.º 2
0
    def __init__(self, proto = None, config=None):
        logger.debug("{!s} __init__".format(self))

        connection.__init__(self, proto)
        self.config = SipConfig(config=config)

        self.personality = self.config.get_personality_by_address(self.local.host)

        logger.info("SIP Session created with personality '{}'".format(self.personality))
        self._auth = None
        self._state = None
Exemplo n.º 3
0
class SipSession(connection):
    ESTABLISHED, CLOSED = range(2)

    shared_config_values = [
        "config"
    ]

    def __init__(self, proto = None, config=None):
        logger.debug("{!s} __init__".format(self))

        connection.__init__(self, proto)
        self.config = SipConfig(config=config)

        self.personality = self.config.get_personality_by_address(self.local.host)

        logger.info("SIP Session created with personality '{}'".format(self.personality))
        self._auth = None
        self._state = None


    def handle_established(self):
        logger.debug("{!s} handle_established".format(self))
        self._state = SipSession.ESTABLISHED

        self.timeouts.idle = 10
        self.timeouts.sustain = 120
        self.processors()

        # fake a connection entry
        i = incident("dionaea.connection.udp.connect")
        i.con = self
        i.report()


    def handle_timeout_sustain(self):
        logger.debug("{!s} handle_timeout_sustain".format(self))
        return True

    def handle_timeout_idle(self):
        logger.debug("{!s} handle_timeout_idle".format(self))
        self.close()
        return False

    def handle_io_in(self, data):
        if self._state == SipSession.CLOSED:
            # Don't process any data while the connection is closed.
            return len(data)

        logger.debug("{!s} handle_io_in".format(self))

        if self.transport == "udp":
            # Header must be terminated by an empty line.
            # If empty line is missing add it.
            # This works only for sip over udp but not for sip over tcp,
            # because one UDP package is exactly one sip message.
            # SIP-Servers like Asterisk do it the same way.
            len_used = len(data)

            if not b"\n\r\n" in data and not b"\n\n" in data:
                data = data + b"\n\r\n"

            # all lines must end with \r\n
            data = data.replace(b"\r\n", b"\n")
            data = data.replace(b"\n", b"\r\n")
            try:
                msg = rfc3261.Message.froms(data, session=self)
            except rfc3261.SipParsingError:
                self.close()
                return len_used
            except ErrorWithResponse as response:
                self.send(response.create_response().dumps())
                self.close()
                return len_used

        elif self.transport in ("tcp", "tls"):
            try:
                (len_used, data_load) = rfc3261.Message.loads(data, session=self)
            except rfc3261.SipParsingError:
                self.close()
                return len(data)
            except ErrorWithResponse as response:
                self.send(response.create_response().dumps())
                self.close()
                return len(data)

            # this is not the complete message, wait for the rest
            if len_used == 0:
                return 0

            msg = rfc3261.Message(**data_load)
            logger.debug("Got {} bytes, Used {} bytes".format(len(data), len_used))

        msg.set_personality(self.personality)

        handler_name = msg.method.decode("utf-8").upper()

        if not self.config.is_handled_by_personality(handler_name, self.personality):
            self.handle_unknown(msg)
            return len(data)

        logger.info("Received: {}".format(handler_name))

        if handler_name in ('ACK','BYE','CANCEL'):
            self._handle_ABC(msg)
        else:
            try:
                func = getattr(self, "handle_" + handler_name, None)
            except:
                func = None
            if func is not None and callable(func):
                func(msg)
            else:
                self.handle_unknown(msg)

        logger.debug("io_in: returning {}".format(len_used))
        return len_used

    def close(self):
        logger.debug("{!s} close".format(self))
        self._state = SipSession.CLOSED
        connection.close(self)

    def handle_unknown(self, msg):
        logger.debug("{!s} unknown".format(self))
        logger.warn("Unknown SIP header: {}".format(repr(msg.method)[:128]))

        icd = incident("dionaea.modules.python.sip.command")
        icd.con = self
        msg_to_icd(msg, d=icd)
        icd.report()

        res = msg.create_response(rfc3261.NOT_IMPLEMENTED)
        res.dumps()
        self.send(res.dumps())

    def _handle_ABC(self, msg):
        handler_name = msg.method.decode("utf-8").upper()
        # check if Call-ID header exist
        if not msg.header_exist(b"call-id"):
            return

        # Get Call-Id and check if there's already a SipSession
        call_id = msg.headers.get(b"call-id").value

        # ToDo: remove? we don't use it
        # cseq = msg.headers.get(b"cseq").get_raw()

        # Find SipSession and delete it
        if call_id not in g_call_ids or g_call_ids[call_id] is None:
            logger.warn("{!s} request does not match any existing SIP session".format(handler_name))
            icd = incident("dionaea.modules.python.sip.command")
            icd.con = self
            msg_to_icd(msg,d=icd)
            icd.report()
            self.send(msg.create_response(rfc3261.CALL_TRANSACTION_DOSE_NOT_EXIST).dumps())
            return

        try:
            g_call_ids[call_id].handle_msg_in(msg)
        except AuthenticationError:
            logger.warn("Authentication failed for {!s} request".format(handler_name))


    def handle_INVITE(self, msg):
        logger.debug("{!s} handle_INVITE".format(self))

        # Read Call-ID field and create new SipCall instance on first INVITE
        # request received (remote host might send more than one because of time
        # outs or because he wants to flood the honeypot)
        #logger.debug("Currently active sessions: {}".format(self._callids))

        if not msg.header_exist(b"call-id"):
            return

        call_id = msg.headers.get(b"call-id").value

        if call_id in g_call_ids and g_call_ids[call_id] is None:
            logger.warn("SIP session with Call-ID {} already exists".format(call_id[:128]))
            # ToDo: error
            return

        # Establish a new SIP Call
        new_call = SipCall(
            self.transport,
            call_id,
            self,
            msg
        )

        # Store session object in sessions dictionary
        g_call_ids[call_id] = new_call

        i = incident("dionaea.connection.link")
        i.parent = self
        i.child = new_call
        i.report()

        try:
            new_call.handle_msg_in(msg)
        except AuthenticationError:
            logger.warn("Authentication failed, not creating SIP session")
            new_call.close()
            del new_call

    def handle_OPTIONS(self, msg):
        logger.debug("{!s} handle_OPTIONS".format(self))
        icd = incident("dionaea.modules.python.sip.command")
        icd.con = self
        msg_to_icd(msg,d=icd)
        icd.report()

        res = msg.create_response(rfc3261.OK)
        res.headers.append(rfc3261.Header(name="Accept", value="application/sdp"))
        res.headers.append(rfc3261.Header(name="Accept-Language", value="en"))

        self.send(res.dumps())

    def handle_REGISTER(self, msg):
        """
        :See: http://tools.ietf.org/html/rfc3261#section-10
        """
        logger.debug("{!s} handle_REGISTER".format(self))

        icd = incident("dionaea.modules.python.sip.command")
        icd.con = self
        msg_to_icd(msg,d=icd)
        icd.report()

        # ToDo: check for request-uri?
        if not msg.headers_exist([b"to", b"from", b"call-id", b"cseq"]):
            logger.warn("REGISTER, header missing")
            # ToDo: return error
            return

        to = msg.headers.get(b"to")
        user_id = to.get_raw().uri.user

        u = self.config.get_user_by_username(self.personality, user_id)

        # given user not found
        if u is None:
            res = msg.create_response(rfc3261.NOT_FOUND)
            self.send(res.dumps())
            return

        if u.password is not None and u.password != "":
            header_auth = msg.headers.get(b"authorization", None)
            if header_auth is None or self._auth is None:
                # ToDo: change nonce
                self._auth = rfc2617.Authentication(
                    method = "digest",
                    algorithm = "md5",
                    nonce = "foobar123",
                    realm = u.realm
                )
                res = msg.create_response(rfc3261.UNAUTHORIZED)
                res.headers.append(rfc3261.Header(name=b"www-authenticate", value=self._auth))
                self.send(res.dumps())
                return

            auth_response = rfc2617.Authentication.froms(header_auth[0].value)

            # ToDo: change realm
            if not self._auth.check(u.username, u.password, "REGISTER", auth_response):
                # ToDo: change nonce
                self._auth = rfc2617.Authentication(
                    method="digest",
                    algorithm="md5",
                    nonce=b"foobar123",
                    realm=u.realm
                )
                res = msg.create_response(rfc3261.UNAUTHORIZED)
                res.headers.append(rfc3261.Header(name=b"www-authenticate", value=self._auth))
                self.send(res.dumps())
                return

            # ToDo: Report authentication incident
            #i = incident("dionaea.modules.python.sip.authentication")
            #i.authenticationSuccessful = expected == authLineDict['response']
            #i.realm = realm
            #i.uri = uri
            #i.nonce = authLineDict['nonce']
            #i.challengeResponse = authLineDict['response']
            #i.expected = expected
            #i.report()

        user = User(user_id, msg=msg)
        g_reg_manager.register(user)

        res = msg.create_response(rfc3261.OK)
        self.send(res.dumps())

    def send(self, s):
        logger.debug("{!s} send".format(self))

        logger.debug('Sending message "{}" to ({}:{})'.format(
            s, self.remote.host, self.remote.port))
        connection.send(self, s)
Exemplo n.º 4
0
class SipSession(connection):
    ESTABLISHED, CLOSED = range(2)

    shared_config_values = ["config"]

    def __init__(self, proto=None, config=None):
        logger.debug("{!s} __init__".format(self))

        connection.__init__(self, proto)
        self.config = SipConfig(config=config)

        self.personality = self.config.get_personality_by_address(
            self.local.host)

        logger.info("SIP Session created with personality '{}'".format(
            self.personality))
        self._auth = None
        self._state = None

    def handle_established(self):
        logger.debug("{!s} handle_established".format(self))
        self._state = SipSession.ESTABLISHED

        self.timeouts.idle = 10
        self.timeouts.sustain = 120
        self.processors()

        # fake a connection entry
        i = incident("dionaea.connection.udp.connect")
        i.con = self
        i.report()

    def handle_timeout_sustain(self):
        logger.debug("{!s} handle_timeout_sustain".format(self))
        return True

    def handle_timeout_idle(self):
        logger.debug("{!s} handle_timeout_idle".format(self))
        self.close()
        return False

    def handle_io_in(self, data):
        if self._state == SipSession.CLOSED:
            # Don't process any data while the connection is closed.
            return len(data)

        logger.debug("{!s} handle_io_in".format(self))

        if self.transport == "udp":
            # Header must be terminated by an empty line.
            # If empty line is missing add it.
            # This works only for sip over udp but not for sip over tcp,
            # because one UDP package is exactly one sip message.
            # SIP-Servers like Asterisk do it the same way.
            len_used = len(data)

            if not b"\n\r\n" in data and not b"\n\n" in data:
                data = data + b"\n\r\n"

            # all lines must end with \r\n
            data = data.replace(b"\r\n", b"\n")
            data = data.replace(b"\n", b"\r\n")
            try:
                msg = rfc3261.Message.froms(data, session=self)
            except rfc3261.SipParsingError:
                self.close()
                return len_used
            except ErrorWithResponse as response:
                self.send(response.create_response().dumps())
                self.close()
                return len_used

        elif self.transport in ("tcp", "tls"):
            try:
                (len_used, data_load) = rfc3261.Message.loads(data,
                                                              session=self)
            except rfc3261.SipParsingError:
                self.close()
                return len(data)
            except ErrorWithResponse as response:
                self.send(response.create_response().dumps())
                self.close()
                return len(data)

            # this is not the complete message, wait for the rest
            if len_used == 0:
                return 0

            msg = rfc3261.Message(**data_load)
            logger.debug("Got {} bytes, Used {} bytes".format(
                len(data), len_used))

        msg.set_personality(self.personality)

        handler_name = msg.method.decode("utf-8").upper()

        if not self.config.is_handled_by_personality(handler_name,
                                                     self.personality):
            self.handle_unknown(msg)
            return len(data)

        logger.info("Received: {}".format(handler_name))

        if handler_name in ('ACK', 'BYE', 'CANCEL'):
            self._handle_ABC(msg)
        else:
            try:
                func = getattr(self, "handle_" + handler_name, None)
            except:
                func = None
            if func is not None and callable(func):
                func(msg)
            else:
                self.handle_unknown(msg)

        logger.debug("io_in: returning {}".format(len_used))
        return len_used

    def close(self):
        logger.debug("{!s} close".format(self))
        self._state = SipSession.CLOSED
        connection.close(self)

    def handle_unknown(self, msg):
        logger.debug("{!s} unknown".format(self))
        logger.warn("Unknown SIP header: {}".format(repr(msg.method)[:128]))

        icd = incident("dionaea.modules.python.sip.command")
        icd.con = self
        msg_to_icd(msg, d=icd)
        icd.report()

        res = msg.create_response(rfc3261.NOT_IMPLEMENTED)
        res.dumps()
        self.send(res.dumps())

    def _handle_ABC(self, msg):
        handler_name = msg.method.decode("utf-8").upper()
        # check if Call-ID header exist
        if not msg.header_exist(b"call-id"):
            return

        # Get Call-Id and check if there's already a SipSession
        call_id = msg.headers.get(b"call-id").value

        # ToDo: remove? we don't use it
        # cseq = msg.headers.get(b"cseq").get_raw()

        # Find SipSession and delete it
        if call_id not in g_call_ids or g_call_ids[call_id] is None:
            logger.warn(
                "{!s} request does not match any existing SIP session".format(
                    handler_name))
            icd = incident("dionaea.modules.python.sip.command")
            icd.con = self
            msg_to_icd(msg, d=icd)
            icd.report()
            self.send(
                msg.create_response(
                    rfc3261.CALL_TRANSACTION_DOSE_NOT_EXIST).dumps())
            return

        try:
            g_call_ids[call_id].handle_msg_in(msg)
        except AuthenticationError:
            logger.warn(
                "Authentication failed for {!s} request".format(handler_name))

    def handle_INVITE(self, msg):
        logger.debug("{!s} handle_INVITE".format(self))

        # Read Call-ID field and create new SipCall instance on first INVITE
        # request received (remote host might send more than one because of time
        # outs or because he wants to flood the honeypot)
        #logger.debug("Currently active sessions: {}".format(self._callids))

        if not msg.header_exist(b"call-id"):
            return

        call_id = msg.headers.get(b"call-id").value

        if call_id in g_call_ids and g_call_ids[call_id] is None:
            logger.warn("SIP session with Call-ID {} already exists".format(
                call_id[:128]))
            # ToDo: error
            return

        # Establish a new SIP Call
        new_call = SipCall(self.transport, call_id, self, msg)

        # Store session object in sessions dictionary
        g_call_ids[call_id] = new_call

        i = incident("dionaea.connection.link")
        i.parent = self
        i.child = new_call
        i.report()

        try:
            new_call.handle_msg_in(msg)
        except AuthenticationError:
            logger.warn("Authentication failed, not creating SIP session")
            new_call.close()
            del new_call

    def handle_OPTIONS(self, msg):
        logger.debug("{!s} handle_OPTIONS".format(self))
        icd = incident("dionaea.modules.python.sip.command")
        icd.con = self
        msg_to_icd(msg, d=icd)
        icd.report()

        res = msg.create_response(rfc3261.OK)
        res.headers.append(
            rfc3261.Header(name="Accept", value="application/sdp"))
        res.headers.append(rfc3261.Header(name="Accept-Language", value="en"))

        self.send(res.dumps())

    def handle_REGISTER(self, msg):
        """
        :See: http://tools.ietf.org/html/rfc3261#section-10
        """
        logger.debug("{!s} handle_REGISTER".format(self))

        icd = incident("dionaea.modules.python.sip.command")
        icd.con = self
        msg_to_icd(msg, d=icd)
        icd.report()

        # ToDo: check for request-uri?
        if not msg.headers_exist([b"to", b"from", b"call-id", b"cseq"]):
            logger.warn("REGISTER, header missing")
            # ToDo: return error
            return

        to = msg.headers.get(b"to")
        user_id = to.get_raw().uri.user

        u = self.config.get_user_by_username(self.personality, user_id)

        # given user not found
        if u is None:
            res = msg.create_response(rfc3261.NOT_FOUND)
            self.send(res.dumps())
            return

        if u.password is not None and u.password != "":
            header_auth = msg.headers.get(b"authorization", None)
            if header_auth is None or self._auth is None:
                # ToDo: change nonce
                self._auth = rfc2617.Authentication(method="digest",
                                                    algorithm="md5",
                                                    nonce="foobar123",
                                                    realm=u.realm)
                res = msg.create_response(rfc3261.UNAUTHORIZED)
                res.headers.append(
                    rfc3261.Header(name=b"www-authenticate", value=self._auth))
                self.send(res.dumps())
                return

            auth_response = rfc2617.Authentication.froms(header_auth[0].value)

            # ToDo: change realm
            if not self._auth.check(u.username, u.password, "REGISTER",
                                    auth_response):
                # ToDo: change nonce
                self._auth = rfc2617.Authentication(method="digest",
                                                    algorithm="md5",
                                                    nonce=b"foobar123",
                                                    realm=u.realm)
                res = msg.create_response(rfc3261.UNAUTHORIZED)
                res.headers.append(
                    rfc3261.Header(name=b"www-authenticate", value=self._auth))
                self.send(res.dumps())
                return

            # ToDo: Report authentication incident
            #i = incident("dionaea.modules.python.sip.authentication")
            #i.authenticationSuccessful = expected == authLineDict['response']
            #i.realm = realm
            #i.uri = uri
            #i.nonce = authLineDict['nonce']
            #i.challengeResponse = authLineDict['response']
            #i.expected = expected
            #i.report()

        user = User(user_id, msg=msg)
        g_reg_manager.register(user)

        res = msg.create_response(rfc3261.OK)
        self.send(res.dumps())

    def send(self, s):
        logger.debug("{!s} send".format(self))

        logger.debug('Sending message "{}" to ({}:{})'.format(
            s, self.remote.host, self.remote.port))
        connection.send(self, s)
Exemplo n.º 5
0
#  Sipvicious (c) Sandro Gaucci: http://code.google.com/p/sipvicious
################################################################################

import logging
import random
import os
import datetime
import tempfile

from dionaea.core import connection, g_dionaea, incident
from dionaea import pyev, ServiceLoader

from dionaea.sip.extras import msg_to_icd, SipConfig, ErrorWithResponse

# load config before loading the other sip modules
g_sipconfig = SipConfig(g_dionaea.config()['modules']['python'].get("sip", {}))

from dionaea.sip import rfc3261
from dionaea.sip import rfc4566
from dionaea.sip import rfc2617  # auth

g_default_loop = pyev.default_loop()

logger = logging.getLogger('sip')
logger.setLevel(logging.DEBUG)

_SipCall_sustain_timeout = 20


class AuthenticationError(Exception):
    """Exception class for errors occuring during SIP authentication"""