Our Blog

gowitness – a new tool for an old idea

Reading time ~4 min

On a recent assessment I had an incredibly large IP space that was in scope. Almost an entire /8 to be precise. While it is possible to scan ranges like that with things like masscan, nmap and the likes, I was interested in web interfaces for this particular client as I quickly came to realise that they had a large amount of third party web services exposed with default login credentials left unchanged. Nessus would tell me that “there is a web interface running there”, but I wanted more in terms of what is running.

This is definitely not a new idea. A quick google reveals Eyewitness that seems to do exactly what I wanted. It has many great features like taking screenies of web interfaces as well as VNC/RDP sessions together with attempting to login using default credentials. Neat! The only pity was, it took quite a bit of time to run and you had to provide it a list of urls to work through. Other projects also exist such as http-screenshot-htmlhttpscreenshot and Snapper.

My love for Golang increases every day, and with the likes of Chrome Headless being around now, I figured I’d take a shot at implementing something that will let me screenshot whatever is found in a CIDR range using a single go binary. Once that is done, an HTML report should be generated letting you scroll through all of the interfaces that were found, including the response headers and any additional DNS names found in the web services’ SSL certificate (if it had any). I started building on this idea a while back actually, but only recently needed to get it in a functional state.

So, gowitness is born. At its core, gowitness will let you scan a CIDR range on a number of ports using both http and https protocols. Any web interfaces found will have its response headers recorded, along with a bunch of information about the SSL certificate (if one is presented). Then, a screenshot is taken using Chrome Headless and stored on disk. All of this is done using goroutines for some concurrency. This can be tuned heavily depending on your network speed. To give you an idea of speed, on my last assessment I managed to scan 2 /16’s and a /17 network together with taking ~1600 screenshots in just under 3 hours using 100 “threads” (specified with --threads 100). If you have a ton of web interfaces within the IP range, beware to not specify too many threads as Chrome might just eat your computer alive. Once the scan is complete, a report can be generated and opened in a browser to scroll through the results.

Scanning a network is not all gowitness can do. It is also possible to provide a file containing URL’s as source, or just scan and screenshot a single URL. Lets look at some examples:

Scanning a small CIDR using the default number of threads and wait timeout. 16 permutations are created as ports 80,443,8080 and 8443 are scanned using both http and https:

An example single URL scan:

Finally, when running gowitness generate, a report is generated that can used to view the results of the scan. A report may look as follows:

gowitness report output

chrome and “ignore-ssl-errors”

This one bit me, hard. After spending a ton of time building this tool, I realised that web interfaces with invalid SSL certificates were not getting screenshots taken. A known limitation it seems, but not something I could wait for to get implemented. I quickly looked at Firefox’ headless features and noticed that it doesn’t allow you to concurrently run multiple instances, meaning my goroutines would be useless. MEH.

Plan B it is! Without the ability to screenshot SSL enabled web interfaces, this tools implementation with Chrome Headless would be a dead end. Thankfully though, considering we are using Golang, we could use the built in NewSingleHostReverseProxy helper, which I did. What this means is that as soon as gowitness detects that an SSL enabled web interface should have a screenshot taken, it will start a new HTTP -> HTTPS reverse proxy on a random port and configure the command line arguments for Chrome Headless to rather connect to the proxy on localhost using plain HTTP and screenshot that. The reverse proxy is then configured to ignore any SSL related errors and just passthrough requests and responses. B-)

get the code / tool!

You can find gowitness on Github today at https://github.com/sensepost/gowitness! Releases are available for many platforms, or you can build from source.