nuclei/v2/pkg/requests/generator.go

279 lines
5.1 KiB
Go
Raw Normal View History

2020-07-24 11:37:01 +00:00
package requests
import (
"sync"
"time"
"github.com/projectdiscovery/nuclei/v2/pkg/generators"
)
2020-07-29 19:20:39 +00:00
type GeneratorState int
const (
fifteen = 15
initial GeneratorState = iota
running
done
2020-07-29 19:20:39 +00:00
)
2020-07-24 11:37:01 +00:00
type Generator struct {
sync.RWMutex
positionPath int
positionRaw int
gchan chan map[string]interface{}
currentGeneratorValue map[string]interface{}
2020-07-29 19:20:39 +00:00
state GeneratorState
2020-07-24 11:37:01 +00:00
}
type GeneratorFSM struct {
sync.RWMutex
payloads map[string]interface{}
basePayloads map[string][]string
generator func(payloads map[string][]string) (out chan map[string]interface{})
Generators map[string]*Generator
Type generators.Type
Paths []string
Raws []string
}
func NewGeneratorFSM(typ generators.Type, payloads map[string]interface{}, paths, raws []string) *GeneratorFSM {
var gsfm GeneratorFSM
gsfm.payloads = payloads
gsfm.Paths = paths
gsfm.Raws = raws
2020-10-12 06:14:07 +00:00
gsfm.Type = typ
2020-07-24 11:37:01 +00:00
if len(gsfm.payloads) > 0 {
// load payloads if not already done
if gsfm.basePayloads == nil {
gsfm.basePayloads = generators.LoadPayloads(gsfm.payloads)
}
generatorFunc := generators.SniperGenerator
2020-07-24 11:37:01 +00:00
switch typ {
case generators.PitchFork:
generatorFunc = generators.PitchforkGenerator
case generators.ClusterBomb:
generatorFunc = generators.ClusterbombGenerator
case generators.Sniper:
generatorFunc = generators.SniperGenerator
2020-07-24 11:37:01 +00:00
}
2020-07-24 11:37:01 +00:00
gsfm.generator = generatorFunc
}
2020-07-24 11:37:01 +00:00
gsfm.Generators = make(map[string]*Generator)
return &gsfm
}
func (gfsm *GeneratorFSM) Add(key string) {
gfsm.Lock()
defer gfsm.Unlock()
if _, ok := gfsm.Generators[key]; !ok {
gfsm.Generators[key] = &Generator{state: initial}
2020-07-24 11:37:01 +00:00
}
}
func (gfsm *GeneratorFSM) Has(key string) bool {
gfsm.RLock()
defer gfsm.RUnlock()
_, ok := gfsm.Generators[key]
2020-07-24 11:37:01 +00:00
return ok
}
func (gfsm *GeneratorFSM) Delete(key string) {
gfsm.Lock()
defer gfsm.Unlock()
delete(gfsm.Generators, key)
}
func (gfsm *GeneratorFSM) ReadOne(key string) {
gfsm.RLock()
defer gfsm.RUnlock()
g, ok := gfsm.Generators[key]
2020-07-24 11:37:01 +00:00
if !ok {
return
}
for afterCh := time.After(fifteen * time.Second); ; {
2020-07-24 11:37:01 +00:00
select {
// got a value
case curGenValue, ok := <-g.gchan:
if !ok {
g.Lock()
g.gchan = nil
g.state = done
2020-07-29 19:20:39 +00:00
g.currentGeneratorValue = nil
2020-07-24 11:37:01 +00:00
g.Unlock()
2020-07-24 11:37:01 +00:00
return
}
g.currentGeneratorValue = curGenValue
2020-07-24 11:37:01 +00:00
return
// timeout
case <-afterCh:
g.Lock()
g.gchan = nil
g.state = done
2020-07-24 11:37:01 +00:00
g.Unlock()
2020-07-24 11:37:01 +00:00
return
}
}
}
func (gfsm *GeneratorFSM) InitOrSkip(key string) {
gfsm.RLock()
defer gfsm.RUnlock()
g, ok := gfsm.Generators[key]
if !ok {
return
}
if len(gfsm.payloads) > 0 {
g.Lock()
defer g.Unlock()
2020-07-24 11:37:01 +00:00
if g.gchan == nil {
g.gchan = gfsm.generator(gfsm.basePayloads)
g.state = running
2020-07-24 11:37:01 +00:00
}
}
}
func (gfsm *GeneratorFSM) Value(key string) map[string]interface{} {
gfsm.RLock()
defer gfsm.RUnlock()
g, ok := gfsm.Generators[key]
if !ok {
return nil
}
return g.currentGeneratorValue
}
2020-07-29 19:20:39 +00:00
func (gfsm *GeneratorFSM) hasPayloads() bool {
return len(gfsm.basePayloads) > 0
}
2020-07-24 11:37:01 +00:00
func (gfsm *GeneratorFSM) Next(key string) bool {
gfsm.RLock()
defer gfsm.RUnlock()
g, ok := gfsm.Generators[key]
if !ok {
return false
}
if g.positionPath+g.positionRaw >= len(gfsm.Paths)+len(gfsm.Raws) {
return false
}
2020-07-24 11:37:01 +00:00
return true
}
2020-07-29 19:20:39 +00:00
2020-07-24 11:37:01 +00:00
func (gfsm *GeneratorFSM) Position(key string) int {
gfsm.RLock()
defer gfsm.RUnlock()
g, ok := gfsm.Generators[key]
if !ok {
return 0
}
return g.positionPath + g.positionRaw
}
func (gfsm *GeneratorFSM) Reset(key string) {
gfsm.Lock()
defer gfsm.Unlock()
2020-07-24 11:37:01 +00:00
if !gfsm.Has(key) {
gfsm.Add(key)
}
g, ok := gfsm.Generators[key]
if !ok {
return
}
g.positionPath = 0
g.positionRaw = 0
}
func (gfsm *GeneratorFSM) Current(key string) string {
gfsm.RLock()
defer gfsm.RUnlock()
g, ok := gfsm.Generators[key]
if !ok {
return ""
}
if g.positionPath < len(gfsm.Paths) && len(gfsm.Paths) != 0 {
return gfsm.Paths[g.positionPath]
}
return gfsm.Raws[g.positionRaw]
}
func (gfsm *GeneratorFSM) Total() int {
2020-10-12 06:14:07 +00:00
estimatedRequestsWithPayload := 0
if len(gfsm.basePayloads) > 0 {
switch gfsm.Type {
case generators.Sniper:
for _, kv := range gfsm.basePayloads {
estimatedRequestsWithPayload += len(kv)
}
case generators.PitchFork:
// Positional so it's equal to the length of one list
for _, kv := range gfsm.basePayloads {
estimatedRequestsWithPayload += len(kv)
break
}
case generators.ClusterBomb:
// Total of combinations => rule of product
prod := 1
for _, kv := range gfsm.basePayloads {
prod = prod * len(kv)
}
estimatedRequestsWithPayload += prod
}
}
return len(gfsm.Paths) + len(gfsm.Raws) + estimatedRequestsWithPayload
2020-07-24 11:37:01 +00:00
}
func (gfsm *GeneratorFSM) Increment(key string) {
gfsm.Lock()
defer gfsm.Unlock()
g, ok := gfsm.Generators[key]
if !ok {
return
}
if len(gfsm.Paths) > 0 && g.positionPath < len(gfsm.Paths) {
g.positionPath++
return
}
if len(gfsm.Raws) > 0 && g.positionRaw < len(gfsm.Raws) {
// if we have payloads increment only when the generators are done
if g.gchan == nil {
g.state = done
2020-07-24 11:37:01 +00:00
g.positionRaw++
}
}
}