不断扫描进程,识别到有新增进程则立即推送相关信息,包括进程名、进程ID、如有命令则显示命令行、父进程追溯等(目前只通过Linux
下的ps
命令实现)。
项目地址:https://github.com/Finb/bark-server
部署文档:https://day.app/2018/06/bark-server-document/
除了Bark
还可以使用其他推送服务,比如钉钉机器人等。
这里使用了第三方库go-ps
:https://github.com/mitchellh/go-ps
首先在服务器上运行Bark
服务,手机上安装Bark
客户端,在客户端上添加Bark
服务的URL
,获得一串带KEY
的URL
,可以从客户端复制下来,稍后会用到。
没做过开发的业余Go
代码如下:
package main
import (
ps "github.com/mitchellh/go-ps"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"os/exec"
"runtime"
"sort"
"strconv"
"strings"
"time"
)
type psMap struct {
ParentPid int
ExecutableName string
}
func main() {
var oldProcessList map[int]psMap
var isFirstRun bool = true
ch := make(chan []ps.Process, 1)
processList, err := ps.Processes()
if err != nil {
log.Fatalln(err)
}
go func() {
for {
tmpProcessList, err := ps.Processes()
if err != nil {
log.Fatalln(err)
}
ch <- tmpProcessList
}
}()
go func() {
for {
for _, v := range <- ch {
processList = append(processList, v)
}
time.Sleep(100 * time.Millisecond) //检测新进程的时间间隔
}
}()
for {
time.Sleep(time.Second)
ch <- processList
processList = unique(processList)
var newProcessList map[int]psMap
newProcessList = make(map[int]psMap, len(processList))
for _, v := range processList {
var newPsMap psMap
newPsMap.ParentPid = v.PPid()
newPsMap.ExecutableName = v.Executable()
newProcessList[v.Pid()] = newPsMap
}
if isFirstRun {
oldProcessList = newProcessList
isFirstRun = false
} else {
var isNew bool = false
var diffLists []int
for i, _ := range newProcessList {
if newProcessList[i] != oldProcessList[i] {
if runtime.GOOS == "linux" && newProcessList[i].ExecutableName != "xxx" { //Linux下需要忽略的进程名
if isNew == false {
isNew = true
}
diffLists = append(diffLists, i)
continue
}
if runtime.GOOS == "windows" && newProcessList[i].ExecutableName != "xxx" { //Windows下需要忽略的进程名
if isNew == false {
isNew = true
}
diffLists = append(diffLists, i)
continue
}
if runtime.GOOS != "linux" && runtime.GOOS != "windows" {
if isNew == false {
isNew = true
}
diffLists = append(diffLists, i)
}
}
}
if len(diffLists) > 0 {
sort.Ints(diffLists)
var noneLittleChildList []int
for i := len(diffLists) - 1; i >= 0 && !isExists(noneLittleChildList, diffLists[i]); i-- {
messageText := "[" + strconv.Itoa(diffLists[i]) + "] " + newProcessList[diffLists[i]].ExecutableName
currPpid := newProcessList[diffLists[i]].ParentPid
for currPpid >= 1 {
messageText = "[" + strconv.Itoa(currPpid) + "] " + newProcessList[currPpid].ExecutableName + " -> " + messageText
noneLittleChildList = append(noneLittleChildList, currPpid)
currPpid = newProcessList[currPpid].ParentPid
}
if len(messageText) > 0 {
if runtime.GOOS == "linux" {
grepCurrProcess, err := exec.Command("ps", "h", "-eo", "user,group,stime,tty,pcpu,%mem,args", "-q", strconv.Itoa(diffLists[i])).CombinedOutput() //使用ps命令获取当前进程的用户、用户组、开始时间、tty、cpu使用率、内存使用率、参数
if err != nil {
log.Println("ps cmd error:", i, err, string(grepCurrProcess))
} else {
grepCurrProcessString := strings.TrimSpace(strings.Replace(string(grepCurrProcess), "\n", " ", -1))
for strings.Contains(grepCurrProcessString, " ") {
grepCurrProcessString = strings.Replace(grepCurrProcessString, " ", " ", -1)
}
messageText = messageText + " {" + grepCurrProcessString + "}"
}
}
if len(os.Args) == 2 {
sendPush(messageText)
}
log.Println(messageText)
}
}
}
if isNew {
oldProcessList = newProcessList
isNew = false
}
}
processList = nil
<- ch
}
}
func sendPush(body string) {
form := url.Values{}
form.Add("sound", "shake") //设置消息铃声
form.Add("group", os.Args[1]+"主机进程监控") //设置分组
form.Add("title", os.Args[1]+" 进程监控") //设置标题
form.Add("body", body) //推送内容
client := &http.Client{}
req, err := http.NewRequest("POST", 客户端添加Bark服务URL后的得到的那串带KEY的URL, strings.NewReader(form.Encode()))
if err != nil {
log.Println("Failure :", err)
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
resp, err := client.Do(req)
if err != nil {
log.Println("Failure :", err)
}
respBody, _ := ioutil.ReadAll(resp.Body)
log.Println("response Status :", resp.Status)
log.Println("response Headers :", resp.Header)
log.Println("response Body :", string(respBody))
}
func isExists(arr []int, currItem int) bool {
for _, v := range arr {
if v == currItem {
return true
}
}
return false
}
func unique(arr []ps.Process) []ps.Process {
occured := map[ps.Process]bool{}
result := []ps.Process{}
for e := range arr {
if occured[arr[e]] != true {
occured[arr[e]] = true
result = append(result, arr[e])
}
}
return result
}
编译完以后运行:
./main [自定义名称,比如服务器名字]
这些问题还请请哥哥姐姐们指点指点~
不管扫描间隔时间多小,总会有一些立马执行完的命令(如ls
)会逃过检测
windows
下如何通过cmd
或者powershell
获取指定进程的指定参数(我没有去查,也不太想写)
很烦人,特别是有人在爆破我的ssh
时,就算有登录失败处理策略,但每次ssh
连接的时候就会产生新进程,在凌晨时候手机跟疯狗一样…
不过Bark
是不错的,也可以结合其他工具使用,强烈推荐。