143 lines
3.3 KiB
Go
143 lines
3.3 KiB
Go
package gobustertftp
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"text/tabwriter"
|
|
|
|
"git.sual.in/casual/gobuster-lib/libgobuster"
|
|
|
|
"github.com/pin/tftp/v3"
|
|
)
|
|
|
|
// GobusterTFTP is the main type to implement the interface
|
|
type GobusterTFTP struct {
|
|
globalopts *libgobuster.Options
|
|
options *OptionsTFTP
|
|
}
|
|
|
|
// NewGobusterTFTP creates a new initialized NewGobusterTFTP
|
|
func NewGobusterTFTP(globalopts *libgobuster.Options, opts *OptionsTFTP) (*GobusterTFTP, error) {
|
|
if globalopts == nil {
|
|
return nil, fmt.Errorf("please provide valid global options")
|
|
}
|
|
|
|
if opts == nil {
|
|
return nil, fmt.Errorf("please provide valid plugin options")
|
|
}
|
|
|
|
g := GobusterTFTP{
|
|
options: opts,
|
|
globalopts: globalopts,
|
|
}
|
|
return &g, nil
|
|
}
|
|
|
|
// Name should return the name of the plugin
|
|
func (d *GobusterTFTP) Name() string {
|
|
return "TFTP enumeration"
|
|
}
|
|
|
|
// PreRun is the pre run implementation of gobustertftp
|
|
func (d *GobusterTFTP) PreRun(ctx context.Context, progress *libgobuster.Progress) error {
|
|
_, err := tftp.NewClient(d.options.Server)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ProcessWord is the process implementation of gobustertftp
|
|
func (d *GobusterTFTP) ProcessWord(ctx context.Context, word string, progress *libgobuster.Progress) error {
|
|
c, err := tftp.NewClient(d.options.Server)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.SetTimeout(d.options.Timeout)
|
|
wt, err := c.Receive(word, "octet")
|
|
if err != nil {
|
|
// file not found
|
|
if d.globalopts.Verbose {
|
|
progress.ResultChan <- Result{
|
|
Filename: word,
|
|
Found: false,
|
|
ErrorMessage: err.Error(),
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
result := Result{
|
|
Filename: word,
|
|
Found: true,
|
|
}
|
|
if n, ok := wt.(tftp.IncomingTransfer).Size(); ok {
|
|
result.Size = n
|
|
}
|
|
progress.ResultChan <- result
|
|
return nil
|
|
}
|
|
|
|
func (d *GobusterTFTP) AdditionalWords(word string) []string {
|
|
return []string{}
|
|
}
|
|
|
|
// GetConfigString returns the string representation of the current config
|
|
func (d *GobusterTFTP) GetConfigString() (string, error) {
|
|
var buffer bytes.Buffer
|
|
bw := bufio.NewWriter(&buffer)
|
|
tw := tabwriter.NewWriter(bw, 0, 5, 3, ' ', 0)
|
|
o := d.options
|
|
|
|
if _, err := fmt.Fprintf(tw, "[+] Server:\t%s\n", o.Server); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if _, err := fmt.Fprintf(tw, "[+] Threads:\t%d\n", d.globalopts.Threads); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if d.globalopts.Delay > 0 {
|
|
if _, err := fmt.Fprintf(tw, "[+] Delay:\t%s\n", d.globalopts.Delay); err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
|
|
if _, err := fmt.Fprintf(tw, "[+] Timeout:\t%s\n", o.Timeout.String()); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
wordlist := "stdin (pipe)"
|
|
if d.globalopts.Wordlist != "-" {
|
|
wordlist = d.globalopts.Wordlist
|
|
}
|
|
if _, err := fmt.Fprintf(tw, "[+] Wordlist:\t%s\n", wordlist); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if d.globalopts.PatternFile != "" {
|
|
if _, err := fmt.Fprintf(tw, "[+] Patterns:\t%s (%d entries)\n", d.globalopts.PatternFile, len(d.globalopts.Patterns)); err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
|
|
if d.globalopts.Verbose {
|
|
if _, err := fmt.Fprintf(tw, "[+] Verbose:\ttrue\n"); err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
|
|
if err := tw.Flush(); err != nil {
|
|
return "", fmt.Errorf("error on tostring: %w", err)
|
|
}
|
|
|
|
if err := bw.Flush(); err != nil {
|
|
return "", fmt.Errorf("error on tostring: %w", err)
|
|
}
|
|
|
|
return strings.TrimSpace(buffer.String()), nil
|
|
}
|