From 66975f1b439dcbb185b9b7c2d6ca382606cc23d2 Mon Sep 17 00:00:00 2001 From: Shulhan Date: Sat, 25 Sep 2021 02:31:30 +0700 Subject: all: prevent leaking Target and HttpTarget headers and variables In case two or more users access the Trunks web and set the target variables, the last user that run any HttpTarget will set the Target variables or HttpTarget headers/variables. The next user that open the Trunks web will see the values of headers and variables from the latest run. This changes fix this issue by generating new RunRequest using request original target --- example/example.go | 2 +- run_request.go | 108 ++++++++++++++++++++++++++++++----------------------- trunks.go | 23 ++---------- 3 files changed, 65 insertions(+), 68 deletions(-) diff --git a/example/example.go b/example/example.go index abf6c0e..3bf7395 100644 --- a/example/example.go +++ b/example/example.go @@ -259,7 +259,7 @@ func (ex *Example) registerTargets() (err error) { }, Params: trunks.KeyFormInput{ "Param1": trunks.FormInput{ - Label: "X-FreeForm", + Label: "Param1", Hint: "Parameter with number.", Kind: trunks.FormInputKindNumber, Value: "123", diff --git a/run_request.go b/run_request.go index bbb4f2d..174781d 100644 --- a/run_request.go +++ b/run_request.go @@ -12,79 +12,93 @@ import ( vegeta "github.com/tsenart/vegeta/v12/lib" ) +// +// RunRequest define the request to run HTTP or WebSocket target. +// type RunRequest struct { - Locker sync.Mutex - Target *Target - HttpTarget *HttpTarget - WebSocketTarget *WebSocketTarget + Locker sync.Mutex `json:"-"` + Target Target + HttpTarget HttpTarget + WebSocketTarget WebSocketTarget result *AttackResult } -func (rr *RunRequest) String() string { - return fmt.Sprintf("Target:%v HttpTarget:%v\n", rr.Target, rr.HttpTarget) -} - // -// mergeHttpTarget merge the request parameter into original target and HTTP -// target. +// generateRunRequest merge the run request with original target and HTTP +// target into new RunRequest. // -func (rr *RunRequest) mergeHttpTarget(env *Environment, origTarget *Target, origHttpTarget *HttpTarget) { - if rr.Target.Opts.Duration > 0 && rr.Target.Opts.Duration <= env.MaxAttackDuration { - origTarget.Opts.Duration = rr.Target.Opts.Duration +func generateRunRequest( + env *Environment, + req *RunRequest, + origTarget *Target, + origHttpTarget *HttpTarget, +) (outrr *RunRequest) { + if req.Target.Opts.Duration > 0 && req.Target.Opts.Duration <= env.MaxAttackDuration { + origTarget.Opts.Duration = req.Target.Opts.Duration } - - if rr.Target.Opts.RatePerSecond > 0 && rr.Target.Opts.RatePerSecond <= env.MaxAttackRate { - origTarget.Opts.RatePerSecond = rr.Target.Opts.RatePerSecond + if req.Target.Opts.RatePerSecond > 0 && req.Target.Opts.RatePerSecond <= env.MaxAttackRate { + origTarget.Opts.RatePerSecond = req.Target.Opts.RatePerSecond origTarget.Opts.ratePerSecond = vegeta.Rate{ - Freq: rr.Target.Opts.RatePerSecond, + Freq: req.Target.Opts.RatePerSecond, Per: time.Second, } } + if req.Target.Opts.Timeout > 0 && req.Target.Opts.Timeout <= DefaultAttackTimeout { + origTarget.Opts.Timeout = req.Target.Opts.Timeout + } + if origHttpTarget.IsCustomizable { + origHttpTarget.Method = req.HttpTarget.Method + origHttpTarget.Path = req.HttpTarget.Path + origHttpTarget.RequestType = req.HttpTarget.RequestType + } - if rr.Target.Opts.Timeout > 0 && rr.Target.Opts.Timeout <= DefaultAttackTimeout { - origTarget.Opts.Timeout = rr.Target.Opts.Timeout + outrr = &RunRequest{ + Target: *origTarget, + HttpTarget: *origHttpTarget, } - origTarget.Vars = rr.Target.Vars - rr.Target = origTarget + outrr.Target.Vars = req.Target.Vars + outrr.HttpTarget.Headers = req.HttpTarget.Headers + outrr.HttpTarget.Params = req.HttpTarget.Params - if origHttpTarget.IsCustomizable { - origHttpTarget.Method = rr.HttpTarget.Method - origHttpTarget.Path = rr.HttpTarget.Path - origHttpTarget.RequestType = rr.HttpTarget.RequestType - } - origHttpTarget.Headers = rr.HttpTarget.Headers - origHttpTarget.Params = rr.HttpTarget.Params - rr.HttpTarget = origHttpTarget + return outrr } // -// mergeWebSocketTarget merge the request parameter into original target and -// WebSocket target. +// generateWebSocketTarget merge the run request with original target and +// WebSocket target into new RunRequest // -func (rr *RunRequest) mergeWebSocketTarget(env *Environment, - origTarget *Target, origWebSocketTarget *WebSocketTarget, -) { - if rr.Target.Opts.Duration > 0 && rr.Target.Opts.Duration <= env.MaxAttackDuration { - origTarget.Opts.Duration = rr.Target.Opts.Duration +func generateWebSocketTarget( + env *Environment, + req *RunRequest, + origTarget *Target, + origWebSocketTarget *WebSocketTarget, +) (outrr *RunRequest) { + if req.Target.Opts.Duration > 0 && req.Target.Opts.Duration <= env.MaxAttackDuration { + origTarget.Opts.Duration = req.Target.Opts.Duration } - - if rr.Target.Opts.RatePerSecond > 0 && rr.Target.Opts.RatePerSecond <= env.MaxAttackRate { - origTarget.Opts.RatePerSecond = rr.Target.Opts.RatePerSecond + if req.Target.Opts.RatePerSecond > 0 && req.Target.Opts.RatePerSecond <= env.MaxAttackRate { + origTarget.Opts.RatePerSecond = req.Target.Opts.RatePerSecond origTarget.Opts.ratePerSecond = vegeta.Rate{ - Freq: rr.Target.Opts.RatePerSecond, + Freq: req.Target.Opts.RatePerSecond, Per: time.Second, } } + if req.Target.Opts.Timeout > 0 && req.Target.Opts.Timeout <= DefaultAttackTimeout { + origTarget.Opts.Timeout = req.Target.Opts.Timeout + } - if rr.Target.Opts.Timeout > 0 && rr.Target.Opts.Timeout <= DefaultAttackTimeout { - origTarget.Opts.Timeout = rr.Target.Opts.Timeout + outrr = &RunRequest{ + Target: *origTarget, + WebSocketTarget: *origWebSocketTarget, } + outrr.Target.Vars = req.Target.Vars + outrr.WebSocketTarget.Headers = req.WebSocketTarget.Headers + outrr.WebSocketTarget.Params = req.WebSocketTarget.Params - origTarget.Vars = rr.Target.Vars - rr.Target = origTarget + return outrr +} - origWebSocketTarget.Headers = rr.WebSocketTarget.Headers - origWebSocketTarget.Params = rr.WebSocketTarget.Params - rr.WebSocketTarget = origWebSocketTarget +func (rr *RunRequest) String() string { + return fmt.Sprintf("Target:%v HttpTarget:%v\n", rr.Target, rr.HttpTarget) } diff --git a/trunks.go b/trunks.go index 44d6400..2972b54 100644 --- a/trunks.go +++ b/trunks.go @@ -272,9 +272,6 @@ func (trunks *Trunks) apiTargetAttack(epr *libhttp.EndpointRequest) (resbody []b if err != nil { return nil, errInternal(err) } - if req.Target == nil { - return nil, errInvalidTarget("") - } origTarget := trunks.getTargetByID(req.Target.ID) if origTarget == nil { @@ -290,7 +287,7 @@ func (trunks *Trunks) apiTargetAttack(epr *libhttp.EndpointRequest) (resbody []b return nil, errAttackNotAllowed() } - req.mergeHttpTarget(trunks.Env, origTarget, origHttpTarget) + req = generateRunRequest(trunks.Env, req, origTarget, origHttpTarget) req.result, err = newAttackResult(trunks.Env, req) if err != nil { @@ -386,19 +383,12 @@ func (trunks *Trunks) apiTargetRunHttp(epr *libhttp.EndpointRequest) ([]byte, er if err != nil { return nil, errInternal(err) } - if req.Target == nil { - return nil, errInvalidTarget("") - } origTarget := trunks.getTargetByID(req.Target.ID) if origTarget == nil { return nil, errInvalidTarget(req.Target.ID) } - if req.HttpTarget == nil { - return nil, errInvalidHttpTarget("") - } - origHttpTarget := origTarget.getHttpTargetByID(req.HttpTarget.ID) if origHttpTarget == nil { return nil, errInvalidHttpTarget(req.HttpTarget.ID) @@ -411,7 +401,7 @@ func (trunks *Trunks) apiTargetRunHttp(epr *libhttp.EndpointRequest) ([]byte, er req.Target.Name = origTarget.Name res, err = trunks.runHttpTarget(req) } else { - req.mergeHttpTarget(trunks.Env, origTarget, origHttpTarget) + req := generateRunRequest(trunks.Env, req, origTarget, origHttpTarget) res, err = req.HttpTarget.Run(req) } if err != nil { @@ -431,25 +421,18 @@ func (trunks *Trunks) apiTargetRunWebSocket(epr *libhttp.EndpointRequest) ([]byt if err != nil { return nil, errInternal(err) } - if req.Target == nil { - return nil, errInvalidTarget("") - } origTarget := trunks.getTargetByID(req.Target.ID) if origTarget == nil { return nil, errInvalidTarget(req.Target.ID) } - if req.WebSocketTarget == nil { - return nil, errInvalidWebSocketTarget("") - } - origWsTarget := origTarget.getWebSocketTargetByID(req.WebSocketTarget.ID) if origWsTarget == nil { return nil, errInvalidWebSocketTarget(req.WebSocketTarget.ID) } - req.mergeWebSocketTarget(trunks.Env, origTarget, origWsTarget) + req = generateWebSocketTarget(trunks.Env, req, origTarget, origWsTarget) res, err := req.WebSocketTarget.Run(req) if err != nil { -- cgit v1.3