Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions internal/tests/integration/javascript_http_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//go:build integration
// +build integration

package integration_test

import (
"io"
"net/http"
"net/http/httptest"
"strings"
)

// startJSHTTPServer starts a local HTTP server exercising the generic paths
// used by the nuclei/http javascript integration templates.
func startJSHTTPServer() *httptest.Server {
mux := http.NewServeMux()
mux.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Test", "ok")
_, _ = io.WriteString(w, "hello")
})
mux.HandleFunc("/echo-header", func(w http.ResponseWriter, r *http.Request) {
_, _ = io.WriteString(w, r.Header.Get("X-Token"))
})
mux.HandleFunc("/echo", func(w http.ResponseWriter, r *http.Request) {
b, _ := io.ReadAll(r.Body)
_, _ = w.Write(b)
})
mux.HandleFunc("/set-cookie", func(w http.ResponseWriter, r *http.Request) {
http.SetCookie(w, &http.Cookie{Name: "sid", Value: "abc"})
_, _ = io.WriteString(w, "set")
})
mux.HandleFunc("/echo-cookie", func(w http.ResponseWriter, r *http.Request) {
c, err := r.Cookie("sid")
if err != nil || c.Value != "abc" {
_, _ = io.WriteString(w, "missing")
return
}
_, _ = io.WriteString(w, "sid-ok")
})
mux.HandleFunc("/redir", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/land", http.StatusFound)
})
mux.HandleFunc("/land", func(w http.ResponseWriter, r *http.Request) {
_, _ = io.WriteString(w, "landed")
})
return httptest.NewServer(mux)
}

type javascriptHTTPGet struct{}

func (j *javascriptHTTPGet) Execute(filePath string) error {
ts := startJSHTTPServer()
defer ts.Close()

// Target as host:port so javascript Host/Port args populate cleanly.
hostPort := strings.TrimPrefix(ts.URL, "http://")
results, err := runSignedNucleiTemplateAndGetResults(filePath, hostPort, debug)
if err != nil {
return err
}
return expectResultsCount(results, 1)
}

type javascriptHTTPClientFlow struct{}

func (j *javascriptHTTPClientFlow) Execute(filePath string) error {
ts := startJSHTTPServer()
defer ts.Close()

hostPort := strings.TrimPrefix(ts.URL, "http://")
results, err := runSignedNucleiTemplateAndGetResults(filePath, hostPort, debug)
if err != nil {
return err
}
return expectResultsCount(results, 1)
}

type javascriptHTTPDenied struct{}

