Skip to content

Commit abbf936

Browse files
committed
init v1.0
0 parents  commit abbf936

29 files changed

+1675
-0
lines changed

core/banner.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package core
2+
3+
import (
4+
"fmt"
5+
"mqtts/utils"
6+
)
7+
8+
var banner = `
9+
███╗ ███╗ ██████╗ ████████╗████████╗███████╗
10+
████╗ ████║██╔═══██╗╚══██╔══╝╚══██╔══╝██╔════╝
11+
██╔████╔██║██║ ██║ ██║ ██║ ███████╗
12+
██║╚██╔╝██║██║▄▄ ██║ ██║ ██║ ╚════██║
13+
██║ ╚═╝ ██║╚██████╔╝ ██║ ██║ ███████║
14+
╚═╝ ╚═╝ ╚══▀▀═╝ ╚═╝ ╚═╝ ╚══════╝
15+
16+
version: %s
17+
18+
`
19+
20+
func ShowBanner() {
21+
fmt.Printf(banner, utils.Version)
22+
}

core/client.go

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
package core
2+
3+
import (
4+
"crypto/tls"
5+
"crypto/x509"
6+
"errors"
7+
"fmt"
8+
MQTT "github.com/eclipse/paho.mqtt.golang"
9+
"mqtts/utils"
10+
"strconv"
11+
"strings"
12+
"sync"
13+
"time"
14+
)
15+
16+
var tmpClient = &Client{}
17+
var tmpClientLock sync.Mutex
18+
19+
type Client struct {
20+
CurrentClient MQTT.Client
21+
ClientOptions *MQTT.ClientOptions
22+
ClientLocker *sync.Mutex
23+
MessageHandler func(client *Client, msg *Message)
24+
Certificate x509.Certificate
25+
}
26+
27+
type Message struct {
28+
Topic string
29+
Msg string
30+
}
31+
32+
func ConnectWithOpts(opts *TargetOptions) Client {
33+
client := GetMQTTClient(opts)
34+
connectError := client.Connect()
35+
if connectError == nil {
36+
SetClientToken(opts.Host, opts.Port, *client)
37+
return *client
38+
} else {
39+
SetClientToken(opts.Host, opts.Port, *client)
40+
utils.OutputInfoMessage(opts.Host, opts.Port, "Connect mqtt server failed err:"+connectError.Error())
41+
return *client
42+
}
43+
}
44+
45+
func GenerateClientId(id string) string {
46+
return "mqttSecurityCheck" + id
47+
}
48+
49+
func connectHandler(client MQTT.Client) {
50+
//utils.OutputInfoMessage("Connect MQTT Service Success")
51+
}
52+
53+
func connectLostHandler(client MQTT.Client, err error) {
54+
reader := client.OptionsReader()
55+
if len(reader.Servers()) > 0 {
56+
utils.OutputErrorMessageWithoutOption("[" + reader.Servers()[0].Host + "] Loss MQTT connection")
57+
}
58+
}
59+
60+
func verifyPeerCertificateHandler(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
61+
cert, _ := x509.ParseCertificate(rawCerts[0])
62+
tmpClient.Certificate = *cert
63+
setCertificate(tmpClient)
64+
return nil
65+
}
66+
67+
func verifyConnectionHandler(state tls.ConnectionState) error {
68+
return nil
69+
}
70+
71+
func GetMQTTClient(opts *TargetOptions) *Client {
72+
clientOptions := MQTT.NewClientOptions()
73+
broker := opts.Protocol + "://" + opts.Host + ":" + strconv.Itoa(opts.Port)
74+
if strings.EqualFold(opts.Protocol, "tcp") || strings.EqualFold(opts.Protocol, "ssl") {
75+
clientOptions.AddBroker(broker)
76+
}
77+
if strings.EqualFold(opts.Protocol, "ws") || strings.EqualFold(opts.Protocol, "wss") {
78+
clientOptions.AddBroker(broker + "/mqtt")
79+
}
80+
clientOptions.SetUsername(opts.UserName)
81+
clientOptions.SetPassword(opts.Password)
82+
if !strings.EqualFold(opts.ClientId, "") {
83+
clientOptions.SetClientID(opts.ClientId)
84+
} else {
85+
clientId := utils.GetRandomString(6, "string")
86+
clientOptions.SetClientID(utils.GetRandomString(6, "string"))
87+
opts.ClientId = clientId
88+
}
89+
clientOptions.SetConnectTimeout(time.Millisecond * 5000)
90+
clientOptions.SetOnConnectHandler(connectHandler)
91+
clientOptions.SetConnectionLostHandler(connectLostHandler)
92+
tlsConfig := tls.Config{
93+
InsecureSkipVerify: true,
94+
VerifyPeerCertificate: verifyPeerCertificateHandler,
95+
VerifyConnection: verifyConnectionHandler,
96+
}
97+
clientOptions.SetTLSConfig(&tlsConfig)
98+
client := MQTT.NewClient(clientOptions)
99+
return &Client{
100+
CurrentClient: client,
101+
ClientOptions: clientOptions,
102+
ClientLocker: &sync.Mutex{},
103+
}
104+
}
105+
106+
func (client *Client) Connect() error {
107+
if !client.CurrentClient.IsConnected() {
108+
client.ClientLocker.Lock()
109+
defer client.ClientLocker.Unlock()
110+
if !client.CurrentClient.IsConnected() {
111+
if token := client.CurrentClient.Connect(); token.Wait() && token.Error() != nil {
112+
client.saveCertificate(currentCertificate().Certificate)
113+
return token.Error()
114+
} else {
115+
client.saveCertificate(currentCertificate().Certificate)
116+
}
117+
}
118+
}
119+
return nil
120+
}
121+
122+
func defaultMessageHandler(c *Client, message *Message) {
123+
fmt.Println(message.Msg)
124+
}
125+
126+
func (client *Client) messageHandler(c MQTT.Client, message MQTT.Message) {
127+
if client.MessageHandler == nil {
128+
//utils.OutputErrorMessage("Not subscribe message")
129+
return
130+
}
131+
msg := &Message{
132+
Topic: message.Topic(),
133+
Msg: string(message.Payload()),
134+
}
135+
client.MessageHandler(client, msg)
136+
}
137+
138+
func (client *Client) Subscribe(handler func(c *Client, message *Message), qos byte, topics ...string) error {
139+
if client.MessageHandler != nil {
140+
return errors.New("messageHandler has been bound, have to clear messageHandler first")
141+
}
142+
143+
if len(topics) == 0 {
144+
return errors.New("subscribe method must set topic")
145+
}
146+
147+
if handler != nil {
148+
client.MessageHandler = handler
149+
} else {
150+
client.MessageHandler = defaultMessageHandler
151+
}
152+
153+
filters := make(map[string]byte)
154+
for _, topic := range topics {
155+
filters[topic] = qos
156+
}
157+
client.CurrentClient.SubscribeMultiple(filters, client.messageHandler)
158+
return nil
159+
}
160+
161+
func (client *Client) Unsubscribe(topics ...string) {
162+
client.MessageHandler = nil
163+
client.CurrentClient.Unsubscribe(topics...)
164+
}
165+
166+
func (client *Client) saveCertificate(certificate x509.Certificate) {
167+
client.Certificate = certificate
168+
}
169+
170+
func currentCertificate() *Client {
171+
tmpClientLock.Lock()
172+
defer tmpClientLock.Unlock()
173+
return tmpClient
174+
}
175+
176+
func setCertificate(c *Client) {
177+
tmpClientLock.Lock()
178+
tmpClient = c
179+
tmpClientLock.Unlock()
180+
}

