Esempio n. 1
0
    def recv(self):
        self.response_data = self._transport.recv()
        self.response_header = MSRPCRespHeader(self.response_data)
        off = self.response_header.get_header_size()
        if self.response_header.get_type() == MSRPC_FAULT and self.response_header.get_frag_len() >= off+4:
            status_code = unpack("<L",self.response_data[off:off+4])[0]
            if rpc_status_codes.has_key(status_code):
                raise Exception(rpc_status_codes[status_code])
            else:
                raise Exception('Unknown DCE RPC fault status code: %.8x' % status_code)
        answer = self.response_data[off:]
        auth_len = self.response_header.get_auth_len()
        if auth_len:
            auth_len += 8
            auth_data = answer[-auth_len:]
            ntlmssp   = ntlm.NTLMAuthHeader(data = auth_data)
            answer = answer[:-auth_len]

            if ntlmssp['auth_level'] == ntlm.NTLM_AUTH_PKT_PRIVACY:
                answer = self.cipher_encrypt(answer)

            if ntlmssp['auth_pad_len']:
                answer = answer[:-ntlmssp['auth_pad_len']]

            if ntlmssp['auth_level'] in [ntlm.NTLM_AUTH_PKT_INTEGRITY, ntlm.NTLM_AUTH_PKT_PRIVACY]:
                ntlmssp = ntlm.NTLMAuthVerifier(data = auth_data)
                data = self.cipher_encrypt(ntlmssp['data'])
                zero, crc, sequence = unpack('<LLL', data)
                self.sequence = sequence + 1

        return answer
Esempio n. 2
0
    def load(self, data):
        ptr = unpack('<L', data[:4])[0]
        index = 4
        if 0 == ptr:  # No data. May be a bug in certain versions of Samba.
            return

        self._count, _, self._max_count = unpack('<LLL',
                                                 data[index:index + 12])
        index += 12

        # Read each object's header.
        for i in range(0, self._count):
            aindex, length, size, _ = unpack('<LHHL', data[index:index + 12])
            self._elements.append(MSRPCArray(aindex, length, size))
            index += 12

        # Read the objects themselves.
        for element in self._elements:
            max_len, offset, curlen = unpack('<LLL', data[index:index + 12])
            index += 12
            element.set_name(
                unicode(data[index:index + 2 * curlen], 'utf-16le'))
            element.set_max_len(max_len)
            element.set_offset(offset)
            element.set_length2(curlen)
            index += 2 * curlen
            if curlen & 0x1: index += 2  # Skip padding.
Esempio n. 3
0
    def load(self, data):
        ptr = unpack('<L', data[:4])[0]
        index = 4
        if 0 == ptr: # No data. May be a bug in certain versions of Samba.
            return

        self._count, _, self._max_count = unpack('<LLL', data[index:index+12])
        index += 12

        # Read each object's header.
        for i in range(0, self._count):
            aindex, length, size, _ = unpack('<LHHL', data[index:index+12])
            self._elements.append(MSRPCArray(aindex, length, size))
            index += 12

        # Read the objects themselves.
        for element in self._elements:
            max_len, offset, curlen = unpack('<LLL', data[index:index+12])
            index += 12
            element.set_name(unicode(data[index:index+2*curlen], 'utf-16le'))
            element.set_max_len(max_len)
            element.set_offset(offset)
            element.set_length2(curlen)
            index += 2*curlen
            if curlen & 0x1: index += 2 # Skip padding.
Esempio n. 4
0
    def recv(self):
        self.response_data = self._transport.recv()
        self.response_header = MSRPCRespHeader(self.response_data)
        off = self.response_header.get_header_size()
        if self.response_header.get_type(
        ) == MSRPC_FAULT and self.response_header.get_frag_len() >= off + 4:
            status_code = unpack("<L", self.response_data[off:off + 4])[0]
            if rpc_status_codes.has_key(status_code):
                raise Exception(rpc_status_codes[status_code])
            else:
                raise Exception('Unknown DCE RPC fault status code: %.8x' %
                                status_code)
        answer = self.response_data[off:]
        auth_len = self.response_header.get_auth_len()
        if auth_len:
            auth_len += 8
            auth_data = answer[-auth_len:]
            ntlmssp = ntlm.NTLMAuthHeader(data=auth_data)
            answer = answer[:-auth_len]

            if ntlmssp['auth_level'] == ntlm.NTLM_AUTH_PKT_PRIVACY:
                answer = self.cipher_encrypt(answer)

            if ntlmssp['auth_pad_len']:
                answer = answer[:-ntlmssp['auth_pad_len']]

            if ntlmssp['auth_level'] in [
                    ntlm.NTLM_AUTH_PKT_INTEGRITY, ntlm.NTLM_AUTH_PKT_PRIVACY
            ]:
                ntlmssp = ntlm.NTLMAuthVerifier(data=auth_data)
                data = self.cipher_encrypt(ntlmssp['data'])
                zero, crc, sequence = unpack('<LLL', data)
                self.sequence = sequence + 1

        return answer
