python - 传入参数时变量更改类型?
问题描述
我正在修补一个适用于 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
...
解决方案
类的所有普通实例方法(非@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 的要求显示定义。
推荐阅读
- python - 拥有允许更新某些成员的几乎复制构造函数的优雅方式
- c# - 如何使用实体框架通过 SetParameters 设置 Code First 连接字符串
- javascript - 单击后在一个寻呼机上切换汉堡菜单
- csv - 带有 CSV 测试数据的程序化 JMeter 配置
- c# - REST API 网址模式
- jmeter - Jmeter:无效的uri转义绝对路径无效
- node.js - nodeJS中的JWT管理员角色检查
- javascript - 删除某些产品的“添加到购物车”
- javascript - 回车键按回车后页面导航
- python-3.x - pandas groupby 如何在列上聚合并转换为每个单元格都是字典的矩阵