core/client_token.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package core
2+
3+
import (
4+
"strconv"
5+
"sync"
6+
)
7+
8+
type clientTokenMap struct {
9+
ClientInfo map[string]Client
10+
}
11+
12+
var ctMap *clientTokenMap
13+
var clientOnce sync.Once
14+
15+
func getClientMap() *clientTokenMap {
16+
clientOnce.Do(func() {
17+
ctMap = &clientTokenMap{}
18+
ctMap.ClientInfo = make(map[string]Client)
19+
})
20+
return ctMap
21+
}
22+
23+
func SetClientToken(host string, port int, client Client) {
24+
if ctMap != nil && ctMap.ClientInfo != nil {
25+
ctMap.ClientInfo[host+":"+strconv.Itoa(port)] = client
26+
} else {
27+
getClientMap()
28+
ctMap.ClientInfo[host+":"+strconv.Itoa(port)] = client
29+
}
30+
}
31+
32+
func GetClientToken(opts *TargetOptions, existing bool) Client {
33+
if ctMap != nil && ctMap.ClientInfo != nil {
34+
if _, existKey := ctMap.ClientInfo[opts.Host+":"+strconv.Itoa(opts.Port)]; existKey {
35+
if ctMap.ClientInfo[opts.Host+":"+strconv.Itoa(opts.Port)].CurrentClient.IsConnected() {
36+
return ctMap.ClientInfo[opts.Host+":"+strconv.Itoa(opts.Port)]
37+
}
38+
}
39+
}
40+
if !existing {
41+
return ConnectWithOpts(opts)
42+
} else {
43+
return Client{}
44+
}
45+
}