Esempio n. 5
0
    def sendDHCP(self,
                 type,
                 chaddr,
                 hostname=None,
                 ip=None,
                 xid=None,
                 opts=[]):
        p = DhcpPacket()

        opt = [('message-type', type)] + list(opts)

        if xid is None:
            xid = randint(0, 0xffffffff)
        if ip:
            ip = structure.unpack('!L', socket.inet_aton(ip))[0]
            p['ciaddr'] = ip
            opt.append(('requested-ip', ip))

        if hostname is not None:
            for i in range(0, len(hostname), 255):
                opt.append(('host-name', hostname[i:i + 255]))

        p['op'] = p.BOOTREQUEST
        p['xid'] = xid
        p['chaddr'] = chaddr
        p['cookie'] = 0x63825363
        p['options'] = opt

        self.sock.send(str(p))
Esempio n. 6
0
    def portmap_dump(self, rpc_handle='\x00' * 20):
        if self.endianness == '>':
            from impacket.structure import unpack, pack
            try:
                rpc_handle = ''.join(map(chr, rpc_handle))
            except:
                pass

            uuid = list(unpack('<LLHHBB6s', rpc_handle))
            rpc_handle = pack('>LLHHBB6s', *uuid)

        lookup = EPMLookupRequestHeader(endianness=self.endianness)
        lookup.set_handle(rpc_handle)
        self._dcerpc.send(lookup)

        data = self._dcerpc.recv()
        resp = EPMRespLookupRequestHeader(data)

        return resp
Esempio n. 7
0
    def portmap_dump(self, rpc_handle = '\x00'*20):
        if self.endianness == '>':
            from impacket.structure import unpack,pack
            try:
                rpc_handle = ''.join(map(chr, rpc_handle))
            except:
                pass
            
            uuid = list(unpack('<LLHHBB6s', rpc_handle))
            rpc_handle = pack('>LLHHBB6s', *uuid)

        lookup = EPMLookupRequestHeader(endianness = self.endianness)
        lookup.set_handle(rpc_handle);
        self._dcerpc.send(lookup)

        data = self._dcerpc.recv()
        resp = EPMRespLookupRequestHeader(data)

        return resp
Esempio n. 8
0
    def sendDHCP(self, type, chaddr, hostname = None, ip = None, xid = None,opts = []):
        p = DhcpPacket()

        opt = [('message-type',type)] + list(opts)

        if xid is None:
            xid = randint(0,0xffffffff)
        if ip:
            ip = structure.unpack('!L',socket.inet_aton(ip))[0]
            p['ciaddr'] = ip
            opt.append(('requested-ip',ip))

        if hostname is not None:
            for i in range(0,len(hostname),255):
                opt.append(('host-name',hostname[i:i+255]))

        p['op']     = p.BOOTREQUEST
        p['xid']    = xid
        p['chaddr'] = chaddr
        p['cookie'] = 0x63825363
        p['options'] = opt
        
        self.sock.send(str(p))
Esempio n. 9
0
File: dhcp.py Progetto: mrlzh/sLANt
    def sendDHCP(self, type, chaddr, hostname=None, ip=None, xid=None, opts=[]):
        p = DhcpPacket()

        opt = [("message-type", type)] + list(opts)

        if xid is None:
            xid = randint(0, 0xFFFFFFFF)
        if ip:
            ip = structure.unpack("!L", socket.inet_aton(ip))[0]
            p["ciaddr"] = ip
            opt.append(("requested-ip", ip))

        if hostname is not None:
            for i in range(0, len(hostname), 255):
                opt.append(("host-name", hostname[i : i + 255]))

        p["op"] = p.BOOTREQUEST
        p["xid"] = xid
        p["chaddr"] = chaddr
        p["cookie"] = 0x63825363
        p["options"] = opt

        self.sock.send(str(p))
