首页 > 解决方案 > 传入参数时变量更改类型?

问题描述

我正在修补一个适用于 NTLM 网络协议的工具,我有一个结构对象,我在其中索引一个字符串并传递给一个函数,在函数的范围内,变量从 a<type 'str'>变为<type 'instance'>

函数调用:

# type(self.challengeMessage['challenge']) == <type 'str'>
self.ParseHTTPHash(self.challengeMessage['challenge'])

内部函数:

def ParseHTTPHash(challenge):
    # type(challenge) == <type 'instance'>
    challenge.encode("hex") # causes exception due to being instance type and not string

挑战消息对象:

class NTLMAuthChallenge(Structure):

    structure = (
        ('','"NTLMSSP\x00'),
        ('message_type','<L=2'),
        ('domain_len','<H-domain_name'),
        ('domain_max_len','<H-domain_name'),
        ('domain_offset','<L=40'),
        ('flags','<L=0'),
        ('challenge','8s'),
        ('reserved','8s=""'),
        ('TargetInfoFields_len','<H-TargetInfoFields'),
        ('TargetInfoFields_max_len','<H-TargetInfoFields'),
        ('TargetInfoFields_offset','<L'),
        ('VersionLen','_-Version','self.checkVersion(self["flags"])'), 
        ('Version',':'),
        ('domain_name',':'),
        ('TargetInfoFields',':'))

    @staticmethod
    def checkVersion(flags):
        if flags is not None:
           if flags & NTLMSSP_NEGOTIATE_VERSION == 0:
              return 0
        return 8

    def getData(self):
        if self['TargetInfoFields'] is not None and type(self['TargetInfoFields']) is not bytes:
            raw_av_fields = self['TargetInfoFields'].getData()
            self['TargetInfoFields'] = raw_av_fields
        return Structure.getData(self)

    def fromString(self,data):
        Structure.fromString(self,data)
        self['domain_name'] = data[self['domain_offset']:][:self['domain_len']]
        self['TargetInfoFields'] = data[self['TargetInfoFields_offset']:][:self['TargetInfoFields_len']]
        return self

奇怪的是,如果我在函数中self传入ParseHTTPHasH(self)并引用它,self.challengeMessage['challenge']它不会将类型更改为实例。这里发生了什么?

(编辑:)

为原始帖子的模糊性道歉,很难用这个大文件显示上下文

总体布局上下文:

class HTTPRelayServer(Thread):
        ...
        # Parse NTLMv1/v2 hash with challengeMessage & token * custom *
        # check out responder ParseSMBHash to implement for smbrelayserver.py
        # replace impacket/impacket/examples/ntlmrelayx/servers/httprelayserver.py
        def ParseHTTPHash(self,client,data):
            LMhashLen    = struct.unpack('<H',data[12:14])[0]
            LMhashOffset = struct.unpack('<H',data[16:18])[0]
            LMHash       = data[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()

            NthashLen    = struct.unpack('<H',data[20:22])[0]
            NthashOffset = struct.unpack('<H',data[24:26])[0]
            NTHash       = data[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()

            UserLen      = struct.unpack('<H',data[36:38])[0]
            UserOffset   = struct.unpack('<H',data[40:42])[0]
            User         = data[UserOffset:UserOffset+UserLen].replace('\x00','')

            # parameter reference
*---------> NumChal = self.challengeMessage['challenge'].encode("hex")

            if NthashLen == 24:
                HostNameLen     = struct.unpack('<H',data[46:48])[0]
                HostNameOffset  = struct.unpack('<H',data[48:50])[0]
                HostName        = data[HostNameOffset:HostNameOffset+HostNameLen].replace('\x00','')
                WriteHash       = '%s::%s:%s:%s:%s' % (User, HostName, LMHash, NTHash, NumChal)

            if NthashLen > 24:
                NthashLen      = 64
                DomainLen      = struct.unpack('<H',data[28:30])[0]
                DomainOffset   = struct.unpack('<H',data[32:34])[0]
                Domain         = data[DomainOffset:DomainOffset+DomainLen].replace('\x00','')
                HostNameLen    = struct.unpack('<H',data[44:46])[0]
                HostNameOffset = struct.unpack('<H',data[48:50])[0]
                HostName       = data[HostNameOffset:HostNameOffset+HostNameLen].replace('\x00','')
                WriteHash      = '%s::%s:%s:%s:%s' % (User, Domain, NumChal, NTHash[:32], NTHash[32:])
            return WriteHash

        def do_PROPFIND(self):
            proxy = False
            if (".jpg" in self.path) or (".JPG" in self.path):
                content = """<?xml version="1.0"?><D:multistatus xmlns:D="DAV:"><D:response><D:href>http://webdavrelay/file/image.JPG/</D:href><D:propstat><D:prop><D:creationdate>2016-11-12T22:00:22Z</D:creationdate><D:displayname>image.JPG</D:displayname><D:getcontentlength>4456</D:getcontentlength><D:getcontenttype>image/jpeg</D:getcontenttype><D:getetag>4ebabfcee4364434dacb043986abfffe</D:getetag><D:getlastmodified>Mon, 20 Mar 2017 00:00:22 GMT</D:getlastmodified><D:resourcetype></D:resourcetype><D:supportedlock></D:supportedlock><D:ishidden>0</D:ishidden></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response></D:multistatus>"""
            else:
                content = """<?xml version="1.0"?><D:multistatus xmlns:D="DAV:"><D:response><D:href>http://webdavrelay/file/</D:href><D:propstat><D:prop><D:creationdate>2016-11-12T22:00:22Z</D:creationdate><D:displayname>a</D:displayname><D:getcontentlength></D:getcontentlength><D:getcontenttype></D:getcontenttype><D:getetag></D:getetag><D:getlastmodified>Mon, 20 Mar 2017 00:00:22 GMT</D:getlastmodified><D:resourcetype><D:collection></D:collection></D:resourcetype><D:supportedlock></D:supportedlock><D:ishidden>0</D:ishidden></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response></D:multistatus>"""

            messageType = 0
            if self.headers.getheader('Authorization') is None:
                self.do_AUTHHEAD(message='NTLM')
                pass
            else:
                typeX = self.headers.getheader('Authorization')
                try:
                    _, blob = typeX.split('NTLM')
                    token = base64.b64decode(blob.strip())
                except:
                    self.do_AUTHHEAD()
                messageType = struct.unpack('<L', token[len('NTLMSSP\x00'):len('NTLMSSP\x00') + 4])[0]

            if messageType == 1:
                if not self.do_ntlm_negotiate(token, proxy=proxy):
                    LOG.info("do negotiate failed, sending redirect")
                    self.do_REDIRECT()
            elif messageType == 3:
                authenticateMessage = ntlm.NTLMAuthChallengeResponse()
                authenticateMessage.fromString(token)
                if authenticateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE:
                    LOG.info("Authenticating against %s://%s as %s\\%s SUCCEED" % (
                        self.target.scheme, self.target.netloc, authenticateMessage['domain_name'].decode('utf-16le'),
                        authenticateMessage['user_name'].decode('utf-16le')))
                else:
                    LOG.info("Authenticating against %s://%s as %s\\%s SUCCEED" % (
                        self.target.scheme, self.target.netloc, authenticateMessage['domain_name'].decode('ascii'),
                        authenticateMessage['user_name'].decode('ascii')))
                self.do_ntlm_auth(token, authenticateMessage)
                self.do_attack()

                # Function call
*------------>  print(self.ParseHTTPHash(self,str(token)))

                self.send_response(207, "Multi-Status")
                self.send_header('Content-Type', 'application/xml')
                self.send_header('Content-Length', str(len(content)))
                self.end_headers()
                self.wfile.write(content)
                return
        ...

标签: pythonprotocolspenetration-testingpenetration-tools

解决方案


类的所有普通实例方法(非@staticmethod或其他)都采用第一个参数,即调用它们的对象。

所以,当你打电话

obj.foo(param)

obj在类的对象上C,它大致转换为

C.foo(obj, param)

通常实现为

class C:
    def foo(self, param):
        pass # whatever

否则,实例方法将不知道C它应该处理哪个类的实例。

所以,如果ParseHTTPHash是一个实例方法,你应该把它称为self.ParseHTTPHash(param),但是你声明它是错误的。

如果ParseHTTPHash不是实例方法,则不应像一开始那样调用它self.ParseHTTPHash(param),因为该语法专门用于实例方法。

知道哪种情况适用的唯一方法是让您ParseHTTPHash按照@RafalS 的要求显示定义。


推荐阅读