core/cmd_parser.go

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package core
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"mqtts/utils"
7+
"os"
8+
"strconv"
9+
"strings"
10+
)
11+
12+
type ScanArgs struct {
13+
CommonScan bool
14+
UnauthScan bool
15+
AnyPwdScan bool
16+
SystemInfo bool
17+
BruteScan bool
18+
AutoScan bool
19+
TopicsList bool
20+
WaitTime int
21+
UserPath string
22+
PwdPath string
23+
TargetFile string
24+
GoroutinePoolSize int
25+
}
26+
27+
func CmdArgsParser() *ScanArgs {
28+
var host string
29+
var port int
30+
var username string
31+
var password string
32+
var protocol string
33+
var clientId string
34+
var unauthScan bool
35+
var anyPwdScan bool
36+
var autoScan bool
37+
var systemInfo bool
38+
var topicsList bool
39+
var userPath string
40+
var pwdPath string
41+
var waitTime int
42+
var bruteScan bool
43+
var targetFile string
44+
var goroutinePoolSize int
45+
var showVersion bool
46+
flag.StringVar(&host, "t", "", "input target ip or host")
47+
flag.IntVar(&port, "p", 1883, "input target port default is 1883/tcp")
48+
flag.StringVar(&username, "username", "", "input username")
49+
flag.StringVar(&password, "password", "", "input password")
50+
flag.StringVar(&protocol, "protocol", "", "input protocol tcp/ssl/ws/wss")
51+
flag.StringVar(&clientId, "clientid", "", "input password default is 6 random string")
52+
flag.BoolVar(&unauthScan, "u", false, "unauth scan (support batch scanning)")
53+
flag.BoolVar(&anyPwdScan, "a", false, "any username/password login scan for EMQX emqx_plugin_template plugin (support batch scanning)")
54+
flag.BoolVar(&bruteScan, "b", false, "username and password brute force")
55+
flag.BoolVar(&autoScan, "au", false, "automatic scanning according to service conditions")
56+
flag.BoolVar(&systemInfo, "s", false, "mqtt server system topic info scan (batch scanning is not supported)")
57+
flag.BoolVar(&topicsList, "ts", false, "mqtt server topic list scan (batch scanning is not supported)")
58+
flag.StringVar(&userPath, "nf", "", "brute force username list file path, default is ./username.txt")
59+
flag.StringVar(&pwdPath, "pf", "", "brute force password list file path, default is ./password.txt")
60+
flag.IntVar(&waitTime, "w", 15, "systemInfo scan and topics scan wait time, unit: seconds, default 15s")
61+
flag.StringVar(&targetFile, "tf", "", "batch scan target file, line format split with \\t host port [protocol | clientId | username | password]")
62+
flag.IntVar(&goroutinePoolSize, "g", 10, "batch scan goroutine pool size")
63+
flag.BoolVar(&showVersion, "v", false, "show version")
64+
flag.Parse()
65+
if showVersion {
66+
fmt.Println(utils.Version)
67+
os.Exit(0)
68+
}
69+
if strings.EqualFold(host, "") && strings.EqualFold(targetFile, "") {
70+
flag.Usage()
71+
os.Exit(0)
72+
}
73+
if !strings.EqualFold(host, "") && !strings.EqualFold(targetFile, "") {
74+
utils.OutputErrorMessageWithoutOption("Single targets and batch targets cannot be set at the same time")
75+
os.Exit(0)
76+
}
77+
if !strings.EqualFold(host, "") {
78+
setSingleTarget(protocol, host, port, clientId, username, password)
79+
}
80+
if !strings.EqualFold(targetFile, "") {
81+
setTargets(targetFile)
82+
}
83+
if !unauthScan && !anyPwdScan && !systemInfo && !topicsList && !bruteScan && !autoScan {
84+
utils.OutputErrorMessageWithoutOption("Must specify the type of scan")
85+
os.Exit(0)
86+
}
87+
if !strings.EqualFold(targetFile, "") && (systemInfo || topicsList) {
88+
utils.OutputErrorMessageWithoutOption("Topic info scanning and topic list scanning do not support batch")
89+
os.Exit(0)
90+
}
91+
return &ScanArgs{
92+
UnauthScan: unauthScan,
93+
AnyPwdScan: anyPwdScan,
94+
BruteScan: bruteScan,
95+
AutoScan: autoScan,
96+
SystemInfo: systemInfo,
97+
TopicsList: topicsList,
98+
WaitTime: waitTime,
99+
UserPath: userPath,
100+
PwdPath: pwdPath,
101+
GoroutinePoolSize: goroutinePoolSize,
102+
}
103+
}
104+
105+
func setSingleTarget(protocol string, host string, port int, clientId string, username string, password string) {
106+
SetTargetInfo(protocol, host, port, clientId, username, password)
107+
}
108+
109+
func setTargets(targetFile string) {
110+
lines, err := utils.ReadFileByLine(targetFile)
111+
if err != nil {
112+
utils.OutputErrorMessageWithoutOption("Load target file failed")
113+
os.Exit(0)
114+
}
115+
for num, line := range lines {
116+
targetInfo := strings.Split(line, " ")
117+
if len(targetInfo) < 2 {
118+
utils.OutputErrorMessageWithoutOption("Target format or data error in line " + strconv.Itoa(num+1) + ": " + line)
119+
}
120+
if len(targetInfo) < 6 {
121+
for range utils.IterRange(6 - len(targetInfo)) {
122+
targetInfo = append(targetInfo, "")
123+
}
124+
}
125+
host := targetInfo[0]
126+
port, err := strconv.Atoi(targetInfo[1])
127+
if err != nil {
128+
utils.OutputErrorMessageWithoutOption("Target port parse error in line " + strconv.Itoa(num+1) + ": " + line)
129+
continue
130+
}
131+
protocol := targetInfo[2]
132+
clientId := targetInfo[3]
133+
username := targetInfo[4]
134+
password := targetInfo[5]
135+
SetTargetInfo(protocol, host, port, clientId, username, password)
136+
}
137+
138+
}

0 commit comments

Comments
 (0)