Esempio n. 10
0
    def recv(self):
        finished = False
        forceRecv = 0
        retAnswer = ''
        while not finished:
            # At least give me the MSRPCRespHeader, especially important for TCP/UDP Transports
            self.response_data = self._transport.recv(
                forceRecv, count=MSRPCRespHeader._SIZE)
            self.response_header = MSRPCRespHeader(self.response_data)
            # Ok, there might be situation, especially with large packets, that the transport layer didn't send us the full packet's contents
            # So we gotta check we received it all
            while (len(self.response_data) < self.response_header['frag_len']):
                self.response_data += self._transport.recv(
                    forceRecv,
                    count=(self.response_header['frag_len'] -
                           len(self.response_data)))
            off = self.response_header.get_header_size()
            if self.response_header[
                    'type'] == MSRPC_FAULT and self.response_header[
                        'frag_len'] >= off + 4:
                status_code = unpack("<L", self.response_data[off:off + 4])[0]
                if rpc_status_codes.has_key(status_code):
                    raise Exception(rpc_status_codes[status_code])
                else:
                    raise Exception('Unknown DCE RPC fault status code: %.8x' %
                                    status_code)
            if self.response_header['flags'] & MSRPC_LASTFRAG:
                # No need to reassembly DCERPC
                finished = True
            else:
                # Forcing Read Recv, we need more packets!
                forceRecv = 1
            answer = self.response_data[off:]
            auth_len = self.response_header['auth_len']
            if auth_len:
                auth_len += 8
                auth_data = answer[-auth_len:]
                ntlmssp = ntlm.DCERPC_NTLMAuthHeader(data=auth_data)
                answer = answer[:-auth_len]

                if ntlmssp['auth_level'] == ntlm.NTLM_AUTH_PKT_PRIVACY:

                    if self.__flags & ntlm.NTLMSSP_NTLM2_KEY:
                        # TODO: FIX THIS, it's not calculating the signature well
                        # Since I'm not testing it we don't care... yet
                        answer, signature = ntlm.SEAL(
                            self.__flags,
                            self.__serverSigningKey,
                            self.__serverSealingKey,
                            answer,
                            answer,
                            self.__sequence,
                            self.__serverSealingHandle,
                            isDCE=True)
                    else:
                        answer, signature = ntlm.SEAL(
                            self.__flags,
                            self.__serverSigningKey,
                            self.__serverSealingKey,
                            answer,
                            answer,
                            self.__sequence,
                            self.__serverSealingHandle,
                            isDCE=True)
                        self.__sequence += 1
                else:
                    ntlmssp = ntlm.DCERPC_NTLMAuthVerifier(data=auth_data)
                    if self.__flags & ntlm.NTLMSSP_NTLM2_KEY:
                        signature = ntlm.SIGN(self.__flags,
                                              self.__serverSigningKey,
                                              answer,
                                              self.__sequence,
                                              self.__serverSealingHandle,
                                              isDCE=True)
                    else:
                        signature = ntlm.SIGN(self.__flags,
                                              self.__serverSigningKey,
                                              ntlmssp['data'],
                                              self.__sequence,
                                              self.__serverSealingHandle,
                                              isDCE=True)
                        # Yes.. NTLM2 doesn't increment sequence when receiving
                        # the packet :P
                        self.__sequence += 1

                if ntlmssp['auth_pad_len']:
                    answer = answer[:-ntlmssp['auth_pad_len']]

            retAnswer += answer
        return retAnswer
