Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/protocols/headless/engine/rules.go
2072 views
1
package engine
2
3
import (
4
"fmt"
5
"net/http"
6
"net/http/httputil"
7
"strings"
8
9
"github.com/go-rod/rod"
10
"github.com/go-rod/rod/lib/proto"
11
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
12
)
13
14
// routingRuleHandler handles proxy rule for actions related to request/response modification
15
func (p *Page) routingRuleHandler(httpClient *http.Client) func(ctx *rod.Hijack) {
16
return func(ctx *rod.Hijack) {
17
// usually browsers don't use chunked transfer encoding, so we set the content-length nevertheless
18
ctx.Request.Req().ContentLength = int64(len(ctx.Request.Body()))
19
for _, rule := range p.rules {
20
if rule.Part != "request" {
21
continue
22
}
23
24
switch rule.Action {
25
case ActionSetMethod:
26
rule.Do(func() {
27
ctx.Request.Req().Method = rule.Args["method"]
28
})
29
case ActionAddHeader:
30
ctx.Request.Req().Header.Add(rule.Args["key"], rule.Args["value"])
31
case ActionSetHeader:
32
ctx.Request.Req().Header.Set(rule.Args["key"], rule.Args["value"])
33
case ActionDeleteHeader:
34
ctx.Request.Req().Header.Del(rule.Args["key"])
35
case ActionSetBody:
36
body := rule.Args["body"]
37
ctx.Request.Req().ContentLength = int64(len(body))
38
ctx.Request.SetBody(body)
39
}
40
}
41
42
// each http request is performed via the native go http client
43
// we first inject the shared cookies
44
if !p.options.DisableCookie {
45
if cookies := p.ctx.CookieJar.Cookies(ctx.Request.URL()); len(cookies) > 0 {
46
httpClient.Jar.SetCookies(ctx.Request.URL(), cookies)
47
}
48
}
49
50
// perform the request
51
_ = ctx.LoadResponse(httpClient, true)
52
53
if !p.options.DisableCookie {
54
// retrieve the updated cookies from the native http client and inject them into the shared cookie jar
55
// keeps existing one if not present
56
if cookies := httpClient.Jar.Cookies(ctx.Request.URL()); len(cookies) > 0 {
57
p.ctx.CookieJar.SetCookies(ctx.Request.URL(), cookies)
58
}
59
}
60
61
for _, rule := range p.rules {
62
if rule.Part != "response" {
63
continue
64
}
65
66
switch rule.Action {
67
case ActionAddHeader:
68
ctx.Response.Headers().Add(rule.Args["key"], rule.Args["value"])
69
case ActionSetHeader:
70
ctx.Response.Headers().Set(rule.Args["key"], rule.Args["value"])
71
case ActionDeleteHeader:
72
ctx.Response.Headers().Del(rule.Args["key"])
73
case ActionSetBody:
74
body := rule.Args["body"]
75
ctx.Response.Headers().Set("Content-Length", fmt.Sprintf("%d", len(body)))
76
ctx.Response.SetBody(rule.Args["body"])
77
}
78
}
79
80
// store history
81
req := ctx.Request.Req()
82
var rawReq string
83
if raw, err := httputil.DumpRequestOut(req, true); err == nil {
84
rawReq = string(raw)
85
}
86
87
// attempts to rebuild the response
88
var rawResp strings.Builder
89
respPayloads := ctx.Response.Payload()
90
if respPayloads != nil {
91
rawResp.WriteString(fmt.Sprintf("HTTP/1.1 %d %s\n", respPayloads.ResponseCode, respPayloads.ResponsePhrase))
92
for _, header := range respPayloads.ResponseHeaders {
93
rawResp.WriteString(header.Name + ": " + header.Value + "\n")
94
}
95
rawResp.WriteString("\n")
96
rawResp.WriteString(ctx.Response.Body())
97
}
98
99
// dump request
100
historyData := HistoryData{
101
RawRequest: rawReq,
102
RawResponse: rawResp.String(),
103
}
104
p.addToHistory(historyData)
105
}
106
}
107
108
// routingRuleHandlerNative handles native proxy rule
109
func (p *Page) routingRuleHandlerNative(e *proto.FetchRequestPaused) error {
110
// ValidateNFailRequest validates if Local file access is enabled
111
// and local network access is enables if not it will fail the request
112
// that don't match the rules
113
if err := protocolstate.ValidateNFailRequest(p.options.Options, p.page, e); err != nil {
114
return err
115
}
116
body, _ := FetchGetResponseBody(p.page, e)
117
headers := make(map[string][]string)
118
for _, h := range e.ResponseHeaders {
119
headers[h.Name] = []string{h.Value}
120
}
121
122
var statusCode int
123
if e.ResponseStatusCode != nil {
124
statusCode = *e.ResponseStatusCode
125
}
126
127
// attempts to rebuild request
128
var rawReq strings.Builder
129
rawReq.WriteString(fmt.Sprintf("%s %s %s\n", e.Request.Method, e.Request.URL, "HTTP/1.1"))
130
for _, header := range e.Request.Headers {
131
rawReq.WriteString(fmt.Sprintf("%s\n", header.String()))
132
}
133
if e.Request.HasPostData {
134
rawReq.WriteString(fmt.Sprintf("\n%s\n", e.Request.PostData))
135
}
136
137
// attempts to rebuild the response
138
var rawResp strings.Builder
139
rawResp.WriteString(fmt.Sprintf("HTTP/1.1 %d %s\n", statusCode, e.ResponseStatusText))
140
for _, header := range e.ResponseHeaders {
141
rawResp.WriteString(header.Name + ": " + header.Value + "\n")
142
}
143
rawResp.WriteString("\n")
144
rawResp.Write(body)
145
146
// dump request
147
historyData := HistoryData{
148
RawRequest: rawReq.String(),
149
RawResponse: rawResp.String(),
150
}
151
p.addToHistory(historyData)
152
153
return FetchContinueRequest(p.page, e)
154
}
155
156