Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/js/libs/oracle/oracle.go
2852 views
1
package oracle
2
3
import (
4
"context"
5
"database/sql"
6
"fmt"
7
"net"
8
"strconv"
9
"time"
10
11
"github.com/praetorian-inc/fingerprintx/pkg/plugins"
12
"github.com/praetorian-inc/fingerprintx/pkg/plugins/services/oracledb"
13
"github.com/projectdiscovery/nuclei/v3/pkg/js/utils"
14
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
15
goora "github.com/sijms/go-ora/v2"
16
)
17
18
type (
19
// IsOracleResponse is the response from the IsOracle function.
20
// this is returned by IsOracle function.
21
// @example
22
// ```javascript
23
// const oracle = require('nuclei/oracle');
24
// const isOracle = oracle.IsOracle('acme.com', 1521);
25
// ```
26
IsOracleResponse struct {
27
IsOracle bool
28
Banner string
29
}
30
// Client is a client for Oracle database.
31
// Internally client uses oracle/godror driver.
32
// @example
33
// ```javascript
34
// const oracle = require('nuclei/oracle');
35
// const client = new oracle.OracleClient();
36
// ```
37
OracleClient struct {
38
connector *goora.OracleConnector
39
}
40
)
41
42
// IsOracle checks if a host is running an Oracle server
43
// @example
44
// ```javascript
45
// const oracle = require('nuclei/oracle');
46
// const isOracle = oracle.IsOracle('acme.com', 1521);
47
// log(toJSON(isOracle));
48
// ```
49
func (c *OracleClient) IsOracle(ctx context.Context, host string, port int) (IsOracleResponse, error) {
50
executionId := ctx.Value("executionId").(string)
51
return memoizedisOracle(executionId, host, port)
52
}
53
54
// @memo
55
func isOracle(executionId string, host string, port int) (IsOracleResponse, error) {
56
resp := IsOracleResponse{}
57
58
dialer := protocolstate.GetDialersWithId(executionId)
59
if dialer == nil {
60
return IsOracleResponse{}, fmt.Errorf("dialers not initialized for %s", executionId)
61
}
62
63
timeout := 5 * time.Second
64
conn, err := dialer.Fastdialer.Dial(context.TODO(), "tcp", net.JoinHostPort(host, strconv.Itoa(port)))
65
if err != nil {
66
return resp, err
67
}
68
defer func() {
69
_ = conn.Close()
70
}()
71
72
oracledbPlugin := oracledb.ORACLEPlugin{}
73
service, err := oracledbPlugin.Run(conn, timeout, plugins.Target{Host: host})
74
if err != nil {
75
return resp, err
76
}
77
if service == nil {
78
return resp, nil
79
}
80
resp.Banner = service.Version
81
resp.Banner = service.Metadata().(plugins.ServiceOracle).Info
82
resp.IsOracle = true
83
return resp, nil
84
}
85
86
func (c *OracleClient) oracleDbInstance(connStr string, executionId string) (*goora.OracleConnector, error) {
87
if c.connector != nil {
88
return c.connector, nil
89
}
90
91
connector := goora.NewConnector(connStr)
92
oraConnector, ok := connector.(*goora.OracleConnector)
93
if !ok {
94
return nil, fmt.Errorf("failed to cast connector to OracleConnector")
95
}
96
97
// Create custom dialer wrapper
98
customDialer := &oracleCustomDialer{
99
executionId: executionId,
100
}
101
102
oraConnector.Dialer(customDialer)
103
104
c.connector = oraConnector
105
106
return oraConnector, nil
107
}
108
109
// Connect connects to an Oracle database
110
// @example
111
// ```javascript
112
// const oracle = require('nuclei/oracle');
113
// const client = new oracle.OracleClient;
114
// client.Connect('acme.com', 1521, 'XE', 'user', 'password');
115
// ```
116
func (c *OracleClient) Connect(ctx context.Context, host string, port int, serviceName string, username string, password string) (bool, error) {
117
connStr := goora.BuildUrl(host, port, serviceName, username, password, nil)
118
119
return c.ConnectWithDSN(ctx, connStr)
120
}
121
122
func (c *OracleClient) ConnectWithDSN(ctx context.Context, dsn string) (bool, error) {
123
executionId := ctx.Value("executionId").(string)
124
125
connector, err := c.oracleDbInstance(dsn, executionId)
126
if err != nil {
127
return false, err
128
}
129
130
db := sql.OpenDB(connector)
131
defer func() {
132
_ = db.Close()
133
}()
134
135
db.SetMaxOpenConns(1)
136
db.SetMaxIdleConns(0)
137
138
// Test the connection
139
err = db.Ping()
140
if err != nil {
141
return false, err
142
}
143
144
return true, nil
145
}
146
147
// ExecuteQuery connects to MS SQL database using given credentials and executes a query.
148
// It returns the results of the query or an error if something goes wrong.
149
// @example
150
// ```javascript
151
// const oracle = require('nuclei/oracle');
152
// const client = new oracle.OracleClient;
153
// const result = client.ExecuteQuery('acme.com', 1521, 'username', 'password', 'XE', 'SELECT @@version');
154
// log(to_json(result));
155
// ```
156
func (c *OracleClient) ExecuteQuery(ctx context.Context, host string, port int, username, password, dbName, query string) (*utils.SQLResult, error) {
157
if host == "" || port <= 0 {
158
return nil, fmt.Errorf("invalid host or port")
159
}
160
161
isOracleResp, err := c.IsOracle(ctx, host, port)
162
if err != nil {
163
return nil, err
164
}
165
if !isOracleResp.IsOracle {
166
return nil, fmt.Errorf("not a oracle service")
167
}
168
169
connStr := goora.BuildUrl(host, port, dbName, username, password, nil)
170
171
return c.ExecuteQueryWithDSN(ctx, connStr, query)
172
}
173
174
// ExecuteQueryWithDSN executes a query on an Oracle database using a DSN
175
// @example
176
// ```javascript
177
// const oracle = require('nuclei/oracle');
178
// const client = new oracle.OracleClient;
179
// const result = client.ExecuteQueryWithDSN('oracle://user:password@host:port/service', 'SELECT @@version');
180
// log(to_json(result));
181
// ```
182
func (c *OracleClient) ExecuteQueryWithDSN(ctx context.Context, dsn string, query string) (*utils.SQLResult, error) {
183
executionId := ctx.Value("executionId").(string)
184
185
connector, err := c.oracleDbInstance(dsn, executionId)
186
if err != nil {
187
return nil, err
188
}
189
db := sql.OpenDB(connector)
190
defer func() {
191
_ = db.Close()
192
}()
193
194
db.SetMaxOpenConns(1)
195
db.SetMaxIdleConns(0)
196
197
rows, err := db.Query(query)
198
if err != nil {
199
return nil, err
200
}
201
202
data, err := utils.UnmarshalSQLRows(rows)
203
if err != nil {
204
if data != nil && len(data.Rows) > 0 {
205
return data, nil
206
}
207
return nil, err
208
}
209
return data, nil
210
}
211
212