闲着没事搞了小程序,在Window上面往linux机器上群发命令,
写的不好欢迎大家指正,还有就是用此工具发送恶意命令的人请离开,
编译了一份64_Window和linux的程序,供大家参考使用,Rm_tmp_cmd.exe 在win下面提供使用!
我的目录结构:
flagparse
--------flag.go
Getconf
--------getconfig.go
Maste
--------scp.go
--------ssh_client.go
Zip_File
--------zip.go
maste.go
ssh.conf
命令文件:ssh.conf
第一行是需要群发的命令,用英文','隔开
然后下面是主机IP:PORT user password command ---->这个command的是只发给这个主机的命令,不会发到其他的主机上,可以理解为私有的命令
0`ls -a,df -h
1`127.0.0.1:5000`root`123456`ls -l,free -m
2`127.0.0.1:5000`root`123456`df -h,pwd
3`127.0.0.1:5506`root`123456`cd /mnt/ && python ping.py > 2015.txt &
flag.go
命令行解析参数文件:
package flagparse
import (
"flag"
)
func Flag() (*string, *bool, *string, *bool) {
var (
sendfile = flag.String("F", "", "此参数表示向所有标签主机发送文件,参数代表文件路径,例如:-F=/mnt/2015.go")
Global_command = flag.Bool("G", false, "此参数代表是否执行全局命令,默认是不启用,如果启用使用:-G=true或-G")
SendAll = flag.String("S", "", "此参数代表向这些标签的主机发送命令:-S=1,2执行1,2标签的命令")
PrintLog = flag.Bool("P", false, "此参数默认表示是否印输出执行结果,如果打印日志使用:-P=true或-P")
)
flag.Parse()
return sendfile, Global_command, SendAll, PrintLog
}
getconfig.go
解析配置文件(ssh.conf)
package Getconf
import (
"bufio"
"fmt"
"io"
"os"
"path/filepath"
"strings"
)
//获取ssh.conf的配置文件,以map的形式把每行的数据返回
func GetConfig() map[string][]string {
ProPath := os.Args[0]
os.Chdir(filepath.Dir(ProPath))
Config := make(map[string][]string)
File, err := os.Open("ssh.conf")
if err != nil {
fmt.Println("From GetConfig :", err)
}
defer File.Close()
Buf := bufio.NewReader(File)
for {
line, _, err := Buf.ReadLine()
if err != nil {
if err == io.EOF {
break
}
fmt.Println("From GetConfig :", err)
break
}
x := strings.Split(string(line), "`")
Config[x[0]] = x[1:]
}
return Config
}
scp.go
用来发送文件:
package Maste
import (
"Zip_File"
"fmt"
"go-ssh/ssh"
"io"
"os"
"path/filepath"
"strings"
)
func Use_Scp_Send(SendAll, Path *string, config map[string][]string, Ok, Err, Sta chan string) {
FlagList := strings.Split(*SendAll, ",")
Name := filepath.Base(*Path)
SendFilePath := *Path
OldPath, _ := os.Getwd()
if File, e := os.Stat(SendFilePath); e == nil {
if File.IsDir() {
Zip_File.AddFilesToZip(SendFilePath, Name)
SendFilePath = fmt.Sprintf("%s\\%s.zip", OldPath, Name)
Name = fmt.Sprintf("%s.zip", Name)
}
} else {
fmt.Println(SendFilePath, " :不存在!")
os.Exit(2)
}
fmt.Println("发送的文件名:", Name)
if *SendAll == "" {
for i, _ := range config {
if i != "0" {
go connect(config[i][0], config[i][1], config[i][2], SendFilePath, Name, Ok, Err, Sta)
}
}
} else {
for _, i := range FlagList {
go connect(config[i][0], config[i][1], config[i][2], SendFilePath, Name, Ok, Err, Sta)
}
}
}
func connect(ip, user, password, FilePath, Name string, Ok, Err, Sta chan string) {
Auth := []ssh.AuthMethod{ssh.Password(password)}
conf := ssh.ClientConfig{Auth: Auth, User: user}
Client, err0 := ssh.Dial("tcp", ip, &conf)
if err0 == nil {
Ok <- fmt.Sprint(ip, " 连接状态:Ok")
} else {
Err <- fmt.Sprint(ip, " 连接错误:", err0)
}
defer Client.Close()
conn, err1 := Client.NewSession()
if err1 == nil {
Ok <- fmt.Sprint(ip, " 会话状态:Ok")
} else {
Err <- fmt.Sprint(ip, " 会话错误:", err1)
}
defer conn.Close()
go func() {
Buf := make([]byte, 1024)
w, _ := conn.StdinPipe()
defer w.Close()
File, _ := os.Open(FilePath)
defer File.Close()
info, _ := File.Stat()
fmt.Fprintln(w, "C0644", info.Size(), Name)
for {
n, err := File.Read(Buf)
fmt.Fprint(w, string(Buf[:n]))
if err != nil {
if err == io.EOF {
return
} else {
panic(err)
}
}
}
}()
err3 := conn.Run("scp -qrt /mnt/") //会保存在mnt下面
if err3.Error() == "Process exited with: 1. Reason was: ()" {
Ok <- fmt.Sprint(ip, " 执行状态:Ok")
Sta <- "Ok"
} else {
Err <- fmt.Sprint(ip, " 执行错误:", err3)
}
}
ssh_client.go
连接主机主程序
package Maste
import (
"bytes"
"fmt"
"go-ssh/ssh"
)
func SSH_Client(ip_port, user, password string, command []string, P bool, Ok, Err, Res chan string) {
PassWd := []ssh.AuthMethod{ssh.Password(password)}
Conf := ssh.ClientConfig{User: user, Auth: PassWd}
Client, err := ssh.Dial("tcp", ip_port, &Conf)
if err == nil {
Ok <- fmt.Sprint(ip_port, " 连接状态:Ok")
} else {
Err <- fmt.Sprint(ip_port, " ErrorInfo:", err)
return
}
defer Client.Close()
for _, Command := range command {
if session, err := Client.NewSession(); err == nil {
defer session.Close()
var Result bytes.Buffer
session.Stderr = &Result
session.Stdout = &Result
err = session.Run(Command)
if err == nil {
Ok <- fmt.Sprint(ip_port, " 命令:", Command, " 执行状态:Ok")
} else {
Err <- fmt.Sprint(ip_port, " ErrorInfo:", err)
}
if P {
Res <- fmt.Sprint(ip_port, " 执行结果\n", Result.String())
}
}
}
}
zip.go
使用发送文件之前会调用此函数来进行压缩
package Zip_File
import (
"archive/zip"
"fmt"
"io"
"os"
"path/filepath"
//"strings"
)
func AddFilesToZip(Path, Name string) {
//var PathName string
File, _ := os.Create(fmt.Sprintf("%s.zip", Name))
/*
PS := strings.Split(Path, "/")
if len(PS) == 2 {
PathName = fmt.Sprintf("%s/", PS[0])
} else {
PathName = strings.Join(PS[:len(PS)-1], "/")
}
os.Chdir(PathName)
Path = PS[len(PS)-1]
*/
os.Chdir(filepath.Dir(Path))
Path = filepath.Base(Path)
defer File.Close()
Zip := zip.NewWriter(File)
defer Zip.Close()
walk := func(Path string, info os.FileInfo, err error) error {
if err != nil {
fmt.Println(err)
return err
}
if info.IsDir() {
return nil
}
Src, _ := os.Open(Path)
defer Src.Close()
h := &zip.FileHeader{Name: Path, Method: zip.Deflate, Flags: 0x800}
FileName, _ := Zip.CreateHeader(h)
io.Copy(FileName, Src)
Zip.Flush()
return nil
}
filepath.Walk(Path, walk)
}
maste.go
入口程序
package main
import (
"Getconf"
"Maste"
"flagparse"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
)
var Rm_cmd_path, _ = os.Getwd()
var (
timeout int = 0
TimeOut int = 10
Ok chan string = make(chan string)
Err chan string = make(chan string)
Res chan string = make(chan string)
Sta chan string = make(chan string)
)
func main() {
var Num int
Sendfile, Global_command, SendAll, PrintLog := flagparse.Flag()
config := Getconf.GetConfig()
if *Sendfile != "" {
TimeOut = 3600
Maste.Use_Scp_Send(SendAll, Sendfile, config, Ok, Err, Sta)
} else {
SendCommand(SendAll, Global_command, PrintLog, config)
}
if *SendAll == "" {
Num = len(config) - 1
} else {
Num = len(strings.Split(*SendAll, ","))
}
defer RmFile(Sendfile)
for {
Check_status(*PrintLog, Num, Sendfile)
}
}
//根据参数发送命令
func SendCommand(SendAll *string, Global_command, PrintLog *bool, config map[string][]string) {
FlagList := strings.Split(*SendAll, ",")
if *SendAll == "" {
for _, i := range FlagList {
Com := Global_cmd(config["0"])
go Maste.SSH_Client(config[i][0], config[i][1], config[i][2], Com, *PrintLog, Ok, Err, Res)
}
} else {
for _, i := range FlagList {
Com := Private_cmd(config["0"], config[i][3], *Global_command)
go Maste.SSH_Client(config[i][0], config[i][1], config[i][2], Com, *PrintLog, Ok, Err, Res)
}
}
}
//解析ssh.conf中的command字段:
func Global_cmd(Global []string) []string {
return strings.Split(Global[0], ",")
}
func Private_cmd(Global []string, Private string, Globlcomand bool) []string {
if Globlcomand {
Private_cmd := strings.Split(Private, ",")
var cmd []string = Global_cmd(Global)
for _, i := range Private_cmd {
cmd = append(cmd, i)
}
return cmd
} else {
return strings.Split(Private, ",")
}
}
//获取chan管道的状态.
func Check_status(P bool, Num int, Sendfile *string) {
var Break int = 0
if P {
for {
select {
case x := <-Err:
fmt.Println(x)
timeout = TimeOut - 2
case y := <-Ok:
fmt.Println(y)
timeout = 0
case z := <-Res:
fmt.Println(z)
timeout = 0
case <-Sta:
Break = Break + 1
if Break >= Num {
RmFile(Sendfile)
os.Exit(1)
}
default:
if timeout > TimeOut {
os.Exit(2)
}
timeout = timeout + 1
time.Sleep(1e9)
}
}
} else {
for {
select {
case x := <-Err:
fmt.Println(x)
timeout = TimeOut - 2
case y := <-Ok:
fmt.Println(y)
timeout = 0
case <-Sta:
Break = Break + 1
if Break >= Num {
RmFile(Sendfile)
os.Exit(3)
}
default:
if timeout > TimeOut {
os.Exit(4)
}
timeout = timeout + 1
time.Sleep(1e9)
}
}
}
}
func RmFile(Sendfile *string) {
os.Chdir(Rm_cmd_path)
if info, err := os.Stat(*Sendfile); err == nil && info.IsDir() {
Rm_Path := fmt.Sprintf("%s.zip", filepath.Base(*Sendfile))
cmd := exec.Command("Rm_tmp_cmd.exe", Rm_Path)
cmd.Run()
}
}