Skip to content

Commit

Permalink
Add vhost scanning
Browse files Browse the repository at this point in the history
  • Loading branch information
liamg committed Jan 12, 2020
1 parent fc4c7dc commit 251b6b7
Show file tree
Hide file tree
Showing 14 changed files with 405 additions and 87 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
80 changes: 73 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,90 @@ A full word list is included in the binary, meaning maximum portability and mini

```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.

```

## Installation

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
3 changes: 3 additions & 0 deletions cmd/scout/url.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ var urlCmd = &cobra.Command{
}()

go func() {
defer func() {
_ = recover()
}()
for uri := range busyChan {
genericOutputChan <- tml.Sprintf("Checking %s...", uri)
}
Expand Down
66 changes: 47 additions & 19 deletions cmd/scout/vhost.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ import (
"github.com/spf13/cobra"
)

var ip string
var port int
var useSSL bool
var contentHashing bool

var vhostCmd = &cobra.Command{
Use: "vhost [base_domain]",
Short: "Discover VHOSTs on a given web server.",
Expand All @@ -39,6 +44,10 @@ var vhostCmd = &cobra.Command{

baseDomain := args[0]

if strings.HasPrefix(baseDomain, "https://") {
useSSL = true
}

if parsedURL, err := url.Parse(args[0]); err == nil && parsedURL.Host != "" {
baseDomain = parsedURL.Host
}
Expand All @@ -47,9 +56,7 @@ var vhostCmd = &cobra.Command{
baseDomain = baseDomain[:strings.Index(baseDomain, "/")]
}

panic(baseDomain)

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

var intStatusCodes []int
Expand All @@ -63,14 +70,25 @@ var vhostCmd = &cobra.Command{
intStatusCodes = append(intStatusCodes, i)
}

options := &scan.URLOptions{
PositiveStatusCodes: intStatusCodes,
ResultChan: resultChan,
BusyChan: busyChan,
Parallelism: parallelism,
Extensions: extensions,
Filename: filename,
SkipSSLVerification: skipSSLVerification,
ipStr := ip
if ipStr == "" {
ipStr = "-"
}

portStr := strconv.Itoa(port)
if port == 0 {
portStr = "-"
}

options := &scan.VHOSTOptions{
BaseDomain: baseDomain,
Parallelism: parallelism,
ResultChan: resultChan,
BusyChan: busyChan,
UseSSL: useSSL,
IP: ip,
Port: port,
ContentHashing: contentHashing,
}
if wordlistPath != "" {
var err error
Expand All @@ -84,19 +102,21 @@ var vhostCmd = &cobra.Command{

tml.Printf(
`
<blue>[</blue><yellow>+</yellow><blue>] Target URL</blue><yellow> %s
<blue>[</blue><yellow>+</yellow><blue>] Base Domain</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
<blue>[</blue><yellow>+</yellow><blue>] IP</blue><yellow> %s
<blue>[</blue><yellow>+</yellow><blue>] Port</blue><yellow> %s
<blue>[</blue><yellow>+</yellow><blue>] Using SSL</blue><yellow> %t
`,
options.TargetURL.String(),
options.BaseDomain,
options.Parallelism,
strings.Join(options.Extensions, ","),
strings.Join(statusCodes, ","),
ipStr,
portStr,
options.UseSSL,
)

scanner := scan.NewURLScanner(options)
scanner := scan.NewVHOSTScanner(options)

waitChan := make(chan struct{})

Expand All @@ -105,12 +125,15 @@ var vhostCmd = &cobra.Command{

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

go func() {
defer func() {
_ = recover()
}()
for uri := range busyChan {
genericOutputChan <- tml.Sprintf("Checking %s...", uri)
}
Expand Down Expand Up @@ -166,5 +189,10 @@ var vhostCmd = &cobra.Command{

func init() {

vhostCmd.Flags().BoolVar(&useSSL, "ssl", useSSL, "Use HTTPS when connecting to the server.")
vhostCmd.Flags().StringVar(&ip, "ip", ip, "IP address to connect to - defaults to the DNS A record for the base domain.")
vhostCmd.Flags().IntVar(&port, "port", port, "Port to connect to - defaults to 80 or 443 if --ssl is set.")
vhostCmd.Flags().BoolVar(&contentHashing, "hash-contents", contentHashing, "Hash each response body to detect differences for catch-all scenarios.")

rootCmd.AddCommand(vhostCmd)
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.13

require (
github.com/avast/retry-go v2.4.3+incompatible
github.com/go-bindata/go-bindata v3.1.2+incompatible // indirect
github.com/liamg/tml v0.2.0
github.com/magiconair/properties v1.8.0
github.com/sirupsen/logrus v1.4.2
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-bindata/go-bindata v3.1.2+incompatible h1:5vjJMVhowQdPzjE1LdxyFF7YFTXg5IgGVW4gBr5IbvE=
github.com/go-bindata/go-bindata v3.1.2+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
Expand Down

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions pkg/scan/url_scanner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/stretchr/testify/require"
)

func TestScanner(t *testing.T) {
func TestURLScanner(t *testing.T) {

server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
Expand Down Expand Up @@ -45,7 +45,7 @@ func TestScanner(t *testing.T) {

}

func TestRedirects(t *testing.T) {
func TestURLScannerWithRedirects(t *testing.T) {

server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
Expand Down
14 changes: 8 additions & 6 deletions pkg/scan/vhost_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ import (
)

type VHOSTOptions struct {
BaseDomain string // target url
Timeout time.Duration // http request timeout
Parallelism int // parallel routines
ResultChan chan URLResult // chan to return results on - otherwise will be returned in slice
BusyChan chan string // chan to use to update current job
BaseDomain string // target url
Timeout time.Duration // http request timeout
Parallelism int // parallel routines
ResultChan chan VHOSTResult // chan to return results on - otherwise will be returned in slice
BusyChan chan string // chan to use to update current job
Wordlist wordlist.Wordlist
SkipSSLVerification bool
UseSSL bool
IP string
Port int
ContentHashing bool
}

type VHOSTResult struct {
Expand All @@ -38,7 +40,7 @@ func (opt *VHOSTOptions) Inherit() {
opt.Parallelism = DefaultURLOptions.Parallelism
}
if opt.Wordlist == nil {
wordlistBytes, err := data.Asset("assets/wordlist.txt")
wordlistBytes, err := data.Asset("assets/vhost.txt")
if err != nil {
wordlistBytes = []byte{}
}
Expand Down
Loading

0 comments on commit 251b6b7

Please sign in to comment.