Exemplo n.º 1
0
    def parse(self):

        try:

            #Parsing the "connect" command arguments
            amfCmd = self.get("connect")

            for arg in amfCmd.args:
                if type(arg) == dict:
                    for prop in arg:
                        self.RTMP[prop] = arg[prop]
                else:

                    if type(arg) == str:
                        extra_type = "S:"
                    if type(arg) == bool:
                        extra_type = "B:"
                    if type(arg) == int:
                        extra_type = "N:"

                    self.RTMP["extra"] += extra_type + str(arg) + " "

            #Parsing the "play" command arguments
            amfCmd = self.get("play")

            for arg in amfCmd.args:
                if arg:
                    self.RTMP["playPath"] = arg
                    break

            self.RTMP["url"] = os.path.join(self.RTMP["tcUrl"],
                                            self.RTMP["playPath"])

        except Exception as e:
            logger.error("Error during the RTMP properties parsing: %s" % e)
Exemplo n.º 2
0
    def parse(self):
        
        try:
        
            #Parsing the "connect" command arguments
            amfCmd = self.get("connect")
            
            for arg in amfCmd.args:
                if type(arg) == dict:
                    for prop in arg:
                        self.RTMP[prop] = arg[prop]
                else:
                
                    if type(arg) == str:
                        extra_type = "S:"
                    if type(arg) == bool:
                        extra_type = "B:"
                    if type(arg) == int:
                        extra_type = "N:"
                    
                    self.RTMP["extra"] += extra_type + str(arg) + " "

            #Parsing the "play" command arguments
            amfCmd = self.get("play")
            
            for arg in amfCmd.args:
                if arg:
                    self.RTMP["playPath"] = arg
                    break

            self.RTMP["url"] = os.path.join(self.RTMP["tcUrl"], self.RTMP["playPath"])
        
        except Exception as e:
            logger.error("Error during the RTMP properties parsing: %s" % e)
Exemplo n.º 3
0
def PacketHandler(pkt):

    global streams
    global rtmp_port
    global out_mode
    global quit_first

    if pkt.haslayer(TCP) and pkt.haslayer(Raw):

        #Skipping if the rtmp_port is defined and is different from the packet dest port
        if rtmp_port != 0 and pkt[TCP].dport != rtmp_port:
            return

        sport = pkt[TCP].sport
        
        #hexdump(pkt.load)

        """
        The easiest way to follow the TCP streams is to use the source port as
        distinction element. So i will consider each packet with the same source
        port as part of the same TCP stream """
        if sport not in streams:
            stream = Stream(pkt.load)
            streams[sport] = stream
        else:
            streams[sport].appendData(pkt.load)

        if streams[sport].dontScanAgain:
            return
        
        #This is the mininium size that an RTMP stream must have to contains interesting data...
        if streams[sport].size > 0x600*2:
            logger.debug("Dissecting stream: %s" % sport)

            rtmp = rtmpParser()

            try:
                amfCmds = rtmp.rtmpParseStream(streams[sport])

                #If I have 2 AMF commands (play and connect), I can print the results
                if amfCmds.count() == 2:
                    logger.info("\n* RTMP Stream found!")
                    amfCmds.printOut(out_mode)
                    streams[sport].dontScanAgain = True
                    if quit_first:
                        sys.exit(0)
                else:
                    streams[sport].offset = 0

            except StreamNoMoreBytes:
                logger.debug("No more bytes to read from the stream!")

            except Exception as e:
                logger.error("Error parsing the RTMP stream: %s" % e)
