Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/js/libs/telnet/telnet.go
2848 views
1
package telnet
2
3
import (
4
"context"
5
"fmt"
6
"net"
7
"strconv"
8
"time"
9
10
"github.com/praetorian-inc/fingerprintx/pkg/plugins"
11
"github.com/praetorian-inc/fingerprintx/pkg/plugins/services/telnet"
12
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
13
"github.com/projectdiscovery/nuclei/v3/pkg/utils/telnetmini"
14
)
15
16
// Telnet protocol constants
17
const (
18
IAC = 255 // Interpret As Command
19
WILL = 251 // Will
20
WONT = 252 // Won't
21
DO = 253 // Do
22
DONT = 254 // Don't
23
SB = 250 // Subnegotiation Begin
24
SE = 240 // Subnegotiation End
25
ECHO = 1 // Echo
26
SUPPRESS_GO_AHEAD = 3 // Suppress Go Ahead
27
TERMINAL_TYPE = 24 // Terminal Type
28
NAWS = 31 // Negotiate About Window Size
29
ENCRYPT = 38 // Encryption option (0x26)
30
)
31
32
type (
33
// IsTelnetResponse is the response from the IsTelnet function.
34
// this is returned by IsTelnet function.
35
// @example
36
// ```javascript
37
// const telnet = require('nuclei/telnet');
38
// const isTelnet = telnet.IsTelnet('acme.com', 23);
39
// log(toJSON(isTelnet));
40
// ```
41
IsTelnetResponse struct {
42
IsTelnet bool
43
Banner string
44
}
45
46
// TelnetInfoResponse is the response from the Info function.
47
// @example
48
// ```javascript
49
// const telnet = require('nuclei/telnet');
50
// const client = new telnet.TelnetClient();
51
// const info = client.Info('acme.com', 23);
52
// log(toJSON(info));
53
// ```
54
TelnetInfoResponse struct {
55
SupportsEncryption bool
56
Banner string
57
Options map[int][]int
58
}
59
60
// TelnetClient is a client for Telnet servers.
61
// @example
62
// ```javascript
63
// const telnet = require('nuclei/telnet');
64
// const client = new telnet.TelnetClient();
65
// ```
66
TelnetClient struct{}
67
)
68
69
// IsTelnet checks if a host is running a Telnet server.
70
// @example
71
// ```javascript
72
// const telnet = require('nuclei/telnet');
73
// const isTelnet = telnet.IsTelnet('acme.com', 23);
74
// log(toJSON(isTelnet));
75
// ```
76
func IsTelnet(ctx context.Context, host string, port int) (IsTelnetResponse, error) {
77
executionId := ctx.Value("executionId").(string)
78
return memoizedisTelnet(executionId, host, port)
79
}
80
81
// @memo
82
func isTelnet(executionId string, host string, port int) (IsTelnetResponse, error) {
83
resp := IsTelnetResponse{}
84
85
timeout := 5 * time.Second
86
dialer := protocolstate.GetDialersWithId(executionId)
87
if dialer == nil {
88
return IsTelnetResponse{}, fmt.Errorf("dialers not initialized for %s", executionId)
89
}
90
91
conn, err := dialer.Fastdialer.Dial(context.TODO(), "tcp", net.JoinHostPort(host, strconv.Itoa(port)))
92
if err != nil {
93
return resp, err
94
}
95
defer func() {
96
_ = conn.Close()
97
}()
98
99
telnetPlugin := telnet.TELNETPlugin{}
100
service, err := telnetPlugin.Run(conn, timeout, plugins.Target{Host: host})
101
if err != nil {
102
return resp, err
103
}
104
if service == nil {
105
return resp, nil
106
}
107
resp.Banner = service.Metadata().(plugins.ServiceTelnet).ServerData
108
resp.IsTelnet = true
109
return resp, nil
110
}
111
112
// Connect tries to connect to provided host and port with telnet.
113
// Optionally provides username and password for authentication.
114
// Returns state of connection. If the connection is successful,
115
// the function will return true, otherwise false.
116
// @example
117
// ```javascript
118
// const telnet = require('nuclei/telnet');
119
// const client = new telnet.TelnetClient();
120
// const connected = client.Connect('acme.com', 23, 'username', 'password');
121
// ```
122
func (c *TelnetClient) Connect(ctx context.Context, host string, port int, username string, password string) (bool, error) {
123
executionId := ctx.Value("executionId").(string)
124
125
dialer := protocolstate.GetDialersWithId(executionId)
126
if dialer == nil {
127
return false, fmt.Errorf("dialers not initialized for %s", executionId)
128
}
129
130
if !protocolstate.IsHostAllowed(executionId, host) {
131
return false, protocolstate.ErrHostDenied.Msgf(host)
132
}
133
134
// Create TCP connection
135
conn, err := dialer.Fastdialer.Dial(context.TODO(), "tcp", net.JoinHostPort(host, strconv.Itoa(port)))
136
if err != nil {
137
return false, err
138
}
139
140
// Create telnet client using the telnetmini library
141
client := telnetmini.New(conn)
142
defer func() {
143
_ = client.Close()
144
}()
145
146
// Handle authentication if credentials provided
147
if username != "" && password != "" {
148
// Set a timeout context for authentication
149
authCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
150
defer cancel()
151
152
if err := client.Auth(authCtx, username, password); err != nil {
153
return false, err
154
}
155
}
156
157
return true, nil
158
}
159
160
// Info gathers information about the telnet server including encryption support.
161
// Uses the telnetmini library's DetectEncryption helper function.
162
// WARNING: The connection used for detection becomes unusable after this call.
163
// @example
164
// ```javascript
165
// const telnet = require('nuclei/telnet');
166
// const client = new telnet.TelnetClient();
167
// const info = client.Info('acme.com', 23);
168
// log(toJSON(info));
169
// ```
170
func (c *TelnetClient) Info(ctx context.Context, host string, port int) (TelnetInfoResponse, error) {
171
executionId := ctx.Value("executionId").(string)
172
173
if !protocolstate.IsHostAllowed(executionId, host) {
174
return TelnetInfoResponse{}, protocolstate.ErrHostDenied.Msgf(host)
175
}
176
177
// Create TCP connection for encryption detection
178
dialer := protocolstate.GetDialersWithId(executionId)
179
if dialer == nil {
180
return TelnetInfoResponse{}, fmt.Errorf("dialers not initialized for %s", executionId)
181
}
182
183
conn, err := dialer.Fastdialer.Dial(context.TODO(), "tcp", net.JoinHostPort(host, strconv.Itoa(port)))
184
if err != nil {
185
return TelnetInfoResponse{}, err
186
}
187
defer func() {
188
_ = conn.Close()
189
}()
190
191
// Use the telnetmini library's DetectEncryption helper function
192
// Note: The connection becomes unusable after this call
193
encryptionInfo, err := telnetmini.DetectEncryption(conn, 7*time.Second)
194
if err != nil {
195
return TelnetInfoResponse{}, err
196
}
197
198
return TelnetInfoResponse{
199
SupportsEncryption: encryptionInfo.SupportsEncryption,
200
Banner: encryptionInfo.Banner,
201
Options: encryptionInfo.Options,
202
}, nil
203
}
204
205
// GetTelnetNTLMInfo implements the Nmap telnet-ntlm-info.nse script functionality.
206
// This function uses the telnetmini library and SMB packet crafting functions to send
207
// MS-TNAP NTLM authentication requests with null credentials. It might work only on
208
// Microsoft Telnet servers.
209
// @example
210
// ```javascript
211
// const telnet = require('nuclei/telnet');
212
// const client = new telnet.TelnetClient();
213
// const ntlmInfo = client.GetTelnetNTLMInfo('acme.com', 23);
214
// log(toJSON(ntlmInfo));
215
// ```
216
func (c *TelnetClient) GetTelnetNTLMInfo(ctx context.Context, host string, port int) (*telnetmini.NTLMInfoResponse, error) {
217
executionId := ctx.Value("executionId").(string)
218
219
if !protocolstate.IsHostAllowed(executionId, host) {
220
return nil, protocolstate.ErrHostDenied.Msgf(host)
221
}
222
223
dialer := protocolstate.GetDialersWithId(executionId)
224
if dialer == nil {
225
return nil, fmt.Errorf("dialers not initialized for %s", executionId)
226
}
227
228
// Create TCP connection
229
conn, err := dialer.Fastdialer.Dial(context.TODO(), "tcp", net.JoinHostPort(host, strconv.Itoa(port)))
230
if err != nil {
231
return nil, err
232
}
233
defer func() {
234
_ = conn.Close()
235
}()
236
237
// Create telnet client using the telnetmini library
238
client := telnetmini.New(conn)
239
defer func() {
240
_ = client.Close()
241
}()
242
243
// Set timeout
244
_ = conn.SetDeadline(time.Now().Add(10 * time.Second))
245
246
// Use the MS-TNAP packet crafting functions from our telnetmini library
247
// Create MS-TNAP Login Packet (Option Command IS) as per Nmap script
248
tnapLoginPacket := telnetmini.CreateTNAPLoginPacket()
249
250
// Send the MS-TNAP login packet
251
_, err = conn.Write(tnapLoginPacket)
252
if err != nil {
253
return nil, fmt.Errorf("failed to send MS-TNAP login packet: %w", err)
254
}
255
256
// Read response data
257
buffer := make([]byte, 4096)
258
n, err := conn.Read(buffer)
259
if err != nil {
260
return nil, fmt.Errorf("failed to read response: %w", err)
261
}
262
263
if n == 0 {
264
return nil, fmt.Errorf("no response received")
265
}
266
267
// Parse NTLM response using our telnetmini library functions
268
response := buffer[:n]
269
270
// Use the parsing functions from our library instead of reimplementing
271
// This should use the NTLM parsing functions we added to telnetmini
272
ntlmInfo, err := telnetmini.ParseNTLMResponse(response)
273
if err != nil {
274
return nil, fmt.Errorf("failed to parse NTLM response: %w", err)
275
}
276
277
return ntlmInfo, nil
278
}
279
280