Skip to content

Commit

Permalink
feat: add all-tags (-at) and all-params (-ap) flags
Browse files Browse the repository at this point in the history
- Add -at flag to search across all vulnerability tags
- Add -ap flag to find all parameterized URLs
- Update README with new features
- Improve tag validation handling
  • Loading branch information
h0tak88r committed Dec 4, 2024
1 parent 90744d0 commit 23bd08b
Show file tree
Hide file tree
Showing 8 changed files with 282 additions and 45 deletions.
26 changes: 14 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ ParamX is a tool designed to extract interesting subdomains and parameters from
- Processes URLs from files or standard input.
- Custom parameter value replacement.
- Easy configuration using YAML templates not JSON like gf
- Supports all-tags mode to search across all vulnerability types
- Supports all-params mode to find any parameterized URLs

## Templates
- You can find our written templates here [paramx-tempalets](https://github.com/cyinnove/paramx-templates) or you can create your own, it's so easy to do
Expand All @@ -38,8 +40,6 @@ list:
- param2
```



## Installation

To install ParamX:
Expand All @@ -56,9 +56,11 @@ ParamX is executed via command-line interface (CLI) with several options to cust
- `-tp` : Directory where YAML configuration files are located.
- `-l` : Path to a file containing URLs (one per line).
- `-tag` : The type of bug to extract the URLs based on it (default: "xss"). Supported values: xss, sqli, lfi, rce, idor, ssrf, ssti, redirect.
- `-at` : Search for URLs matching all vulnerability tags.
- `-ap` : Hunt for all kinds of parameterized URLs regardless of tag.
- `-rw` : Replace the parameter value with a custom value.
- `-t` : Path to a custom template.
- `-ut` : Update the templates.
- `-o` : Path to a file where the results should be saved.

### Examples

Expand All @@ -74,28 +76,28 @@ This will show output like :

![poc.png](/static/poc.png)

#### Using Custom Template
#### Search All Tags

To use a custom template for extraction:
To search for parameters matching any vulnerability type:

```sh
cat urls.txt | paramx -t /path/to/custom_template.yaml
cat urls.txt | paramx -at
```

#### Replacing Parameter Values
#### Find All Parameterized URLs

To replace the parameter value with a custom value:
To find all URLs that contain parameters, regardless of type:

```sh
paramx -rw "custom_value" -l urls.txt
cat urls.txt | paramx -ap
```

#### Updating Templates
#### Save Results to File

To update the YAML configuration templates:
To save the results to a file:

```sh
paramx -ut
cat urls.txt | paramx -tag xss -o results.txt
```

## Contributing
Expand Down
2 changes: 2 additions & 0 deletions cmd/paramx/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ func init() {
flag.StringVar(&opts.TempletesPath, "tp", "", "Directory where YAML configuration files are located.")
flag.StringVar(&opts.FileInput, "l", "", "Path to a file containing URLs (one per line).")
flag.StringVar(&opts.Tag, "tag", "xss", "The type of bug to extract the URLs based on it (default: \"xss\"). Supported values: xss, sqli, lfi, rce, idor, ssrf, ssti, redirect.")
flag.BoolVar(&opts.AllTags, "at", false, "Search for URLs matching all vulnerability tags (overrides -tag).")
flag.BoolVar(&opts.AllParams, "ap", false, "Hunt for all kinds of parameterized URLs regardless of tag (overrides -tag).")
flag.StringVar(&opts.ReplaceWith, "rw", "", "Replace the parameter value with a custom value.")
flag.StringVar(&opts.CustomTemplete, "t", "", "Path to a custom template.")
flag.StringVar(&opts.OutputFile, "o", "", "Path to a file where the results should be saved.")
Expand Down
34 changes: 17 additions & 17 deletions internal/config/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package config

import (
"fmt"
"os"
"os/exec"
"path/filepath"
Expand All @@ -21,7 +22,6 @@ func (t TemplateType) String() string {
return [...]string{"subdomain", "path", "query"}[t]
}


var TempletesPath = filepath.Join(os.Getenv("HOME"), "paramx-templates")

type Data struct {
Expand All @@ -32,22 +32,22 @@ type Data struct {

// Check config path
func DownloadTempletes() error {
if _, err := exec.LookPath("git"); err != nil {
return fmt.Errorf("git is not installed or not found in PATH")
}

if _, err := os.Stat(TempletesPath); os.IsNotExist(err) {
logify.Infof("Templates directory does not exist. Cloning repository...")
cmd := exec.Command("git", "clone", "https://github.com/cyinnove/paramx-templates.git", TempletesPath)
err := cmd.Run()
if err != nil {
return err
}
logify.Infof("Param Templetes installed successfully.")
return nil
}

return nil
if _, err := exec.LookPath("git"); err != nil {
return fmt.Errorf("git is not installed or not found in PATH")
}

if _, err := os.Stat(TempletesPath); os.IsNotExist(err) {
logify.Infof("Templates directory does not exist. Cloning repository...")
cmd := exec.Command("git", "clone", "https://github.com/cyinnove/paramx-templates.git", TempletesPath)
err := cmd.Run()
if err != nil {
return err
}
logify.Infof("Param Templetes installed successfully.")
return nil
}

return nil
}

// LoadConfig loads configuration files from the specified directory and returns a slice of Data objects.
Expand Down
3 changes: 2 additions & 1 deletion internal/runner/options.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package runner


// Options represents the configuration options for the runner.
type Options struct {
URLs []string // URLs is a list of target URLs.
TempletesPath string // TempletesPath is the path to the templates directory.
Tag string // Tag is the type of bug to be injected.
AllTags bool // AllTags enables searching for all vulnerability tags.
AllParams bool // AllParams enables hunting for all parameterized URLs.
FileInput string // FileInput is the path to the input file.
ReplaceWith string // ReplaceWith is the string to replace the bug with.
CustomTemplete string // CustomTemplete is the path to the custom templete.
Expand Down
47 changes: 42 additions & 5 deletions internal/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,23 +59,60 @@ func Run(opts *Options) {
}

default:
logify.Infof("Starting getting parameters from %d urls for tag %s", len(opts.URLs), opts.Tag)
var result []string
tags := []string{"xss"}

if opts.AllTags {
// Define all supported tags
tags = []string{"xss", "sqli", "lfi", "rce", "idor", "ssrf", "ssti", "redirect"}
logify.Infof("Searching for parameters matching all vulnerability tags")
} else if opts.AllParams {
logify.Infof("Hunting for all parameterized URLs")
result = utils.RemoveDuplicates(grep.GrepAllParameters(opts.URLs))
} else {
// Validate single tag when not in all-tags mode
validTags := []string{"xss", "ssrf", "sqli", "lfi", "rce", "idor", "ssti", "redirect", "isubs"}
isValid := false
for _, validTag := range validTags {
if validTag == opts.Tag {
isValid = true
break
}
}
if !isValid {
logify.Fatalf("Invalid tag, please add a valid tag like (xss, ssrf, sqli, lfi, rce, idor, ssti, redirect, isubs)")
}
logify.Infof("Starting getting parameters from %d urls for tag %s", len(opts.URLs), opts.Tag)
tags = []string{opts.Tag}
}

result := utils.RemoveDuplicates(grep.GrepParameters(opts.URLs, configs, opts.Tag, opts.ReplaceWith))
if !opts.AllParams {
for _, tag := range tags {
// Skip validation in GrepParameters since we've already validated
tagResults := grep.GrepParametersNoValidate(opts.URLs, configs, tag, opts.ReplaceWith)
result = append(result, tagResults...)
}
result = utils.RemoveDuplicates(result)
}

for _, r := range result {
fmt.Fprintln(os.Stdout, r)
}

logify.Infof("Found %d parameter with tag %s", len(result), opts.Tag)
if opts.AllTags {
logify.Infof("Found %d parameters across all tags", len(result))
} else if opts.AllParams {
logify.Infof("Found %d parameterized URLs", len(result))
} else {
logify.Infof("Found %d parameter with tag %s", len(result), opts.Tag)
}

if opts.OutputFile != "" {
if err := utils.OutputTextResult(result, opts.OutputFile ); err != nil {
if err := utils.OutputTextResult(result, opts.OutputFile); err != nil {
logify.Fatalf("Error writing to file: %s\n", err.Error())
}
logify.Infof("URLs saved to %s", opts.OutputFile)
}

}

}
Binary file added paramx
Binary file not shown.
54 changes: 44 additions & 10 deletions pkg/grep/grep.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ func isTypeExist(tag string, types []string) bool {

// GrepParameters searches for parameters in the given URLs based on the provided configurations and bug type.
// It replaces the found parameters with the specified replacement string.
// The function takes in the following parameters:
// - urls: A slice of strings representing the URLs to search for parameters.
// - configs: A slice of *config.Data representing the configurations to use for parameter extraction.
// - tag: A string representing the bug type to search for.
// - replaceWith: A string representing the replacement value for the found parameters.
func GrepParameters(urls []string, configs []*config.Data, tag, replaceWith string) []string {
tags := []string{}

Expand All @@ -38,22 +33,29 @@ func GrepParameters(urls []string, configs []*config.Data, tag, replaceWith stri
logify.Fatalf("Invalid tag , please add a valid tag like (xss, ssrf, sqli, lfi, rce, idor, ssti, redirect, isubs)")
}

return GrepParametersNoValidate(urls, configs, tag, replaceWith)
}

// GrepParametersNoValidate is similar to GrepParameters but skips tag validation.
// This is used internally when we've already validated the tag elsewhere.
func GrepParametersNoValidate(urls []string, configs []*config.Data, tag, replaceWith string) []string {
result := []string{}

for _, rawURL := range urls {
params, fullURL := extractParameters(rawURL, replaceWith)

for _, cfg := range configs {

if !(cfg.Part == types.Query.String()) {
continue
}

for _, param := range cfg.List {

if strings.EqualFold(cfg.Tag, tag) {
if !(strings.EqualFold(cfg.Tag, tag)) {
continue
}

if _, exists := params[param]; exists {
for paramName := range params {
for _, param := range cfg.List {
if strings.EqualFold(paramName, param) {
result = append(result, fullURL)
}
}
Expand Down Expand Up @@ -105,3 +107,35 @@ func GrepSubdomains(urls []string, configs []*config.Data) []string {

return result
}

// GrepAllParameters finds all URLs that contain any parameters, regardless of tag.
// It returns a slice of strings containing all URLs with parameters.
func GrepAllParameters(urls []string) []string {
result := []string{}

for _, rawURL := range urls {
parsedURL, err := url.Parse(rawURL)
if err != nil {
continue
}

// Check if URL has query parameters
if parsedURL.RawQuery != "" {
result = append(result, rawURL)
continue
}

// Check if URL has path parameters
if strings.Contains(parsedURL.Path, ";") {
result = append(result, rawURL)
continue
}

// Check for matrix parameters or other parameter formats
if strings.Contains(rawURL, "=") {
result = append(result, rawURL)
}
}

return result
}
Loading

0 comments on commit 23bd08b

Please sign in to comment.