Exemplo n.º 4
0
def PacketHandler(pkt):

    global streams
    global rtmp_port
    global out_mode
    global quit_first

    if pkt.haslayer(TCP) and pkt.haslayer(Raw):

        #Skipping if the rtmp_port is defined and is different from the packet dest port
        if rtmp_port != 0 and pkt[TCP].dport != rtmp_port:
            return

        sport = pkt[TCP].sport

        #hexdump(pkt.load)
        """
        The easiest way to follow the TCP streams is to use the source port as
        distinction element. So i will consider each packet with the same source
        port as part of the same TCP stream """
        if sport not in streams:
            stream = Stream(pkt.load)
            streams[sport] = stream
        else:
            streams[sport].appendData(pkt.load)

        if streams[sport].dontScanAgain:
            return

        #This is the mininium size that an RTMP stream must have to contains interesting data...
        if streams[sport].size > 0x600 * 2:
            logger.debug("Dissecting stream: %s" % sport)

            rtmp = rtmpParser()

            try:
                amfCmds = rtmp.rtmpParseStream(streams[sport])

                #If I have 2 AMF commands (play and connect), I can print the results
                if amfCmds.count() == 2:
                    logger.info("\n* RTMP Stream found!")
                    amfCmds.printOut(out_mode)
                    streams[sport].dontScanAgain = True
                    if quit_first:
                        sys.exit(0)
                else:
                    streams[sport].offset = 0

            except StreamNoMoreBytes:
                logger.debug("No more bytes to read from the stream!")

            except Exception as e:
                logger.error("Error parsing the RTMP stream: %s" % e)
Exemplo n.º 5
0
    logger.info("Andrea Fabrizi - [email protected]\n")

    streams = dict()

    #Not sniffing, reading from dump file
    if args.pcapfile:
        logger.info("Reading packets from dump file '%s'..." % args.pcapfile)
        sniff(offline=args.pcapfile, filter="tcp", prn = PacketHandler)

    #Sniffing on the specified device
    elif args.device:
        logger.info("Starting sniffing on %s..." % args.device)
        try:
            sniff(iface=args.device, prn = PacketHandler)
        except socket.error as e:
            logger.error("Error opening %s for sniffing: %s" % (args.device, e))
            logger.info("Are you root and the device is correct?")
            sys.exit(1)

    #Default action, sniffing on all the devices
    else:
        logger.info("Starting sniffing on all devices...")
        try:
            sniff(prn = PacketHandler)
        except socket.error as e:
            logger.error("Error opening device for sniffing: %s" % e)
            logger.info("Are you root?")
            sys.exit(1)
    

Exemplo n.º 6
0
    def rtmpParsePacket (self, stream):

        """
        Looking for the packet header
        byte 1
        BB BBBBBB
        The first 2 bit indicates the header type as following:
            b00 = 12 byte header (full header).
            b01 = 8 bytes - like type b00. not including message ID (4 last bytes).
            b10 = 4 bytes - Basic Header and timestamp (3 bytes) are included.
            b11 = 1 byte - only the Basic Header is included.

        The last 6 bit indicates the chunk stream ID
        """
        byte = stream.getByte()
        header_type = byte >> 6
        chunk_stream_id = byte << 2
        chunk_stream_id = chunk_stream_id >> 2

        #Header type b00
        if header_type == 0:
            timestamp = Utils.str2num(stream.getBytes(3))
            body_size = Utils.str2num(stream.getBytes(3))
            packet_type = stream.getByte()
            stream_id = Utils.str2num(stream.getBytes(4))
        
        #Header type b01
        elif header_type == 1:
            timestamp = Utils.str2num(stream.getBytes(3))
            body_size = Utils.str2num(stream.getBytes(3))
            packet_type = stream.getByte()

            """ 
        Header type b10 or b11
        Maybe this means that we reached the end of the stream
        with the setBufferLenght command, so simply I will set the entire stream "as readed"
        to end the parsing process """
        elif header_type == 2 or header_type == 3:
            stream.offset = stream.size
            return None

        else:
            logger.error("RTMP header type not supported: %d", header_type)
            return None

        #Now reading the RTMP payload from the stream
        magic_byte = 0xC0 + chunk_stream_id
        magic_bytes_count = body_size / 128
        rtmp_payload = stream.getBytes(body_size + magic_bytes_count)

        if rtmp_payload == None:
            return None

        #Unchunking the payload
        n = 0
        while (n<len(rtmp_payload)):
            if (n % 128 == 0) and (n != 0):
                if rtmp_payload[n] == chr(magic_byte):
                    rtmp_payload = rtmp_payload[:n] + rtmp_payload[n+1:]
                else:
                    logger.debug("Expected RTMP magic byte not found in the payload: %d" % n)
                    return None
            n = n + 1            
       
        """
        Now parsing the payload!
        I will create a new Stream object, containing only the payload, to pass to the
        parsing function """
        rtmp_payload_stream = Stream(rtmp_payload)

        #If it's an AMF/AMF3 command
        if packet_type == self.AMF_COMMAND or packet_type == self.AMF3_COMMAND:

            amf = amfCommand()

            #rtmp_payload_stream.dump()

            """ 
            In case of AMF3 command, there is an extra byte at the beginning of the body
            So, lets get it! """
            if packet_type == self.AMF3_COMMAND:
                rtmp_payload_stream.getByte()

            """
            The structure of the RTMP Command is:
                (String) <Command Name>
                (Number) <Transaction Id>
                (Mixed)  <Argument> ex. Null, String, Object: {key1:value1, key2:value2 ... }
            """

            #Reading AMF Command
            amf.name = self.rtmpParseObject(rtmp_payload_stream)

            #We are interested only in "connect" and "play" objects for our purpose
            if amf.name not in ["connect","play"]:
                logger.debug("Found an unuseful command, skypping!: %s" % amf.name)
                return None

            #Reading AMF Transaction ID
            amf.transaction_id = self.rtmpParseObject(rtmp_payload_stream)

            #Reading all the AMF arguments
            while (rtmp_payload_stream.haveBytes()):
                amf.args.append(self.rtmpParseObject(rtmp_payload_stream))

            return amf
        
        #Otherwise, I can discard it...
        else:
            logger.debug("Found an unuseful packet type, skypping!: %d" % packet_type)
            
        return None
