From 8b45a1c54ab23009cc052edb40330eeac5c69680 Mon Sep 17 00:00:00 2001 From: DVKunion Date: Sun, 23 Jul 2023 13:53:26 +0800 Subject: [PATCH] feat(veinmind-trace): complete code --- .github/workflows/veinmind-build.yml | 1 + .github/workflows/veinmind-package.yml | 7 +- .github/workflows/veinmind-push.yml | 1 + plugins/go/veinmind-trace/Dockerfile | 4 +- plugins/go/veinmind-trace/README.en.md | 3 - plugins/go/veinmind-trace/README.md | 88 ++++++++++-- plugins/go/veinmind-trace/cmd/cli.go | 51 ++++--- plugins/go/veinmind-trace/go.mod | 3 +- plugins/go/veinmind-trace/go.sum | 4 +- .../veinmind-trace/pkg/analyzer/analyzer.go | 10 +- .../go/veinmind-trace/pkg/analyzer/file.go | 126 ++++++++++++++++-- .../go/veinmind-trace/pkg/analyzer/process.go | 102 ++++++++++---- .../go/veinmind-trace/pkg/analyzer/user.go | 32 ----- .../go/veinmind-trace/pkg/security/file.go | 35 +++-- .../go/veinmind-trace/pkg/security/process.go | 17 +-- .../pkg/security/process_test.go | 6 +- plugins/go/veinmind-trace/pkg/system/init.go | 7 - plugins/go/veinmind-trace/pkg/system/user.go | 47 ------- veinmind-runner/Dockerfile | 2 + 19 files changed, 361 insertions(+), 185 deletions(-) delete mode 100644 plugins/go/veinmind-trace/README.en.md delete mode 100644 plugins/go/veinmind-trace/pkg/analyzer/user.go delete mode 100644 plugins/go/veinmind-trace/pkg/system/init.go delete mode 100644 plugins/go/veinmind-trace/pkg/system/user.go diff --git a/.github/workflows/veinmind-build.yml b/.github/workflows/veinmind-build.yml index 892d64fe..10afae27 100644 --- a/.github/workflows/veinmind-build.yml +++ b/.github/workflows/veinmind-build.yml @@ -22,6 +22,7 @@ jobs: veinmind-weakpass, veinmind-webshell, veinmind-minio, + veinmind-trace ] path: [ ./plugins/go/ ] include: diff --git a/.github/workflows/veinmind-package.yml b/.github/workflows/veinmind-package.yml index b63be488..20945ba2 100644 --- a/.github/workflows/veinmind-package.yml +++ b/.github/workflows/veinmind-package.yml @@ -91,6 +91,10 @@ jobs: with: name: veinmind-backdoor-amd64 path: ./ + - uses: actions/download-artifact@v3 + with: + name: veinmind-trace-amd64 + path: ./ - uses: actions/download-artifact@v3 with: name: veinmind-minio-amd64 @@ -113,10 +117,11 @@ jobs: mv veinmind-escape_${{env.CI_GOOS}}_${{env.CI_GOARCH}} veinmind-escape mv veinmind-privilege-escalation_${{env.CI_GOOS}}_${{env.CI_GOARCH}} veinmind-privilege-escalation mv veinmind-minio_${{env.CI_GOOS}}_${{env.CI_GOARCH}} veinmind-minio + mv veinmind-trace_${{env.CI_GOOS}}_${{env.CI_GOARCH}} veinmind-trace mv ./plugins/python/veinmind-history ./veinmind-history rm -rf ./veinmind-runner && mv veinmind-runner_${{env.CI_GOOS}}_${{env.CI_GOARCH}} veinmind-runner chmod +x veinmind-runner veinmind-malicious veinmind-vuln veinmind-webshell veinmind-backdoor veinmind-unsafe-mount veinmind-log4j2 veinmind-weakpass veinmind-iac veinmind-sensitive veinmind-basic veinmind-escape veinmind-privilege-escalation - tar cvzf veinmind-runner.tar.gz veinmind-runner veinmind-malicious veinmind-vuln veinmind-webshell veinmind-minio veinmind-backdoor \ + tar cvzf veinmind-runner.tar.gz veinmind-runner veinmind-malicious veinmind-vuln veinmind-webshell veinmind-minio veinmind-backdoor veinmind-trace \ veinmind-unsafe-mount veinmind-log4j2 veinmind-weakpass veinmind-iac veinmind-sensitive veinmind-basic veinmind-escape veinmind-privilege-escalation \ ./veinmind-history - uses: actions/upload-artifact@v3 diff --git a/.github/workflows/veinmind-push.yml b/.github/workflows/veinmind-push.yml index 9282c8ff..1094721c 100644 --- a/.github/workflows/veinmind-push.yml +++ b/.github/workflows/veinmind-push.yml @@ -58,6 +58,7 @@ jobs: veinmind-weakpass, veinmind-webshell, veinmind-minio, + veinmind-trace ] path: [ ./plugins/go/ ] name: ${{ matrix.plugin }} diff --git a/plugins/go/veinmind-trace/Dockerfile b/plugins/go/veinmind-trace/Dockerfile index 61a048a2..27ce62dd 100644 --- a/plugins/go/veinmind-trace/Dockerfile +++ b/plugins/go/veinmind-trace/Dockerfile @@ -1,4 +1,4 @@ -FROM veinmind/go1.18:1.9.21-bullseye as builder +FROM veinmind/go1.18:1.9.42-bullseye as builder WORKDIR /build COPY .. . RUN make build @@ -8,7 +8,7 @@ WORKDIR /build COPY --from=builder /build/veinmind-trace . RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && apk add upx && upx -9 veinmind-trace -FROM veinmind/base:1.9.21-bullseye as release +FROM veinmind/base:1.9.42-bullseye as release WORKDIR /tool COPY --from=compresser /build/veinmind-trace . RUN echo "#!/bin/bash\n\n./veinmind-trace \$*" > /tool/entrypoint.sh && chmod +x /tool/entrypoint.sh && chmod +x /tool/veinmind-trace diff --git a/plugins/go/veinmind-trace/README.en.md b/plugins/go/veinmind-trace/README.en.md deleted file mode 100644 index eb078b78..00000000 --- a/plugins/go/veinmind-trace/README.en.md +++ /dev/null @@ -1,3 +0,0 @@ -# veinmind-trace - -this is description file diff --git a/plugins/go/veinmind-trace/README.md b/plugins/go/veinmind-trace/README.md index f49eb5c1..67af61ba 100644 --- a/plugins/go/veinmind-trace/README.md +++ b/plugins/go/veinmind-trace/README.md @@ -5,16 +5,80 @@ veinmind-trace 是由长亭科技自研的一款容器安全检测工具