Esempio n. 11
0
    def bind(self, uuid, alter = 0, bogus_binds = 0):
        bind = MSRPCBind(endianness = self.endianness)

        syntax = '\x04\x5d\x88\x8a\xeb\x1c\xc9\x11\x9f\xe8\x08\x00\x2b\x10\x48\x60'

        if self.endianness == '>':
            syntax = unpack('<LHHBB6s', syntax)
            syntax = pack('>LHHBB6s', *syntax)

            uuid = list(unpack('<LHHBB6sHH', uuid))

            uuid[-1] ^= uuid[-2]
            uuid[-2] ^= uuid[-1]
            uuid[-1] ^= uuid[-2]
            
            uuid = pack('>LHHBB6sHH', *uuid)

        ctx = 0
        for i in range(bogus_binds):
            bind.set_ctx_id(self._ctx, index = ctx)
            bind.set_trans_num(1, index = ctx)
            bind.set_if_binuuid('A'*20, index = ctx)
            bind.set_xfer_syntax_binuuid(syntax, index = ctx)
            bind.set_xfer_syntax_ver(2, index = ctx)

            self._ctx += 1
            ctx += 1

        bind.set_ctx_id(self._ctx, index = ctx)
        bind.set_trans_num(1, index = ctx)
        bind.set_if_binuuid(uuid,index = ctx)
        bind.set_xfer_syntax_binuuid(syntax, index = ctx)
        bind.set_xfer_syntax_ver(2, index = ctx)

        bind.set_ctx_num(ctx+1)

        if alter:
            bind.set_type(MSRPC_ALTERCTX)

        if (self.__auth_level != ntlm.NTLM_AUTH_NONE):
            if (self.__username is None) or (self.__password is None):
                self.__username, self.__password, nth, lmh = self._transport.get_credentials()
            auth = ntlm.NTLMAuthNegotiate()
            auth['auth_level']  = self.__auth_level
            auth['auth_ctx_id'] = self._ctx + 79231 
            bind.set_auth_data(str(auth))

        self._transport.send(bind.get_packet())

        s = self._transport.recv()
        if s != 0:
            resp = MSRPCBindAck(s)
        else:
            return 0 #mmm why not None?

        if resp.get_type() == MSRPC_BINDNAK:
            resp = MSRPCBindNak(s)
            status_code = resp.get_reason()
            if rpc_status_codes.has_key(status_code):
                raise Exception(rpc_status_codes[status_code], resp)
            else:
                raise Exception('Unknown DCE RPC fault status code: %.8x' % status_code, resp)
            
        self.__max_xmit_size = resp.get_max_tfrag()

        if self.__auth_level != ntlm.NTLM_AUTH_NONE:
            authResp = ntlm.NTLMAuthChallenge(data = resp.get_auth_data().tostring())
            self._ntlm_challenge = authResp['challenge']
            response = ntlm.NTLMAuthChallengeResponse(self.__username,self.__password, self._ntlm_challenge)
            response['auth_ctx_id'] = self._ctx + 79231 
            response['auth_level'] = self.__auth_level

            if self.__auth_level in (ntlm.NTLM_AUTH_CONNECT, ntlm.NTLM_AUTH_PKT_INTEGRITY, ntlm.NTLM_AUTH_PKT_PRIVACY):
                if self.__password:
                    key = ntlm.compute_nthash(self.__password)
                    if POW:
                        hash = POW.Digest(POW.MD4_DIGEST)
                    else:
                        hash = MD4.new()
                    hash.update(key)
                    key = hash.digest()
                else:
                    key = '\x00'*16

            if POW:
                cipher = POW.Symmetric(POW.RC4)
                cipher.encryptInit(key)
                self.cipher_encrypt = cipher.update
            else:
                cipher = ARC4.new(key)
                self.cipher_encrypt = cipher.encrypt

            if response['flags'] & ntlm.NTLMSSP_KEY_EXCHANGE:
                session_key = 'A'*16     # XXX Generate random session key
                response['session_key'] = self.cipher_encrypt(session_key)
                if POW:
                    cipher = POW.Symmetric(POW.RC4)
                    cipher.encryptInit(session_key)
                    self.cipher_encrypt = cipher.update
                else:
                    cipher = ARC4.new(session_key)
                    self.cipher_encrypt = cipher.encrypt

            self.sequence = 0

            auth3 = MSRPCHeader()
            auth3.set_type(MSRPC_AUTH3)
            auth3.set_auth_data(str(response))
            self._transport.send(auth3.get_packet(), forceWriteAndx = 1)

        return resp     # means packet is signed, if verifier is wrong it fails
