Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jselvi committed Jan 10, 2020
0 parents commit 3cad96b
Show file tree
Hide file tree
Showing 7 changed files with 409 additions and 0 deletions.
55 changes: 55 additions & 0 deletions README.md
@@ -0,0 +1,55 @@
# WStalker: an easy proxy

WStalker is a HTTP/HTTPS Proxy with full Request/Response logging. The main purpose of WStalker is to provide an easy way for developers to configure their testing tools to use this proxy and register the valid connections they use to test Web Services. The resulting CSV file can be used in security testing, by importing the requests/responses into your favourite testing tool.

## Compile or Download WStalker

To use it, you can compile your own binaries from the source code by running `./build.sh`.
You can also download a set of binaries that were already ready for you [from here](https://github.com/nccgroup/wstalker).

## Running WStalker

Once you have the binary, it is executed without any additional parameter. In Windows, it can be executed by double clicking the EXE file.

```
$ ./wstalker
2019/10/18 09:19:30 Creating HTTP Proxy
2019/10/18 09:19:30 Starting in 127.0.0.1:8080
2019/10/18 09:19:31 Saving Request in wstalker.csv
2019/10/18 09:19:31 Stalking Connections...
```

Now, it is necessary to configure the tool that we are using (browser or any other tool that we are using to test your web services) to use http://127.0.0.1:8080 as a proxy. When we start running requests, wstalker will start showing one line per request.

```
2019/10/18 09:20:53 GET - http://ifconfig.co/
2019/10/18 09:20:54 GET - http://detectportal.firefox.com/success.txt
2019/10/18 09:20:54 GET - http://detectportal.firefox.com/success.txt
2019/10/18 09:20:54 GET - http://detectportal.firefox.com/success.txt
2019/10/18 09:20:54 GET - http://ifconfig.co/favicon.ico
2019/10/18 09:20:54 GET - http://detectportal.firefox.com/success.txt
2019/10/18 09:20:54 GET - http://detectportal.firefox.com/success.txt
2019/10/18 09:20:54 GET - http://detectportal.firefox.com/success.txt
2019/10/18 09:20:54 GET - http://detectportal.firefox.com/success.txt
2019/10/18 09:20:54 GET - http://detectportal.firefox.com/success.txt
2019/10/18 09:20:54 GET - http://detectportal.firefox.com/success.txt
2019/10/18 09:20:54 GET - http://detectportal.firefox.com/success.txt
2019/10/18 09:20:54 GET - http://detectportal.firefox.com/success.txt
```

When all the tests have been performed, wstalker can be stopped by pressing CTRL+C or closing the window.

```
2019/10/18 09:21:01 Closing wstalker
```

## Output of WStalker

A file `wstalker.csv` will be generated, containing information about each request: `[REQUEST_IN_BASE64],[RESPONSE_IN_BASE64],METHOD,URL`.
Each new execution of `wstalker` appends the new requests and responses to the existing file.

This file could contain credentials and critical information, so it is recommended to send it encrypted or using a secure mechanisms.

## Do not install wstalker's CA

Note that wstalker is using a CA to generate certificates but, for simplicity purposes, that CA's private key is included in the code, so *PLEASE DO NOT INSTALL IT IN YOUR BROWSER OR OPERATING SYSTEM*, since that would mean that attackers could intercept your connections by generating certificates signed by wstalker's CA.
72 changes: 72 additions & 0 deletions cmd/wstalker/main.go
@@ -0,0 +1,72 @@
package main

import (
"fmt"
"log"
"os"
"os/signal"

"../../pkg/filedump"
"../../pkg/httproxy"
)

const (
addr = "127.0.0.1:8080"
filename = "wstalker.csv"
)

func main() {
// Create Proxy
log.Println("Creating HTTP Proxy")
h, e1 := httproxy.NewHttProxy()
if e1 != nil {
log.Fatal(e1)
}

// Start Proxy
log.Println("Starting in " + addr)
e1 = h.StartBackground(addr)
if e1 != nil {
log.Fatal(e1)
}

// Manage CTRL+C
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt)
go func() {
<-sig
fmt.Print("\r")
e := h.StopBackground()
if e != nil {
log.Fatal(e)
}
log.Println("Stopped HTTP Proxy")
}()

// Prepare FileDump
log.Println("Saving Request in " + filename)
f, e2 := filedump.NewFileDump(filename)
if e2 != nil {
log.Fatal(e2)
}
defer f.Close()

// Read until Stop
log.Println("Stalking Connections...")
for {
method, url, request, response, e := h.Read()
if e != nil {
break
}

// Print Method and URL
log.Println(method + " - " + url)

// Write into file
e = f.Write(method, url, request, response)
if e != nil {
log.Fatal(e)
}
}
log.Println("Closing wstalker")
}
3 changes: 3 additions & 0 deletions pkg/filedump/doc.go
@@ -0,0 +1,3 @@
package filedump

// Package filedump is...
36 changes: 36 additions & 0 deletions pkg/filedump/main.go
@@ -0,0 +1,36 @@
package filedump

import (
"fmt"
"os"
)

// FileDump is ...
type FileDump struct {
filename string
file *os.File
}

// NewFileDump function...
func NewFileDump(filename string) (*FileDump, error) {
var e error
f := &FileDump{}

f.filename = filename
f.file, e = os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if e != nil {
return nil, e
}

return f, nil
}

func (f *FileDump) Write(method, url, request, response string) error {
_, e := fmt.Fprintf(f.file, request+","+response+","+method+","+url+"\n")
return e
}

