class Child(Core):
    def parse_args(self, dn, con_id, first_pkt, dbg=0, ssh_p=22):
        self.dn = dn
        self.con_id = str(con_id)
        self.first_pkt = first_pkt
        self.ssh_p = ssh_p
        Automaton.parse_args(self, debug=dbg)

    def master_filter(self, pkt):
        if (Core.master_filter(self, pkt) and pkt[IP].src == self.ip_client):
            qname = Core.parse_qname(self, pkt)
            if len(qname) >= 4:
                if qname[-2].isdigit() and qname[-3] == self.con_id:
                    self.msg_type = qname[-4]
                    if len(qname) == 4 and self.msg_type in [_IWT]:
                        return True
                    if len(qname) > 4 and self.msg_type in [
                            _ACK, _DATA, _FAST, _DONE
                    ]:
                        self.arg = qname[-5]
                        self.payload = qname[:-5]
                        return True
        return False

    def calculate_limit_size(self, pkt):
        s = self.pkt_max_size - len(
            pkt[DNS]) - 2 * len(DNSRR()) - 3 * len(self.dn) - len("ns.") - 10
        if pkt[DNSQR].qtype == TXT:
            max_size = 512
            s -= len(str(s))
        else:
            max_size = self.qname_max_size
        return min((s, 1)[s < 1], max_size)

    def fragment_data(self, data, limit_size, qtype):
        if qtype == CNAME:
            qname = []
            rest = data
            while len(rest) > 0:
                d = rest[:limit_size]
                qname.append('.'.join([
                    d[i:i + self.label_size]
                    for i in range(0, len(d), self.label_size)
                ]))
                rest = rest[limit_size:]
        elif qtype == TXT:
            qname = [
                data[i:i + limit_size] for i in range(0, len(data), limit_size)
            ]
        return qname

    def compress(self, l):
        """ [1,2,4,12,7,11,3,14,13] => '1-4.7.11-14' """
        l.sort()
        temp = [[l[0]]]
        result = []
        j = 0
        for i in range(1, len(l)):
            if l[i] == l[i - 1] + 1:
                temp[j] += [l[i]]
            else:
                temp.append([l[i]])
                j += 1
        for r in temp:
            if len(r) > 1:
                result.append("{0}-{1}".format(r[0], r[-1]))
            else:
                result.append(str(r[0]))
        return ".".join(result)

    @ATMT.state(initial=True)
    def START(self):
        self.label_size = 63
        self.qname_max_size = 253
        self.pkt_max_size = 512
        self.recv_data = {}
        self.ip_client = self.first_pkt[IP].src
        self.is_first_wyw_pkt = True
        self.iwt_pkt = None
        raise self.TICKLING()

    @ATMT.state()
    def TICKLING(self):
        s = socket.socket()
        s.connect(("127.0.0.1", self.ssh_p))
        self.stream = StreamSocket(s, Raw)
        ssh_msg = self.stream.recv()
        raise self.CON(ssh_msg.load)

    @ATMT.state()
    def CON(self, ssh_msg):
        if ssh_msg == "":
            raise self.TICKLING()
        s = self.calculate_limit_size(self.first_pkt)
        qtype = self.first_pkt[DNSQR].qtype
        self.frag_reply = self.fragment_data(b64encode(ssh_msg), s, qtype)
        if len(self.frag_reply) == 1:
            pkt = Core.forge_packet(
                self, self.first_pkt,
                "{0}.{1}.0.{2}".format(_CON, self.con_id, self.frag_reply[0]))
        else:
            pkt = Core.forge_packet(
                self, self.first_pkt,
                "{0}.{1}.{2}".format(_CON, self.con_id,
                                     str(len(self.frag_reply) - 1)))
        send(pkt, verbose=0)
        raise self.WAITING()

    @ATMT.state()
    def WAITING(self):
        pass

    @ATMT.timeout(WAITING, 600)
    def timeout_reached(self):
        raise self.END()

    @ATMT.receive_condition(WAITING)
    def data_pkt(self, pkt):
        if self.msg_type in [_ACK, _FAST]:
            pkt_nb = self.arg
            if pkt_nb.isdigit():
                raise self.DATA_RECEPTION(pkt, int(pkt_nb))

    @ATMT.receive_condition(WAITING)
    def iwt_pkt(self, pkt):
        if self.msg_type == _IWT:
            raise self.IWT(pkt)

    @ATMT.receive_condition(WAITING)
    def ttm_pkt(self, pkt):
        if self.msg_type == _DATA:
            asked_pkt = self.arg
            if asked_pkt.isdigit():
                raise self.DATA_EMISSION(pkt, int(asked_pkt))

    @ATMT.receive_condition(WAITING)
    def done_pkt(self, pkt):
        if self.msg_type == _DONE:
            code = self.arg
            if code == _ACK or code == _DATA:
                raise self.DONE(pkt, code)

    @ATMT.state()
    def DATA_RECEPTION(self, pkt, pkt_nb):
        if not self.recv_data.has_key(pkt_nb):
            self.recv_data[pkt_nb] = "".join(self.payload)
        if self.msg_type == _ACK:
            ack_pkt = Core.forge_packet(self, pkt,
                                        "{0}.{1}".format(_ACK, pkt_nb))
            send(ack_pkt, verbose=0)
            raise self.WAITING()
        elif self.msg_type == _FAST:
            self.fast_pkt = pkt
            self.to_ack = [pkt_nb]

    @ATMT.receive_condition(DATA_RECEPTION)
    def got_data(self, pkt):
        if self.msg_type == _FAST:
            if self.arg.isdigit():
                self.fast_pkt = pkt
                pkt_nb = int(self.arg)
                if not self.recv_data.has_key(pkt_nb):
                    self.recv_data[pkt_nb] = "".join(self.payload)
                if pkt_nb not in self.to_ack:
                    self.to_ack.append(pkt_nb)

    @ATMT.timeout(DATA_RECEPTION, 0.5)
    def ack(self):
        #TODO check the limit size
        l = self.compress(self.to_ack)
        ack_pkt = Core.forge_packet(self, self.fast_pkt,
                                    "{0}.{1}".format(_FAST, l))
        send(ack_pkt, verbose=0)
        raise self.WAITING()

    @ATMT.state()
    def IWT(self, pkt):
        """IWT (I Want This) state of the Child automaton.
        After receiving a WYW (What You Want) pkt from the client, the server
        says how many DNS pkts he needs to send the reply
        """
        if self.iwt_pkt is not None:
            send(self.iwt_pkt, verbose=0)
        else:
            ssh_reply = self.stream.sniff(count=1, timeout=0.1)
            iwt_pkt = Core.forge_packet(self, pkt, _DONE)
            if len(ssh_reply) > 0:
                qtype = pkt[DNSQR].qtype
                s = self.calculate_limit_size(pkt)
                self.frag_reply = self.fragment_data(
                    b64encode(ssh_reply[0].load), s, qtype)
                self.iwt_pkt = Core.forge_packet(
                    self, pkt, "{0}.{1}".format(_IWT,
                                                str(len(self.frag_reply))))
                iwt_pkt = self.iwt_pkt
            send(iwt_pkt, verbose=0)
        raise self.WAITING()

    @ATMT.state()
    def DATA_EMISSION(self, pkt, asked_pkt):
        if asked_pkt <= len(self.frag_reply):
            data_pkt = Core.forge_packet(
                self, pkt,
                "{0}.{1}.{2}".format(_DATA, str(asked_pkt),
                                     self.frag_reply[-(asked_pkt + 1)]))
            send(data_pkt, verbose=0)
        raise self.WAITING()

    @ATMT.state()
    def DONE(self, pkt, code):
        if code == _ACK:
            if self.recv_data.keys() == range(0, len(self.recv_data)):
                d = "".join(self.recv_data.values())
                ssh_request = Raw(b64decode(d))
                self.stream.send(ssh_request)
                self.recv_data.clear()
                send(Core.forge_packet(self, pkt, _DONE), verbose=0)
        elif code == _DATA:
            self.iwt_pkt = None
            send(Core.forge_packet(self, pkt, _DONE), verbose=0)
        raise self.WAITING()

    @ATMT.state(final=True)
    def END(self):
        pass