Esempio n. 12
0
    def recv(self):
        finished = False
        forceRecv = 0
        retAnswer = ''
        while not finished:
            # At least give me the MSRPCRespHeader, especially important for 
            # TCP/UDP Transports
            self.response_data = self._transport.recv(forceRecv, count=MSRPCRespHeader._SIZE)
            self.response_header = MSRPCRespHeader(self.response_data)
            # Ok, there might be situation, especially with large packets, that 
            # the transport layer didn't send us the full packet's contents
            # So we gotta check we received it all
            while ( len(self.response_data) < self.response_header['frag_len'] ):
               self.response_data += self._transport.recv(forceRecv, count=(self.response_header['frag_len']-len(self.response_data)))

            off = self.response_header.get_header_size()

            if self.response_header['type'] == MSRPC_FAULT and self.response_header['frag_len'] >= off+4:
                status_code = unpack("<L",self.response_data[off:off+4])[0]
                if rpc_status_codes.has_key(status_code):
                    raise Exception(rpc_status_codes[status_code])
                else:
                    raise Exception('Unknown DCE RPC fault status code: %.8x' % status_code)

            if self.response_header['flags'] & MSRPC_LASTFRAG:
                # No need to reassembly DCERPC
                finished = True
            else:
                # Forcing Read Recv, we need more packets!
                forceRecv = 1

            answer = self.response_data[off:]
            auth_len = self.response_header['auth_len']
            if auth_len:
                auth_len += 8
                auth_data = answer[-auth_len:]
                sec_trailer = SEC_TRAILER(data = auth_data)
                answer = answer[:-auth_len]

                if sec_trailer['auth_level'] == RPC_C_AUTHN_LEVEL_PKT_PRIVACY:
                    if self.__auth_type == RPC_C_AUTHN_WINNT:
                        if self.__flags & ntlm.NTLMSSP_NTLM2_KEY:
                            # TODO: FIX THIS, it's not calculating the signature well
                            # Since I'm not testing it we don't care... yet
                            answer, signature =  ntlm.SEAL(self.__flags, 
                                    self.__serverSigningKey, 
                                    self.__serverSealingKey,  
                                    answer, 
                                    answer, 
                                    self.__sequence, 
                                    self.__serverSealingHandle)
                        else:
                            answer, signature = ntlm.SEAL(self.__flags, 
                                    self.__serverSigningKey, 
                                    self.__serverSealingKey, 
                                    answer, 
                                    answer, 
                                    self.__sequence, 
                                    self.__serverSealingHandle)
                            self.__sequence += 1
                else:
                    if self.__auth_type == RPC_C_AUTHN_WINNT:
                        ntlmssp = auth_data[12:]
                        if self.__flags & ntlm.NTLMSSP_NTLM2_KEY:
                            signature =  ntlm.SIGN(self.__flags, 
                                    self.__serverSigningKey, 
                                    answer, 
                                    self.__sequence, 
                                    self.__serverSealingHandle)
                        else:
                            signature = ntlm.SIGN(self.__flags, 
                                    self.__serverSigningKey, 
                                    ntlmssp, 
                                    self.__sequence, 
                                    self.__serverSealingHandle)
                            # Yes.. NTLM2 doesn't increment sequence when receiving
                            # the packet :P
                            self.__sequence += 1
                
                if sec_trailer['auth_pad_len']:
                    answer = answer[:-sec_trailer['auth_pad_len']]
              
            retAnswer += answer
        return retAnswer
