《2019补天白帽大会》——【Red Teaming 红队行动】分论坛 文字版实录

发布者:Editor
发布于:2019-05-31 14:25

《2019补天白帽大会》 ——Red Teaming 红队行动


时间:2019年5月29日(13:30-17:30)

地点:上海雅居乐万豪酒店(5F)


[正式开始]


主持人:各位朋友们,下午好!

欢迎大家来到补天白帽大会红队分论坛,这个论坛讨论的是“实战化安全能力”中的攻击能力,我相信选择这个分论坛一定是大家今天做的最明智的决定。

今天也是一个值得纪念的日子,奇安信旗下的 A-TEAM首次在公开场合与大家见面,A-TEAM 是奇安信集团旗下的一支纯技术研究团队,主要致力于 Web 渗透,APT 攻防、对抗,以及前瞻性攻防工具预研。我们从底层原理、协议层面进行严肃、有深度的技术研究,深入还原攻与防的技术本质。

A-TEAM也是奇安信CERT背后的支撑团队,凭借着对攻击者更深入的理解与相关领域的技术积累,在过去的一年里我们曾多次抢先提供windows域、exchange、weblogic等重大安全问题的预警及可行的处置措施。

未来我们将秉承古典黑客精神进行有深度、服务实战的安全研究工作,同时我们会不定期发布一些项目向社会贡献自己的一份力量,具体信息可以关注我们的GitHub。

今天A-TEAM首次公开亮相,也带来了五个非常硬核的议题,与大家一起分享探讨。在议题分享前,让我们一起隆重邀请我的好朋友,著名老黑客TB为本次论坛致开幕词,有情TB!


[盘古创始人 TB:开场致辞。]

    

TB:感谢大家!首先,作为一个东道主,因为我们是盘古团代。我们希望大家如果有兴趣的话,明天可以参加“Mosec”论坛。我这里致辞也没有准备什么稿子,我这里也不想多说什么了。我本身也是做技术的,我希望大家能够在“白帽子”的路上不忘初心、不要抛弃这一块兴趣,能够在技术这一块做深、做广。什么叫做深、做广呢?就是说有一些漏洞,我们要挖掘这些漏洞详细的底层原因,然后去探究这些东西。然后“做广”,是因为我觉得黑客或者白帽子领域需要知识的广度,光知道一“点”东西,很难达到攻击或者是防御的效果,希望大家要做到广度和深度。

    

其它的也不说了,主要就是这些。预祝Red Teaming红队论坛成功。

    

主持人:提到APT很多都讲到邮件。我今天给大家带来一个新的视角,由我们的工程师来给大家讲一个从邮件开始如何不利用传统手段,一步一步达到目标的过程。


Pr0mise:红队行动,邮件战争


 

大家好,今天给大家分享的议题叫做邮件战争,介绍了我去年的一次重点围绕邮件展开的渗透经历。目的是给大家分享一种渗透思路,以及后渗透过程中的思维方式。我是本次议题的演讲人刘伟,接下来我做一个简单的自我介绍。


本人就职于奇安信A-Team,是一名渗透测试工程师。其实我一开始是做免杀的,后来觉得太难了就转行做web,由于入行太晚,我学web安全的时候各种waf设备大行其道,需要测试的站点大多部署在阿里云上,并且安装了安全狗/网站卫士等软件,此时我的御剑和明小子失去了作用,这还怎么测? web安全也太难了,只能转行做做渗透了。


出于工作性质的原因,我接触了很多拓扑复杂且安全设备繁多的环境,也渐渐熟知了各类安全设备的对抗手段。我们都知道现在的安全设备日益完善,网络环境日趋复杂。传统的渗透“三板斧”可能就不再适用了。何谓三板斧?


首先说第一板斧,当我们通过邮件鱼或者Web漏洞利用等任意什么手段,拿到了对方内网一台机器的权限后,会进行简单的信息收集、做初期的环境侦查。比如:会提取凭据等一系列对攻击者有利的信息,之后对信息进行归类分析。假设没有找到有价值信息,我们会进行网段探测:这是第二板斧。


我们会用一些工具进行网络扫描,比如nmap。尝试探测对方内网的网络拓扑,了解网段分布,继而识别企业组件的指纹,根据指纹搜索漏洞信息,或是审计代码挖洞。找到漏洞后接下来就是第三板斧"漏洞利用"。


如果getshell成功,就继续进行信息收集,重复三板斧的过程,直到提取到有价值信息(管理员凭据)之后,进行凭据利用,打到目标机。

这个过程其实存在一系列的问题,比如我用nmap进行网端探测获取对方目标网络拓扑的时候,由于nmap无法精准的识别哪些机器是“蜜罐”,哪些是真实资产,所以可能产生蜜罐设备告警。而且nmap的扫描指纹有明显的特征,所以会被ids识别。


当面对一个极度重视安全,并且部署了全量安全设备的企业时,我们需要一点不一样的经历。


首先,我通过邮件钓鱼的方案打到对方内网里一台HR的机器,我进行简单信息收集后,发现对方域网里有一个ACL缺陷,此处缺陷可以间接影响到整个域,我只要利用此处ACL缺陷就能完成本次渗透,控制所有账户的凭据。那么,什么是ACL呢?

ACL全称叫作访问控制列表,列表内的记录叫做访问控制条目,也就是ace. 域内的所有对象的权限控制都是通过ACL实现的。

    

大家熟悉的ACL作用对象有成员账户、机器账户、组,组策略、文档服务器等。接下来我举一个小例子,让大家了解ACL的作用。假设我们是Domain admins组,要添加一个名为test的用户到domain Users组里面,添加成功后,domain user组里会有一个test的成员。这是因为domain user组内的acl里有一条ace为“允许domain admins组对它进行完全控制”。


这里我为什么要强调组呢?


这牵扯到ACL的一个特性,叫做继承。我以去年的exchange ssrf漏洞利用链举例,加深大家的理解。漏洞的核心利用点在于域上的有一条ACE写的是允许Exchange windows permission组进行任意的ACL修改。也就是说,当我们控制住Exchange windows permission组的任何一个用户后,就可以发出如下的acl请求,让test用户对domain admins组有完全控制权。


而exchange trusted subsystem组属于Exchange windows permission组,他们是父子关系,所以可以继承父组的acl。当他发出相同的acl请求时,也会返回成功。


又由于exchange的机器账户属于exchange trusted subsystem组,所以当他发出相同的acr请求时,也会返回成功。


攻击者如果在内网里发现了一个作用于Exchange机器账户的ssrf的漏洞,就可以控制域内所有的账户。 acl的配置保存在哪里呢?


这些信息其实保存在域数据库上面,域数据库提供了一些接口访问所有的acl信息,接口的上层协议是ldap,有一些工具可以通过ldap检索所有的配置,利用缺陷推导出这个域内有哪些攻击路径。


常见的工具有Bloodhound,invoke aclpwn等。接下来我以Bloodhound在实战中进行效果测试,大家能够看到这个图上“G-IT可以对EXCHANGE WINDOWS PERMISSIONS添加成员,Exchange windows permission组能对域内进行任意的acl修改,当攻击者能够控制IT部门这11个账户中任意一个账户之后,他就能完成本次渗透了。接下来我对这一处ACL缺陷进行成因分析:通常来说IT部门需要将新员工的帐号进行精准的权限控制,这一步通过将账号添加到已经配置好acl的组里来实现。也就是说It部门需要有添加成员的特权,这个过程中,出于安全考虑,拒绝了it部门向高特权用户组添加成员,比如域管组。但是忽略了一些高特权的系统组,比如:ex windows permission组。

    

接下来有一个简单的流程展示,IT组成员可以继承自身组的ACL将自身账户添加到Ex Win Permission内,继而继承Exchange windows commission.组的acl,将自己提权为域管理员。接下来要面临的一个问题是,如何控制IT组的成员。


传统思路有进行密码的爆破。考虑到对方企业密码策略较为复杂,有14位以上的数字、字母等特殊字符组成。同时我们在爆破的过程中,可能不可避免的会在域控上留下一些审计失败的LOG,这个时候就会触发日志审计预警。其它可以尝试控制IT部门成员的PC机,之后可能通过一些传统的工具提取凭据,这个时候就有了IT部门某位员工的帐号权限,但是此条难度较大,所以也忽略:因为IT部门员工可能具备较强的安全意识。我们控制一些关联登陆的网站提取关于IT组成员账户的凭据,但是此种方案可能有点本末倒置。那么有没有不需要密码,就能利用IT组的成员账户向域内添加成员的方案呢?这里不妨思考一下添加域成员的原理,假设我们在域内执行net User, 它会通过SMB连接一个域控的一个叫samr的命名管道,从而间接连接到域数据库上。假设域数据库对某位用户进行身份认定成功、权限鉴定之后就会返回成功的信息,但是其实域数据库提供了其它的接口,就像我刚刚提到的LDAP。但是LDAP协议其实是可以被攻击的,LDAP支持NTLM认证,NTLM由于自身的缺陷可以导致中间人攻击。


正常的NTLM认证流程,正常的想要域内添加成员的话,要把自身的发送到到ldap上,身份认证等成功返回相关的信息。中间人攻击流程我诱导IT部门的员工跟我这台中间人的机器进行NTLM认证,此时就可以拿到凭据跟ldap进行认证,认证成功之后我可以在这台中间人的机器上继承IT成员组织的ACL。也就是说,我不需要密码,就能在域上添加一个成员。此时确定了要进行NTLM Relay攻击,就要选择一个可以触发NTLM Relay的载体。通常是有几种:浏览器、文件服务器,社交工具,邮件。浏览器需要大量的交互,所以pass。如果能够触发IT跟内部某台文档服务器的通讯,我们对这台文档服务器进行渗透、投毒。比如:投毒一个快捷方式,这条快捷方式指向中间人的服务器,然后下一次到IT部门的员工访问文档服务器的时候,就会处罚NTLM的认证。但是我们的渗透是黑盒的,由于此时也没有控制到一些进行流量监控的设备,也不能进行DNS劫持,所以我不知道IT部门的员工日常访问的位置,所以此方案忽略。再者“社交工具”,假设能够找到社交工具能跟NTLM触发的点,也可以进行NTLM Relay,但是这条挖掘成本过高。那么,只剩下邮件这个渠道。


这里要思考一下,邮件触发NTLM Relay的点,一般有以下几种。

1.邮件添加a标签,诱导点击。

2.邮件添加各类可触发认证的附件。但是这些方案都需要交互,IT部门的员工都有较强的安全意识,假设我给他们直接发送这类需要交互的恶意邮件,可能会被他们意识到此次攻击行动,导致渗透过程的终止。有没有不需要交互的方案?我在持续监控被控端的过程中,发现他们所用的邮件客户端outlook在加载外部资源时有不同的策略。首先是加载外部邮箱的时候,当一个外部邮箱给它发送邮件,其实它并不会完全的加载邮件中所有的内容,它会只加载邮件正文中的文本内容。正文里的图片需要经过手工确认后才能加载,但是企业内部邮箱发来邮件的时候,会完全加载正文里的所有的内容。

    

其实这是一个比较奇怪的问题,我查阅MSDN的文档发现,outlook默认来说,它会自动加载其他员工发送的外部图片。我们不妨这样理解,outlook认为外部的发件人是不可信任的、是不安全的。认为内部的域员工发来的邮件是可以信任的,因为它是“熟人”。它认为“熟人”应该没有问题,但是熟人真的没有问题吗?我们利用outlook自动加载内部域邮箱发来的邮件图片这一个,可以制定核心的框架。比如:我可以控制内部的一个员工的邮箱,他符合outlook的熟人策略。以他的身份发送一个恶意邮件给IT部门的任意员工,IT部门的任意员工在outlook上预览此封邮件会自动加载unc标签,这个时候就可以跟中间人进行NTLM认证,此时就可以把IT部门的员工凭据转发到域控的Dc ldaps上。此时我就可以在域内进行任意的修改,比如:将攻击者已经控制的账户提升为“域管”。这个核心的渗透框架有没有问题呢?

    

