Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/js/global/scripts.go
2070 views
1
package global
2
3
import (
4
"bytes"
5
"context"
6
"embed"
7
"math/rand"
8
"net"
9
"reflect"
10
"time"
11
12
"github.com/Mzack9999/goja"
13
"github.com/logrusorgru/aurora"
14
"github.com/projectdiscovery/gologger"
15
"github.com/projectdiscovery/nuclei/v3/pkg/js/gojs"
16
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
17
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/utils/vardump"
18
"github.com/projectdiscovery/nuclei/v3/pkg/types"
19
"github.com/projectdiscovery/utils/errkit"
20
stringsutil "github.com/projectdiscovery/utils/strings"
21
)
22
23
var (
24
//go:embed js
25
embedFS embed.FS
26
27
//go:embed exports.js
28
exports string
29
// knownPorts is a list of known ports for protocols implemented in nuclei
30
knowPorts = []string{"80", "443", "8080", "8081", "8443", "53"}
31
)
32
33
// default imported modules
34
// there might be other methods to achieve this
35
// but this is most straightforward
36
var (
37
defaultImports = `
38
var structs = require("nuclei/structs");
39
var bytes = require("nuclei/bytes");
40
`
41
)
42
43
// initBuiltInFunc initializes runtime with builtin functions
44
func initBuiltInFunc(runtime *goja.Runtime) {
45
46
_ = gojs.RegisterFuncWithSignature(runtime, gojs.FuncOpts{
47
Name: "Rand",
48
Signatures: []string{"Rand(n int) []byte"},
49
Description: "Rand returns a random byte slice of length n",
50
FuncDecl: func(n int) []byte {
51
b := make([]byte, n)
52
for i := range b {
53
b[i] = byte(rand.Intn(255))
54
}
55
return b
56
},
57
})
58
59
_ = gojs.RegisterFuncWithSignature(runtime, gojs.FuncOpts{
60
Name: "RandInt",
61
Signatures: []string{"RandInt() int"},
62
Description: "RandInt returns a random int",
63
FuncDecl: func() int64 {
64
return rand.Int63()
65
},
66
})
67
68
_ = gojs.RegisterFuncWithSignature(runtime, gojs.FuncOpts{
69
Name: "log",
70
Signatures: []string{
71
"log(msg string)",
72
"log(msg map[string]interface{})",
73
},
74
Description: "log prints given input to stdout with [JS] prefix for debugging purposes ",
75
FuncDecl: func(call goja.FunctionCall) goja.Value {
76
arg := call.Argument(0).Export()
77
switch value := arg.(type) {
78
case string:
79
gologger.DefaultLogger.Print().Msgf("[%v] %v", aurora.BrightCyan("JS"), value)
80
case map[string]interface{}:
81
gologger.DefaultLogger.Print().Msgf("[%v] %v", aurora.BrightCyan("JS"), vardump.DumpVariables(value))
82
default:
83
gologger.DefaultLogger.Print().Msgf("[%v] %v", aurora.BrightCyan("JS"), value)
84
}
85
return call.Argument(0)
86
},
87
})
88
89
_ = gojs.RegisterFuncWithSignature(runtime, gojs.FuncOpts{
90
Name: "getNetworkPort",
91
Signatures: []string{
92
"getNetworkPort(port string, defaultPort string) string",
93
},
94
Description: "getNetworkPort registers defaultPort and returns defaultPort if it is a colliding port with other protocols",
95
FuncDecl: func(call goja.FunctionCall) goja.Value {
96
inputPort := call.Argument(0).String()
97
if inputPort == "" || stringsutil.EqualFoldAny(inputPort, knowPorts...) {
98
// if inputPort is empty or a know port of other protocol
99
// return given defaultPort
100
return call.Argument(1)
101
}
102
return call.Argument(0)
103
},
104
})
105
106
// is port open check is port is actually open
107
// it can be invoked as isPortOpen(host, port, [timeout])
108
// where timeout is optional and defaults to 5 seconds
109
_ = gojs.RegisterFuncWithSignature(runtime, gojs.FuncOpts{
110
Name: "isPortOpen",
111
Signatures: []string{
112
"isPortOpen(host string, port string, [timeout int]) bool",
113
},
114
Description: "isPortOpen checks if given TCP port is open on host. timeout is optional and defaults to 5 seconds",
115
FuncDecl: func(ctx context.Context, host string, port string, timeout ...int) (bool, error) {
116
if len(timeout) > 0 {
117
var cancel context.CancelFunc
118
ctx, cancel = context.WithTimeout(ctx, time.Duration(timeout[0])*time.Second)
119
defer cancel()
120
}
121
if host == "" || port == "" {
122
return false, errkit.New("isPortOpen: host or port is empty")
123
}
124
125
executionId := ctx.Value("executionId").(string)
126
dialer := protocolstate.GetDialersWithId(executionId)
127
if dialer == nil {
128
panic("dialers with executionId " + executionId + " not found")
129
}
130
131
conn, err := dialer.Fastdialer.Dial(ctx, "tcp", net.JoinHostPort(host, port))
132
if err != nil {
133
return false, err
134
}
135
_ = conn.Close()
136
return true, nil
137
},
138
})
139
140
_ = gojs.RegisterFuncWithSignature(runtime, gojs.FuncOpts{
141
Name: "isUDPPortOpen",
142
Signatures: []string{
143
"isUDPPortOpen(host string, port string, [timeout int]) bool",
144
},
145
Description: "isUDPPortOpen checks if the given UDP port is open on the host. Timeout is optional and defaults to 5 seconds.",
146
FuncDecl: func(ctx context.Context, host string, port string, timeout ...int) (bool, error) {
147
if len(timeout) > 0 {
148
var cancel context.CancelFunc
149
ctx, cancel = context.WithTimeout(ctx, time.Duration(timeout[0])*time.Second)
150
defer cancel()
151
}
152
if host == "" || port == "" {
153
return false, errkit.New("isPortOpen: host or port is empty")
154
}
155
156
executionId := ctx.Value("executionId").(string)
157
dialer := protocolstate.GetDialersWithId(executionId)
158
if dialer == nil {
159
panic("dialers with executionId " + executionId + " not found")
160
}
161
162
conn, err := dialer.Fastdialer.Dial(ctx, "udp", net.JoinHostPort(host, port))
163
if err != nil {
164
return false, err
165
}
166
_ = conn.Close()
167
return true, nil
168
},
169
})
170
171
_ = gojs.RegisterFuncWithSignature(runtime, gojs.FuncOpts{
172
Name: "ToBytes",
173
Signatures: []string{
174
"ToBytes(...interface{}) []byte",
175
},
176
Description: "ToBytes converts given input to byte slice",
177
FuncDecl: func(call goja.FunctionCall) goja.Value {
178
var buff bytes.Buffer
179
allVars := []any{}
180
for _, v := range call.Arguments {
181
if v.Export() == nil {
182
continue
183
}
184
if v.ExportType().Kind() == reflect.Slice {
185
// convert []datatype to []interface{}
186
// since it cannot be type asserted to []interface{} directly
187
rfValue := reflect.ValueOf(v.Export())
188
for i := 0; i < rfValue.Len(); i++ {
189
allVars = append(allVars, rfValue.Index(i).Interface())
190
}
191
} else {
192
allVars = append(allVars, v.Export())
193
}
194
}
195
for _, v := range allVars {
196
buff.WriteString(types.ToString(v))
197
}
198
return runtime.ToValue(buff.Bytes())
199
},
200
})
201
202
_ = gojs.RegisterFuncWithSignature(runtime, gojs.FuncOpts{
203
Name: "ToString",
204
Signatures: []string{
205
"ToString(...interface{}) string",
206
},
207
Description: "ToString converts given input to string",
208
FuncDecl: func(call goja.FunctionCall) goja.Value {
209
var buff bytes.Buffer
210
for _, v := range call.Arguments {
211
exported := v.Export()
212
if exported != nil {
213
buff.WriteString(types.ToString(exported))
214
}
215
}
216
return runtime.ToValue(buff.String())
217
},
218
})
219
220
// register additional helpers
221
registerAdditionalHelpers(runtime)
222
}
223
224
// RegisterNativeScripts are js scripts that were added for convenience
225
// and abstraction purposes we execute them in every runtime and make them
226
// available for use in any js script
227
// see: scripts/ for examples
228
func RegisterNativeScripts(runtime *goja.Runtime) error {
229
initBuiltInFunc(runtime)
230
231
dirs, err := embedFS.ReadDir("js")
232
if err != nil {
233
return err
234
}
235
for _, dir := range dirs {
236
if dir.IsDir() {
237
continue
238
}
239
// embeds have / as path separator (on all os)
240
contents, err := embedFS.ReadFile("js" + "/" + dir.Name())
241
if err != nil {
242
return err
243
}
244
// run all built in js helper functions or scripts
245
_, err = runtime.RunString(string(contents))
246
if err != nil {
247
return err
248
}
249
}
250
// exports defines the exports object
251
_, err = runtime.RunString(exports)
252
if err != nil {
253
return err
254
}
255
256
// import default modules
257
_, err = runtime.RunString(defaultImports)
258
if err != nil {
259
return errkit.Wrapf(err, "could not import default modules %v", defaultImports)
260
}
261
262
return nil
263
}
264
265