1
1
// This is effectively a library for .NET remoting functionality
2
2
// The exploit remoting service tool by tyranid was the primary
3
- // resource for this and this is basically a port of that project with the ntlmssp
3
+ // resource for this and this is basically a port of that project with the ntlmssp
4
4
// Note: Everything is in little endian
5
5
6
6
// Usage Example:
29
29
package dotnetremoting
30
30
31
31
import (
32
+ "encoding/binary"
32
33
"fmt"
33
34
"net"
34
35
"net/url"
35
36
"time"
36
- "encoding/binary"
37
37
38
38
"github.com/LeakIX/nns"
39
39
"github.com/LeakIX/ntlmssp"
40
- "github.com/vulncheck-oss/go-exploit/transform"
41
40
"github.com/vulncheck-oss/go-exploit/output"
41
+ "github.com/vulncheck-oss/go-exploit/transform"
42
42
)
43
43
44
44
// types and 'enums'.
45
- type Message struct {
45
+ type Message struct {
46
46
PreambleData string
47
- HeaderData string
47
+ HeaderData string
48
48
}
49
49
50
- // Strings, because go thinks strings are as nifty as bytes
50
+ // Strings, because go thinks strings are as nifty as bytes.
51
51
type MessageResponse struct {
52
- MajorVersion string
53
- MinorVersion string
54
- OperationType string
52
+ MajorVersion string
53
+ MinorVersion string
54
+ OperationType string
55
55
ContentDistribution string
56
- DataLength int
57
- Headers map [string ]string
58
- Data string
56
+ DataLength int
57
+ Headers map [string ]string
58
+ Data string
59
59
}
60
60
61
61
type OperationType string
62
+
62
63
const ( // OPERATION TYPES (ushort)
63
64
OperationTypeRequest OperationType = "\x00 \x00 "
64
65
OperationTypeOneWayRequest OperationType = "\x01 \x00 "
65
66
OperationTypeReply OperationType = "\x02 \x00 "
66
67
)
67
68
68
69
type HeaderToken string
70
+
69
71
const ( // HEADER TOKENS (ushort)
70
72
HeaderTokenEndHeaders HeaderToken = "\x00 \x00 "
71
73
HeaderTokenCustom HeaderToken = "\x01 \x00 "
@@ -77,6 +79,7 @@ const ( // HEADER TOKENS (ushort)
77
79
)
78
80
79
81
type HeaderDataFormat string
82
+
80
83
const ( // HEADER DATA FORMAT (byte)
81
84
HeaderDataFormatVoid HeaderDataFormat = "\x00 "
82
85
HeaderDataFormatCountedString HeaderDataFormat = "\x01 "
@@ -86,36 +89,39 @@ const ( // HEADER DATA FORMAT (byte)
86
89
)
87
90
88
91
type ContentDistribution string
92
+
89
93
const ( // CONTENT DISTRIBUTION (ushort)
90
94
ContentDistributionNotChunked ContentDistribution = "\x00 \x00 "
91
95
ContentDistributionChunked ContentDistribution = "\x01 \x00 "
92
96
)
93
97
94
98
type StringEncoding string
99
+
95
100
const ( // STRING ENCODING (byte)
96
101
StringEncodingUnicode StringEncoding = "\x00 "
97
102
StringEncodingUtf8 StringEncoding = "\x01 "
98
103
)
99
104
100
105
type TCPStatusCode string
106
+
101
107
const ( // TCP STATUS CODE (byte)
102
108
TCPStatusCodeSuccess TCPStatusCode = "\x00 "
103
109
TCPStatusCodeError TCPStatusCode = "\x01 "
104
110
)
105
111
106
-
107
112
// The 'preamble' is basically the set of headers before the body.
108
113
func (msg * Message ) WritePreamble (uri string , opType OperationType , dataLength int , contentDistribution ContentDistribution , contentType string ) {
109
114
uriObj , err := url .Parse (uri )
110
115
if err != nil {
111
116
output .PrintfFrameworkError ("Could not write preamble: error trying to parse provided uri=%s, err=%s" , uri , err )
112
- return
117
+
118
+ return
113
119
}
114
120
msg .PreambleData = ".NET"
115
- msg .PreambleData += "\x01 " // major version
116
- msg .PreambleData += "\x00 " // minor version
117
- msg .PreambleData += string (opType ) // operation type
118
- msg .PreambleData += string (contentDistribution ) // content distribution
121
+ msg .PreambleData += "\x01 " // major version
122
+ msg .PreambleData += "\x00 " // minor version
123
+ msg .PreambleData += string (opType ) // operation type
124
+ msg .PreambleData += string (contentDistribution ) // content distribution
119
125
msg .PreambleData += transform .PackLittleInt32 (dataLength ) // length of payload to be sent
120
126
msg .AddContentTypeHeader (contentType )
121
127
if uri != "" {
@@ -153,7 +159,7 @@ func (msg *Message) AddURIHeader(uri string, headerToken HeaderToken) {
153
159
// this will probably be application/octet-stream almost every time but making options.
154
160
func (msg * Message ) AddContentTypeHeader (contentType string ) {
155
161
msg .HeaderData += string (HeaderTokenContentType )
156
- msg .HeaderData += string (HeaderDataFormatCountedString )
162
+ msg .HeaderData += string (HeaderDataFormatCountedString )
157
163
addCountedString (& msg .HeaderData , StringEncodingUtf8 , contentType )
158
164
}
159
165
@@ -173,7 +179,7 @@ func (msg *Message) AddStatusCodeHeader(isError bool) { // untested
173
179
msg .HeaderData += transform .PackLittleInt16 (1 )
174
180
175
181
return
176
- }
182
+ }
177
183
// success
178
184
msg .HeaderData += transform .PackLittleInt16 (0 )
179
185
}
@@ -197,12 +203,12 @@ func (msg *MessageResponse) Dump() {
197
203
// Parsing functions.
198
204
func ParseResponseFromConn (conn net.Conn ) (MessageResponse , bool ) {
199
205
msg := MessageResponse {}
200
- magicBuf := make ([]byte , 4 )
201
- majorVerBuf := make ([]byte , 1 )
202
- minorVerBuf := make ([]byte , 1 )
203
- opTypeBuf := make ([]byte , 2 )
204
- contentDistributionBuf := make ([]byte , 2 )
205
- dataLengthBuf := make ([]byte , 4 )
206
+ magicBuf := make ([]byte , 4 )
207
+ majorVerBuf := make ([]byte , 1 )
208
+ minorVerBuf := make ([]byte , 1 )
209
+ opTypeBuf := make ([]byte , 2 )
210
+ contentDistributionBuf := make ([]byte , 2 )
211
+ dataLengthBuf := make ([]byte , 4 )
206
212
207
213
// checking magic bytes from message
208
214
_ , err := conn .Read (magicBuf )
@@ -241,7 +247,7 @@ func ParseResponseFromConn(conn net.Conn) (MessageResponse, bool) {
241
247
242
248
return MessageResponse {}, false
243
249
}
244
- msg .OperationType = string (opTypeBuf )
250
+ msg .OperationType = string (opTypeBuf )
245
251
246
252
_ , err = conn .Read (contentDistributionBuf )
247
253
if err != nil {
@@ -294,14 +300,14 @@ func readHeadersFromConn(conn net.Conn) (map[string]string, bool) {
294
300
}
295
301
296
302
// while we have not read the End of Headers 'token'
297
- for string (tokenBuf ) != string (HeaderTokenEndHeaders ) {
303
+ for string (tokenBuf ) != string (HeaderTokenEndHeaders ) {
298
304
name := string (tokenBuf )
299
305
value := ""
300
306
301
307
switch string (tokenBuf ) {
302
308
case string (HeaderTokenCustom ): // HeaderTokenCustom
303
309
// untested
304
- str , ok := readHeaderStringFromConn (conn )
310
+ str , ok := readHeaderStringFromConn (conn )
305
311
if ! ok {
306
312
output .PrintFrameworkError ("Failed reading custom header name from response" )
307
313
@@ -326,43 +332,43 @@ func readHeadersFromConn(conn net.Conn) (map[string]string, bool) {
326
332
}
327
333
328
334
switch string (dataTypeBuf ) {
329
- case string (HeaderDataFormatVoid ):
330
- break
331
- case string (HeaderDataFormatCountedString ):
332
- data , ok := readHeaderStringFromConn (conn )
333
- if ! ok {
334
- output .PrintFrameworkError ("Failed reading counted header string" )
335
-
336
- return map [string ]string {}, false
337
- }
338
- value = data
339
- case string (HeaderDataFormatByte ):
340
- dataBuf := make ([]byte , 1 )
341
- _ , err = conn .Read (dataBuf )
342
- if err != nil {
343
- output .PrintfFrameworkError ("Failed reading format byte, err=%s" , err )
344
-
345
- return map [string ]string {}, false
346
- }
347
- value = string (dataBuf )
348
- case string (HeaderDataFormatUint16 ):
349
- dataBuf := make ([]byte , 2 )
350
- _ , err = conn .Read (dataBuf )
351
- if err != nil {
352
- output .PrintfFrameworkError ("Failed reading uint16, err=%s" , err )
353
-
354
- return map [string ]string {}, false
355
- }
356
- value = string (dataBuf )
357
- case string (HeaderDataFormatInt32 ):
358
- dataBuf := make ([]byte , 4 )
359
- _ , err = conn .Read (dataBuf )
360
- if err != nil {
361
- output .PrintfFrameworkError ("Failed reading uint32, err=%s" , err )
362
-
363
- return map [string ]string {}, false
364
- }
365
- value = string (dataBuf )
335
+ case string (HeaderDataFormatVoid ):
336
+ break
337
+ case string (HeaderDataFormatCountedString ):
338
+ data , ok := readHeaderStringFromConn (conn )
339
+ if ! ok {
340
+ output .PrintFrameworkError ("Failed reading counted header string" )
341
+
342
+ return map [string ]string {}, false
343
+ }
344
+ value = data
345
+ case string (HeaderDataFormatByte ):
346
+ dataBuf := make ([]byte , 1 )
347
+ _ , err = conn .Read (dataBuf )
348
+ if err != nil {
349
+ output .PrintfFrameworkError ("Failed reading format byte, err=%s" , err )
350
+
351
+ return map [string ]string {}, false
352
+ }
353
+ value = string (dataBuf )
354
+ case string (HeaderDataFormatUint16 ):
355
+ dataBuf := make ([]byte , 2 )
356
+ _ , err = conn .Read (dataBuf )
357
+ if err != nil {
358
+ output .PrintfFrameworkError ("Failed reading uint16, err=%s" , err )
359
+
360
+ return map [string ]string {}, false
361
+ }
362
+ value = string (dataBuf )
363
+ case string (HeaderDataFormatInt32 ):
364
+ dataBuf := make ([]byte , 4 )
365
+ _ , err = conn .Read (dataBuf )
366
+ if err != nil {
367
+ output .PrintfFrameworkError ("Failed reading uint32, err=%s" , err )
368
+
369
+ return map [string ]string {}, false
370
+ }
371
+ value = string (dataBuf )
366
372
}
367
373
}
368
374
@@ -375,7 +381,7 @@ func readHeadersFromConn(conn net.Conn) (map[string]string, bool) {
375
381
376
382
return map [string ]string {}, false
377
383
}
378
- output .PrintfFrameworkTrace ("token value %x" ,tokenBuf )
384
+ output .PrintfFrameworkTrace ("token value %x" , tokenBuf )
379
385
}
380
386
output .PrintFrameworkTrace ("done parsing headers" )
381
387
@@ -384,7 +390,7 @@ func readHeadersFromConn(conn net.Conn) (map[string]string, bool) {
384
390
385
391
func readHeaderStringFromConn (conn net.Conn ) (string , bool ) {
386
392
encodingTypeBuf := make ([]byte , 1 )
387
- stringLengthBuf := make ([]byte , 4 )
393
+ stringLengthBuf := make ([]byte , 4 )
388
394
_ , err := conn .Read (encodingTypeBuf )
389
395
if err != nil {
390
396
output .PrintfFrameworkError ("Failed reading encoding type from header string" )
@@ -401,7 +407,6 @@ func readHeaderStringFromConn(conn net.Conn) (string, bool) {
401
407
// encodingType := string(encodingTypeBuf) // sorry, just going to ignore this for now.
402
408
stringLength := int (binary .LittleEndian .Uint32 (stringLengthBuf ))
403
409
404
-
405
410
stringData , ok := readNBytes (conn , stringLength )
406
411
if ! ok {
407
412
return "" , false
@@ -410,8 +415,8 @@ func readHeaderStringFromConn(conn net.Conn) (string, bool) {
410
415
return stringData , true
411
416
}
412
417
413
- // don't love this function
414
- func readNBytes (conn net.Conn , n int ) (string , bool ){
418
+ // don't love this function.
419
+ func readNBytes (conn net.Conn , n int ) (string , bool ) {
415
420
data := ""
416
421
buf := make ([]byte , 1 ) // ugh...
417
422
remaining := n
@@ -432,8 +437,9 @@ func readNBytes(conn net.Conn, n int) (string, bool){
432
437
}
433
438
434
439
// Helper functions.
435
- //nolint:unparam
436
440
// This is private on purpose to promote helper functions to keep things easier to use.
441
+ //
442
+ //nolint:unparam
437
443
func addCountedString (msg * string , encodingType StringEncoding , stringValue string ) {
438
444
* msg += string (encodingType )
439
445
* msg += transform .PackLittleInt32 (len (stringValue ))
@@ -443,15 +449,15 @@ func addCountedString(msg *string, encodingType StringEncoding, stringValue stri
443
449
// Some connection helper functions, exists mostly to wrap around ntlmssp.
444
450
// For anonymous connections, just pass "" to user and password.
445
451
func GetNTLMSSPTCPConnection (user string , password string , socketAddr string ) (net.Conn , error ) {
446
- ntlmsspClient , err := ntlmssp .NewClient (ntlmssp .SetCompatibilityLevel (1 ), ntlmssp .SetUserInfo (user , password ))
447
- if err != nil {
448
- return nil , fmt .Errorf ("error creating NTLMSSPClient, err=%w" , err )
449
- }
450
- nnsConn , err := nns .DialNTLMSSP (socketAddr , ntlmsspClient , 10 * time .Second )
451
- if err != nil {
452
- return nil , fmt .Errorf ("error connecting with NTLMSSP to %s, err=%w" , socketAddr , err )
453
- }
454
- output .PrintfFrameworkStatus ("NTLMSSP connection to %s was successful" , socketAddr )
455
-
456
- return nnsConn , nil
452
+ ntlmsspClient , err := ntlmssp .NewClient (ntlmssp .SetCompatibilityLevel (1 ), ntlmssp .SetUserInfo (user , password ))
453
+ if err != nil {
454
+ return nil , fmt .Errorf ("error creating NTLMSSPClient, err=%w" , err )
455
+ }
456
+ nnsConn , err := nns .DialNTLMSSP (socketAddr , ntlmsspClient , 10 * time .Second )
457
+ if err != nil {
458
+ return nil , fmt .Errorf ("error connecting with NTLMSSP to %s, err=%w" , socketAddr , err )
459
+ }
460
+ output .PrintfFrameworkStatus ("NTLMSSP connection to %s was successful" , socketAddr )
461
+
462
+ return nnsConn , nil
457
463
}
0 commit comments