示例#2
0
文件: go.py 项目: shikata-ga-nai/ATM
def sendFlag(ip):
	s = socket.socket()
	s.connect((ip, 2997))
	ss = StreamSocket(s, Raw)
	ss.send(Raw("Flag is: l0053_lips_m1ght_s1nk_sh1ps "))
	s.close()
示例#3
0
class Child(Core):
    def parse_args(self, dn, con_id, first_pkt, dbg=0, ssh_p=22):
        self.dn = dn
        self.con_id = str(con_id)
        self.first_pkt = first_pkt
        self.ssh_p = ssh_p
        Automaton.parse_args(self, debug=dbg)

    def master_filter(self, pkt):
        if (Core.master_filter(self, pkt) and pkt[IP].src == self.ip_client):
            qname = Core.parse_qname(self, pkt)
            if len(qname) >= 4:
                if qname[-2].isdigit() and qname[-3] == self.con_id:
                    self.msg_type = qname[-4]
                    if len(qname) == 4 and self.msg_type in [_IWT]:
                        return True
                    if len(qname) > 4 and self.msg_type in [
                        _ACK, _DATA, _FAST, _DONE
                    ]:
                        self.arg = qname[-5]
                        self.payload = qname[:-5]
                        return True
        return False

    def calculate_limit_size(self, pkt):
        s = self.pkt_max_size - len(pkt[DNS]) - 2*len(
            DNSRR()
        ) - 3*len(self.dn) - len("ns.") - 10
        if pkt[DNSQR].qtype == TXT:
            max_size = 512
            s -= len(str(s))
        else:
            max_size = self.qname_max_size
        return min((s, 1)[s < 1], max_size)

    def fragment_data(self, data, limit_size, qtype):
        if qtype == CNAME:
            qname = []
            rest = data
            while len(rest) > 0:
                d = rest[:limit_size]
                qname.append(
                    '.'.join(
                        [
                            d[i:i+self.label_size] for i in range(
                                0, len(d), self.label_size,
                            )
                        ],
                    ),
                )
                rest = rest[limit_size:]
        elif qtype == TXT:
            qname = [
                data[i:i+limit_size] for i in range(0, len(data), limit_size)
            ]
        return qname

    def compress(self, l):
        """ [1,2,4,12,7,11,3,14,13] => '1-4.7.11-14' """
        l.sort()
        temp = [[l[0]]]
        result = []
        j = 0
        for i in range(1, len(l)):
            if l[i] == l[i-1]+1:
                temp[j] += [l[i]]
            else:
                temp.append([l[i]])
                j += 1
        for r in temp:
            if len(r) > 1:
                result.append("{0}-{1}".format(r[0], r[-1]))
            else:
                result.append(str(r[0]))
        return ".".join(result)

    @ATMT.state(initial=True)
    def START(self):
        self.label_size = 63
        self.qname_max_size = 253
        self.pkt_max_size = 512
        self.recv_data = {}
        self.ip_client = self.first_pkt[IP].src
        self.is_first_wyw_pkt = True
        self.iwt_pkt = None
        raise self.TICKLING()

    @ATMT.state()
    def TICKLING(self):
        s = socket.socket()
        s.connect(("127.0.0.1", self.ssh_p))
        self.stream = StreamSocket(s, Raw)
        ssh_msg = self.stream.recv()
        raise self.CON(ssh_msg.load)

    @ATMT.state()
    def CON(self, ssh_msg):
        if ssh_msg == "":
            raise self.TICKLING()
        s = self.calculate_limit_size(self.first_pkt)
        qtype = self.first_pkt[DNSQR].qtype
        self.frag_reply = self.fragment_data(b64encode(ssh_msg), s, qtype)
        if len(self.frag_reply) == 1:
            pkt = Core.forge_packet(
                self, self.first_pkt, "{0}.{1}.0.{2}".format(
                    _CON, self.con_id, self.frag_reply[0],
                ),
            )
        else:
            pkt = Core.forge_packet(
                self, self.first_pkt, "{0}.{1}.{2}".format(
                    _CON, self.con_id, str(len(self.frag_reply)-1),
                ),
            )
        send(pkt, verbose=0)
        raise self.WAITING()

    @ATMT.state()
    def WAITING(self):
        pass

    @ATMT.timeout(WAITING, 600)
    def timeout_reached(self):
        raise self.END()

    @ATMT.receive_condition(WAITING)
    def data_pkt(self, pkt):
        if self.msg_type in [_ACK, _FAST]:
            pkt_nb = self.arg
            if pkt_nb.isdigit():
                raise self.DATA_RECEPTION(pkt, int(pkt_nb))

    @ATMT.receive_condition(WAITING)
    def iwt_pkt(self, pkt):
        if self.msg_type == _IWT:
            raise self.IWT(pkt)

    @ATMT.receive_condition(WAITING)
    def ttm_pkt(self, pkt):
        if self.msg_type == _DATA:
            asked_pkt = self.arg
            if asked_pkt.isdigit():
                raise self.DATA_EMISSION(pkt, int(asked_pkt))

    @ATMT.receive_condition(WAITING)
    def done_pkt(self, pkt):
        if self.msg_type == _DONE:
            code = self.arg
            if code == _ACK or code == _DATA:
                raise self.DONE(pkt, code)

    @ATMT.state()
    def DATA_RECEPTION(self, pkt, pkt_nb):
        if pkt_nb in self.recv_data:
            self.recv_data[pkt_nb] = "".join(self.payload)
        if self.msg_type == _ACK:
            ack_pkt = Core.forge_packet(
                self, pkt, "{0}.{1}".format(_ACK, pkt_nb),
            )
            send(ack_pkt, verbose=0)
            raise self.WAITING()
        elif self.msg_type == _FAST:
            self.fast_pkt = pkt
            self.to_ack = [pkt_nb]

    @ATMT.receive_condition(DATA_RECEPTION)
    def got_data(self, pkt):
        if self.msg_type == _FAST:
            if self.arg.isdigit():
                self.fast_pkt = pkt
                pkt_nb = int(self.arg)
                if pkt_nb in self.recv_data:
                    self.recv_data[pkt_nb] = "".join(self.payload)
                if pkt_nb not in self.to_ack:
                    self.to_ack.append(pkt_nb)

    @ATMT.timeout(DATA_RECEPTION, 0.5)
    def ack(self):
        # TODO check the limit size
        l = self.compress(self.to_ack)
        ack_pkt = Core.forge_packet(
            self, self.fast_pkt, "{0}.{1}".format(_FAST, l),
        )
        send(ack_pkt, verbose=0)
        raise self.WAITING()

    @ATMT.state()
    def IWT(self, pkt):
        """IWT (I Want This) state of the Child automaton.
        After receiving a WYW (What You Want) pkt from the client, the server
        says how many DNS pkts he needs to send the reply
        """
        if self.iwt_pkt is not None:
            send(self.iwt_pkt, verbose=0)
        else:
            ssh_reply = self.stream.sniff(count=1, timeout=0.1)
            iwt_pkt = Core.forge_packet(self, pkt, _DONE)
            if len(ssh_reply) > 0:
                qtype = pkt[DNSQR].qtype
                s = self.calculate_limit_size(pkt)
                self.frag_reply = self.fragment_data(
                    b64encode(ssh_reply[0].load), s, qtype,
                )
                self.iwt_pkt = Core.forge_packet(
                    self, pkt,
                    "{0}.{1}".format(_IWT, str(len(self.frag_reply))),
                )
                iwt_pkt = self.iwt_pkt
            send(iwt_pkt, verbose=0)
        raise self.WAITING()

    @ATMT.state()
    def DATA_EMISSION(self, pkt, asked_pkt):
        if asked_pkt <= len(self.frag_reply):
            data_pkt = Core.forge_packet(
                self, pkt,
                "{0}.{1}.{2}".format(
                    _DATA, str(asked_pkt), self.frag_reply[-(asked_pkt+1)],
                ),
            )
            send(data_pkt, verbose=0)
        raise self.WAITING()

    @ATMT.state()
    def DONE(self, pkt, code):
        if code == _ACK:
            if self.recv_data.keys() == range(0, len(self.recv_data)):
                d = "".join(self.recv_data.values())
                ssh_request = Raw(b64decode(d))
                self.stream.send(ssh_request)
                self.recv_data.clear()
                send(Core.forge_packet(self, pkt, _DONE), verbose=0)
        elif code == _DATA:
            self.iwt_pkt = None
            send(Core.forge_packet(self, pkt, _DONE), verbose=0)
        raise self.WAITING()

    @ATMT.state(final=True)
    def END(self):
        pass