// Close function...
func (f *FileDump) Close() error {
return f.file.Close()
}
106 changes: 106 additions & 0 deletions pkg/httproxy/ca.go
@@ -0,0 +1,106 @@
package httproxy

import (
"crypto/tls"
"crypto/x509"

"github.com/elazarl/goproxy"
)

var caCert = []byte(`-----BEGIN CERTIFICATE-----
MIIEvDCCAqQCCQCD9c6+9fhpzzANBgkqhkiG9w0BAQsFADAgMQswCQYDVQQGEwJV
SzERMA8GA1UEAwwId3N0YWxrZXIwHhcNMTkwNjA3MTcyMzA3WhcNMTkwNzA3MTcy
MzA3WjAgMQswCQYDVQQGEwJVSzERMA8GA1UEAwwId3N0YWxrZXIwggIiMA0GCSqG
SIb3DQEBAQUAA4ICDwAwggIKAoICAQDFJA9cRVtsKCCFTPXAQTtPpfPACxddbRQf
wVwBMkwKjkobtVwfD8OG+Mr5rrDRikuaSBTOHof7Se6SQwpx4zWMM9xRWzvRaUeo
Dk6tJE7+pGQt+O5quqM+UFIGmlq2s4E/1eDIiaAHCFfa8CnZ5DbpHKug5CO+C3NJ
XV3A71CZjgMbel4xZd09BR6/yfGf8SB35R70aaJRpNUMdKSUU9PxzsXVFj/2EQLs
4PCycBDRRfJgLfitjrUUM6G7Qh42rKSW6oEFdBA1T6J3lr6jR03Ir9QxxAVbAfj3
43tGflYpJOQKL+ilJn+0U/H+yGTtvoDmZSkhK/IY/TEUrV8B3TuzYJm1ACkKArFI
MzplZ+YRCnOp/nE+Ohf2pAEV8ZEmlVuuGy3JN+GxvkHUwFtXXyXPtZ0eX4O8RtlF
oK7ZntoBRHwbBYtIJg7C1jWLLc9BhYAeAO6vT3kup1UCormvKaaxUuELkztaLqEf
8GXoQTyBVSwaDGHuJv+liFambNh20tm068844mjbXnLqRT6BGjlhSIz9/v3ElGfV
c22Ewer3xUZnmDUqzaljgQX5K+OGl7xW1Yrk0AFl/Enh7k0D8h9aSwEusbsUqvY+
8kTP7kN+qmuDSSGFsnJp0j1Zq7nzxpRelaUC2mFfvBqZWFkocwjmWLwFb6zWOb/J
1BP3C0OzlQIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQCHjpCxwwuY0NHS4FoMhNCd
gwfL6rcp4E2l+IpuaeYraqEA/suofxlh5LAWcqRqZH7S+XnOU5z+zl7thZp7lDJ1
uVVDpv0TqEUbveutn9kpJ7/DPF/AJ+BJMM6smoRH3WxYxJ8Zv129OoYtNh8SgkZq
tsp8NK3GbGqX7xbwBwmzrBvwwitIYuC28RB4s3/qVyIMfJ/nUN81HPROOZRL6UGi
TN2C3PLUtdHvLFZY9TzrUvK5aS8+oFAasaa79XcW6AFscARhHw2RdquWFl7tSL2v
zTD2dgtFzbwCx22dDzPWVLB8K4neuB6Kvm2ChivN+MrzUiplZbRGHQvIED0I7H8Y
3T3raTfuLSgLFW4x4Eq1J3ZjiCWV/hwWqistGwR6eWCmkFumc4Cv1SDdFDdpbT6B
xDyKqvJpsrjjf/tyU1qDBlGZ2VKYQ/Dh7VmtCTWE2CwkWsywOSApjlPdzVgQqQJh
LeQhVyzih1qJ24oBQP9xPcJM2aXzDvaP25zyrCo/Bz4Y1n9evQ0hhVH0r29LOEQC
4GOVk5gCvDyi8IVBr5Y//5pLq4dPlAo4kKdWmSjCB4zhawkhH3st6Z7VsKzWelAR
TjHiABHR5Y27cpPgAFe1bUoW25dpKqpaXo5WvuP3N7LSmRckIfQsv/EoqWTIK+dM
a1HDBNJoeWpbflmbuJZqCg==
-----END CERTIFICATE-----`)

// Intentionally left here. Check README.md for more information.
var caKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----`)

func (h *HttProxy) setCA(caCert, caKey []byte) error {
goproxyCa, err := tls.X509KeyPair(caCert, caKey)
if err != nil {
return err
}
if goproxyCa.Leaf, err = x509.ParseCertificate(goproxyCa.Certificate[0]); err != nil {
return err
}
goproxy.GoproxyCa = goproxyCa
goproxy.OkConnect = &goproxy.ConnectAction{Action: goproxy.ConnectAccept, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
goproxy.MitmConnect = &goproxy.ConnectAction{Action: goproxy.ConnectMitm, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
goproxy.HTTPMitmConnect = &goproxy.ConnectAction{Action: goproxy.ConnectHTTPMitm, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
goproxy.RejectConnect = &goproxy.ConnectAction{Action: goproxy.ConnectReject, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
return nil
}
3 changes: 3 additions & 0 deletions pkg/httproxy/doc.go
@@ -0,0 +1,3 @@
package httproxy

// Package httproxy is...

0 comments on commit 3cad96b

Please sign in to comment.