我在实际测试的时候,我发现受害者在outlook内预览一个恶意邮件的时候,恶意邮件IMG标签如果指向的是一个 UNC 路径,那么会有长时间的弹窗,这其实是明显的异常。我根据IE Relay的启发,我发现outlook也没有修复 http 重定向至 SMB 的问题,所以我就利用这种方案来bypass 了弹窗。此时我只控制的一台HR电脑和内网的一台Linux服务器,假如直接以HR的邮箱发送恶意邮件。那么可能会面临如下的场景:IT部门的员工在内部的IM工具上跟HR进行邮件主题的详细对接,他们可能会发现一个比较明显的异常。因为HR本人并没有发送此封恶意邮件,这就会导致我们渗透过程的终止。既然不能直接发,只能间接发了。也就是说,我要想方设法打通HR跟IT部门之间的联系。根据“六度人脉理论”,我们在地球上跟任意一个陌生人之间的关系链不会超过六层。也就是说,HR可能认识一个人叫X,X可能认识一个人叫Y,Y某或许会认识一个与IT有频繁邮件交流的人,此时就能构造一个熟人链条让HR跟IT部门之间有合理的交流。

    

我的邮件要如何构造才能在没有密码的情况下,控制这个熟人链条内这些节点的邮箱帐号呢?我通过简单的信息收集,发现邮件服务器Exchange。Exchange提供了很多接口,比如:EWS,它还提供了有ECP、OWA等。还有一些其它的接口,我就不作过多介绍了。这里重点介绍一下EWS接口,EWS是 Exchange 提供的一个 WebService 接口,可以通过这个接口来访问用户的邮箱。这个接口支持NLTM跟Kerberos。这个时候其实就能在不需要密码的情况下,构造一份为邮件构建熟人链条的邮箱节点。初始受害者如果构造一个恶意邮件满足outlook的熟人策略,此时熟人链中的节点在本地的outlook上御览此封邮件就会自动加载IMG的标签,Bypass outlook的一个弹窗。之后302跳转到已经控制的中间人机器,这台中间人机器就可以把熟人链中节点的凭据转发到EWS接口上,完成NTLM的认证,此时就是不需要密码接管熟人链中邮箱的全过程。

    

这封恶意邮件应该如何构造呢?或者是说如何让恶意邮件的主题更合理一些?这里我设计了一个简单的工具来实现自动化的流程,当我控制的这个初始受害者也就是HR给别人发送邮件的时候,我监控这个发送的动作,匹配这个发送动作中的收件人的邮箱。假设他是给一些熟人链中节点之外的邮箱发送邮件,那么就继续循环,假设或者是说直到这个HR给熟人链中的节点X发送邮件的时候,我污染邮件正文。污染邮件正文会有一个恶意的IMG标签,此时就能成功接管熟人链中节点邮箱帐号权限。那么这个污染邮件正文,是如何来实现的呢?当HR给熟人链中的节点发送一封邮件之后,我会立即跟着发送一封一模一样的邮件,唯一的区别在于恶意邮件中多了一个IMG的标签。在熟人链中的节点的outlook里,预览或者是说在outlook里查看它收到的邮件的时候,它会看到两封邮件。第一封就是我们的恶意邮件,第二封是正常邮件。

    

我根据上述的方案,设计了一套横向移动过程中基于流程,我把所有的受害者凭据放到一个资源池监控所有人的邮件发送。匹配到熟人邮箱污染正文,转到EWS接管对方的邮箱,再把对方的邮箱凭据载入到受害者资源池里面,直到受害者给IT部门的人发送邮件,那么我也是实现相同的污染邮件正文,但是此时就不是转到EWS接口上,而是转到域控的LDAPS接口,我就能接管IT部门的凭据,集成IT组的ACL,在域上进行任意ACL修改,让任意一个帐号有域管的特权。

    

