Skip to content

Commit

Permalink
Merge pull request #8 from liamg/liamg-add-vhost-scanning
Browse files Browse the repository at this point in the history
Add vhost scanning
  • Loading branch information
liamg authored Jan 12, 2020
2 parents d23ece3 + 248fccd commit 78cdd94
Show file tree
Hide file tree
Showing 18 changed files with 993 additions and 226 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/scout
/.idea
/.idea
/bin
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ build:
test:
GO111MODULE=on go test -v -race -timeout 30m ./...

import-wordlist:
./scripts/import-wordlist.sh
import-wordlists:
./scripts/import-wordlists.sh
90 changes: 82 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,100 @@

[![Travis Build Status](https://travis-ci.org/liamg/scout.svg?branch=master)](https://travis-ci.org/liamg/scout)

Scout is a URL fuzzer for discovering undisclosed files and directories on a web server.
Scout is a URL fuzzer for discovering undisclosed VHOSTS, files and directories on a web server.

<p align="center">
<img width="746" height="417" src="./demo.png" />
</p>

A full word list is included in the binary, meaning maximum portability and minimal configuration. Aim and fire!

## Usage

```bash


Usage:
scout [url] [flags]
scout [command]

Available Commands:
help Help about any command
url Discover URLs on a given web server.
vhost Discover VHOSTs on a given web server.

Flags:
-d, --debug Enable debug logging.
-x, --extensions stringArray File extensions to detect. (default [php,htm,html])
-h, --help help for scout
-n, --no-colours Disable coloured output.
-p, --parallelism int Parallel routines to use for sending requests. (default 10)
-w, --wordlist string Path to wordlist file. If this is not specified an internal wordlist will be used.
-d, --debug Enable debug logging.
-h, --help help for scout
-n, --no-colours Disable coloured output.
-p, --parallelism int Parallel routines to use for sending requests. (default 10)
-k, --skip-ssl-verify Skip SSL certificate verification.
-w, --wordlist string Path to wordlist file. If this is not specified an internal wordlist will be used.

Use "scout [command] --help" for more information about a command.

```


### Discover URLs

```bash
$ scout url http://192.168.1.1

[+] Target URL http://192.168.1.1
[+] Routines 10
[+] Extensions php,htm,html
[+] Positive Codes 200,302,301,400,403,500,405,204,401,301,302

[302] http://192.168.1.1/css
[302] http://192.168.1.1/js
[302] http://192.168.1.1/language
[302] http://192.168.1.1/style
[302] http://192.168.1.1/help
[401] http://192.168.1.1/index.htm
[302] http://192.168.1.1/image
[200] http://192.168.1.1/log.htm
[302] http://192.168.1.1/script
[401] http://192.168.1.1/top.html
[200] http://192.168.1.1/shares
[200] http://192.168.1.1/shares.php
[200] http://192.168.1.1/shares.htm
[200] http://192.168.1.1/shares.html
[401] http://192.168.1.1/traffic.htm
[401] http://192.168.1.1/reboot.htm
[302] http://192.168.1.1/debug
[401] http://192.168.1.1/debug.htm
[401] http://192.168.1.1/debug.html
[401] http://192.168.1.1/start.htm

Scan complete. 28 results found.

```

### Discover VHOSTs

```bash
$ scout vhost https://google.com

[+] Base Domain google.com
[+] Routines 10
[+] IP -
[+] Port -
[+] Using SSL true

[302] account.google.com
[302] accounts.google.com
[301] blog.google.com
[200] code.google.com
[301] dev.google.com
[302] local.google.com
[302] m.google.com
[301] mail.google.com
[301] mobile.google.com
[200] www.google.com
[301] admin.google.com
[302] chat.google.com

Scan complete. 12 results found.

```

Expand Down
74 changes: 74 additions & 0 deletions assets/vhost.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
a
account
accounts
admin
admin-dev
alpha
alpha-www
api
app
archive
b
beta
beta-www
blog
c
chat
clients
code
d
dev
development
dev-www
download
e
email
f
g
h
i
j
k
l
local
m
mail
mobile
n
o
p
panel
q
r
s
sandbox
secret
secure
staging
staging-www
status
t
test
testing
test-www
u
uat
upload
v
v1
v2
v3
v4
v5
v6
v7
v8
v9
w
web
www
www2
www3
x
y
z
179 changes: 0 additions & 179 deletions cmd/scout/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,190 +2,11 @@ package main

import (
"fmt"
"io/ioutil"
"log"
"net/url"
"os"
"strconv"
"strings"

"github.com/liamg/scout/pkg/scan"
"github.com/liamg/scout/pkg/wordlist"
"github.com/liamg/tml"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

var rootCmd = &cobra.Command{
Use: "scout [url]",
Short: "Scout is a portable URL fuzzer",
Long: `A fast and portable url fuzzer - see https://github.com/liamg/scout for more information`,
Run: func(cmd *cobra.Command, args []string) {

log.SetOutput(ioutil.Discard)

if debug {
logrus.SetLevel(logrus.DebugLevel)
}

if noColours {
tml.DisableFormatting()
}

if len(args) == 0 {
tml.Println("<bold><red>Error:</red></bold> You must specify a target URL.")
os.Exit(1)
}

parsedURL, err := url.ParseRequestURI(args[0])
if err != nil {
tml.Printf("<bold><red>Error:</red></bold> Invalid URL: %s\n", err)
os.Exit(1)
}

resultChan := make(chan scan.Result)
busyChan := make(chan string, 0x400)

var intStatusCodes []int

for _, code := range statusCodes {
i, err := strconv.Atoi(code)
if err != nil {
tml.Printf("<bold><red>Error:</red></bold> Invalid status code entered: %s.\n", code)
os.Exit(1)
}
intStatusCodes = append(intStatusCodes, i)
}

options := &scan.Options{
PositiveStatusCodes: intStatusCodes,
TargetURL: *parsedURL,
ResultChan: resultChan,
BusyChan: busyChan,
Parallelism: parallelism,
Extensions: extensions,
Filename: filename,
SkipSSLVerification: skipSSLVerification,
}
if wordlistPath != "" {
options.Wordlist, err = wordlist.FromFile(wordlistPath)
if err != nil {
tml.Printf("<bold><red>Error:</red></bold> %s\n", err)
os.Exit(1)
}
}
options.Inherit()

tml.Printf(
`
<blue>[</blue><yellow>+</yellow><blue>] Target URL</blue><yellow> %s
<blue>[</blue><yellow>+</yellow><blue>] Routines</blue><yellow> %d
<blue>[</blue><yellow>+</yellow><blue>] Extensions</blue><yellow> %s
<blue>[</blue><yellow>+</yellow><blue>] Positive Codes</blue><yellow> %s
`,
options.TargetURL.String(),
options.Parallelism,
strings.Join(options.Extensions, ","),
strings.Join(statusCodes, ","),
)

scanner := scan.NewScanner(options)

waitChan := make(chan struct{})

genericOutputChan := make(chan string)
importantOutputChan := make(chan string)

go func() {
for result := range resultChan {
importantOutputChan <- tml.Sprintf("<blue>[</blue><yellow>%d</yellow><blue>]</blue> %s\n", result.StatusCode, result.URL.String())
}
close(waitChan)
}()

go func() {
for uri := range busyChan {
genericOutputChan <- tml.Sprintf("Checking %s...", uri)
}
}()

outChan := make(chan struct{})
go func() {

defer close(outChan)

for {
select {
case output := <-importantOutputChan:
clearLine()
fmt.Printf(output)
FLUSH:
for {
select {
case str := <-genericOutputChan:
if str == "" {
break FLUSH
}
default:
break FLUSH
}
}
case <-waitChan:
return
case output := <-genericOutputChan:
clearLine()
fmt.Printf(output)
}
}

}()

results, err := scanner.Scan()
if err != nil {
clearLine()
tml.Printf("<bold><red>Error:</red></bold> %s\n", err)
os.Exit(1)
}
logrus.Debug("Waiting for output to flush...")
<-waitChan
close(genericOutputChan)
<-outChan

clearLine()
tml.Printf("\n<bold><green>Scan complete. %d results found.</green></bold>\n\n", len(results))

},
}

func clearLine() {
fmt.Printf("\033[2K\r")
}

var parallelism = scan.DefaultOptions.Parallelism
var extensions = scan.DefaultOptions.Extensions
var statusCodes []string
var noColours = false
var wordlistPath string
var debug bool
var filename string
var skipSSLVerification bool

func main() {

for _, code := range scan.DefaultOptions.PositiveStatusCodes {
statusCodes = append(statusCodes, strconv.Itoa(code))
}

rootCmd.Flags().IntVarP(&parallelism, "parallelism", "p", parallelism, "Parallel routines to use for sending requests.")
rootCmd.Flags().StringSliceVarP(&extensions, "extensions", "x", extensions, "File extensions to detect.")
rootCmd.Flags().BoolVarP(&noColours, "no-colours", "n", noColours, "Disable coloured output.")
rootCmd.Flags().StringVarP(&wordlistPath, "wordlist", "w", wordlistPath, "Path to wordlist file. If this is not specified an internal wordlist will be used.")
rootCmd.Flags().BoolVarP(&debug, "debug", "d", debug, "Enable debug logging.")
rootCmd.Flags().StringVarP(&filename, "filename", "f", filename, "Filename to seek in the directory being searched. Useful when all directories report 404 status.")
rootCmd.Flags().BoolVarP(&skipSSLVerification, "skip-ssl-verify", "k", skipSSLVerification, "Skip SSL certificate verification.")
rootCmd.Flags().StringSliceVarP(&statusCodes, "status-codes", "s", statusCodes, "HTTP status codes which indicate a positive find.")

if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
Expand Down
Loading

0 comments on commit 78cdd94

Please sign in to comment.