Esempio n. 13
0
    def bind(self, uuid, alter=0, bogus_binds=0):
        bind = MSRPCBind(endianness=self.endianness)

        syntax = '\x04\x5d\x88\x8a\xeb\x1c\xc9\x11\x9f\xe8\x08\x00\x2b\x10\x48\x60'

        if self.endianness == '>':
            syntax = unpack('<LHHBB6s', syntax)
            syntax = pack('>LHHBB6s', *syntax)

            uuid = list(unpack('<LHHBB6sHH', uuid))

            uuid[-1] ^= uuid[-2]
            uuid[-2] ^= uuid[-1]
            uuid[-1] ^= uuid[-2]

            uuid = pack('>LHHBB6sHH', *uuid)

        ctx = 0
        for i in range(bogus_binds):
            bind.set_ctx_id(self._ctx, index=ctx)
            bind.set_trans_num(1, index=ctx)
            bind.set_if_binuuid('A' * 20, index=ctx)
            bind.set_xfer_syntax_binuuid(syntax, index=ctx)
            bind.set_xfer_syntax_ver(2, index=ctx)

            self._ctx += 1
            ctx += 1

        bind.set_ctx_id(self._ctx, index=ctx)
        bind.set_trans_num(1, index=ctx)
        bind.set_if_binuuid(uuid, index=ctx)
        bind.set_xfer_syntax_binuuid(syntax, index=ctx)
        bind.set_xfer_syntax_ver(2, index=ctx)

        bind.set_ctx_num(ctx + 1)

        if alter:
            bind.set_type(MSRPC_ALTERCTX)

        if (self.__auth_level != ntlm.NTLM_AUTH_NONE):
            if (self.__username is None) or (self.__password is None):
                self.__username, self.__password, nth, lmh = self._transport.get_credentials(
                )
            auth = ntlm.NTLMAuthNegotiate()
            auth['auth_level'] = self.__auth_level
            auth['auth_ctx_id'] = self._ctx + 79231
            bind.set_auth_data(str(auth))

        self._transport.send(bind.get_packet())

        s = self._transport.recv()
        if s != 0:
            resp = MSRPCBindAck(s)
        else:
            return 0  #mmm why not None?

        if resp.get_type() == MSRPC_BINDNAK:
            resp = MSRPCBindNak(s)
            status_code = resp.get_reason()
            if rpc_status_codes.has_key(status_code):
                raise Exception(rpc_status_codes[status_code], resp)
            else:
                raise Exception(
                    'Unknown DCE RPC fault status code: %.8x' % status_code,
                    resp)

        self.__max_xmit_size = resp.get_max_tfrag()

        if self.__auth_level != ntlm.NTLM_AUTH_NONE:
            authResp = ntlm.NTLMAuthChallenge(
                data=resp.get_auth_data().tostring())
            self._ntlm_challenge = authResp['challenge']
            response = ntlm.NTLMAuthChallengeResponse(self.__username,
                                                      self.__password,
                                                      self._ntlm_challenge)
            response['auth_ctx_id'] = self._ctx + 79231
            response['auth_level'] = self.__auth_level

            if self.__auth_level in (ntlm.NTLM_AUTH_CONNECT,
                                     ntlm.NTLM_AUTH_PKT_INTEGRITY,
                                     ntlm.NTLM_AUTH_PKT_PRIVACY):
                if self.__password:
                    key = ntlm.compute_nthash(self.__password)
                    if POW:
                        hash = POW.Digest(POW.MD4_DIGEST)
                    else:
                        hash = MD4.new()
                    hash.update(key)
                    key = hash.digest()
                else:
                    key = '\x00' * 16

            if POW:
                cipher = POW.Symmetric(POW.RC4)
                cipher.encryptInit(key)
                self.cipher_encrypt = cipher.update
            else:
                cipher = ARC4.new(key)
                self.cipher_encrypt = cipher.encrypt

            if response['flags'] & ntlm.NTLMSSP_KEY_EXCHANGE:
                session_key = 'A' * 16  # XXX Generate random session key
                response['session_key'] = self.cipher_encrypt(session_key)
                if POW:
                    cipher = POW.Symmetric(POW.RC4)
                    cipher.encryptInit(session_key)
                    self.cipher_encrypt = cipher.update
                else:
                    cipher = ARC4.new(session_key)
                    self.cipher_encrypt = cipher.encrypt

            self.sequence = 0

            auth3 = MSRPCHeader()
            auth3.set_type(MSRPC_AUTH3)
            auth3.set_auth_data(str(response))
            self._transport.send(auth3.get_packet(), forceWriteAndx=1)

        return resp  # means packet is signed, if verifier is wrong it fails