武器说明。支持中文,支持邮件后门的增加与删除(delegate)。支持邮件污染(包含附件污染+正文污染)。支持关键字搜索及delegate后的关键子搜索,支持已公开的exchange ssrf漏洞利用。可对outlook设置homepage(邮件服务端未打ruler补丁的话,通过邮件污染可以直接渗透个人终端。邮件关系梳理。简单的说就是你发送一封恶意邮件之后,就能接管对方的机器。我控制一个邮箱帐号之后,我会提取它的发件跟收件信息,把这些信息作为一个关系导入到“图数据库”里面。我把发件人跟收件人作为一个节点导入到图数据库之后,直接输入某一个用户的邮箱就可以直接规划出从你到目标邮箱之间最短的攻击路径。

    

完成了定制化的工具开发之后,就涉及到武器部署。武器部署的目的之一,隐藏自己。其次是加大取证难度。这个过程我是通过大量的转发动作来实现的,所以需要你在对方内网里控制一台Linux机器以及你每年有一台外网的vps搭建二次化开发的工具。接下来是一张转发的流程图,它可能较为复杂。(图)这里我不详细讲解这个转发流程的实现了,大家能看到受害者访问已经被污染后的恶意邮件之后,自动加载IMG标签、302跳转到内网一台已经被攻陷的服务器,跟这台已经被攻陷的服务器进行NTLM认证之后,将流量封装转到外网的vps的445端口上。之后外网的vps通过端口的映射,把445端口转到内网的Linux上,然后跟内网的EWS接口完成NTLM认证。设计完这一个部署流程之后,我重新审视了一下,发现貌似还可以更隐蔽一点。也就是说,大多数的邮件网关设备都会对邮件正文进行扫描。提取正文里的UL进行域名的信誉评级,信誉评级几个因素,可能有讲了这个域名是否已经有在IOC指标里出现过。检查这个域名是否是新注册的?假如达到一定的权重之后,他就认为这个邮件里嵌着一个URL是不正常,直接归类到垃圾箱里,受害者就无法接受到这个邮件。

    

这里我发现邮件网关的引擎其实是部署在云端的,部署在云端意味着出口IP跟目标内网出口是对不上的?我在302跳转之前加上一个目标出口IP,然后还加了一个UA的判断,因为我发现所有的都是Office触发,邮件网关肯定不会有Office的UA。所以扫描的时候,无法发现后端已经被攻陷的服务器,所以它可能会将此封恶意邮件进行放行。接下来有一个简单的流程图来展示,这个大家可以简单的理解为“邮件网关”。他获取邮件内容,提取URL,之后关联反病毒引擎对URL进行判断。比如:信誉评级,扫描这个URL上随之附带的一些福建,比如:这个URL有关联的一些文档,会用反病毒引擎对其进行扫描。由于我的域名有302的判断,所以他认为这是一个正常的。

    

万事俱备,让我们看一下这个定制化武器的效果。(图)这是一个简单的展示,我提取了此名招聘HR的发件跟收件的信息,把这些信息作为一个关系节点载入到一个图数据库里,也就是尝试直接定义此名招聘直接上级是谁。我希望能够得到一个最短的路径,下面是一张图形展示。比如:初始受害者为招聘HR,它直接列出了它跟招聘组长也就是直接上级之间最短的路径。我发现他跟招聘组长之间交流的主题,我依据这些邮件主题判断邮件交流的频率,根据这个频率可以进行相应的邮件污染。


通过邮件污染控制H的上级P,现在的供给路线:通过招聘HR达到组长H,通过组长进行进一步邮件关系梳理确定了上级为HRBP head P。现在我们要面临的问题,就是如何打通HRBP Head跟谋为不愿意透露姓名但是与IT有频繁交流的高人之间的联系。这个时候我进行了一个简单的HR部门的架构分析,一般来说人力资源部门会下设以下小组,有:招聘、运营、薪酬、福利、培训等等。运营组复杂维护整个公司所有员工的信息,我作为攻击者只要成功控制了运营组的组长。当运营组的组长跟它的组员进行邮件交流的时候,通过我的定制化的工具进行成功的污染就能控制他的组员。比如:他的组员叫小明和小红。小红需要跟IT部门对接某一个员工的帐号需要什么样的权限。当小红跟IT进行跨部门沟通的时候,也是一个邮件往来的交流。那么,我污染他们的交流邮件,就能控制IT的帐号。此时大家审视一下,我已经打通了更新路径。有招聘HR A,跟它的组长H,跟组长H的上级HRBP。现在面临的一个问题,就是如何打通招聘组与运营组之间的联系。其实这个可以设计一个“迂回”的路径,因为正常两个组长是不会通过邮件进行沟通的。进一步明确的攻击路线如下:HR到H,到HRBP Head,然后想办法迂回控制运营组组长的帐号,运营组组长控制运营组的组员,之后组员跟IT进行交互完成本次渗透。

    

因为周报制度的存在,P某(hrbp head)需要定期向上级(hrvp)进行汇报工作,我通过之前成功污染周报邮件,成功控制了hrvp邮箱帐号。这是我工具的图例演示(图),此时我们就能完善一个攻击路线。我梳理HRVP的邮件关系,得知运营组组长为k,组员Y负责与IT部门对接新员工权限赋予。通过下面的一个邮件信息里的图,印证了我的这个思路。大家能够看到组员Y跟IT部门对接,某一个入职的员工需要在某台文档服务器上有什么样的权限。既然思路验证成功,就能完成整个熟稔连的攻击列表。由招聘的HR到H到HRBP head然后迂回攻击打道运营组长,想办法控制运营组的组长及组员,那么就能完成本次的渗透了。这个时候我遇到了一个意外,因为本次Ex Win Permission加outlook实现的横向流程不是主动出击的方案,是一种被动性的横向移动。所以我在等待的期间,我每控制一个熟人链中要等待,等待的期间遭遇了人力资源部门临时的组织调整,原先的运营组组长换人了。这个时候我就需要针对这种突发状况,进行简单的攻击路线修正。之后当HRVP跟原运营组组长K和新运营组组长Q进行邮件交互的时候,污染他们两个人的邮件成功控制了K跟Q,之后再通过Q跟组员进行邮件交流的时候,控制了组员Y。

    

那么我们做一次整个攻击链条的完整回顾。首先我通过邮件钓鱼的方案控制了对方公司里一名招聘HR的机器,通过它的机器进行初期的环境侦查,发现了域内一处ACL缺陷,通过这个ACL缺陷我画出核心的渗透框架。通过这个反推中其它的关键节点也就是招聘组长H,通过招聘组长H控制HRBP Head,通过HRBP Head打通运营负责人K,然后控制运营新负责人L,然后运营组员Y,IT等达成。这个时候我作为攻击者,我就可以不需要IT组的帐号密码,而继承IT组的ACL。我添加一个攻击者已经控制的邮件帐号,这个时候A就具有Ex Win Permission,它就能够对域上进行任意操作。此时我完成的所有的渗透任务。

    

我们来回顾一下本次渗透流程的优点跟缺点。优点是规避了所有的安全设备,这里我不介绍那种EDR的对抗,只是说IDS。因为中间人的机器进行NTLM Real攻击的时候,IDS设备不会发现异常。缺点,不能说缺点,因为确实没有什么缺点,可以说是缓解的措施。缓解的措施在于,我们可以应用类似于某些服务的签名功能,这个签名可以要求一个用户跟相应的服务进行认证时,用用户的密码生成加密。当然,一般企业也没有开这种。

    

我的演讲结束,谢谢大家!

    

问:EWS之类也有日志,;因为你存在劫持者和本人自己收邮件,所以这里是不是也会有痕迹可以做感知的?

Pr0mise:当防守方已经知道了此次攻击方式之后,可以依据这个攻击方式进行相应的防护。比如:他可以检查。我在渗透过程中有利用到“邮件后门”,这个会在ldap上留一个明显的新建项目,防守方监测这个项目就可以感知到哪些邮件账户已经被攻破。

    

问:你用到A标签。

Pr0mise:其实我没有用到A标签。我在outlook出发有A标签,最终没有选择就是因为它们没有解决交互的问题。

    

问:最后你用的是图片。对吧?

Pr0mise:嗯。

    

问:理论上图片这种接近302转的链接也是可以作为一个感知的点吧?

Pr0mise:只是一个跳转的动作,我觉得这不存在异常。


[2月30日:红对行动,终端日志对抗。]


2月30日:大家好,我分享的议题是“红队行动-终端日志对抗”。在网络安全环境日益恶化的今天,绝大部分的中小企业、政府单位,还有一些特殊部门均采购了越来越多、越来越好的安全产品。这些安全产品中,有一些可以通过对日日志的监控达到预警目的。甚至有一些产品做的非常好,不仅可以预警,还可以做到及时、自动的处置。这样就造成了我们在渗透过程当中,很有可能第一步还没有开始就已经结束了。本议题就是要和这种基于日志查询告警的安全产品进行对抗。我是议题的演讲人邓逊(音)。


由于我是第一次登台分享技术,所以请允许我多花一点时间来介绍自己。我的网络ID是“2月30日”,早年的时候混迹在一个叫“冰点极限”的技术论坛里面。这个论坛是一个非常老,也没有开放注册的一个封闭论坛,里面只讨论一些纯粹的技术。后来创始人觉得做技术可能不挣钱,然后回老家卖蟹肉煲去了。接下来是我的工作经历,为什么我在安全行业做了这么多年,才第一次出来分享技术?是因为我以前的工作性质,领导不允许我们把做的东西、还有研究的东西拿出来做这种演讲。整个工作的历程来说,我都是在处理一些一线的实际技术对抗方面的问题。主要涉及的方面有APT、Web安全、系统安全和数据库等方面,现在供职于奇安信A-Team。


我们要研究一个东西,首先要明确自己的研究对象。

    

研究对象主要有三点:1.终端日志的定义。我这里把系统终端中发生的文件访问、执行命令、网络访问,这些操作产生的日志统称为“终端日志”。这个终端也不仅指是一个Linux操作系统,可以是一个IoT设备、一个打印机,甚至一些什么别的奇奇怪怪的东西。2.本次的研究对象。本议题主要把问题聚焦在命令执行产生的日志上面。3.问题场景的设定。我把场景设定在一个Linux下面的一个低权限的webshell上面。不管我们做测试还是给客户做安全评估,这个过程当中很多时候做外网打点,都是从一个低权限的webshell开始的。Linux低权限webshell是非常常见的场景,也是我们一线工作人员经常遇到的,所以我认为把场景设定在这里是非常有价值的。

    

讲对抗的话,就必须要来认识我们的对手。(图)这个地方简单的列举了一些开源的安全HIDS这种日志告警工具和一些方法,因为时间有限我不可能把所有的产品都拿出来做一下,所以就选了开源、不用花钱的产品。第一个是Shelllog,是通过使用syslog接口或者直接修改Bash源码,然后再通过其它的进程对日志记录进行匹配告警的方法。它的方法比较古老,特点是简单易用,缺点是只能被修改的Shell本身执行的命令。然后Auditd是内核提供的一种审核消息,是通过记录系统产生的系统调用,应用程序做的系统调用,把系统调用的参数进行记录,特点是简单易用,范围非常的广,几乎所有的Linux的发行版本都支持它。这个地方标进行了标红,我们后来会详细的讲到它。第三个是ossec,ossec在监控命令执行这个方面,主要就是依赖于对Auditd日志查询,然后根据内置的规则进行报警。比如给管理员发邮件,甚至是打电话之类的。它的特点是简单易用多平台。第四个轻量级的开源项目snoopy,特点是轻量化、非常的灵活,可以只对你想要的进行设置,缺点是不能对静态编译的文件产生作用。最后一个是osquery也是基于Auditd,它基于的是Auditd一套内置消息机制做的,特点也是多平台、广泛。


前面大概讲了那些产品,如果把每一个产品都拿出来,甚至一些商业软件都拿出来做分析研究的话,那么这个产本太高了。Auditd是工作在最底层的,就是说内核消息的。Osquery是基于同一套Auditd的消息,Ossec是基于查询Auditd日志,所以他们之间的交集是依赖关系。也就是说Osquery和Ossec依赖于Auditd。Snoopy虽然没有依赖Auditd、而是用重载库函数,但是一样最后回到内核系统调用部分来。既然Auditd是总的突破口,我们就以它为研究对象来详细的了解。Auditd是Linux提供的一个日志审计的服务,优势在于管理员可以非常方便通过自己的软件包来安装和配置。左边的Open /etc/passwd是我们经常做的,下面的EXECVE是执行uname。现在我们在一台Centos上配置一套环境,第一步先装好,第二步把Auditd给启动起来。第三步,我们建立一条规则,这一条规则是针对64位的程序。UID等于48,这个是我的实验环境apache用户的UID,监控的系统调用是EXECVE。设好了以后,我们可以看到下面执行的ID命令被忠实的记录下来,执行的命令是哪一个,有几个参数,然后命令的路径和命令执行时候的当前目录,就是CWD。


对于日志类型,我们要思考突破方向,主要有四个方面。

    

突破方向:

    1.删改日志记录。对产生的日志记录进行删除或修改。这个日志已经产生了,我们把其中关于我们自己的东西进行删除,类似于提权成功之后删除apache的访问日志是一样的。

    2.停用日志服务。停止审计日志服务的进程或使他拒绝服务。比如:装了Auditd这种东西,我们把这种服务日志停掉、或者我们有某些漏洞达到“拒绝服务”的效果,让这个日志服务不工作。

    3.规避日志记录。寻找逃避记录的规则,类似于WAF绕过。

    4.污化日志记录。使审计日志记录不到有价值的信息。

    

就是说日志虽然记录了,但是被我打上“马赛克”。打上马赛克之后,即使是人工审核的话,也只能知道有人做了一些操作,他已经走了,但是不知道他干了什么,也不知道他到底成功了没有。然后在我们设定的环境里面,对于第一点“删改日志”我们是没有权限的。绝大多数的Webshell都是运行在www-data、apache等用户下,不具有root权限。第二个是停用日志服务,不具有root权限,没有已知的相关拒绝服务漏洞。规避日志记录,没有预设的豁免规则。像Auditd这种纯粹依赖于自身的系统调用的这种非常稳定、漏洞是非常难找的。然后第三个,规避日志记录,没有预设的豁免规则。最后一点,污化日志记录。因为安全产品是通过对这些日志进行规则的匹配,甚至一些机器学习的东西来发现的。我们把日志涂黑了之后,这种警告就会失效。

    

回忆一下刚刚我们Auditd产生的日志,主要有我们要执行的命令路径,就是我们执行什么,然后我们给它参数是什么,两个部分来组成。我这里进行日志污化,也分成两个部分分别来解决。第一部分就是执行路径,我采用的方法是内存执行。然后参数的一部分,是参数污化。首先第一部分,内存执行。要用内存执行这个主要用到的系统叫memfd-create,这个系统调用的作为是创建一个匿名文件。如果你对“匿名文件”概念不太理解的话,可能绝大多数人对windows要熟悉一点,windows就相当于内存预设文件、你可以这么理解、但是不等同于。它有两个参数:一个是匿名文件的名字,这个名字不重要。比较重要的是第二个参数,就是创建文件的时候给文件一些属性。整个系统调用返回的是一个文件描述服务,就如同我们打开一个文件、Linux上面打开一个文件,我们有Open或者是访问网络系统描述符一样。比较重要的是Flag里面,因为最后要可执行文件。所以我们要在flag里面加上MFD-CLOEXEC标志。最重要的系统调用介绍完了,就可以得到一个基本的流程图(图)。第一步,我先使用memfd-create创建一个匿名文件,再把这个匿名文件的大小进行分配。分配好之后之后再把bin/id这个ELF文件写到匿名文件、也就是写到内存里面。这里值得注意的一点,这里写的文件是本地磁盘的文件,但是它其实不仅可以是本地磁盘,还可以来自于别的地方,最常见的场景就是我们在做渗透的时候,如果要下载一个东西,下载我们自己的ELF文件到内存里面,必然我们要使用一个高信誉的域名。比如:百度云盘这样的高信誉的域名,作为一个图片传上去之后,然后拉回来解码写进去。也就是说,这个地方是灵活的,它可以来自于任何地方。而不管你这个文件;不是说我这个文件必须要有可执行的权限、这个不需要,来自于任何地方都可以,因为我们在memfd-create的时候给了相应的属性。我们知道在Linux每一个文件描述打开以后,都会有自己的/proc/self/fd下面创建一个数字命名的文件,这个文件在这个地方是可以直接使用Execve系统调用。bin/id抽取一个东西,相当于映射到程序的proc/self/fd/N,然后再execve执行。

    

可以看到同样是一个Auditd的日志记录下来的内容,在第一个参数的位置和路径的位置,同时这里也反映执行的命令bin/uname -a,这个地方参数并没有解决,这是我们接下来的第二个部分,就是参数污染。“参数污染”在比较长的一段时间内,都让我一筹莫展。但是后来Cs3.13给了我很大的其实。Cs3.13带来一个新的特性,叫作“进程参数欺骗”。它的作用是什么呢?可以让Windows创建进程的日志,只能记录到一些虚假的参数。这里所谓的“虚假”,就是一些无意义的字符。Cs3.13的特性是怎么让这个东西工作的呢?首先它用一个虚假参数创建了一个子进程,但是这个子进程使用挂起的标志位,让这个进程是挂起的状态。我们如果调过Windows程序就知道,我们的调试器打开一个EXE之后,那个就是挂起的状态,就是在开始的状态停住了。挂起之后再通过ReadProcessMemory和WriteProcessMemory修正参数。接下来恢复子进程执行。我调用CreateProccess启动一个程序,这个API已经返回了。API返回之后,Windows的创建进程日志也完成工作了。它说:你执行的命令我记录下来了,我的工作已经完成了,接下来的工作跟日志服务就没有任何关系了。所以通过这种“暗度陈仓”的方法,Cs3.13成功了。

    

我们要在Linux上面借鉴这个东西,实际上我一查还比较麻烦。因为Linux的execve系统不提供这种功能,同时也没有库函数提供这样的功能。甚至我搜索资料的时候没有一个第三方的库完成这个功能,但是如果我们把上面提到的“挂起进程、搜索内存、写入修正内存,把这看作自动化的程序调试的话,那么Linux有一个ptrace系统调用是非常完美的选项。


为什么说它是一个完美的选项?有下面三点:

    1.稳定易用,由系统调用提供。

    2.支持广泛,大多数发行版本支持。

    3.成熟用例,知名调试器GDB。

    

关于系统调用更详细的,可以看官方文档。我PPT里面,只列了一些我需要的功能。主要有:TRACEME,获取子进程控制权。我启动的子进程状态,要给我挂起来、我要控制它。第二个是GETREGS,获取寄存器值。第三个是PEEKTEXT,它是把像指令地址读取数据。第四个是POKETEXT,写入数据。然后是CONT,继续执行(resume)。再下一个是放弃控制权,DETACH。最后一个是单步执行。有了对API非常深的认识了之后,整个流程就出来了。

    

参数污化:

    1.调试子进程。

    2.虚假参数启动进程。

    

启动完了之后,我们的对手Auditd已经把虚假的参数进行了记录。也就是说,跟Windows的日志服务一样,它说:我的工作已经完成了。他的工作完成了,我们的工作并没有完成。接下来,控制子程序的运行。通过单步运行的方法,一直找到执行这个程序的入口点。找到入口点之后,然后我们修正参数,在内存里面把这个参数重新修正回我们想要传递的参数。修正完了之后,我们再调用把自程序继续跑起来。我对Linux装载器,把一个程序装载开始进程的状态不是特别的熟悉,所以我才需要单步执行一直找到入口点。因为在入口点的位置有参数传递进来,所以那个位置是我最容易找到参数内存地址的地方,并不是说,如果你自己要做这个功能的话,我必须要这么做。不是这个意思,我的这个图是因为我的水平差一点,没有办法在装载期开始的时候找到参数的内存地址。如果你能很快的通过在装载的时候找到,就不需要这一步了。这一点专门提出来讲,是为了规避后面会提到的一个问题。有了这个流程之后,我们继续把两个Demo给连接起来,形成了我们完整的一个Demo。可以看到下面(图)apache用户执行的一个命令之后,可以看到所预期的有uname-A地方的值,这个时候我们的Demo顺利的完成它了使命,把执行的路径和它的参数都打上了马赛克。

    

Demo。我们红队在持续做任务的时候,不可能拿一个Demo就上去弄,因为我们不可能为每一个命令编一次代码。所以必须要提到这个“武器化”,“武器化”我选择了一个最常见的动作,我们要反弹一个Shell。现在我们要把Bash源码拿出来,然后把内存执行和参数污化两个技巧以补丁的形式打到Bash源码里面,重新变异生成一个Shell,然后再把这个Shell绑定到端口上面,这样就形成一个执行的每一个命令都使用了这两个技术。下面是武器化更详尽的细节,左边是Bash源码,下面是execute-cmd.c,这个文件实现Shell-execve函数,右边是libptrace这是我把之前两个Demo结合起来做的静态库,这个静态库实现的execve2,我们把系统调用execve的地方换成我自己的execve2就完成了这个简单的包装了。

    演示代码跟libptrace库代码都在我们奇安信的github上可以下载,有兴趣可以下载一下。

    接下来就是展示我们的效果,我们要把首要的三个产品;因为Auditd的日志已经看到效果了,我们要把三个产品的效果进行展示。首先第一个登场是osquery 脸书的开源工具,左上角是反弹Shell,在里面执行简单命令的一个过程。右下是osquery提供的一个关于select查询。Path这个字段已经全部变成了memfd,这个地方有点不一样,但是不影响,因为全部变成统一的一个东西。然后下面的是snoopy,snoopy是工作在用户层的,自然也逃不过我这个是基于欺骗内核系统调用的方法,我工作的比它更底层。右下角是通过NC在反弹Shell的时候还能看得见的,之后就不知道是执行的是什么。接下来是ossec,ossec可以看得到里面的一些参数、路径,也变成了我们预期那样。在这种情况下,ossec规则和规则匹配联动的一些报警措施就会失效。

    

这三个产品,都已经完全被攻破了。

    

然后接下来要说的,是:这个世界上没有完美的技术。接下来,讲局限性。局限性主要有三个方面:1.隐蔽性,就是说:我在低权限的情况下,除非我在后续的操作当中成功了。否则我在低权限情况下,只能把日志打上马赛克,但是我不能让它完全消失,这算是一个先天的缺陷。2.兼容性。回顾之前参数污化部分的运作原理,是通过挂起进程之后再进行内存修改,相当于预设的调试指令。我们知道Linux有非常多的发行版本,绝大多数的EFL装载器的标准是一样的。但是也不排除有少数的发行版本标准并不一样。或者是说有的程序在编译的时候,加了一些不常见的flag。这个可以通过代码调优,来扩大兼容面积。3.执行效率。因为我们在执行之前、子程序执行之前进行了一些包装,比如:我的代码里面就有单步执行的过程,到入口点的一个过程。这在感官上,就降低了执行的效率。我在执行的时候就发现,有了这个可能会慢两秒钟。这个东西的解决方案,就是去掉调试一步,对装载期子进程内存环境足够非常熟悉,可以在挂起的时候就完成参数的修改,这个是没有问题的。我也非常期待有同学给我分享一下,直接在装载初起挂起的状态就把参数修改过来的方法。

    

我的议题就到这里,谢谢大家!


图南:GraphQL安全指北


图南:大家好!非常感谢大家能参加红队分论坛,到第三个议题了,还是人满为患,非常感谢。我今天讲的议题内容,主题是“GraphQL安全指北”。我先做一下自我介绍,我叫图南,大家也可以叫我“南哥”,是奇安信A-Team的安全研究员,曾经我是一名程序员。可能在座都是做安全相关,比如:漏洞挖掘和渗透测试之类的工作。我觉得我之前做的工作,我是漏洞的生产者,所以我自称为:给大家提供漏洞来挖的这么一个人。我的邮箱是bibotai@qianxin.com,可以通过这个邮箱联系我。我分享的主题和前面两个不太一样,前面两个是攻击思路,攻击思路也非常棒。我是从研究员的角度,从全方位的角度剖析“安全”的问题。在开始之前,我先说一些题外话。

    

这个议题是由我和猎户攻防实验室gyyyy共同完成的,当时我是在我老东家写GraphQL程序、也就是说做开发工作、他也做一些GraphQL相关的开发工作,顺带做一些安全的研究工作。我们俩因为搞同一个东西,然后就一拍即合,说:有空看看安全问题。然后就觉得这个方向蛮好的,然后就写了一篇文章叫《GraphQL安全指北》,这篇文章大家可以在网上搜到。我这个议题是根据那篇文章稍微做了一些修改,然后呈现给大家的。其次议题中的后端源码,是以Node.js为例。但是现在的主流语言如JAVA等各都可以支持GraphQL开发。

    

我开始正式介绍GraphQL。在介绍之前,我请大家看两组HTTP的请求。第一组,我们可以发现大家应该非常常见,左边是一个GET请求,右边是一个POST请求。请求内容和请求体,大家在渗透测试和漏洞挖掘过程中经常会遇到。下一个请求我觉得可能在座的各位有的人已经在渗透测试的时候遇到过类似的请求了,只不过可能有的人不知道是什么东西,有的人知道。这种请求就是GraphQL请求。我大致说一下它的特点,首先我们可以看到它是单路由的状态。也就是说,两个请求用了同一个路由,也就是GraphQL的路由。

    

有些人就说:GraphQL应该是以后Web API主力,也有人说GraphQL最终会代替RESTful成为一个新的Web API。我觉得GraphQL已经进入了我们的视野,所以我觉得详细的了解一下它也是非常必要的。在正式对GraphQL下定义之前,我们先看一下现在已经使用GraphQL的大客户们。首先以Facebook为领头,它是GraphQL的开发者和推广者。有Twitter等大厂,还有Airbnb等等。GraphQL API也会给大家提供一些便利性,比如:产业限制,可能会更少一些。

    

我现在开始真正的对GraphQL下一个定义。GraphQL是由Facebook创造并开源的一种用于API的查询语言。正如图上展示的那样,可以通过它语言的形式描述你想要的数据,然后请求你想要的数据,然后得到可预测的结果。我再用官方的文案去描述一下GraphQL的特点:首先第一个特点,请求您所要的数据不多不少。我们大家可以看这个动图。我在左面请求中只要加一个字段,右面的响应中就会多出来一个字段。我在左面响应删除一个字段,右面的响应也会少一个字段。也就是说,前端想要什么就来什么,不用关心我拿到我不想要或者我拿不到我想要的,这就是说请求你所要的数据不多也不少。第二个是获取多个资源,只用一个请求。传统的API的是通过入口端组织资源的,比如:这个例子,在普通的API的时候要分成两个请求。这里可以通过一个资源扩展到另一个资源。比如:我请求Blog的时候拿到作者数据,添加一个作者资源,添加相关的字段就可以拿到一个它的数据。第三个特点是描述所有可能的类型系统,从这张动图我们可以看到,基本上每一个字段都有其自己的类型。比如:常见的像type里面的类型,这里面author是我们自己定义的类型,关于这个类型系统我后面会继续介绍,大家现在不太了解也没事。后面我就开始说GraphQL核心的组成部分:类型Type。用于描述接口的抽象数据模型,有标量和对象两种。对象由Field组成,同时Field也有自己的Type。第二个组成部分是Schema,用于描述接口获取数据的逻辑,类比RESTful中的每个独立类型URL。一个GraphQL Schema中的恩样本的组件对比类型。Query是用于描述接口的查询类型,有查询、更改和订阅三种。Resolver用于描述接口中的每个Query的解析逻辑,部分GraphQL引擎还提供Field细粒度的Resolver。

    

我觉得只看概念,可能还让没有接触GraphQL的人会有一些模糊,所以我后面展示一个非常简单的示例。这是一个非常简单的GraphQL服务器的组成部分,我们可以先看最上面我框住的最大的部分,那个就是一个type定义,里面描述了要查询数据的形状,并且指定了GraphQL服务器获取数据的方式。Schema包含在Type中,Schema的最基本组件就是对象类型。下面大框里面的小框就是Query是所有GraphQL查询的根。下面的Resolver定义的是用怎样的技术方式从刚才定义的Schema中取出相应的数据。下面就是ApolloServer,这个GraphQL服务器就搭建完成了。

    

我再去对比一下常见的RESTful接口和参数型接口。前两行是参数型接口,把想要传递的后端数据带到URI参数接口,后面是RESTful接口。这两种只是请求的样式不一样,得到的结果是一样的。并且共性,就是我每次请求一个资源,需要发送一个请求。GraphQL是单路由,其次我们可以看到请求体,我想要什么数据,可以把这个数据组织出来,然后得到我想要的响应。这样的话,就会非常灵活。大家可以记住,就是左边那个GraphQL请求的样子,如果以后见到这种样子,就可以认定它为GraphQL请求了,也就可以用到我后面讲的一些安全知识做一些漏洞挖掘和其它的一些研究工作了。

    

我又做了一个动画去展示一下RESTful和GraphQL的区别。首先我们可以看到这个动画反映两点:第一点,首先我发两个请求,这是非常明显的,有“1”和“2”两个请求。然后其次是我在请求Blog的时候拿到的是Blog全量数据。

而GraphQL做到了我想要什么字段拿什么字段。

    

前面我介绍完了GraphQL的相关基础知识,我后面开始讲GraphQL存在的一些安全问题。在开始讲安全问题之前,先给大家展示一下,我们可以看到里面的漏洞,可以注意到奖金还是非常高的。如果我们现在可以挖一些GraphQL漏洞的话,我觉得应该可以赚一笔可观的数额、我觉得是这样。首先我讲一下第一个安全问题的第一点,就是身份认证与权限控制不当的问题。其实GraphQL和其它的API技术是一样的,需要进行身份认证和鉴权。GraphQL官方是推荐把身份认证和鉴权放在业务逻辑层的,我们可以看到这个图,就是他把鉴权的逻辑放到了业务逻辑层。我们可以看一些例子,这还是我从Hackone里面找的一些例子,评分是9.8,还是比较高危,这应该算是一个严重漏洞。可以看到奖金是5千美金,还是非常可观的收入。我把这个详细的用红线划出来,现场展示屏幕可能看不太清,所以我给大家翻译一下。这个文件就是在JavaScript文件中暴露了一个GraphQL接口路径,通过这个GraphQL接口路径在未经身份认证的前提下查询到了很多关键数据。第二个例子是星巴克的,一个获取用户地址簿的GraphQL查询语句可泄漏部分用户地址簿信息。这是一个明显的权限控制不当的问题。

    

对于GraphQL引领者或者开创者来说,它是不是也能逃过一劫呢?我觉得不是的,我已经看到了很多Facebook相关的漏洞。比如这个例子,它是一个不合时宜的授权导致用户可以越权切换别人的预约服务的开关。这个我也把它归类为,权限控制不当的问题。虽然这个漏洞是低危,但是也是达到了一千刀的可观收入。

    

我们看了这么多的例子,有很多身份认证和权限控制不当的问题。我想说一下就是为什么GraphQL会频繁发生这些身份认证无效和权限控制不当的问题?我总结为三点原因:

    1.GraphQL多了一个中间层,对它定义的查询语言进行语法解析执行等操作。

    2.Schem Resolver等种种定义让开发者对它的存在间接增加了复杂难度。

    3.单路由形态,通过不同的field查询得到不同的结果,开发者需要对每个field的resolve做权限控制。

    

在我抛出问题之后,提出一下解决方案。我在这张图展示的就是一个“裸奔”的GraphQL接口,客户端可以通过请求拿到GraphQL里面的服务器里面的数据,这就是一个非常常规的状态了。黑客或者是恶意攻击者,也可以通过构造一个请求去拿到一个返回的数据,这就是没有任何防护的GraphQL服务器。在我提出GraphQL服务器认证无效的解决方案之前,我们先回顾一下RESTful是怎么认证的。GraphQL解决方案,我觉得也可以按照RESTful的思路去做。比如:我也先让他请求一下RESTful服务器,然后让它访问token,这时候客户端带着token请求服务器,然后返回结果就OK了。这也是官方最推出的做法,但是前提是我们应用的服务架构,必须是有支持RESTful的。


方案二:在GraphQL内认证。这是我帮老东家做的一个方案,因为我们之前走的比较激进,因为GraphQL各种好处。我们当时没有其它认证服务器,也没有一些RESTful的接口,这样只能在GraphQL实现了一个登录的逻辑。看这张图,就是客户端先去GraphQL服务器请求token、返回token,然后带着token请求服务器,然后返回就可以了。这里面展示这一套方案的实现代码,我们先看右面的代码。右面是一个登录完返回对象的一个,我们可以看到用户可以带着用户名和密码去登陆,登陆完之后返回的结果里面带着token,这时候再请求GraphQL服务器。左面是整个认证的流程,认证完成之后需要对ApolloServer就是GraphQL服务器做一个对应的修改,也就是说在这里面我通过token获取我的用户,然后把用户塞到GraphQL服务器配置中,在RESTful中进行细粒度的健全和授权认证解决方案。

    

因为GraphQL的这些特性,导致它如果出现认证失效或者权限控制不当的问题之后,会带来一些更多的后果。我把它总结为并发症。首先我说第一个并发症就是内省,在我们熟悉的普通的那些RESTful和参数性接口要先做一步,就是信息收集。我要知道这个里面大致有什么操作,比如:有什么路由,都能执行什么操作,都大致能返回什么结果。这个时候我可能需要得到一个API的全量数据,但是之前的RESTful和参数性接口,我只能猜接口长什么样子,所以我可能就用到一些代理、甚至爬虫,还有爆破的一些方式去拿到我外围API大致的全量数据。但是由于现在我们已经知道了,已经有很多的厂商在用一些虚拟DOM技术,比如:VUE等去做一些前端,导致我们可能用爬虫,还有用代理都不太好使了,这时候我们可能要用一些更高端的技术如Headless去抓全量数据。但是对于GraphQL如果我们想要获取它内部信息的话,可以完全省略这一步,因为它有一个内省自检机制。首先GraphQL自带一个强大的类型自检的机制功能,可以看到通过schema可查询所有的可用对象,通过type查询指令对象的字段。

我后面展示一下schema的用法,这张图展示的是我用schema查询我所有定义查询的schema的情况。

    

下面我展示的是我通过type的查询,查询到所有blog里面type的情况。接下来这张图展示的是我用GraphQL开源的内省工具、输出的详细文档,我们可以看到里面详细的Query文档,包括:Query里面所有的定义,里面要传什么参数,包括注释都会写的很清楚。这其实是一个对开发者非常友好的功能,因为开发者可以不用再去维护一个接口文档,他可以直接开发完GraphQL API之后通过内省文档调用服务器就OK了。这个同时也给安全埋下了一个隐患。

    

说完了第一个并发症,我们可以看一下第二个并发症。这个并发症是我们自己定义的,叫“非预期字段”。我给它定义如下:同一个接口给不同的权限职能、属性、决策使用,正常情况下每一个角色只查询接口的一部分字段。也就是说,它肯定不会两个同时使用。举个例子,就是我要查询的是一个三个字段,有两个需求。第一个需求,查询的是A和B。然后第二个需求,查询的是B和C。但是如果这个接口被恶意利用的话,比如:一个恶意攻击者可以去用“内省”把接口里面的内容都“内省”出来,然后把ABC都查出来,这就是一个不对字段权限的概念。所以如果不对字段权限控制,即可被利用产生非预期字段。

    

GraphQL容易查询出非预期字段的原因:

    1.GraphQL是根据前端请求的字段进行数据回传。

    2.后端Resolver的响应包含对应字段即可。

    3.后端字段扩展对前端无感知无影响。

    

我为什么定义为“非预期字段”是因为我觉得它不只是一个信息泄漏的问题,它还有可能造成一些其它的问题。

    

我现在开始举例子:假如有下面的一个需求。假如有一个开发者叫小明,小明接到了两个需求。第一个需求,管理员可以查看用户的相关信息,需要查看的字段有用户名、邮箱、创建日期。第二个需求,是运营人员需要统计用户数据、输出报表,需要查询信息有用户名、身份证号、登陆地点。我们可以发现这两个需求应该是在开发过程中经常会遇到的,第一个需求它可能是一个系统级别的需求,它需要把这个功能做到系统中,然后给管理员查看。第二个需求,运营人员要做一些活动之类的,他就直接跟成员说:小明你给我导一份数据,数据里包含这些信息就可以了。

    

小明已经开始写代码了,我们看到他搞了一个叫UserInfo的Schema。这种设计其实是GraphQL推荐我们去这样设计的,因为我们可以把一些需求去合并,然后去设计出来一个接口去解决多个问题。这样的话,也方便开发去维护代码,也方便项目推进。但是我们会发现这个身份证号和登录地点并不是一个预期字段,也就是说这两个“点”其实我是不希望让除了运营人员其他人看到的。我这张图就展示了一下,就是这两个需求,还有被恶意利用的情况。

    

首先说第一个需求,就是在管理员需求。管理员通过这个查询,他查询到了他想要的内容。然后是运营人员通过这个查询,查询到了他想要的身份证号和登陆地点的这两个字段。但是如果这个被恶意利用或者被黑客利用,可以构造这样的一个请求,就是把里面的字段全部包含起来,造成了非预期字段泄漏的情况。我觉得非预期字段还有一个并发症,就是我觉得他俩是并行的,就是废弃的字段。废弃的字段也是非预期,但是我把它放在三类。GraphQL为了字段的删除提供了一个废弃的解决方案,如果一个字段不再使用,可以标识“字段为废弃”,但是如果不对废弃字段进行修改,依然可以查询到废弃字段的内容。也就是说,我们可以发现这也是一个对开发非常利好的操作。比如说他有一个字段,他不想要了,然后他就可以标识为废弃就好了。然后我继续举刚才那个例子,架设小明已经意识到了刚才那个信息泄漏的问题了,就是idCardNo和loginLocation是非预期字段,他发现GraphQL文档中有废弃字段可用,就把这两个字段废弃并标识为安全问题,标识完了之后,如果他不对Resolver做修改的话,仍然可以通过内省暴露废弃字段的。这里面有一点,就是在我们进行一些安全研究和漏洞挖掘过程当中,我们会发现有很多的安全问题是利用了开发、测试,还有运维的一些盲点去产生的。如果你问我:为什么会有这些盲点。我只能说,他们可能在平时的一些开发工作中根本就遇不到。

    

如果小明没有仔细阅读那篇GraphQL的文档,或者说他没有仔细阅读“内省”章节,他一定不知道通过给field里面传一个includeDeprecated字段并设置true就可以拿到所有废弃字段。

    

由于开发者小明没有对Resolver做任何修改,所以废弃字段仍然可以查询。我们可以看到这两个字段已经标黄了,提示这两个是废弃字段,但是实际上我查数据没有任何的问题,因为我后端的数据Resolver是没有更改的。

    

刚才讲了一系列权限和授权相关的漏洞,我现在开始说一下GraphQL注入,我这里也引用一下qyyyy的金句:有语法就会有解析,有解析就会有结构和顺序,有结构和顺序注入。

    

再举个例子,小明是前端开发工程师,构建了这样一个前端的GraphQL查询依据。(图)如果黑客用字段拼接,我们可以发现语句结构就发生变化。这个当中多了一个hack对象,hack对象又对user进行了查询,传入username参数,值是admin意图很明显,就是想把管理员的帐号、密码和相关信息查出来,这就是GraphQL注入。GraphQL注入如何解决?幸运的是,它的类型系统可以定义到每一个字段的具体类型值。也就是说,可以作为天然的屏障帮助我们过滤一些恶意的注入。但是在前端、在官网上也是不建议大家用字符串拼接写,所以我们看到解决方案代码,第一行是一样的,第二行都写了一个参数,并且在下面把name传到username参数去,然后把client和query直接传到后端,也就是说最后拼接成GraphQL过程直接交给后端,避免了GraphQL注入。

    

第三个问题就是拒绝服务。在我做安全研究的过程当中,我会发现有很多的对象嵌套的存在,比如:A对象嵌套B对象,B对象嵌套A对象,这样互相嵌套,我可以无穷无尽的展开。如果那个对象里面是一个指令类型而不是引用类型,就很有可能造成诸如OOM之类的问题。OOM其实就是一种拒绝服务,GraphQL也是允许对象间的嵌套关系存在的。如果我们不对对象的嵌套深度进行限制,就会被攻击者利用进行拒绝服务的攻击。

    

最后一个例子,还是小明。小明已经完成了刚才我展示了很多遍的系统,完成之后就有一个需求完成了。需求一,查询所有文章的时候,返回内容中包含作者相关的信息。这个时候突然又来了一个需求,就是说:查询作者的信息,返回内容中包含此作者所写的所有文章。其实大家可以看到,这个需求也是一个非常常见的需求。比如:我想一下先有的一些博客,点一下作者的头像就能列出来这个作者所写过的所有文章。这个时候小明又很快的写代码去了,然后我们可以看到右面的Query是我展现之前Blog查询的。这样就达成了刚才需求二,就是查询author时候返回他所写的所有文章。这也是可以看出GraphQL的优势,可以通过改少量代码完成。在blog查询的时候嵌套author,在author查询的时候嵌套blog,这样无穷无尽。

    

对于拒绝服务的解决方案,我这里只提一点:限制查询的深度。这个代码里面展示的是我当时用graphql-depth-limit包,限制十层。在设计GraphQL接口的时候,应该避免出现嵌套问题,这是一个程序设计或者是一个框架方面的问题。其实在官网上还有一些其它的解决方案,比如:限制一下查询的复杂度。总之就是解决方案,不仅限于查询深度。

    

在结束之前,我想抛出我的两个观点。第一个观点,我觉得GraphQL只是一个接口。它和其它的Web API的接口是一样的,都有可能通过一些对外界数据的接收,然后影响了它的结构、影响了后端,造成了一些安全问题,这个就是大家都有的共性。我觉得我们并不能要求GraphQL去帮我们做很多的安全问题,这个更多还是一个安全意识的问题。所以我觉得它还会存在诸如:XSS、SQL注入、"NoSQL注入、CSRF、远程命令执行。右面的图是展示GraphQL可能会存在的SQL注入和NoSQL注入的。红色背景的字第一行是SQL注入的情况,第二行是NoSQL注入的字段。关于NoSQL注入可能有一些人不太了解,可以看我另一篇文章《NoSQL知多少》。

    

我想抛出的第二个观点,是我本次演讲只是给大家抛了一个砖。至于以后还能引出来什么样的玉?我希望大家能一起来参与一下GraphQL的研究。所以我觉得关于GraphQL研究的点可以有很多,比如:我们所知的GraphQL引擎,有各种语言实现的。不同语言有不同的语言特性,不同的语言特性会不会造成一些新的问题?这个还是我没有研究到的一个方面。还有一个就是它引擎内部执行流程,我也没有仔细去看。既然GraphQL作为一个语言,它一定有语法、也一定有解析。那么,它的语法和解析的一些过程,会不会存在一些问题?比如:我们所知道的有很多的漏洞都是因为语法解析的问题,造成了一些非常严重的漏洞。比如:命令执行。这一块,也是我没有涉及研究的。还有就是对于一些数据外部传的内部校验和数据编码的过程,这个也是我还没有涉及到的。所以我觉得我今天的演讲就到这里,但是希望大家可以后面继续加入到GraphQL研究当中。

    

谢谢大家!

n1nty:红队行动,横向移动与IDS对抗


大家好,我今天带来的议题叫作“横向移动与IDS对抗”。首先做一个简单的自我介绍,我来自于奇安信A-Team。横向移动本身是一个比较宽泛的概念,我标题里面说的横向移动其实指的是某一种具体的行为:当黑客已经通过某些途径进了内网以后,已经通过一些方法获取到内网Windows服务器帐号密码以后,通过这些账与密码去远程控制目标服务器的这么一个行为。后面的内容会跟大家分享我收集到的一些网络上IDS的规则,这一类IDS规则基本上都是用来检测这一类的行为,跟大家分享这一类IDS规则的缺陷和绕过的方式,以及我自己总结出来的我认为是比较好的方法论。我今天说的IDS指的是网络层面的IDS,不包括主机层面的IDS。


前面说到了具体的行为就是当黑客已经有了帐号密码以后,需要远程利用这些去控制Windows服务器。通用有几类方案可以达到这个目的: PSEXEC 类、计划任务类、WMI类、DCOM类和其它类(RDP、WINRM)等。 我今天的演讲内容主要覆盖前四类而不包括其他类。

PSEXEC 类、计划任务类、WMI类、DCOM类,围绕这四类横向移动方案已经出现了很多不同的工具。但是,无论这些工具本身在使用上有多大的差别,只要他依靠的是那四类方案进行横向移动,那么它们就有一个共性:它们所依赖的下层协议是 MSRPC。

    

MSRPC是微软的远程过程调用协议,是基于DCE/RPC改良出来的,跟所有的RPC 类的协议都一样,其目的是为了实现跨进程的过程调用。“过程”可以直白理解成函数。后面我会讲到跟这个协议有关的比较大量的理论知识,所以大家跟紧我一点。

    

MSRPC协议的作用。同一个操作系统上两个不同的进程A.EXE和B.EXE,如果 A.EXE 想调用 B.EXE 中的某一个函数,那么可以通过 MSRPC 进行调用,并且可以拿到这个函数的返回值。这是在同一个操作系统上面运行的两个不同的进程。其实利用 MSRPC 还可以实现跨机器的远程调用,比如运行在机器 1 上的 A.EXE 可以利用 MSRPC 去远程调用运行在机器 2 上的 B.EXE 中的函数,并且拿到调用结果。现在我们知道了MSRPC协议是个什么东西,以及大概的功能是什么。我们重新审视一下前面说到的四类横向移动的方案。假如攻击者、黑客用了这四类方案中的任何一种来对远程机器进行横向移动操作的话,本质都是利用了MSRPC协议对要打的机器所暴露出来的敏感函数进行调用而已(敏感函数指的一般是具体远程进程创建、远程命令执行功能的函数)。这个场景下我们可以将攻击者,也就是发起MSRPC调用的这一端称之为MSRPC客户端,以及被它打的机器称之为是MSRPC协议的服务端。MSRPC协议客户端与服务端到底是怎么通信的呢?或者直接的说,当攻击者、黑客使用这些方案来打另外一台机器的时候,攻击者和目标机器之间到底做了哪些交互?我们首先需要知道MSRPC协议的服务端怎么实现的,我画了一个流程图。

    

第一步,服务端需要定义并且实现RPC接口。第二步,实现完以后需要把这个接口注册到Windows操作系统里面去。第三步,就可以接收RPC调用了。我们首先要知道RPC接口是什么?前面我们说到客户端通过微软RPC的协议调用远程服务端暴露出来的函数,这个说法不是太准确。因为服务端直接暴露的并不是一个函数,直接暴露的是一个接口、接口里面有多个函数。客户端调用的时候,其实是连接到服务端暴露出来的RPC接口上面,再去调用这个接口里面的函数。对于接口来说有两个比较重要的属性:第一个,就是每一个接口都有一个唯一的标识。还有就是接口的版本。用这个图形化的例子看一下,假如自己实现了RPC的服务端,RPC-Server.exe,定义并实现了右边这个名为 IPentest 的接口。可以看到接口的名字下面那一串像是随机字符串一样的东西就是这个接口的唯一标识 IID,以及这个接口里面一共定义了三个函数: RunCmd,序号0;DownloadFile,序号 1; UploadFile,序号 2。 函数序号的作用就是客户端在远程调某一个函数的时候,实际上是通过函数的序号调用的,而不是通过函数的名字。第二步注册RPC接口,注册目的是为了让Windows操作系统真正意义上把我们的接口暴露出去。


注册的时候其实涉及到三个概念。

    1.协议序列。

    我们在注册接口的时候告诉操作系统,我们希望操作系统到底把我们这个接口以什么样的方式对外暴露出去。最常见的一个是纯TCP的协议序列,另一个就是基于SMB命名管道的协议序列。同一个接口,可以通过多个不同的协议序列暴露出去的。

    2.Endpoint(EP)。

    EP是跟协议序列强相关的东西,比如:如果这个接口使用的是纯TCP的协议对外暴露,这个接口的EP对应的就是某一个TCP的端口号,如果这个接口使用命名管道的方式都要暴露,那么你的这个接口使用命名管道协议序列进行对外暴露,那么对应的 EP 就是一个命名管道的名字。当服务端向操作系统注册RPC接口时,可以自己手动指定一个 EP,也可以选择让操作系统帮你随机生成一个。

    3.Endpoint Map(EPM)。

   

 135端口里面运行EPM服务。EPM里面保存的是Endpoint到某一个接口的映射关系。

    

看完理论知识,再用图表的方式重新回顾一下。第一步刚才已经定义并实现好了一个叫IPentest的接口,我们希望这个接口被以纯TCP的协议序列被暴露出来。EP不自己指定,而是由操作系统帮我们生成一个随机的端口也充当 EP。最后一步,就是我们需要把EP保存到EPM, 也就是135端口上运行的那个服务里面去。第三步,我们RPC服务端就已经做好了。做好了服务端以后,我们需要有客户端连接到服务端上面,然后来远程调用服务端接口上面的函数。客户端调用服务端有这么四个步骤:第一步,查找所要调用的目标接口在远程的机器上是以什么样的协议序列被暴露了出来,以及暴露的时候所使用的EP是什么。第二步,当查到第一步的结果后,使用指定的协议序列以及查到的EP连接远程机器。连上以后,第三步绑定要调用的接口。第四步就可以真正的开始调用接口里面的函数了。

    

还是以图象的方式看一下,右边是实现好的远程RPC服务端。假如客户端现在需要调用RPC-Server.exe,需要先查IPentest以什么样的协议序列导出,以及导出的时候是用的什么Endpoint,查到以后以纯TCP的方式连接到远程机器上的33219端口、这是第二步。第三步,它需要绑定到要调用的IPentest接口。绑定的操作就是说我要告诉服务端,接下来到底要调用哪一个接口的什么函数,这是绑定的操作。第四步,就可以开始进行函数的调用了。

    

简单的回顾一下MSRPC协议栈,当客户端通过MSRPC调用远程服务端的时候,所走的协议、所用的端口基本上都在这个图里面了(图)。如果是纯TCP 协议序列,那么下层就是直接的纯TCP协议。这个时候客户端往往连接到服务端所暴露出来的随机高端口。第二个,如果客户端使用命名管道这个协议序列来连接服务端接口的话,那么MSRPC下层就是SMB协议。

    

通过这张图我们可以看到,Windows操作系统默认导出了非常多的接口,这些接口理论上都是可以被远程调用的。前面我归类的四类横向移动方案,都只是对这些Windows默认对外暴露的RPC接口函数的恶意利用。前面我们说到了一个客户端要调用服务端某一个函数需要经过这么四个步骤,现在我们切换到IDS的视角看一下。在四个步骤中,每一个节点上,IDS都是可以做相应的检查,只不过也许检查越靠前,误报率有可能会越高。我们来看一下第一个节点上面IDS有可能做什么样的检查?部署在第一个节点上的IDS规则检查的通常是135这个端口的流量,就是说这个节点上面的IDS规则的工作逻辑一般都是如果发现有人连接服务器135端口,并且通过这个端口上的EPM服务查询了某一个已知的敏感接口(里面包含一些函数可以进行横向移动,比如:远程命令执行等这样的)的信息时候,IDS会认为你既然查这个,那你后面有可能就要调用这个敏感的接口,那么它有可能会产生告警。工作在这一步的规则我们的对抗思路是什么?第一点,如果你有一些没有公开方案使用的是一些目前不为人知的小众接口的话,尽量不要公开了,自己留着用,一旦公开就有可能被人们写到这个规则里面去。第二个,如果你明确的知道你调用的那个远程接口,同时被暴露在了TCP协议序列和SMB协议序列,那么为了绕过这个节点上的 IDS 规则的检测,你应该使用基于命名管道的方式调用你的那个接口。因为你用命名管道的方式调用接口的时候,通常是不需要经过135端口的。135端口主要作用是当你不知道你要调用的那个接口被导出在了哪一个 EP 上的时候,需要通过 135 端口来查询。如果你的接口在命名管道上,这个命名管道的名字通常是事先预设好的并且是固定不变的,所以可以绕过135这一步,那么自然基于这个节点上的IDS规则就抓不到你了。

    

现在我们来看一下第二个节点上的 IDS 规则通常是如何工作的。运行在第二个节点上的 IDS 规则,通常是检查网络中出现的 SMB 流量中的敏感命名管道的名字,来检测横向移动。工作的逻辑就是,如果 IDS 发现在 SMB 流量中出现了一个敏感的命名管道的名字,那么 IDS 认为有人在尝试连接这个敏感的命名管道背后的那一个敏感的 RPC 接口,此时就会产生告警。对抗的思路,我们要知道一个程序如果用命名管道的方式来将一个接口导出的话,那么他是有可能将这个接口导出在多个命名管道上面的,而不是一个。而且Windows里面命名管道是可以有别名的,一个命名管道名字叫A,但是操作系统给它配了别名叫B、C什么的,通过这些个别名我们也可以连接到这些命名管道上面。这种情况下你可以收集常用的IDS规则,可以发现其实很多人检测某一个横向移动方案时所写在 IDS 规则里面的命名管道名字都是固定一个,不会变的。第二个由于这一步的操作检查的是通过SMB的方式调用远程接口的方式,如果你知道远程的接口同时被导出在纯TCP协议序列上,你就用纯TCP协议序列去连接这个 RPC 接口,这个时候就没有所谓命名管道的名字。下面来看一个真实的例子。

    

(图)这三条规则都是用于检测利用远程计划任务进行横向移动的行为。他们的检查原理是一样的,如果 SMB 流量中出现 atsvc 这个命名管道的名字,就进行告警。所以绕过的思路有两点。第一点,远程计划任务不只是被暴露在了 atsvc 这一个命名管道上,而暴露在了其他的比如 srvsvc 上,我们只需要换一个名字去连接,就可以绕过这三条规则。第二点,这三条规则检查的都是命名管道的名字,那么其实远程计划任务接口还被暴露在纯TCP协议序列上,我们如果用纯TCP方式调用远程计划任务接口,也可以绕过这三条规则。第三个检查点,Bind接口。这往往是尝试监查如果发现有人尝试对已知敏感接口进行绑定操作就报警。第三点对抗的思路,还是如果你自己有一些未公开的方法的话,你就还是自己留着自己用,不要被人们写进这个节点上的IDS规则。下一个对抗方式,有点像Web渗透里面的WAF绕过。IDS 在检查数据包的时候有可能只检测前 N 个字节,这个时候我们先发送多个虚假的 Bind 请求,最终再去 Bind 我们实际要调用的那个敏感接口就可以绕过。第四个就是尝试检查你真正去调用的那个函数,这一步对抗其实总结不出来什么太好的规律,只是看具体规则之后再去分析。

    

现在我们看一个具体的例子,拿:PSEXEC这一类工具尝试一下,这一类工具产生的流量IDS看来如何。先看一下 PSEXEC 这一类工具的原理是什么。Windows上面有一个叫Service.exe进程,这个进程定义、实现并导出了一套SCMR接口,允许客户端远程在服务端创建启动停止Windows的服务。所以 PSEXEC这一类方案其实很简单,它通过远程调用SCMR接口在远端的服务器上创建一个服务来实现横向移动。有一点需要提的是这一套接口同时被监听在纯TCP和命名管道两个序列上。介绍完了之后,我们看一下实际PSEXEC.EXE运行完之后产生的流量怎么样。

    

第一步,向目标机器查询 SCMR 被监听在了 TCP 协议序列的哪一个 EP 上。第二步,假如上一个查到的是49157端口,自然是以纯TCP方式连接49157端口。第三步,发起Bind请求,绑定到要调用的SCMR接口。第四步,从流量可以直接的看出来,我们可以看到很多函数的调用,创建服务、启/停服务之类的。前面说到了,客户端调用服务端的四个节点。其实这一块的PSEXEC.EXE例子就是四个步骤在流量方面的呈现方式。通过这个流量图,其实我们可以出来一个问题。问题是什么?我们发现PSEXEC.EXE在执行过程中到底调用了远程机器的哪些函数是可以通过流量直接看到的,这其实是 MSRPC 的加密措施导致的。客户端调用服务端的四个步骤里面,前三个步骤MSRPC并没有为前三个步骤提供任何的加密措施。只有最后一步,提供了半遮半掩的措施。假如第四步启用了 MSRPC加密措施,对于IDS来说,它依然能看到你调用了什么函数,但是无法再看到你给这个函数传了什么参数。这就是 MSRPC 的加密机制。

    

我们再来看看Psexec.py和PSEXEC.EXE产生的流量有什么区别。Psexec.py第一步先建立SMB会议,使用ncacn-np协议序列连接SCMR接口,后续所有数据包经过SMB3加密,IDS无法识别。简单插播一下SMB3加密功能,是从3.0版本引入的。3.0版本是从Windows2012引入的,而且SMB3.0服务端不强求客户端必须使用加密通信,并且多数Windows客户端在连接SMB3.0服务端的时候也不主动使用SMB的加密,这个影响会在后面说到。我们来对比一下,前面说到了exe版本的Psexec和Psexec.py。PSEXEC.EXE协议序列Ncacn-ip-tcp,Endpoint是随机高端口,危险系数是“高”,全程流量近乎明文。Psexec.py协议序列Ncacn-np,Endpoint是命名管道svcctl,危险系数:低,目标主机为2012及以上系统自动启用SMB3加密。高,目标主机为2012以下时全程流量明文。

    

根据刚才对比,我们可以得出来初步的结论:假如你要打的目标机器是2012或者2012以上的机器,你应该优先使用基于命名管道的协议序列的RPC。SMB3的加密功能在Windows默认情况下,多数客户端,哪怕连的是SMB3.0服务端,也不会主动使用加密功能。如果你的目标是2012以下版本的话,那么我们就接着往后看。

    

(图)这条IDS 规则是用于检测利用WMI进行横向移动的方案。它是工作在第一个节点上面的规则,原理就是当它发现有攻击者或者说有人连接了某一台机器135端口,并且同时流量里面出现了WMI所依赖的接口唯一标识的话,它就会产生告警。WMI这种横向移动的方式,最简单最直接的利用方式就是通过Powershell 或者 wmic.exe,但是这两种方式都会被刚才所展示到的IDS规则所抓到。 Python里面有一个非常厉害的库叫 impacket,里面有一个叫wmiexec的工具这个可以绕过刚才说的那条规则,但是它带来的另外一个问题就是我们可以看到在流量里面虽然绕过了第一条规则,实际上用这个工具执行任何命令的时候,你执行命令是通过明文在网络传输的。你虽然绕过了刚才那条规则,但是有可能被工作在第四个节点上的规则给抓到。所以这个时候我们需要对这个工具做一下改造,红框里面的代码是我加上去的,这串代码就是我强行开启加密功能,开启之后执行的命令就是加密的。

    

(图)这个图片展现的是全是抓利用DCOM进行横向移动的IDS规则。总结一下它们其实都是工作在第一个节点,以及第四个节点上面。利用DCOM进行横向移动,这个方法的发明者在首次介绍这个方案的时候用到的代码,就是通过 Powershell创建远程服务器DCOM对象,然后拿到DCOM对象之后做横向移动。这种方案会被刚才列出来的那一堆规则里面的好几个规则给抓到。同时它还有另外一个问题,就是跟刚才那个问题有点类似,就是你执行的命令是“明文”在网络里面传输的。同样的impacket 提供的 dcomexec.py 也是利用 DCOM 类的方案进行横向移动,但是它同样会被我刚才列出来的一堆规则抓到。而且被抓到的原因是因为流量是明文的,这是它被抓到的原因。这里你要对这个文件做一些更改,强制开启加密,开启加密以后,流量也加密了,就可以绕过刚才那些 IDS 规则。这个时候我们就可以得到一个相对完整的总结:当你要打的目标机器是2012或者2012以上的时候,应该优先选择利用SMB命名管道作为协议序列来连接远程接口的那些工具。Windows上面的客户端默认不会使用SMB3加密功能来与服务端通信 ,所以这里我列出来的工具都是用 Python 写的。当你要打的目标是2012以下目标的话,你应该优先使用的是那些在MSRPC过程中全程开启了 PacketPrivacy 身份认证级别的工具,也就是全程启用了 MSRPC 加密的工具。说是“全程开启”实际上也只有最后一步是加密的。比如说我们改过的 wmiexec.py以及 dcomexec.py 等。

    

其实完全看你的目标环境里面的IDS规则怎么写的。要是写的很严格,也是有方法可以去检查出来这些其它方案的。但是我收集了很多IDS的规则,我发现改完之后很多IDS规则就被bypass掉了。

    

(图)这一页是跟主题“横向移动”四个字有关联的。我们现来聊一下利用DCOM方式进行横向移动的方案,这种方案应该是在2017年左右被国外的一个安全研究人员首先公开了这个方案。关于到底什么是COM,什么是DCOM这个话题比较大,希望各位可以回去自己了解一下。我这里总结了一下人们公开的挖掘出来的可以进行横向移动的DCOM的方案,这个列表其实在网上可以随便找到。在我对COM及DCOM学习研究过程中,我发现这些方案都有一些局限性。首先这些DCOM组件里面大多数都是Office系列软件所带有的,你如果想用里面有些组件进行横向研究,要求目标服务器装了Office。另外一种,基本上它们通用的问题,就是这些组件都只能够提供基础的命令执行功能。我在对于这些进行研究的过程中,我一直在想:有没有一种DCOM组件可以提供直接的远程任意代码的执行功能?这些已知公开的组件,基本上只能用来执行命令。

    

我们看一下这个,如果你工作在内网渗透第一线,对于这个肯定不会陌生(图)对不对。它主要的效果就是我们可以利用WMIC来执行任意的VBScript/JScript代码。我发现有一个COM 组件提供了跟WMIC相似的功能,也可以执行任意的代码。甚至我都怀疑,WMIC内部是通过调用这个组件来完成的工作,只不过我没有印证、只是猜想。下面用一张图来展示我们可以在本地调用这个组件执行任意代码,效果就是我通过这一个 COM 组件实现了命令执行的功能,并且拿到了命令的回显结果,这是简单的事例。

    

我们现在要讲的是横向方案,对于 XML DOM Document 这个 COM 组件来讲,它最大的就是:它不是DCOM组件,不能被远程调用。我们必须找到能够远程调用的东西才能达到我们的目的。这个怎么解决?我们可以把一个COM改造成DCOM。当目标COM接口向操作系统注册了ProxyStub,则实现了此COM接口的COM组件存在被远程调用的可能性。我们具体怎么去把它由一个COM改造成为DCOM呢?其实如果多看一些资料,这方面的过程并不复杂。我在没有实践之前觉得很复杂,但是实际上我研究出来以后,发现你只需要对注册表里面的一些值做一些变动,一个原本不能被远程调用的COM组件就变成了DCOM,变成可以被远程调用了。将 COM 改造成为 DCOM 的过程需要我们操作注册表,操作注册表的操作是可以远程实现的。什么意思呢?就是我们可以远程连接到一台机器上,远程把这台机器上的上的 XML DOM Document组件由COM改成DCOM,然后就可以利用这个COM组件(现在应该叫DCOM组件了)来做我们任何想要做的事情。

   

至少可以做到这么四类事情:支持直接命令回显,上传、下载二进制文件,远程内存执行任意.NET PE,MIMIKATZ集成。

    

一般人们用的那些方案,只所以能够看到命令的回显结果,是因为把命令的回显结果保存到另外一个地方。要么是文件里面,要么是注册表里面。命令执行完以后,通过读文件、读注册表,把这个结果读回来,这是一种间接的命令回显方式。而我这里提到的方案,支持的是直接的命令结果回显,你可以直接拿到命令的回显结果,不需要把这个结果保存到一个其他地方再从这个地方去读取。第四个(MIMIKATZ 集成)其实算第三个的子集,这个工具太常用了。


简单的看一下实现的效果。(图)功能不是很全,因为就是两天时间写出来的。首先看一下第一个效果,命令执行。效果从图片上看起来好像没有什么区别,但是这个回显是直接拿到的,并不是保存到文件或者其它地方再读回来的,这是直接拿过来的。第二个,客户端向服务端上传一个文件,传上去以后在服务端也是可以打开的。下面这个例子,就是二进制文件的下载。这里演示的例子,就是下载CMD文件回到本地,也是可以打开的。最后是远程内存执行 MIMIKATZ,之前应该有出过其他方案,但是那些方案我看到过都是事先将mimikatz代码保存到远程服务器的一个地方比如注册表里面再通过其他的方式放入内存执行。我的方案跟这些方案不一样,MIMIKATZ 的代码不需要被保存到远程服务器的任务地方,而是被当作一个参数传到服务端内存里面去的,然后进行内存执行,然后通过同样的通道把结果拿回来。


最后打个广告,我们团队现在主要做的是红蓝对抗方面的实战与研究,有的时候会迸出来一些小想法或者实践中需要的工具,这个时候有可能会把它武器化。对于有些工具我们选择上传到github上面去:

https://github.com/QAX-A-Team


仙果:红队行动,攻防之杀毒软件对抗

    

果:谢谢大家,其实上台我还是有一点紧张的。为什么呢?本来准备的议题是准备了半小时,但是我看到的内容其实是50分钟。也就是说,我要扩展20分钟时间。这20分钟的时间,扩展什么呢?给大家加点私货。我来之前领导跟我说:你可以讲、可以分享,但是不能讲到我们目前用到的一些技术。这个让我非常的纠结,因为对于我来说,我非常希望把我这边掌握的技术给大家公开,让大家一块儿来成长。但是公司既然有要求了,这个属于没办法的事情。有些技术不能说得太细,大家理解。

    

一、自我介绍。

    这个已经说很多次了,略过。

    

二、何为“杀毒软件对抗”。

    简单的来说“免杀”。

    

三、杀毒软件解析。

    一笔带过。

    

四、杀毒软件对抗技术。

    

五、思路和方法分享。

    

讲的时候PPT的内容,可能更多是以PE的。加点私货,更多是跟软件漏洞相关的,毕竟是老本行。

   

仙果,主要做的是安全攻防对抗研究,物联网安全攻防对抗研究。何为“杀毒软件对抗”?来看一个图片。大家熟悉吗?这个图片,颜色很熟悉,如果是之前可能不敢把这个图片放出来,现在放出来也没问题了,毕竟奇安信和360集团已经分家了,是吧?然后来看,免杀了。再来看另外一张,又免杀了。这种“免杀”技术更多的是分析一种叫免杀对抗的基于技术方法。在我们拿到的样本之后,我们不止要研究防御技术,还要研究攻防对抗技术。一个是提高杀毒软件的能力,还有就是提高攻击技术实力。这里提到“红队”的概念,主要提高红队技术对抗的能力。传统的攻防对抗上,遇到杀毒软件的情况是最多的。真正的目标企业,不装杀毒软件的情况几乎没有。我们自己的安全人员可能会选择裸奔,我不知道在座的各位有多少是做二进制安全的。之前据我了解很多是做渗透测试,所以呢更多是偏向于思路上面,就是免杀技术对抗思路方面。在实际的攻防对抗上面,这里不单单是说国内360,也不只是杀毒软件对抗,还有IDS或者其它防御产品对抗。我们知道国外的安全公司公开很多国内的攻防对抗组织。为什么会公开,技术稍微做好一点,然后就可以做到不被公开。而一旦公开之后,所付出的很多成本,行政成本、政治成本以及经济成本都是非常高。提升对抗技术就可以避免这些问题。我不知道大家在日常渗透的时候遇到杀毒软件产品的情形多不多,实战攻防对抗经常能够遇到,此时就必须提升技术对抗能力,而杀毒软件是一个比较好的入口点。牵扯到第四点,我没有写的很具体,就是实战对抗技术储备。储备这样的技术,因为说不定哪天我们就会用到。

    

我们来看杀毒软件的解析。如果梳理杀毒软件的厂商,你会发现主流的安全厂商。比如:卡巴斯基、诺顿、赛门铁克、AVG等公司成立都非常早,那个时候我们还是小学生,杀毒软件的厂商已经有了。它们发展了这么多年,他们的技术积累是非常丰富的,而且他们能够存活这么多年,他们的技术积累就可想而知。最开始的时候可能采用基本的方法对抗木马病毒,比如:对付冲击波、蠕虫病毒的时候,采用特征码或者是一些基础规则的扫描。发展到后面2000年-2005年的时候,可能更多是采用其他方式。2005年-2014年新的技术,主动防御技术和虚拟化技术都发展起来了。到了2014年-2018年,提到更多的是“下一代杀毒软件”技术。比如:“云”厂商。2019年也就是今年,我们现在的情况,是不是说:杀毒软件已经消亡了呢?像现在比如大家在装Win10的时候,大家在用Win10时候更多是考虑性能,而不是考虑是否还再要去装一个杀毒软件。现在杀毒软件它是否要消亡?这个问题其实是一个非常好的命题。

    

我们再来看(图)这个列表很长,我传了一个简单的小的样本上去。一大长串的杀毒软件,但是我们在实际的攻防对抗上面,其实会遇到这么多的杀毒软件吗?不会。可能遇到一个主流的,而且它是分地区、分方向的。可能东欧、俄罗斯或者是东北亚,更多的是卡巴斯基,南北美洲可能更多的是赛门铁克或者什么。东南亚可能更多的是一些小的不出名的杀毒软件。这种时候你可能就需要针对每一个目标地区的杀毒软件,做更详细的规划、跟详细的分类,然后做它们分别的技术储备。

    

这里面能够看到比较多的是主流的,其中卡巴斯基、AVG、AVAST这种都是非常主流。08年之后大家知道小红伞的可能会比较多,但是真正有多少人会用小红伞这样一个杀毒软件?其实它做的是相当好,但它确实是可以被绕过。

    

这里来梳理一下杀毒软件的查杀技术。

    1.特征码、广谱特征码(复合特征码)。

    这个实际是多个MD5的比较。08年之前,这种应用是非常多的。而且当时360闹过一个笑话,它是直接根据“文件名”来判断查杀的。

    2.内存特征码。

    因为杀毒软件本身的权限是相当于内核权限,它的权限是比较高的,可以监控内核,在内存中对特征码进行监控。

    3.启发式杀毒。

    启发式杀毒更多的是根据一个行为、一个操作调用或者是其它各种各样的行为,然后判定“恶意行为”。这里面讲“启发式杀毒”过程,其实很原理化。

    4.虚拟机技术。

    虚拟机技术在前两年是非常之火的,代码放到一个虚拟机里面去执行,然后来判断到底是不是恶意的还是正常的。这里面有一个很大的问题是什么?虚拟机不可能完全模拟全部的操作指令,或者是我可以在我的代码里面去分析你到底是不是在虚拟机里面,这个会在下面讲到。

    

诺顿出了一个什么样的查杀机制呢?把你要执行的文件,不管是MD5还是其它的方式也好,发到云端,然后判断多少人来执行了这个文件。如果人少,它会给一个比例。如果已经上传,已经定义的话,就直接下发,说:这是一个恶意的软件。像这种怎么来做这种对抗?其实最终都是有办法来进行对抗的。

    

这两个工具大家有没有很熟悉的(VirTest5.0和MyCCL复合特征码丁炜器Ver1.1 Build58)。我们看了有工具、有原理,还有我们知道杀毒软件是怎么查杀的。这个时候我们怎么来做“免杀”,或者怎么做杀毒软件的对抗?

    

杀毒软件要查杀,肯定是要你有相应的行为是恶意的。有一个问题是什么呢?恶意的行为和正常的行为,区别在哪里?这个时候要思考这样的一个问题。它的真正的区别是什么?为什么木马行为被抓出来,正常的行为和恶意的行为其实是没有区别的。在操作系统看来,它是没有区别的。这时候怎么来做?其实你只要抓住这一点,然后就有办法来“过”杀毒软件。

    

(图)这是一个免杀的最基本的操作。这个叫什么呢?在原来很早之前它叫“加花指令”,因为通过之前的工具,我们能定位出来特征码。这个时候你去修改这些特征码。杀毒软件免杀:1.过静态。2.过动态。3.过云。原来你需要过静态、过动态,然后就可以了,现在还要再加一个“云”。可能这里面所说的把“过虚拟化”这个给省略了,过动态其实包括了虚拟化。这里面我们强调一个,是过静态的技术。静态技术其实好过,当你有源代码的情况下非常好过,因为你可以定位到查杀的具体动作点。但是很多的时候面临的一个工情形是没有源代码,或者是根本用不到源代码,那么就有很多汇编指令的应用。

    

之前学破解的时候有一个顺口溜,叫“74“变“75“,“84“变“85”,很老的一个段子。基本免杀的原理是把你的指令给操作复杂化。把指令序列改得很乱,这个时候不管是静态还是动态,它的顺序就乱了,而杀毒软件在进行识别的时候,它是不能准确的识别,去过掉静态检测。另外一点就是这里面强调一个“虚拟化的对抗”,虚拟化的对抗是一个比较主流的。我们提到之前的特征码,启发式或其它的查杀技术,它可能都没有虚拟化做的这么彻底。那么,我们就想办法来绕过这一点。

    

(图)这是一个检查是否是在调试状态的一个代码,首先是fs:30,然后取fs:30指向地址里面的一个值,获取调试标志。判断这个标志之后,就可以判断出来它到底是否是在这样一个虚拟机里面执行的状态。这个杀毒软件可以识别的,杀毒软件可以识别这一串机器码。我们这个时候针对这个机器码再做一个变形,功能是同样的,复杂程度更高.这个时候其实它在杀毒软件检测的时候,其实就无能为力了。我们再来看另外一点,这也是虚拟机的一个对抗,它去检测TickCount,TickCount如果小于1000的话,它肯定是在虚拟机里面,然后我们再来看,这个时候它来检测CPU的核心数,检测CPU的核心数我们知道虚拟机里面去模拟这样的一个技术。那么,它的核心数、它为了保证检测效率,它模拟的一个核心,主流的可能两个、三个、四个都有,再有一个就是我分配大量的内存,我分配大批量的内存。如果它分配不成功的话,肯定是有问题的。再然后我们看,这是一个什么呢?这就是一个绕过的技巧,通过注册“互斥”然后来绕过它。知道叫杀毒软件检测是有顺序往下执行的,这个时候我们如果采用多线程,比如:互斥这种多方面的技术,就可以绕过很大部分的杀毒软件。

    

上面说的这些可能更多的是跟PE相关的,杀毒软件对抗,还有一种是利用杀毒软件自身的漏洞,操作系统都有漏洞,那么杀毒软件肯定也有漏洞。以前出过什么样的呢?出过这样的一个漏洞,就是杀毒软件在解析、进行虚拟执行的时候出现的安全问题,比如:杀毒软件在解析JS代码的时候,因为它要模拟去执行时候就造成了一个缓冲区溢出,它是可以直接在杀毒软件环境里面去做一个任意代码执行的漏洞,这个时候就可以做任何事情。

    

(图)这是一个熊猫杀毒软件,某一个版本存在权限提升漏洞。我们来看录像!(视频短片-这个会在桌面上释放一个文件,可以看到熊猫杀毒软件有存在这样的一个安全问题。除了熊猫杀毒软件之外,是不是其它的杀毒软件也存在这样的问题?)是不是存在影响范围更大的,比如:熊猫杀毒软件只是个人端的。如果是企业端的杀毒软件,比如:赛门铁克。我知道赛门铁克在前些年,包括:现在在很多企业里面用的都是非常多的。企业版杀毒软件是有个集中管理端,统一进行杀毒软件更新,像域的结构一样,域下面的客户端装了各个杀毒软件的组件。这个时候如果说杀毒软件的服务器出现了安全的问题,它出现安全问题之后你可以给下面的客户端去推送这样一个更新,默认客户端是信任的。这样的问题就大条了。大条在什么地方?完全信任。就像是最近这两年比较流行的供应链、软件供应链攻击一样,造成的后果就是你只要更新,杀毒软件的服务端推送更新之后下面所有的客户端、执行的更新,然后来执行这样的一个exe或者是其它的功能。这样你在整个在做渗透,在做这样的横向移动的时候,其实就非常的方便,不需要有操作系统的0day漏洞,也不需要去做水坑。一条杀毒软件的指令过去,下面所有的客户端全部被覆盖。而且不止是赛门铁克,也包括其它的杀毒软件。

    

(图)下面是私货时间。我之前讲的除了杀毒软件的漏洞之外,更多讲的是PE的对抗技术。我觉得大家如果有在有源代码的情况下,可能就很容易能够过了。因为你知道查的点,具体哪一条,你改动起来就比较容易了。但是如果是软件漏洞呢?从Office漏洞来说,它有几大行为。第一个,Office漏洞的三段式。从三段式说起:第一,有恶意文档。第二,有木马病毒。第三,有正常的文档。这三段式组成的一个文档类的漏洞利用,这样一个三段式在做杀毒软件对抗的时候,有几个危险点。第一,漏洞的触发点,动态的漏洞出发点。第二,执行的行为。第三,释放之后你的木马和远控的行为。它的三段式,杀毒软件会在这三段里面同时来做检测,而且更变态的是什么?杀毒软件的漏洞缓解技术,不仅是在操作系统里面,也在这样的一个杀毒软件里面。这个在麦咖啡的企业版,体现的是最明显的。我们说回Office漏洞的三段式里面,如果我们能够减少Office软件漏洞利用的三段式,把三段式改成两段式或者是一段式,这个时候杀毒软件是不是就没有效果了,或者说很难检测。从Office软件漏洞利用的三段式到二段式、到一段式。一段式是什么?我们先说二段式,二段式是利用漏洞和正常文档是同一个文档。具体怎么做到?两段式是一个漏洞率文档和正常文档是同一个,再加一个远控和木马的文件,构成了一个两段式的文档。这个时候杀毒软件升级,升级以后检测你释放的行为、你释放的动作。这个时候其实在做的时候就发现一个什么问题呢?你只要释放,不管你是怎么释放的,总会被检测。

    

还有一个问题,我们所有的说:有一个问题没有解决。是什么问题?漏洞执行点的问题。漏洞执行点,如果杀毒软件来做的话,我们HOOK软件漏洞触发点比如说:Office办公软件类,不管你是怎么执行,你都要执行到那个点上去。这个时候如果来做这样的一个防御?其实这个方法还是有的。叫什么方法呢?杀毒软件去监测的时候,是有一个文件格式识别。文件格式识别的一个功能。如果是办公软件类的,我让你识别不出来办公软件类的就可以了,从根本上解决这个问题。比如说,我们一个DOC的文档被识别成了一个7Z或者是识别成了一个EXE。这个时候针对这种办公软件类的检测就失效了,这就是一个整体利用的过程和思路,也是从最开始的一个软件漏洞的对抗到现在一个技术的发展。

    

我们来梳理一下,我们执行了哪些技术。第一个,从软件漏洞利用的三段式里面改成一段式。从一段式里面改变文件格式的一个从根本的文件格式,那么就完美的避过了杀毒软件。还有一点,这里面提到了是文档类的。我们再来说成Adobe Reader漏洞,Adobe Reader一两年才公布几个比较好用的,以前是比较多的。针对Adobe Reader对抗,其实也是非常多的。不知道大家在打开PDF的时候有没有发现一个问题,有些文字是复制不出来的,或者是由于版权的要求,你只能去阅读而不能去修改、删除。这个时候你会发现,它里面的文档是加密的。这个技术其实是可以用到这样一个“免杀”技术里面去的,因为杀毒软件要做这种检测,那么它肯定要做一个特征码。这个时候其实如果我们让它检测不到,或者是无法识别。首先是什么呢?首先是PDF的文件格式,它是基于“流”的,它解开这个“流”自然能看到里面的“文”。如果让它解不开这个“流”,是不是就可以规避很大一部分杀毒软件?这个时候就可以用到一个方法,然后把它加密,而且加密强度可以很高。还有一个是什么呢?制作PDF的工具,Adobe Reader只是一个PDF的阅读器。制作PDF的文档工具有很多,这个时候你不一定非要用Adobe Reader官方的PDF编辑器,可以用其它的。这个时候每一个不同的工具生成的PDF文档都是格式上面有区别的,杀毒软件不可能针对每一种文档、每一种PDF的版本文档都去做检测。这个时候,我们的机会就来了。叫什么呢?通过各种各样的工具、各种各样的制作工具组合起来,包括:PDF的表单工具,这样的一些工具组合起来使用,就直接让杀毒软件失效。

    

下面我们来看什么呢?这是卡巴斯基,这是一个Offcie的漏洞,我们看它执行的效果。这个时候我们看到静态肯定是没有问题的,执行呢?也是没有问题的,打开是没有任何反应的。这个时候其实当你下次打开的时候,已经执行起来,计算器弹出来。可能给大家去演示弹计算器是一个比较常见的,只是弹一个计算器。我们再来看另外一个,这是诺顿的。静态上面都是没有问题的,这是检测了其中一个(视频演示),这个没有弹计算器,而弹了“扫雷”。我们再来看另外还是卡巴斯基,这个录像做的时间是2018年的,实际上现在利用也是没有问题的。这是一个PDF的漏洞,为什么看的比较卡呢?是因为是在虚拟机里面,它的性能还是有限。(视频演示)这里给大家说一点,就是在实际的攻防对抗当中,杀毒软件只是对抗当中的一部分。红队在具体研究的时候,杀毒软件最终不是目的,它只是其中落地的一步。文档类的杀毒软件对抗可以用各种各样的技术,它比木马的难度在于你的文档、你的漏洞要过一层,你的动态行为也要过一层,所以说:它的难度体现在这一点。

    

视频演示——这是AVG的杀毒软件,这是一个远控的演示。远控的演示,可能大家见识的都已经是比较多了,这个就没有什么好说的了。我们看,它正在对EXE进行扫描,他在内部对EXE进行虚拟执行。等它虚拟完成之后,然后再判断到底是正常的还是恶意的。这个时候它就找不到问题了,这里面可以看到这个远控就已经上线了。)

    

