244 lines
5.8 KiB
Go
Raw Normal View History

2020-12-22 01:02:38 +05:30
// Inspired from https://github.com/ffuf/ffuf/blob/master/pkg/input/input.go
package generators
import (
"github.com/pkg/errors"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog"
)
2020-12-22 01:02:38 +05:30
// Generator is the generator struct for generating payloads
type Generator struct {
2021-11-04 02:41:56 +05:30
Type AttackType
2020-12-22 01:02:38 +05:30
payloads map[string][]string
}
// New creates a new generator structure for payload generation
2021-11-04 02:41:56 +05:30
func New(payloads map[string]interface{}, attackType AttackType, templatePath string, catalog *catalog.Catalog) (*Generator, error) {
if attackType.String() == "" {
attackType = BatteringRamAttack
}
// Resolve payload paths if they are files.
payloadsFinal := make(map[string]interface{})
for name, payload := range payloads {
payloadsFinal[name] = payload
}
for name, payload := range payloads {
payloadStr, ok := payload.(string)
if ok {
final, resolveErr := catalog.ResolvePath(payloadStr, templatePath)
if resolveErr != nil {
return nil, errors.Wrap(resolveErr, "could not read payload file")
}
payloadsFinal[name] = final
}
}
2020-12-29 12:08:46 +05:30
generator := &Generator{}
if err := generator.validate(payloads, templatePath); err != nil {
return nil, err
}
compiled, err := loadPayloads(payloadsFinal)
2020-12-22 01:02:38 +05:30
if err != nil {
return nil, err
}
2021-11-04 02:41:56 +05:30
generator.Type = attackType
2020-12-29 12:08:46 +05:30
generator.payloads = compiled
2020-12-26 22:52:33 +05:30
2021-10-13 13:19:00 +05:30
// Validate the batteringram payload set
2021-11-04 02:41:56 +05:30
if attackType == BatteringRamAttack {
if len(payloads) != 1 {
2021-10-13 13:19:00 +05:30
return nil, errors.New("batteringram must have single payload set")
}
}
return generator, nil
2020-12-22 01:02:38 +05:30
}
// Iterator is a single instance of an iterator for a generator structure
type Iterator struct {
2021-11-04 02:41:56 +05:30
Type AttackType
2020-12-22 01:02:38 +05:30
position int
msbIterator int
2020-12-26 22:52:33 +05:30
total int
2020-12-22 01:02:38 +05:30
payloads []*payloadIterator
}
// NewIterator creates a new iterator for the payloads generator
func (g *Generator) NewIterator() *Iterator {
var payloads []*payloadIterator
for name, values := range g.payloads {
payloads = append(payloads, &payloadIterator{name: name, values: values})
}
2020-12-26 22:52:33 +05:30
iterator := &Iterator{
Type: g.Type,
payloads: payloads,
}
iterator.total = iterator.Total()
return iterator
2020-12-22 01:02:38 +05:30
}
2020-12-26 22:52:33 +05:30
// Reset resets the iterator back to its initial value
func (i *Iterator) Reset() {
i.position = 0
i.msbIterator = 0
for _, payload := range i.payloads {
payload.resetPosition()
2020-12-22 01:02:38 +05:30
}
}
// Remaining returns the amount of requests left for the generator.
func (i *Iterator) Remaining() int {
return i.total - i.position
}
// Total returns the amount of input combinations available
2020-12-22 01:02:38 +05:30
func (i *Iterator) Total() int {
count := 0
switch i.Type {
2021-11-04 02:41:56 +05:30
case BatteringRamAttack:
for _, p := range i.payloads {
count += len(p.values)
}
2021-11-04 02:41:56 +05:30
case PitchForkAttack:
2020-12-26 22:52:33 +05:30
count = len(i.payloads[0].values)
2021-09-01 20:03:53 +05:30
for _, p := range i.payloads {
if count > len(p.values) {
count = len(p.values)
}
}
2021-11-04 02:41:56 +05:30
case ClusterbombAttack:
2020-12-22 01:02:38 +05:30
count = 1
for _, p := range i.payloads {
2021-02-26 13:13:11 +05:30
count *= len(p.values)
2020-12-22 01:02:38 +05:30
}
}
return count
}
// Value returns the next value for an iterator
2020-12-26 22:52:33 +05:30
func (i *Iterator) Value() (map[string]interface{}, bool) {
2020-12-22 01:02:38 +05:30
switch i.Type {
2021-11-04 02:41:56 +05:30
case BatteringRamAttack:
return i.batteringRamValue()
2021-11-04 02:41:56 +05:30
case PitchForkAttack:
2020-12-22 01:02:38 +05:30
return i.pitchforkValue()
2021-11-04 02:41:56 +05:30
case ClusterbombAttack:
2020-12-22 01:02:38 +05:30
return i.clusterbombValue()
default:
return i.batteringRamValue()
2020-12-22 01:02:38 +05:30
}
}
// batteringRamValue returns a list of all payloads for the iterator
func (i *Iterator) batteringRamValue() (map[string]interface{}, bool) {
2020-12-26 22:52:33 +05:30
values := make(map[string]interface{}, 1)
2020-12-22 01:02:38 +05:30
currentIndex := i.msbIterator
payload := i.payloads[currentIndex]
2020-12-26 22:52:33 +05:30
if !payload.next() {
i.msbIterator++
if i.msbIterator == len(i.payloads) {
return nil, false
}
return i.batteringRamValue()
2020-12-22 01:02:38 +05:30
}
2020-12-26 22:52:33 +05:30
values[payload.name] = payload.value()
payload.incrementPosition()
i.position++
2020-12-26 22:52:33 +05:30
return values, true
2020-12-22 01:02:38 +05:30
}
// pitchforkValue returns a map of keyword:value pairs in same index
2020-12-26 22:52:33 +05:30
func (i *Iterator) pitchforkValue() (map[string]interface{}, bool) {
2020-12-22 01:02:38 +05:30
values := make(map[string]interface{}, len(i.payloads))
for _, p := range i.payloads {
2020-12-26 22:52:33 +05:30
if !p.next() {
return nil, false
2020-12-22 01:02:38 +05:30
}
2020-12-26 22:52:33 +05:30
values[p.name] = p.value()
p.incrementPosition()
2020-12-22 01:02:38 +05:30
}
i.position++
2020-12-26 22:52:33 +05:30
return values, true
2020-12-22 01:02:38 +05:30
}
// clusterbombValue returns a combination of all input pairs in key:value format.
2020-12-26 22:52:33 +05:30
func (i *Iterator) clusterbombValue() (map[string]interface{}, bool) {
if i.position >= i.total {
return nil, false
}
2020-12-22 01:02:38 +05:30
values := make(map[string]interface{}, len(i.payloads))
// Should we signal the next InputProvider in the slice to increment
signalNext := false
first := true
for index, p := range i.payloads {
if signalNext {
2020-12-26 22:52:33 +05:30
p.incrementPosition()
2020-12-22 01:02:38 +05:30
signalNext = false
}
2020-12-26 22:52:33 +05:30
if !p.next() {
2020-12-22 01:02:38 +05:30
// No more inputs in this inputprovider
if index == i.msbIterator {
// Reset all previous wordlists and increment the msb counter
i.msbIterator++
i.clusterbombIteratorReset()
// Start again
return i.clusterbombValue()
}
2020-12-26 22:52:33 +05:30
p.resetPosition()
2020-12-22 01:02:38 +05:30
signalNext = true
}
2020-12-26 22:52:33 +05:30
values[p.name] = p.value()
2020-12-22 01:02:38 +05:30
if first {
2020-12-26 22:52:33 +05:30
p.incrementPosition()
2020-12-22 01:02:38 +05:30
first = false
}
}
2020-12-26 22:52:33 +05:30
i.position++
return values, true
2020-12-22 01:02:38 +05:30
}
func (i *Iterator) clusterbombIteratorReset() {
for index, p := range i.payloads {
if index < i.msbIterator {
2020-12-26 22:52:33 +05:30
p.resetPosition()
2020-12-22 01:02:38 +05:30
}
if index == i.msbIterator {
2020-12-26 22:52:33 +05:30
p.incrementPosition()
2020-12-22 01:02:38 +05:30
}
}
}
// payloadIterator is a single instance of an iterator for a single payload list.
type payloadIterator struct {
index int
name string
values []string
}
2020-12-26 22:52:33 +05:30
// next returns true if there are more values in payload iterator
func (i *payloadIterator) next() bool {
return i.index < len(i.values)
2020-12-22 01:02:38 +05:30
}
2020-12-26 22:52:33 +05:30
// resetPosition resets the position of the payload iterator
func (i *payloadIterator) resetPosition() {
2020-12-22 01:02:38 +05:30
i.index = 0
}
2020-12-26 22:52:33 +05:30
// incrementPosition increments the position of the payload iterator
func (i *payloadIterator) incrementPosition() {
2020-12-22 01:02:38 +05:30
i.index++
}
2020-12-26 22:52:33 +05:30
// value returns the value of the payload at an index
func (i *payloadIterator) value() string {
return i.values[i.index]
2020-12-22 01:02:38 +05:30
}