Esempio n. 14
0
    def packetHandler(self, hdr, data):
        eth = self.decoder.decode(data)
        eth_type = eth.get_ether_type()
        src_mac = ImpactPacket.Ethernet.as_eth_addr(eth.get_ether_shost())

        if src_mac == self.local_mac_str:
            # 忽略所有从本地网卡发出的数据包
            return

        if eth_type == ImpactPacket.ARP.ethertype:
            # 收到 ARP 包
            arp = eth.child()
            op_name = arp.get_op_name(arp.get_ar_op())
            saddr = arp.as_pro(arp.get_ar_spa())
            taddr = arp.as_pro(arp.get_ar_tpa())

            if op_name == 'REQUEST' and saddr != '0.0.0.0' and saddr == taddr:
                # 对端已经有 IP,将本地 IP 设为与其同一子网
                print 'Got gratuitous ARP packet'
                local_addr = arp.get_ar_spa()
                if local_addr[-1] + 1 > 254:
                    local_addr[-1] -= 1
                else:
                    local_addr[-1] += 1

                # 设置本地 IP 并结束抓包
                self.laddr = arp.as_pro(local_addr)
                self.lmask = '255.255.255.0'
                self.done = True
        elif eth_type == ImpactPacket.IP.ethertype:
            # 收到 IP 包
            ip = eth.child()
            src_addr = ip.get_ip_src()
            dst_addr = ip.get_ip_dst()

            if ip.get_ip_p() == ImpactPacket.UDP.protocol:
                udp = ip.child()
                src_port = udp.get_uh_sport()
                dst_port = udp.get_uh_dport()

                if src_addr == '0.0.0.0' \
                        and dst_addr == '255.255.255.255' \
                        and src_port == 68 \
                        and dst_port == 67:
                    # 收到非本网卡发送的 DHCP 请求广播包,解析数据包
                    dhcp = DhcpPacket(udp.get_data_as_string())
                    msg_type = dhcp.getOptionValue('message-type')

                    # 构造 DHCP 响应包公用字段
                    dhcp_r = DhcpPacket()
                    dhcp_r['op'] = DhcpPacket.BOOTREPLY
                    dhcp_r['xid'] = dhcp['xid']
                    dhcp_r['secs'] = dhcp['secs']
                    dhcp_r['yiaddr'] = structure.unpack('!L', socket.inet_aton(self.predef_cip))[0]
                    dhcp_r['siaddr'] = structure.unpack('!L', socket.inet_aton(self.predef_sip))[0]
                    dhcp_r['chaddr'] = dhcp['chaddr']
                    dhcp_r['cookie'] = dhcp['cookie']

                    opts = [
                        ('subnet-mask', structure.unpack('!L', socket.inet_aton(self.predef_mask))[0]),
                        ('lease-time', self.predef_lease),
                        ('server-id', structure.unpack('!L', socket.inet_aton(self.predef_sip))[0]),
                        ('router', (structure.unpack('!L', socket.inet_aton(self.predef_router))[0],)),
                        ('domain-name-server', (structure.unpack('!L', socket.inet_aton(self.predef_dns))[0],)),
                    ]
                    if msg_type == DhcpPacket.DHCPDISCOVER:
                        print 'Got DHCP discover packet, responds with DHCP offer packet'

                        opts.append(('message-type', DhcpPacket.DHCPOFFER))
                    elif msg_type == DhcpPacket.DHCPREQUEST:
                        print 'Got DHCP request packet, responds with DHCP ack packet'

                        dhcp_r['ciaddr'] = structure.unpack('!L', socket.inet_aton(self.predef_cip))[0]
                        opts.append(('message-type', DhcpPacket.DHCPACK))

                        # DHCP ACK 响应发送后即完成 IP 配置过程
                        # 设置本地 IP 并结束抓包
                        self.laddr = self.predef_sip
                        self.lmask = self.predef_mask
                        self.done = True

                    # 依次构造 Ethernet/IP/UDP/DHCP 包结构
                    dhcp_r['_options'] = dhcp_r.packOptions(opts)
                    data = ImpactPacket.Data(str(dhcp_r))

                    udp_r = ImpactPacket.UDP()
                    udp_r.set_uh_sport(67)
                    udp_r.set_uh_dport(68)
                    udp_r.contains(data)

                    ip_r = ImpactPacket.IP()
                    ip_r.set_ip_src(self.predef_sip)
                    ip_r.set_ip_dst(self.predef_cip)
                    ip_r.contains(udp_r)

                    eth_r = ImpactPacket.Ethernet()
                    eth_r.set_ether_shost(self.local_mac)
                    eth_r.set_ether_dhost(eth.get_ether_shost())
                    eth_r.contains(ip_r)

                    # 通过 PCAP 发送响应包
                    self.pcap.sendpacket(eth_r.get_packet())