XenoG 发布于2022年11月8日 分享 发布于2022年11月8日 0x00 前言 Outlook Access的缩写是OWA,它是Exchange用来在Web上发送和接收电子邮件的界面。默认情况下,它对所有邮箱用户开放。 通常,我们使用浏览器访问OWA和阅读邮件。但是从渗透测试的角度来说,我们需要通过命令行来实现同样的功能。 目前看不到合适的开源代码和参考资料,打算根据自己的理解写Python代码,实现阅读邮件和下载附件的功能。 0x01 简介 本文将介绍以下内容: 实现理念 实施细节 编程中应注意的问题 开放源代码 使用流程 0x02 实现思路 我暂时没有找到任何关于OWA协议格式的资料,所以只能通过捕获数据包来实现。 这里我用的是Chrome浏览器自带的包捕获工具,在Chrome界面只需按F12选择网络。 0x03 实现细节 1.登录操作 的访问url是https:///OWA/auth.owa 发送发布请求,数据格式: destination=https:///OWA flags=4 forcedownlevel=0 username=password=password text=ISU TF 8=1 成功登录后,Cookie中包含X-OWA-金丝雀,可以作为判断依据。 在实际登录过程中,总共发送了三个数据包,如下图所示 在程序实现方面,使用Python的requests库不需要考虑这个细节。 的完整实现代码已上传至github,地址如下: https://github . com/3g student/howork-of-Python/blob/master/check OWA . py 该代码实现了密码的验证。 这里需要注意的是,OWA只能使用明文密码登录,不能使用哈希。 2.访问资源 通过包捕获,发现基本上每个操作都会按照以下格式实现: 发送邮件包 x-OWA-金丝雀和行动需要在标题中设置。 x-OWA-金丝雀可以通过成功登录后返回的Cookie获得。 需要设置Cookie POST包的数据格式是JSON 结果也是JSON格式的。 为了阅读邮件内容和下载附件,我们需要通过程序实现以下操作: (1)读取文件夹下所有邮件的信息 访问网址是https:///owa/service.svc?action=FindItem 相应的操作是FindItem。 邮政包裹的数据格式: { ' _ _ type ':' FindItemJsonRequest:# Exchange ',' Header ':{ ' _ _ type ':' JsonRequestHeaders:# Exchange ',' request server version ':' Exchange 2013 ',' Time zone context ':' Time zone context:# Exchange ',' Time zone definition ':{ ' _ _ type ':' Time zone definition type:# Exchange ',' Id':'SA Pacific Standard Time'}}},' Body ':{ ' _ _ type ':' finditem request:# Exchange ',' item shape ':{ ' _ _ 需要将其修改为特定的文件夹名称,如inbox或sentitems,MaxEntriesReturned。我们可以指定为99999。 如下图 POST请求的返回结果也是JSON格式,包括文件夹中每条消息的简要信息(如标题、发件人、发送时间、是否已读、是否包含附件等。但不包括正文内容),这与ews的GetFolder操作返回的结果基本相同。 这里我们需要提取每封邮件对应的ConversationId,用它作为参数来读取邮件内容。 在程序实现方面,我们需要在请求中使用会话对象来保持会话状态。 具体实现代码如下: def ListFolder(url、用户名、密码、文件夹、模式): session=requests.session() url1='https://' url '/owa/auth.owa ' 标题={ 用户代理':' Mozilla/5.0(Windows NT 6.3;Win64x64) AppleWebKit/537.36 (KHTML,像壁虎一样)Chrome/81 . 0 . 4044 . 129 Safari/537.36 ' } payload=' destination=https://% s/OWA flags=4 forcedownlevel=0 username=% spasword=% spasword text=ISU TF 8=1 ' %(URL,用户名,密码) r=session.post(url1,headers=headers,data=payload,verify=False) 打印('[*]尝试登录) 如果r.cookies中有“X-OWA-金丝雀": 打印('[ ]有效:% s % s“%(用户名,密码)) 否则: 打印('[!]登录错误) 返回0 打印('[*]尝试列出文件夹) URL 2=' https://' URL '/OWA/服务。SVC,”' action=FindItem ' 标题={ X-OWA金丝雀:r . cookie[' X-OWA-金丝雀'], 操作:' FindItem ', 用户代理:' Mozilla/5.0(Windows NT 6.3;win 64x 64)apple WebKit/537.36(KHTML,像壁虎一样)Chrome/81。0 .4044 .129 Safari/537.36 ' } Body={ ' _ _ type ':' FindItemJsonRequest:# Exchange ',' Header ':{ ' _ _ type ':' JsonRequestHeaders:# Exchange ','请求服务器版本':' Exchange 2013 ','时区上下文':'时区上下文:# Exchange ','时区定义':{ ' _ _ type ':'时区定义类型:# Exchange ',' Id':'SA太平洋标准时间' }}},' Body ':{ ' _ _ type ':' finditem请求:# Exchange ',' ItemShape':{ ' Body[' Body '][' parent folderids '][0][' Id ']=文件夹 r=session.post(url2,headers=headers,json=body,verify=False) 对于负载(r.text)中的项目['正文']['响应邮件']['项目'][0]['根文件夹']['项目']: 打印('对话Id:'项目['对话Id '][' Id ']) 代码会对返回结果的JSON格式进行解析,提取出每份邮件的对话身份 (2)读取指定邮件的内容 访问的全球资源定位器(统一资源定位器)为https:///owa/service.svc?action=GetConversationItems 对应的行动为GetConversationItems 邮政包的数据格式: { ' _ _ type ':' GetConversationItemsJsonRequest:# Exchange ',' Header ':{ ' _ _ type ':' JsonRequestHeaders:# Exchange ',' request server version ':' Exchange 2013 ','时区上下文':'时区上下文:# Exchange ','时区定义':{ ' _ _ type ':'时区定义类型:# Exchange ',' Id':'SA太平洋标准时间' }}},' Body ':{ ' _ _ type ':' getconversationitems request:# Exchange ',' Conversations ':[{]base64,r0 godGetLoader().Load(this)',' InlineImageCustomDataTemplate ':' ' },' ShapeName':'ItemPartUniqueBody ',' sort order ':' DateOrderDescending ',' MaxItemsToReturn':20}} 其中需要修改为邮件对应的对话身份 这里需要注意,通过浏览器抓到的邮政包数据格式,Python无法识别错误的和没错,需要将错误的替换成0,将真实的替换成一 邮政请求的返回结果是JSON格式,包括邮件的详细内容 这里需要提取出邮件附件对应的身份和内容类型,用作保存附件操作的参数 具体的实现代码如下: 定义视图邮件(url,用户名、密码、会话Id): session=requests.session() url1='https://' url '/owa/auth.owa ' 标题={ 用户代理:' Mozilla/5.0(Windows NT 6.3;win 64x 64)apple WebKit/537.36(KHTML,像壁虎一样)Chrome/81。0 .4044 .129 Safari/537.36 ' } payload=' destination=https://% s/OWA flags=4 force down level=0 username=% spas word=% spas word text=ISU TF 8=1 ' %(URL,用户名,密码) r=session.post(url1,headers=headers,data=payload,verify=False) 打印('[*]尝试登录) 如果r.cookies中有“X-OWA-金丝雀": 打印('[ ]有效:% s % s“%(用户名,密码)) 否则: 打印('[!]登录错误) 返回0 打印('[*]尝试查看邮件) URL 2=' https://' URL '/OWA/服务。SVC?action=GetConversationItems ' 标题={ X-OWA金丝雀:r . cookie[' X-OWA-金丝雀'], 操作:' GetConversationItems ', 用户代理:' Mozilla/5.0(Windows NT 6.3;win 64x 64)apple WebKit/537.36(KHTML,像壁虎一样)Chrome/81。0 .4044 .129 Safari/537.36 ' } body={ ' _ _ type ':' GetConversationItemsJsonRequest:# Exchange ',' Header ':{ ' _ _ type ':' JsonRequestHeaders:# Exchange ','请求服务器版本':' Exchange 2013 ','时区上下文':'时区上下文:# Exchange ','时区定义':{ ' _ _ type ':'时区定义类型:# Exchange ' } },' Id':'SA太平洋标准时间},' Body ':{ ' _ _ type ':' getconversationitems request:# Exchange ',' Conversations ':base64,r0lgodlhaqabaiaaaaaaaaaaaaaap///yh5 baaaaaaaaaaaaaaaaaaaaaaibtaa 7 ',' MaximumBodySize':2097152,' InlineImageUrlOnLoadTemplate ':' InlineImageLoader .GetLoader().Load(this)',' InlineImageCustomDataTemplate ':{ id } ' },' ShapeName':'ItemPartUniqueBody ',' sort order ':' DateOrderDescending ',' MaxItemsToReturn':20}} Body[' Body '][' Conversations '][0][' conversation Id '][' Id ']=对话Id r=session.post(url2,headers=headers,json=body,verify=False) 对于负载(r.text)中的项目[' Body '][' response messages '][' Items '][0][' Conversation '][' Conversation nodes '][0][' Items ']: 打印('主题:'项目['主题']) 如果"来自"项目: 打印('发件人:'项目['发件人']['邮箱']['名称']) 打印('发件人电子邮件地址:'项目['发件人']['邮箱']['电子邮件地址']) 否则: 打印("发件人":"本人") 对于项目['收件人]中的用户: 打印('收件人:'用户['姓名']) print(' ToRecipientsEmailAddress:'用户['电子邮件地址']) 打印('显示至:'项目['显示至']) print(' has attachments:' str(项目[' has attachments '])) 如果item['HasAttachments']==True: 对于项目['附件]中的附件: print(' Name:' att['Name']) 打印('内容类型:'属性['内容类型']) 打印(' Id:' att['附件Id '][' Id ']) print(' is read:' str(item[' is read '])) 打印('接收日期时间:'项目['接收日期时间']) print(' Body:\ r \ n ' item['唯一正文']['值']) 打印(' \r\n ') 关闭() 代码会对返回结果的JSON格式进行解析,提取出邮件的具体内容,如果包含多个附件,会逐个输出名称、内容类型和身份 (3)下载附件并保存 访问的全球资源定位器(统一资源定位器)为https:///OWA/服务。SVC/s/getfile附件?id=X-OWA金丝雀= 其中需要修改为附件对应的Id,在登录成功后返回的饼干获得 这里使用得到请求,返回结果的页眉中包括附件的文件名称,返回结果的网页内容为附件的内容 在保存附件时需要注意保存的格式,区分是文本文件还是二进制文件 如果是文本文件,可保存r。文本的内容 如果是二进制文件,可保存r。内容的内容 具体的实现代码如下: 定义下载附件(网址,用户名,密码,Id,模式): session=requests.session() url1='https://' url '/owa/auth.owa ' 标题={ 用户代理:' Mozilla/5.0(Windows NT 6.3;win 64x 64)apple WebKit/537.36(KHTML,像壁虎一样)Chrome/81。0 .4044 .129 Safari/537.36 ' } payload=' destination=https://% s/OWA flags=4 force down level=0 username=% spas word=% spas word text=ISU TF 8=1 ' %(URL,用户名,密码) r=session.post(url1,headers=headers,data=payload,verify=False) 打印('[*]尝试登录) 如果r.cookies中有“X-OWA-金丝雀": 打印('[ ]有效:% s % s“%(用户名,密码)) 否则: 打印('[!]登录错误) 返回0 打印('[*]尝试下载附件) URL 2=' https://' URL '/OWA/服务。SVC/s/getfile附件?Id=' Id ' X-OWA金丝雀=' r . cookie[' X-OWA-金丝雀] 标题={ 用户代理:' Mozilla/5.0(Windows NT 6.3;win 64x 64)apple WebKit/537.36(KHTML,像壁虎一样)Chrome/81。0 .4044 .129 Safari/537.36 ' } r=session.get(url2,headers=headers,verify=False) pattern _ name=re . compile(r ' '(r ' ' .*?)'') 名称=模式名称。查找全部(r . headers[' Content-Disposition ']) 打印('[ ]附件名称:% s“%(名称[0])) if mode=='text ': with open(名称[0],' w ',编码='utf-8 ')作为文件对象: 文件_对象。写入(r。文本) elif mode=='raw ': 用打开(名称[0],' wb ')作为文件对象: 文件_对象。写入(r。内容) 关闭() 完整的实现代码已上传至github,地址如下: https://github。com/3g学生Python作业/blob/master/OWA管理器。巴拉圭 使用示例: (1)查看发件箱中的邮件 python OWA管理器。py 192。168 .1 .1 test1域用户123!列表文件夹 指定文件夹:感谢信 指定输出结果类型:已满 如下图 结果返回邮件总数和每个邮件的信息,这里获取邮件对应的对话id:aaqkadc 4 yjrlndc 1 lwi 0 yjctndezzi 1 hnt q 5 lwzkywy 0 zgzhzdm 0 ngaqajdkohs 5 cphdrnglvbvpnio= (2)读取邮件内容 python OWA管理器。py 192。168 .1 .1 test1域用户123!查看邮件 指定邮件对应的对话身份 如下图 结果返回邮件的具体内容,这里获得附件111.txt的类型为文本/纯文本,对应的id:aamkadc 4 yjrlndc 1 lwi 0 yjctndezzi 1 hnt q 5 lwzyyy 0 zgzhdm 0 ngbaaaaaaaaebalgh 6 ur wqp 6 NLG 9 rxlmybwa 1 ZC fag 9 a 0s 75 no 2 jozsqaaaaaaaaaaaaaaaekaaa 1 ZC fag 9 a 0s 75 no 2 jozsqaaaaaaaaaaaaaabynaabegaqao2t/tjsdj 9 e M9 dwimqlrm= (3)下载附件 python OWA管理器。py 192。168 .1 .1 test1域用户123!下载附件 指定附件对应的身份 指定保存格式为文本 如下图 0x04 小结 本文介绍了编写计算机编程语言代码实现通过Outlook Web Access(OWA)读取交换邮件的实现细节,记录开发过程。 留下回复 链接帖子 意见的链接 分享到其他网站 更多分享选项…
推荐的帖子