這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
閑著沒事搞了小程式,在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 -h1`127.0.0.1:5000`root`123456`ls -l,free -m2`127.0.0.1:5000`root`123456`df -h,pwd3`127.0.0.1:5506`root`123456`cd /mnt/ && python ping.py > 2015.txt &
flag.go命令列解析參數檔案:package flagparseimport ("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 Getconfimport ("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 Masteimport ("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 := *PathOldPath, _ := 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 Masteimport ( "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_Fileimport ("archive/zip""fmt""io""os""path/filepath"//"strings")func AddFilesToZip(Path, Name string) {//var PathName stringFile, _ := 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 mainimport ("Getconf""Maste""flagparse""fmt""os""os/exec""path/filepath""strings""time")var Rm_cmd_path, _ = os.Getwd()var (timeout int = 0TimeOut int = 10Ok 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 intSendfile, Global_command, SendAll, PrintLog := flagparse.Flag()config := Getconf.GetConfig()if *Sendfile != "" {TimeOut = 3600Maste.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 = 0if P {for {select {case x := <-Err:fmt.Println(x)timeout = TimeOut - 2case y := <-Ok:fmt.Println(y)timeout = 0case z := <-Res:fmt.Println(z)timeout = 0case <-Sta:Break = Break + 1if Break >= Num {RmFile(Sendfile)os.Exit(1)}default:if timeout > TimeOut {os.Exit(2)}timeout = timeout + 1time.Sleep(1e9)}}} else {for {select {case x := <-Err:fmt.Println(x)timeout = TimeOut - 2case y := <-Ok:fmt.Println(y)timeout = 0case <-Sta:Break = Break + 1if Break >= Num {RmFile(Sendfile)os.Exit(3)}default:if timeout > TimeOut {os.Exit(4)}timeout = timeout + 1time.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()}}