func (j *javascriptHTTPDenied) Execute(filePath string) error {
results, err := runSignedNucleiTemplateAndGetResults(filePath, "127.0.0.1", debug, "-eh", "203.0.113.10")
if err != nil {
return err
}
return expectResultsCount(results, 1)
}
3 changes: 3 additions & 0 deletions internal/tests/integration/javascript_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ var jsTestcases = []integrationCase{
{Path: "protocols/javascript/net-https.yaml", TestCase: &javascriptNetHttps{}},
{Path: "protocols/javascript/grpc-health.yaml", TestCase: &javascriptGRPCHealth{}},
{Path: "protocols/javascript/grpc-denied.yaml", TestCase: &javascriptGRPCDenied{}},
{Path: "protocols/javascript/http-get.yaml", TestCase: &javascriptHTTPGet{}},
{Path: "protocols/javascript/http-client-flow.yaml", TestCase: &javascriptHTTPClientFlow{}},
{Path: "protocols/javascript/http-denied.yaml", TestCase: &javascriptHTTPDenied{}},
{Path: "protocols/javascript/rsync-test.yaml", TestCase: &javascriptRsyncTest{}, DisableOn: javascriptDockerDisabled, Serial: true},
{Path: "protocols/javascript/vnc-pass-brute.yaml", TestCase: &javascriptVncPassBrute{}, DisableOn: javascriptDockerDisabled, Serial: true},
{Path: "protocols/javascript/postgres-pass-brute.yaml", TestCase: &javascriptPostgresPassBrute{}, DisableOn: javascriptDockerDisabled, Serial: true},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
id: js-http-client-flow

info:
name: nuclei/http client flow
author: pdteam
severity: info
description: |
Exercises nuclei/http Client for Post, cookie jar reuse, and redirect
following against a local HTTP server.

javascript:
- code: |
const http = require('nuclei/http');
const client = new http.Client();
const post = client.Post(BaseURL + '/echo', 'payload');
client.Get(BaseURL + '/set-cookie');
const cookie = client.Get(BaseURL + '/echo-cookie');
const redir = client.Get(BaseURL + '/redir');
post.Body + '|' + cookie.Body + '|' + redir.StatusCode + '|' + redir.Body;
args:
BaseURL: "http://{{Host}}:{{Port}}"
matchers-condition: and
matchers:
- type: dsl
dsl:
- "success == true"
- type: word
part: response
words:
- "payload|sid-ok|200|landed"
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
id: js-http-network-policy-denied

info:
name: nuclei/http network policy denial
author: pdteam
severity: info
description: |
Hardening check for nuclei/http: requesting a host on the exclude list
(RFC 5737 TEST-NET-3) must be rejected by network policy before dialing.

javascript:
- code: |
const http = require('nuclei/http');
let out = "";
try {
http.Get('http://203.0.113.10/');
} catch (e) {
out = "" + e;
}
out;
args:
Host: "{{Host}}"
matchers-condition: and
matchers:
- type: dsl
dsl:
- "success == true"
- type: word
part: response
words:
- "network policy"
- "203.0.113.10"
condition: and
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
id: js-http-get

info:
name: nuclei/http GET
author: pdteam
severity: info
description: |
Exercises nuclei/http package Get and Client.Get/SetHeader against a local
HTTP server (status, body, response headers, default request header).

javascript:
- code: |
const http = require('nuclei/http');
const a = http.Get(BaseURL + '/hello');
const client = new http.Client();
client.SetHeader('X-Token', 'nuclei');
const b = client.Get(BaseURL + '/echo-header');
a.StatusCode + '|' + a.Body + '|' + a.GetHeader('X-Test') + '|' + b.Body;
args:
BaseURL: "http://{{Host}}:{{Port}}"
matchers-condition: and
matchers:
- type: dsl
dsl:
- "success == true"
- type: word
part: response
words:
- "200|hello|ok|nuclei"
1 change: 1 addition & 0 deletions pkg/js/compiler/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
_ "github.com/projectdiscovery/nuclei/v3/pkg/js/generated/go/libdcom"
_ "github.com/projectdiscovery/nuclei/v3/pkg/js/generated/go/libfs"
_ "github.com/projectdiscovery/nuclei/v3/pkg/js/generated/go/libgrpc"
_ "github.com/projectdiscovery/nuclei/v3/pkg/js/generated/go/libhttp"
_ "github.com/projectdiscovery/nuclei/v3/pkg/js/generated/go/libikev2"
_ "github.com/projectdiscovery/nuclei/v3/pkg/js/generated/go/libkerberos"
_ "github.com/projectdiscovery/nuclei/v3/pkg/js/generated/go/libkrbforge"
Expand Down
39 changes: 39 additions & 0 deletions pkg/js/generated/go/libhttp/http.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package http

import (
lib_http "github.com/projectdiscovery/nuclei/v3/pkg/js/libs/http"

"github.com/projectdiscovery/goja"
"github.com/projectdiscovery/nuclei/v3/pkg/js/gojs"
)

var (
module = gojs.NewGojaModule("nuclei/http")
)

func init() {
module.Set(
gojs.Objects{
// Functions
"DecodeNTLM": lib_http.DecodeNTLM,
"Get": lib_http.Get,
"Head": lib_http.Head,
"NegotiateNTLM": lib_http.NegotiateNTLM,
"NewClient": lib_http.NewClient,
"Post": lib_http.Post,
"Request": lib_http.Request,

// Var and consts

// Objects / Classes
"Client": lib_http.NewClient,
"NTLMInfo": gojs.GetClassConstructor[lib_http.NTLMInfo](&lib_http.NTLMInfo{}),
"Options": gojs.GetClassConstructor[lib_http.Options](&lib_http.Options{}),
"Response": gojs.GetClassConstructor[lib_http.Response](&lib_http.Response{}),
},
).Register()
}

func Enable(runtime *goja.Runtime) {
module.Enable(runtime)
}
Loading
Loading