## 功能特性 + + 快速扫描容器中的异常进程: - 1. 隐藏进程(mount -o bind方式) - 2. 反弹shell的进程 - 3. 带有挖矿、黑客工具、可疑进程名的进程 - 4. 包含 Ptrace 的进程 -+ 快速扫描容器中的异常文件系统: - 1. 敏感目录权限异常 - 2. cdk 工具利用痕迹检测 -+ 快速扫描容器中的异常用户: - 1. uid=0 的非root账户 - 2. gid=0 的非root账户 - 3. uid相同的用户 -+ 支持`containerd`/`dockerd`容器运行时 \ No newline at end of file + 1. 隐藏进程(mount -o bind方式) + 2. 反弹shell的进程 + 3. 带有挖矿、黑客工具、可疑进程名的进程 + 4. 包含 Ptrace 的进程 ++ 快速扫描容器中的异常文件系统: + 1. 敏感目录权限异常 + 2. cdk 工具利用痕迹检测 ++ 快速扫描容器中的异常用户: + 1. uid=0 的非root账户 + 2. uid相同的用户 ++ 支持`containerd`/`dockerd`容器运行时 + +## 兼容性 + +- linux/amd64 +- linux/386 +- linux/arm64 + +## 使用方式 + +### 基于可执行文件 + +请先安装`libveinmind`,安装方法可以参考[官方文档](https://github.com/chaitin/libveinmind) + +#### Makefile 一键命令 + +``` +make run ARG="scan xxx" +``` + +#### 自行编译可执行文件进行扫描 + +编译可执行文件 + +``` +make build +``` + +运行可执行文件进行扫描 + +``` +chmod +x veinmind-trace && ./veinmind-trace scan xxx +``` + +### 基于平行容器模式 + +确保机器上安装了`docker`以及`docker-compose` + +#### Makefile 一键命令 + +``` +make run.docker ARG="scan xxxx" +``` + +#### 自行构建镜像进行扫描 + +构建`veinmind-trace`镜像 + +``` +make build.docker +``` + +运行容器进行扫描 + +``` +docker run --rm -it --mount 'type=bind,source=/,target=/host,readonly,bind-propagation=rslave' veinmind-trace scan xxx +``` + +## 使用 + +1. 扫描本地所有镜像 + +``` +./veinmind-trace scan container +``` \ No newline at end of file diff --git a/plugins/go/veinmind-trace/cmd/cli.go b/plugins/go/veinmind-trace/cmd/cli.go index 45d172fa..c250419c 100644 --- a/plugins/go/veinmind-trace/cmd/cli.go +++ b/plugins/go/veinmind-trace/cmd/cli.go @@ -2,12 +2,16 @@ package main import ( "os" + "time" api "github.com/chaitin/libveinmind/go" "github.com/chaitin/libveinmind/go/cmd" "github.com/chaitin/libveinmind/go/plugin" "github.com/chaitin/libveinmind/go/plugin/log" "github.com/chaitin/veinmind-common-go/service/report" + "github.com/chaitin/veinmind-common-go/service/report/event" + + "github.com/chaitin/veinmind-tools/plugins/go/veinmind-trace/pkg/analyzer" ) var reportService = &report.Service{} @@ -32,30 +36,33 @@ func scanContainer(c *cmd.Command, container api.Container) error { log.Error(err) } }() - // 1 - // 2. check process - //analyzer.ScanProcesses(container) + result := make([]*event.TraceEvent, 0) + for _, a := range analyzer.Group { + a.Scan(container) + result = append(result, a.Result()...) + } - // if you want display at runner report, you should send your result to report event - //reportEvent := &event.Event{ - // BasicInfo: &event.BasicInfo{ - // ID: container.ID(), // container id info - // Object: event.NewObject(container), - // Time: time.Now(), // report time, usually use time.Now - // Level: event.None, // report event level - // DetectType: event.Container, // report scan object type - // AlertType: event.BasicContainer, // report alert type, we provide some clearly types of security events, - // EventType: event.Info, // report event type: Risk/Invasion/Info - // }, - // DetailInfo: &event.DetailInfo{ - // // add report detail data in there - // }, - //} - //err = reportService.Client.Report(reportEvent) - //if err != nil { - // return err - //} + for _, e := range result { + reportEvent := &event.Event{ + BasicInfo: &event.BasicInfo{ + ID: container.ID(), // container id info + Object: event.NewObject(container), + Time: time.Now(), // report time, usually use time.Now + Level: e.Level, // report event level + DetectType: event.Container, // report scan object type + AlertType: event.TraceRisk, // report alert type, we provide some clearly types of security events, + EventType: event.Risk, // report event type: Risk/Invasion/Info + }, + DetailInfo: &event.DetailInfo{ + AlertDetail: e, + }, + } + err := reportService.Client.Report(reportEvent) + if err != nil { + log.Error(err) + } + } return nil } diff --git a/plugins/go/veinmind-trace/go.mod b/plugins/go/veinmind-trace/go.mod index cb833ee4..c3c8fc1a 100644 --- a/plugins/go/veinmind-trace/go.mod +++ b/plugins/go/veinmind-trace/go.mod @@ -4,5 +4,6 @@ go 1.16 require ( github.com/chaitin/libveinmind v1.5.6 - github.com/chaitin/veinmind-common-go v1.4.4 + github.com/chaitin/veinmind-common-go v1.4.6 + github.com/stretchr/testify v1.7.4 ) diff --git a/plugins/go/veinmind-trace/go.sum b/plugins/go/veinmind-trace/go.sum index e4faa568..2927c106 100644 --- a/plugins/go/veinmind-trace/go.sum +++ b/plugins/go/veinmind-trace/go.sum @@ -167,8 +167,8 @@ github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chaitin/libveinmind v1.5.2/go.mod h1:TXLYL6GeSAQ7pQ5IxPG4Tp0DuB1QvPPFhqdOjyiWxVU= github.com/chaitin/libveinmind v1.5.6 h1:fyNq142a+uOfYZ68GTzElFXVB0dtEXvs+ffwk24+Vfg= github.com/chaitin/libveinmind v1.5.6/go.mod h1:TXLYL6GeSAQ7pQ5IxPG4Tp0DuB1QvPPFhqdOjyiWxVU= -github.com/chaitin/veinmind-common-go v1.4.4 h1:3oAXapZCH2nbNHjBuxX5zNChK4v4r+/SrbxCCTyCkL0= -github.com/chaitin/veinmind-common-go v1.4.4/go.mod h1:+dshrlmHiBtRV7ATyObBIg3SZoffpNCr1PdahT1LUQo= +github.com/chaitin/veinmind-common-go v1.4.6 h1:MJI05QVs89WB3TwXA4T//f4FX5olLQrG5+Ycqb9POSI= +github.com/chaitin/veinmind-common-go v1.4.6/go.mod h1:+dshrlmHiBtRV7ATyObBIg3SZoffpNCr1PdahT1LUQo= github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= diff --git a/plugins/go/veinmind-trace/pkg/analyzer/analyzer.go b/plugins/go/veinmind-trace/pkg/analyzer/analyzer.go index 71972341..3373789c 100644 --- a/plugins/go/veinmind-trace/pkg/analyzer/analyzer.go +++ b/plugins/go/veinmind-trace/pkg/analyzer/analyzer.go @@ -1,5 +1,13 @@ package analyzer +import ( + api "github.com/chaitin/libveinmind/go" + "github.com/chaitin/veinmind-common-go/service/report/event" +) + +var Group = make([]Analyzer, 0) + type Analyzer interface { - Scan() + Scan(container api.Container) + Result() []*event.TraceEvent } diff --git a/plugins/go/veinmind-trace/pkg/analyzer/file.go b/plugins/go/veinmind-trace/pkg/analyzer/file.go index 1b3158c5..516cb621 100644 --- a/plugins/go/veinmind-trace/pkg/analyzer/file.go +++ b/plugins/go/veinmind-trace/pkg/analyzer/file.go @@ -1,35 +1,143 @@ package analyzer import ( + "io/fs" "syscall" api "github.com/chaitin/libveinmind/go" + "github.com/chaitin/veinmind-common-go/passwd" + "github.com/chaitin/veinmind-common-go/service/report/event" "github.com/chaitin/veinmind-tools/plugins/go/veinmind-trace/pkg/security" ) -type FileAnalyzer struct { - Object api.Container - //Event [] +func init() { + Group = append(Group, &FileAnalyzer{}) } -func (fa *FileAnalyzer) Scan() { - fa.scanFilePerm() +type FileAnalyzer struct { + event []*event.TraceEvent +} +func (fa *FileAnalyzer) Scan(container api.Container) { + fa.event = make([]*event.TraceEvent, 0) + fa.scanFilePerm(container) + fa.scanTrace(container) + fa.scanUser(container) } -func (fa *FileAnalyzer) scanFilePerm() { +func (fa *FileAnalyzer) scanFilePerm(container api.Container) { + // 检测敏感文件权限配置 for dir, perm := range security.SensitiveDirPerm { - if info, err := fa.Object.Stat(dir); err == nil { + if info, err := container.Stat(dir); err == nil { // check uid first sys := info.Sys() if stat, ok := sys.(*syscall.Stat_t); ok && stat.Uid != perm.Uid { - // todo:add event + fa.event = append(fa.event, &event.TraceEvent{ + Name: "Perm of Sensitive File", + From: "File", + Path: dir, + Description: "Incorrect user permissions for sensitive files", + Detail: string(stat.Uid), + Level: event.Medium, + }) } // check perm next if perm.Mode != 0 && info.Mode() != perm.Mode { - // todo:add event + fa.event = append(fa.event, &event.TraceEvent{ + Name: "Perm of Sensitive File", + From: "File", + Path: dir, + Description: "Incorrect file permissions for sensitive files", + Detail: info.Mode().String() + " (should " + perm.Mode.String() + ")", + Level: event.Medium, + }) + } + } + } +} + +func (fa *FileAnalyzer) scanTrace(container api.Container) { + // 检测文件痕迹 + container.Walk("/tmp", func(path string, info fs.FileInfo, err error) error { + for _, re := range security.CDKTrace { + if re.MatchString(path) { + fa.event = append(fa.event, &event.TraceEvent{ + Name: "Attack Trace", + From: "File", + Path: path, + Description: "Found traces of intrusion, it is highly likely that the container has been invaded", + Detail: "cdk trace file", + Level: event.High, + }) + } + } + return nil + }) + container.Walk("/mnt", func(path string, info fs.FileInfo, err error) error { + for _, re := range security.CDKTrace { + if re.MatchString(path) { + fa.event = append(fa.event, &event.TraceEvent{ + Name: "Attack Trace", + From: "File", + Path: path, + Description: "Found traces of intrusion, it is highly likely that the container has been invaded", + Detail: "cdk trace file", + Level: event.High, + }) } } + return nil + }) +} + +func (fa *FileAnalyzer) scanUser(container api.Container) { + // 检查用户passwd + entries, err := passwd.ParseFilesystemPasswd(container) + entryMap := make(map[string]string, 0) + if err != nil { + return } + for _, e := range entries { + // 1. check uid=0 but not root user + if e.Uid == "0" && e.Username != "root" { + fa.event = append(fa.event, &event.TraceEvent{ + Name: "Abnormal user", + From: "File", + Path: "/etc/passwd", + Description: "Abnormal user detected which uid=0 but not root", + Detail: e.Username + ";uid:" + e.Uid + ";gid:" + e.Gid, + Level: event.Medium, + }) + } + // 2. check gid=0 but not root user + //if e.Gid == "0" && e.Username != "root" { + // fa.event = append(fa.event, &event.TraceEvent{ + // Name: "Abnormal user", + // From: "File", + // Path: "/etc/passwd", + // Description: "Abnormal user detected which gid=0 but not root", + // Detail: e.Username + ";uid:" + e.Uid + ";gid:" + e.Gid, + // Level: event.Medium, + // }) + //} + // 3. check same uid user + if _, ok := entryMap[e.Uid]; ok && e.Username != entryMap[e.Uid] { + fa.event = append(fa.event, &event.TraceEvent{ + Name: "Abnormal user", + From: "File", + Path: "/etc/passwd", + Description: "Abnormal user detected which same uid", + Detail: e.Username + ";uid:" + e.Uid + ";gid:" + e.Gid, + Level: event.Medium, + }) + } else { + entryMap[e.Uid] = e.Username + } + + } +} + +func (fa *FileAnalyzer) Result() []*event.TraceEvent { + return fa.event } diff --git a/plugins/go/veinmind-trace/pkg/analyzer/process.go b/plugins/go/veinmind-trace/pkg/analyzer/process.go index b462a454..c603906f 100644 --- a/plugins/go/veinmind-trace/pkg/analyzer/process.go +++ b/plugins/go/veinmind-trace/pkg/analyzer/process.go @@ -1,39 +1,60 @@ package analyzer import ( + "io" + "path/filepath" + "strconv" + api "github.com/chaitin/libveinmind/go" + "github.com/chaitin/veinmind-common-go/service/report/event" "github.com/chaitin/veinmind-tools/plugins/go/veinmind-trace/pkg/security" ) +func init() { + Group = append(Group, &ProcAnalyzer{}) +} + // ProcAnalyzer 检测容器内异常的进程 // 1. 隐藏进程(mount -o bind方式) - // 2. 反弹shell的进程 - // 3. 带有挖矿、黑客工具、可疑进程名的进程 // 4. 包含 Ptrace 的进程 type ProcAnalyzer struct { - Object api.Container - //Event [] - - processes map[int32]api.Process + event []*event.TraceEvent + container api.Container } -func NewProcAnalyzer(container api.Container) { - -} - -func (pa *ProcAnalyzer) Scan() { +func (pa *ProcAnalyzer) Scan(container api.Container) { + pa.event = make([]*event.TraceEvent, 0) + pa.container = container pa.scanHideProcess() - for pid, p := range pa.processes { - pa.scanReverseShell(p, pid) - pa.scanEvalProcess(p) - pa.scanPTraceProcess(p) + pids, err := container.Pids() + if err != nil { + return + } + + for _, pid := range pids { + ps, err := container.NewProcess(pid) + if err != nil { + continue + } + pa.scanReverseShell(ps, pid) + pa.scanEvalProcess(ps, pid) + pa.scanPTraceProcess(container, ps, pid) } } func (pa *ProcAnalyzer) scanHideProcess() { - if security.IsHideProcess(pa.Object) { - // todo + if ok, content := security.IsHideProcess(pa.container); ok { + pa.event = append(pa.event, &event.TraceEvent{ + Name: "Hiding Process", + From: "Process", + Path: "/proc/mounts", + Description: "some hiding process is in /proc/mounts", + Detail: content, + Level: event.High, + }) } } @@ -42,27 +63,62 @@ func (pa *ProcAnalyzer) scanReverseShell(p api.Process, pid int32) { if err != nil { return } - if security.IsReverseShell(pa.Object, pid, cmdLine) { - // todo + if security.IsReverseShell(pa.container, pid, cmdLine) { + pa.event = append(pa.event, &event.TraceEvent{ + Name: "Reverse Shell Process", + From: "Process", + Path: "/proc/" + strconv.Itoa(int(pid)), + Description: "an reverse shell process detect", + Detail: cmdLine, + Level: event.Critical, + }) } } -func (pa *ProcAnalyzer) scanEvalProcess(p api.Process) { +func (pa *ProcAnalyzer) scanEvalProcess(p api.Process, pid int32) { cmdLine, err := p.Cmdline() if err != nil { return } if security.IsEval(cmdLine) { - // todo + pa.event = append(pa.event, &event.TraceEvent{ + Name: "Eval Process", + From: "Process", + Path: "/proc/" + strconv.Itoa(int(pid)), + Description: "an eval shell process detect", + Detail: cmdLine, + Level: event.Critical, + }) } } -func (pa *ProcAnalyzer) scanPTraceProcess(p api.Process) { - status, err := p.Status() +func (pa *ProcAnalyzer) scanPTraceProcess(container api.Container, p api.Process, pid int32) { + cmdLine, err := p.Cmdline() if err != nil { return } - if security.HasPtraceProcess(status) { - // todo + + file, err := container.Open(filepath.Join("/proc", strconv.Itoa(int(pid)), "status")) + if err != nil { + return } + + status, err := io.ReadAll(file) + if err != nil { + return + } + if security.HasPtraceProcess(string(status)) { + pa.event = append(pa.event, &event.TraceEvent{ + Name: "Ptrace Process", + From: "Process", + Path: "/proc/" + strconv.Itoa(int(pid)), + Description: "an process with Ptrace detect", + Detail: cmdLine, + Level: event.High, + }) + } +} + +func (pa *ProcAnalyzer) Result() []*event.TraceEvent { + return pa.event } diff --git a/plugins/go/veinmind-trace/pkg/analyzer/user.go b/plugins/go/veinmind-trace/pkg/analyzer/user.go deleted file mode 100644 index e3f0704c..00000000 --- a/plugins/go/veinmind-trace/pkg/analyzer/user.go +++ /dev/null @@ -1,32 +0,0 @@ -package analyzer - -import ( - api "github.com/chaitin/libveinmind/go" - "github.com/chaitin/veinmind-common-go/passwd" -) - -func checkUsers(fs api.FileSystem) error { - entries, err := passwd.ParseFilesystemPasswd(fs) - entryMap := make(map[string]string, 0) - if err != nil { - return err - } - for _, e := range entries { - // 1. check uid=0 but not root user - if e.Uid == "0" && e.Username != "root" { - // todo: may trace user, warn - } - // 2. check gid=0 but not root user - if e.Gid == "0" && e.Username != "root" { - // todo: may trace user, warn - } - // 3. check same uid user - if _, ok := entryMap[e.Uid]; ok && e.Username != entryMap[e.Uid] { - // todo: may trace add user, warn - } else { - entryMap[e.Uid] = e.Username - } - - } - return nil -} diff --git a/plugins/go/veinmind-trace/pkg/security/file.go b/plugins/go/veinmind-trace/pkg/security/file.go index 614fc6db..6be13afb 100644 --- a/plugins/go/veinmind-trace/pkg/security/file.go +++ b/plugins/go/veinmind-trace/pkg/security/file.go @@ -6,18 +6,27 @@ import ( ) var SensitiveDirPerm = map[string]Perm{ - "/etc/shadow": {0, 0640}, - "/etc/passwd": {0, 0644}, - "/etc/group": {0, 0644}, - "/etc/gshadow": {0, 0640}, - "/etc/ld.so.conf": {0, 0644}, - "/etc/hosts": {0, 0644}, - "/etc/hosts.allow": {0, 0644}, - "/etc/sudoers": {0, 0640}, - "/etc/ld.so.preload": {0, 0600}, - "/var/spool/cron/crontabs": {0, 0730}, - "/var/spool/cron/crontabs/root": {0, 0600}, + "/etc/shadow": {0, 0640}, + "/etc/passwd": {0, 0644}, + "/etc/group": {0, 0644}, + "/etc/gshadow": {0, 0640}, + "/etc/ld.so.conf": {0, 0644}, + "/etc/hosts": {0, 0644}, + "/etc/hosts.allow": {0, 0644}, + "/etc/sudoers": {0, 0640}, + "/etc/ld.so.preload": {0, 0600}, "/lib/x86_64-linux-gnu/security/pam_unix.so": {0, 644}, + + // crontab + "/var/spool/cron/crontabs": {0, fs.ModeDir | 0755}, + "/var/spool/cron/crontabs/root": {0, 0600}, + "/etc/crontab": {0, fs.ModeDir | 0644}, + "/etc/cron.d": {0, fs.ModeDir | 0755}, + "/etc/cron.daily": {0, fs.ModeDir | 0755}, + "/etc/cron.hourly": {0, fs.ModeDir | 0755}, + "/etc/cron.monthly": {0, fs.ModeDir | 0755}, + "/etc/cron.weekly": {0, fs.ModeDir | 0755}, + "/bin/": {0, 0}, "/sbin/": {0, 0}, "/lib/": {0, 0}, @@ -25,7 +34,7 @@ var SensitiveDirPerm = map[string]Perm{ "/usr/": {0, 0}, "/run/": {0, 0}, "/proc/": {0, 0}, - "/root": {0, 0750}, + "/root": {0, fs.ModeDir | 0700}, } type Perm struct { @@ -39,7 +48,7 @@ var CDKTrace = []*regexp.Regexp{ // exp/mount_cgroup.go regexp.MustCompile(`/tmp/cgrp/cdk/notify_on_release`), - regexp.MustCompile(`/cdk_cgres_.*?`), + regexp.MustCompile(`cdk_cgres_.*?`), // exp/rewrite_cgroup_devices.go regexp.MustCompile(`/tmp/cdk_dcgroup.*?`), diff --git a/plugins/go/veinmind-trace/pkg/security/process.go b/plugins/go/veinmind-trace/pkg/security/process.go index b731e470..716a2080 100644 --- a/plugins/go/veinmind-trace/pkg/security/process.go +++ b/plugins/go/veinmind-trace/pkg/security/process.go @@ -16,7 +16,7 @@ var ( hackList = []string{"minerd", "r00t", "sqlmap", "nmap", "hydra", "fscan", "cdk"} ) -func IsHideProcess(fs api.FileSystem) bool { +func IsHideProcess(fs api.FileSystem) (bool, string) { // 隐藏进程检测 // 隐藏进程的几种方法: // 1. 劫持readdir系统调用 @@ -30,15 +30,15 @@ func IsHideProcess(fs api.FileSystem) bool { if _, err := fs.Stat(path); err == nil { file, err := fs.Open(path) if err != nil { - return false + return false, "" } content, err := io.ReadAll(file) if err != nil { - return false + return false, "" } return hasMount(string(content)) } - return false + return false, "" } func IsReverseShell(fs api.FileSystem, pid int32, cmdline string) bool { @@ -78,24 +78,25 @@ func IsEval(cmdline string) bool { } func HasPtraceProcess(content string) bool { - if ok, err := regexp.MatchString(`TracerPid:\s+0`, content); !ok && err == nil { + if ok, err := regexp.MatchString(`TracerPid:\s+0`, content); !ok && err == nil && strings.Contains(content, "TracerPid") { + fmt.Println(content) return true } return false } -func hasMount(content string) bool { +func hasMount(content string) (bool, string) { lines := strings.Split(content, "\n") for _, line := range lines { row := strings.Split(line, " ") if len(row) > 2 { if ok, err := regexp.MatchString(`/proc/\d+`, row[1]); ok && err == nil { - return true + return true, row[1] } } } - return false + return false, "" } func isSocket(fs api.FileSystem, pid int32) (bool, error) { diff --git a/plugins/go/veinmind-trace/pkg/security/process_test.go b/plugins/go/veinmind-trace/pkg/security/process_test.go index 0abf5b66..a266d283 100644 --- a/plugins/go/veinmind-trace/pkg/security/process_test.go +++ b/plugins/go/veinmind-trace/pkg/security/process_test.go @@ -11,8 +11,10 @@ func TestHideMount(t *testing.T) { proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0` content2 := `sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0 proc /proc/1 proc rw,nosuid,nodev,noexec,relatime 0 0` - assert.Equal(t, false, hasMount(content1)) - assert.Equal(t, true, hasMount(content2)) + a, _ := hasMount(content1) + b, _ := hasMount(content2) + assert.Equal(t, false, a) + assert.Equal(t, true, b) } func TestHasPtraceProcess(t *testing.T) { diff --git a/plugins/go/veinmind-trace/pkg/system/init.go b/plugins/go/veinmind-trace/pkg/system/init.go deleted file mode 100644 index e816d07a..00000000 --- a/plugins/go/veinmind-trace/pkg/system/init.go +++ /dev/null @@ -1,7 +0,0 @@ -package system - -// check system init alias - -func checkAlias() { - -} diff --git a/plugins/go/veinmind-trace/pkg/system/user.go b/plugins/go/veinmind-trace/pkg/system/user.go deleted file mode 100644 index 44bb46b5..00000000 --- a/plugins/go/veinmind-trace/pkg/system/user.go +++ /dev/null @@ -1,47 +0,0 @@ -package system - -import ( - api "github.com/chaitin/libveinmind/go" - "github.com/chaitin/veinmind-common-go/passwd" -) - -// 容器用户相关规则 -// 1. 存在uid=0 的非root账户 -// 2. 存在gid=0 的非root账户 -// 3. 存在uid相同的用户 - -const sudoersPath = "/etc/sudoers" - -func checkUsers(fs api.FileSystem) error { - entries, err := passwd.ParseFilesystemPasswd(fs) - entryMap := make(map[string]string, 0) - if err != nil { - return err - } - for _, e := range entries { - // 1. check uid=0 but not root user - if e.Uid == "0" && e.Username != "root" { - // todo: may trace user, warn - } - // 2. check gid=0 but not root user - if e.Gid == "0" && e.Username != "root" { - // todo: may trace user, warn - } - // 3. check same uid user - if _, ok := entryMap[e.Uid]; ok && e.Username != entryMap[e.Uid] { - // todo: may trace add user, warn - } else { - entryMap[e.Uid] = e.Username - } - - } - return nil -} - -func checkSudoers(fs api.FileSystem) error { - return nil -} - -func checkPasswdFile(fs api.FileSystem) error { - return nil -} diff --git a/veinmind-runner/Dockerfile b/veinmind-runner/Dockerfile index 9ee3a9cd..ef981079 100644 --- a/veinmind-runner/Dockerfile +++ b/veinmind-runner/Dockerfile @@ -19,6 +19,7 @@ FROM veinmind/veinmind-vuln:latest as vuln FROM veinmind/veinmind-escape:latest as escape FROM veinmind/veinmind-privilege-escalation:latest as privilege-escalation FROM veinmind/veinmind-minio:latest as minio +FROM veinmind/veinmind-trace:latest as trace FROM veinmind/python3.6:1.9.42-bullseye as release WORKDIR /tool @@ -42,6 +43,7 @@ COPY --from=vuln /tool/veinmind-vuln ./plugin COPY --from=escape /tool/veinmind-escape ./plugin COPY --from=privilege-escalation /tool/veinmind-privilege-escalation ./plugin COPY --from=minio /tool/veinmind-minio ./plugin +COPY --from=trace /tool/veinmind-trace ./plugin RUN pip install -r plugin/veinmind-history/requirements.txt && chmod +x plugin/*/scan.py RUN echo "#!/bin/bash\n\n./veinmind-runner \$*" > /tool/entrypoint.sh && chmod +x /tool/entrypoint.sh && chmod +x /tool/veinmind-runner