我的议题大致主要内容就到这里。想给大家说几点:第一,红队在做这种攻防对抗的时候,其实需要一点就是杀毒软件。真实的攻击、真实的网络攻防对抗,杀毒软件只是其中一环。第二,软件漏洞和杀毒软件的对抗,是一个循环、螺旋上升的过程。它的技术对抗门槛是越来越高的,也希望大家能够投入到“软件漏洞”和“杀毒软件对抗”的工作当中。第三,下来之后非常希望跟大家交流这方面的技术。

    

主持人:感谢大家花费一下午的时间在这里。我觉得应该是不虚此行,希望大家有所收获。我们后续计划在大概今年Q3的时候,举行一些相关的训练营,把今天提到的技术讲得更细,大家可以参与到其中学到更多的东西。同时我有三点希望:1.希望通过介绍红队的这些知识,可以点燃大家心里的火炬。做攻击或者是做渗透这个东西,其实跟现在市场上能看到的最普通的那种我把它定义叫“漏洞测试”是有很明显区别的,大家心里要有这个概念。2.希望以后再跟别人谈起的时候,我们可以有一个共同交流的频率。就是说所谓做“漏洞测试”的人不是做渗透的,我甚至不认为他们是做安全的,我觉得他们像低端的QA,是一个非常机械化的简单的可以被程序替代的工作。3.今天准备的这几个议题,希望给大家传递一些知识,让大家有所收获。

    

再次感谢大家,几个月之后再见。谢谢!


声明:该文观点仅代表作者本人,转载请注明来自看雪