This repository has been archived by the owner on Apr 7, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
attack.go
129 lines (115 loc) · 2.47 KB
/
attack.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
package main
/*
* attack.go
* Connect to an SSH server, run a script
* By J. Stuart McMurray
* Created 20180209
* Last Modified 20180209
*/
import (
"bytes"
"errors"
"fmt"
"io"
"log"
"net"
"sync"
"time"
"golang.org/x/crypto/ssh"
)
// Attacker connects to targets and runs the script by passing it to the
// interpreter's stdin. Targets are read from ch. If noQuoteOutput is true,
// Output will be printed as seen. This is good for debugging, but dangerous.
func Attacker(
ch <-chan string,
conf *ssh.ClientConfig,
interpreter string,
script []byte,
timeout time.Duration,
wg *sync.WaitGroup,
noQuoteOutput bool,
) {
defer wg.Done()
ofs := "q"
if noQuoteOutput {
ofs = "s"
}
for t := range ch {
o, err := attack(
t,
conf,
interpreter,
bytes.NewReader(script),
timeout,
)
/* Output with no error is a good thing */
if nil == err {
m := fmt.Sprintf("[%v] SUCCESS", t)
if 0 != len(o) {
m += fmt.Sprintf(": %"+ofs, string(o))
}
log.Printf("%v", m)
continue
}
/* An error with nil output is a setup error, not a script
error */
if nil == o {
log.Printf("[%v] ERROR: %v", t, err)
continue
}
/* All other errors are execution errors */
m := fmt.Sprintf("[%v] FAIL (%v)", t, err)
if 0 != len(o) {
m += fmt.Sprintf(": %"+ofs, string(o))
}
log.Printf("%v", m)
}
}
/* attack tries to connect to t and tries to run script in the interpreter. It
returns the output and any error encountered. */
func attack(
t string,
conf *ssh.ClientConfig,
interpreter string,
script io.Reader,
timeout time.Duration,
) ([]byte, error) {
/* Connect to target */
c, err := net.DialTimeout("tcp", t, timeout)
if nil != err {
return nil, err
}
defer c.Close()
/* Upgrade to SSH */
var (
sc ssh.Conn
chans <-chan ssh.NewChannel
reqs <-chan *ssh.Request
done = make(chan struct{})
)
go func() {
defer close(done)
sc, chans, reqs, err = ssh.NewClientConn(c, t, conf)
}()
/* Wait for timeout or handshake */
select {
case <-done: /* Handshake happened */
case <-time.After(timeout): /* Timeout */
return nil, errors.New("handshake timeout")
}
/* We have handshook by now, we hope */
if nil != err {
return nil, err
}
defer sc.Close()
cc := ssh.NewClient(sc, chans, reqs)
/* Start a session in which to run the script */
s, err := cc.NewSession()
if nil != err {
return nil, err
}
s.Stdin = script
defer s.Close()
/* Run it and capture output */
return s.CombinedOutput(interpreter)
}