Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/js/libs/mssql/mssql.go
2070 views
1
package mssql
2
3
import (
4
"context"
5
"database/sql"
6
"fmt"
7
"net"
8
"net/url"
9
"strings"
10
"time"
11
12
_ "github.com/microsoft/go-mssqldb"
13
"github.com/praetorian-inc/fingerprintx/pkg/plugins/services/mssql"
14
"github.com/projectdiscovery/nuclei/v3/pkg/js/utils"
15
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
16
)
17
18
type (
19
// Client is a client for MS SQL database.
20
// Internally client uses microsoft/go-mssqldb driver.
21
// @example
22
// ```javascript
23
// const mssql = require('nuclei/mssql');
24
// const client = new mssql.MSSQLClient;
25
// ```
26
MSSQLClient struct{}
27
)
28
29
// Connect connects to MS SQL database using given credentials.
30
// If connection is successful, it returns true.
31
// If connection is unsuccessful, it returns false and error.
32
// The connection is closed after the function returns.
33
// @example
34
// ```javascript
35
// const mssql = require('nuclei/mssql');
36
// const client = new mssql.MSSQLClient;
37
// const connected = client.Connect('acme.com', 1433, 'username', 'password');
38
// ```
39
func (c *MSSQLClient) Connect(ctx context.Context, host string, port int, username, password string) (bool, error) {
40
executionId := ctx.Value("executionId").(string)
41
return memoizedconnect(executionId, host, port, username, password, "master")
42
}
43
44
// ConnectWithDB connects to MS SQL database using given credentials and database name.
45
// If connection is successful, it returns true.
46
// If connection is unsuccessful, it returns false and error.
47
// The connection is closed after the function returns.
48
// @example
49
// ```javascript
50
// const mssql = require('nuclei/mssql');
51
// const client = new mssql.MSSQLClient;
52
// const connected = client.ConnectWithDB('acme.com', 1433, 'username', 'password', 'master');
53
// ```
54
func (c *MSSQLClient) ConnectWithDB(ctx context.Context, host string, port int, username, password, dbName string) (bool, error) {
55
executionId := ctx.Value("executionId").(string)
56
return memoizedconnect(executionId, host, port, username, password, dbName)
57
}
58
59
// @memo
60
func connect(executionId string, host string, port int, username string, password string, dbName string) (bool, error) {
61
if host == "" || port <= 0 {
62
return false, fmt.Errorf("invalid host or port")
63
}
64
if !protocolstate.IsHostAllowed(executionId, host) {
65
// host is not valid according to network policy
66
return false, protocolstate.ErrHostDenied.Msgf(host)
67
}
68
69
target := net.JoinHostPort(host, fmt.Sprintf("%d", port))
70
71
connString := fmt.Sprintf("sqlserver://%s:%s@%s?database=%s&connection+timeout=30",
72
url.PathEscape(username),
73
url.PathEscape(password),
74
target,
75
dbName)
76
77
db, err := sql.Open("sqlserver", connString)
78
if err != nil {
79
return false, err
80
}
81
defer func() {
82
_ = db.Close()
83
}()
84
85
_, err = db.Exec("select 1")
86
if err != nil {
87
switch {
88
case strings.Contains(err.Error(), "connect: connection refused"):
89
fallthrough
90
case strings.Contains(err.Error(), "no pg_hba.conf entry for host"):
91
fallthrough
92
case strings.Contains(err.Error(), "network unreachable"):
93
fallthrough
94
case strings.Contains(err.Error(), "reset"):
95
fallthrough
96
case strings.Contains(err.Error(), "i/o timeout"):
97
return false, err
98
}
99
return false, nil
100
}
101
return true, nil
102
}
103
104
// IsMssql checks if the given host is running MS SQL database.
105
// If the host is running MS SQL database, it returns true.
106
// If the host is not running MS SQL database, it returns false.
107
// @example
108
// ```javascript
109
// const mssql = require('nuclei/mssql');
110
// const isMssql = mssql.IsMssql('acme.com', 1433);
111
// ```
112
func (c *MSSQLClient) IsMssql(ctx context.Context, host string, port int) (bool, error) {
113
executionId := ctx.Value("executionId").(string)
114
return memoizedisMssql(executionId, host, port)
115
}
116
117
// @memo
118
func isMssql(executionId string, host string, port int) (bool, error) {
119
if !protocolstate.IsHostAllowed(executionId, host) {
120
// host is not valid according to network policy
121
return false, protocolstate.ErrHostDenied.Msgf(host)
122
}
123
124
dialer := protocolstate.GetDialersWithId(executionId)
125
if dialer == nil {
126
return false, fmt.Errorf("dialers not initialized for %s", executionId)
127
}
128
129
conn, err := dialer.Fastdialer.Dial(context.TODO(), "tcp", net.JoinHostPort(host, fmt.Sprintf("%d", port)))
130
if err != nil {
131
return false, err
132
}
133
defer func() {
134
_ = conn.Close()
135
}()
136
137
data, check, err := mssql.DetectMSSQL(conn, 5*time.Second)
138
if check && err != nil {
139
return false, nil
140
} else if !check && err != nil {
141
return false, err
142
}
143
if data.Version != "" {
144
return true, nil
145
}
146
return false, nil
147
}
148
149
// ExecuteQuery connects to MS SQL database using given credentials and executes a query.
150
// It returns the results of the query or an error if something goes wrong.
151
// @example
152
// ```javascript
153
// const mssql = require('nuclei/mssql');
154
// const client = new mssql.MSSQLClient;
155
// const result = client.ExecuteQuery('acme.com', 1433, 'username', 'password', 'master', 'SELECT @@version');
156
// log(to_json(result));
157
// ```
158
func (c *MSSQLClient) ExecuteQuery(ctx context.Context, host string, port int, username, password, dbName, query string) (*utils.SQLResult, error) {
159
executionId := ctx.Value("executionId").(string)
160
if host == "" || port <= 0 {
161
return nil, fmt.Errorf("invalid host or port")
162
}
163
if !protocolstate.IsHostAllowed(executionId, host) {
164
// host is not valid according to network policy
165
return nil, protocolstate.ErrHostDenied.Msgf(host)
166
}
167
168
target := net.JoinHostPort(host, fmt.Sprintf("%d", port))
169
170
ok, err := c.IsMssql(ctx, host, port)
171
if err != nil {
172
return nil, err
173
}
174
if !ok {
175
return nil, fmt.Errorf("not a mssql service")
176
}
177
178
connString := fmt.Sprintf("sqlserver://%s:%s@%s?database=%s&connection+timeout=30",
179
url.PathEscape(username),
180
url.PathEscape(password),
181
target,
182
dbName)
183
184
db, err := sql.Open("sqlserver", connString)
185
if err != nil {
186
return nil, err
187
}
188
defer func() {
189
_ = db.Close()
190
}()
191
192
db.SetMaxOpenConns(1)
193
db.SetMaxIdleConns(0)
194
195
rows, err := db.Query(query)
196
if err != nil {
197
return nil, err
198
}
199
200
data, err := utils.UnmarshalSQLRows(rows)
201
if err != nil {
202
if data != nil && len(data.Rows) > 0 {
203
return data, nil
204
}
205
return nil, err
206
}
207
return data, nil
208
}
209
210