Exemplo n.º 7
0
    def rtmpParseObject(self, p):

        #Object type
        b = p.getBytes(1)

        #STRING
        if (b == self.AMF_STRING):
            strlen =  Utils.str2num(p.getBytes(2))
            string = p.getBytes(strlen)
            logger.debug("Found a string [%s]..." % string)
            return string

        #NUMBER
        #Numbers are stored as 8 byte (big endian) float double
        elif (b == self.AMF_NUMBER):
            number = struct.unpack('>d',p.getBytes(8))
            logger.debug("Found a number [%d]..." % number)
            return int(number[0])

        #BOOLEAN
        elif (b == self.AMF_BOOLEAN):
            boolean = False if (p.getBytes(1) == chr(0)) else True
            logger.debug("Found a boolean (%s)..." % boolean)
            return boolean

        #OBJECT
        elif (b == self.AMF_OBJECT):
            logger.debug("Found an object...")
            obj = dict()

            #Reading all the object properties, until End Of Object marker is reached
            while (p.readBytes(3) != "\x00\x00\x09"):
                
                #Property name
                strlen =  Utils.str2num(p.getBytes(2))
                key = p.getBytes(strlen)
                logger.debug("Property name [%s]..." % key)

                #Property value
                val = self.rtmpParseObject(p)

                obj[key] = val

            #Eating the End Of Object marker
            p.getBytes(3)
            
            return obj

        #NULL
        elif (b == self.AMF_NULL):
            logger.debug("Found a NULL byte...")
            return None

        #ARRAY
        #I don't care about it...
        elif (b == self.AMF_ARRAY):
            arraylen =  Utils.str2num(p.getBytes(4))
            logger.debug("Found an array...")
            while (p.readBytes(3) != "\x00\x00\x09"):
                pass
            p.getBytes(3)
            return 0
       
        #Unknown object
        else:
            logger.error("Found an unknown RTMP object: 0x%x" % ord(b))
            return None
Exemplo n.º 8
0
    logger.info("rtmpSnoop v%s - The RTMP Sniffer!" % VERSION)
    logger.info("Andrea Fabrizi - [email protected]\n")

    streams = dict()

    #Not sniffing, reading from dump file
    if args.pcapfile:
        logger.info("Reading packets from dump file '%s'..." % args.pcapfile)
        sniff(offline=args.pcapfile, filter="tcp", prn=PacketHandler)

    #Sniffing on the specified device
    elif args.device:
        logger.info("Starting sniffing on %s..." % args.device)
        try:
            sniff(iface=args.device, prn=PacketHandler, store=0)
        except socket.error as e:
            logger.error("Error opening %s for sniffing: %s" %
                         (args.device, e))
            logger.info("Are you root and the device is correct?")
            sys.exit(1)

    #Default action, sniffing on all the devices
    else:
        logger.info("Starting sniffing on all devices...")
        try:
            sniff(prn=PacketHandler, store=0)
        except socket.error as e:
            logger.error("Error opening device for sniffing: %s" % e)
            logger.info("Are you root?")
            sys.exit(1)