Compare commits

..

1 Commits

26 changed files with 257 additions and 553 deletions

View File

@ -58,7 +58,7 @@ This [should not be news](http://arstechnica.com/security/2016/02/default-settin
* Determine client IP addresses if you are co-hosting a clearnet site.
* Determine your IP address if your setup allows.
* Determine other sites you are co-hosting.
* Determine how active your site is.
* Determine how active your site it.
* Find secret or hidden areas of your site
* and much, much more.

View File

@ -1,34 +1,15 @@
package config
import (
"log"
"time"
)
type OnionscanConfig struct {
TorProxyAddress string
DirectoryDepth int
Fingerprint bool
Timeout time.Duration
Verbose bool
}
func Configure(torProxyAddress string, directoryDepth int, fingerprint bool, timeout int, verbose bool) *OnionscanConfig {
func Configure(torProxyAddress string, directoryDepth int, fingerprint bool) *OnionscanConfig {
onionScan := new(OnionscanConfig)
onionScan.TorProxyAddress = torProxyAddress
onionScan.DirectoryDepth = directoryDepth
onionScan.Fingerprint = fingerprint
onionScan.Timeout = time.Duration(time.Second * time.Duration(timeout))
onionScan.Verbose = verbose
return onionScan
}
func (os *OnionscanConfig) LogInfo(message string) {
if os.Verbose {
log.Printf("INFO: %v", message)
}
}
func (os *OnionscanConfig) LogError(err error) {
log.Printf("ERROR: %v", err)
}

81
main.go
View File

@ -1,7 +1,6 @@
package main
import (
"errors"
"flag"
"fmt"
"github.com/s-rah/onionscan/config"
@ -9,96 +8,54 @@ import (
"io/ioutil"
"log"
"os"
"strings"
)
func main() {
flag.Usage = func() {
fmt.Printf("Usage of %s:\n", os.Args[0])
fmt.Printf(" onionscan [flags] hiddenservice | onionscan [flags] --list list\n")
fmt.Printf(" onionscan [flags] hiddenservice\n")
flag.PrintDefaults()
}
torProxyAddress := flag.String("torProxyAddress", "127.0.0.1:9050", "the address of the tor proxy to use")
simpleReport := flag.Bool("simpleReport", true, "print out a simple report detailing what is wrong and how to fix it, true by default")
reportFile := flag.String("reportFile", "", "the file destination path for report file - if given, the prefix of the file will be the scanned onion service. If not given, the report will be written to stdout")
reportFile := flag.String("reportFile", "", "the file destination path for report file")
jsonReport := flag.Bool("jsonReport", false, "print out a json report providing a detailed report of the scan.")
verbose := flag.Bool("verbose", false, "print out a verbose log output of the scan")
directoryDepth := flag.Int("depth", 100, "depth of directory scan recursion (default: 100)")
fingerprint := flag.Bool("fingerprint", true, "true disables some deeper scans e.g. directory probing with the aim of just getting a fingerprint of the service.")
list := flag.String("list", "", "If provided OnionScan will attempt to read from the given list, rather than the provided hidden service")
timeout := flag.Int("timeout", 120, "read timeout for connecting to onion services")
batch := flag.Int("batch", 10, "number of onions to scan concurrently")
fingerprint := flag.Bool("fingerprint", true, "whether to conduct a full scan, or just fingerprint possible ports")
flag.Parse()
if len(flag.Args()) != 1 && *list == "" {
if len(flag.Args()) != 1 {
flag.Usage()
os.Exit(1)
}
if !*simpleReport && !*jsonReport {
log.Fatalf("You must set one of --simpleReport or --jsonReport")
}
hiddenService := flag.Args()[0]
onionsToScan := []string{}
if *list == "" {
onionsToScan = append(onionsToScan, flag.Args()[0])
log.Printf("Starting Scan of %s\n", flag.Args()[0])
} else {
content, err := ioutil.ReadFile(*list)
if err != nil {
log.Fatalf("Could not read onion file %s\n", *list)
}
onions := strings.Split(string(content), "\n")
for _, onion := range onions[0 : len(onions)-1] {
onionsToScan = append(onionsToScan, onion)
}
log.Printf("Starting Scan of %d onion services\n", len(onionsToScan))
}
log.Printf("Starting Scan of %s\n", hiddenService)
log.Printf("This might take a few minutes..\n\n")
if !*verbose {
log.SetOutput(ioutil.Discard)
}
onionScan := new(OnionScan)
onionScan.Config = config.Configure(*torProxyAddress, *directoryDepth, *fingerprint, *timeout, *verbose)
onionScan.Config = config.Configure(*torProxyAddress, *directoryDepth, *fingerprint)
scanReport, err := onionScan.Scan(hiddenService)
reports := make(chan *report.OnionScanReport)
count := 0
if *batch > len(onionsToScan) {
*batch = len(onionsToScan)
if *jsonReport {
report.GenerateJsonReport(*reportFile, scanReport)
}
// Run an initial batch of 100 requests (or less...)
for count < *batch {
go onionScan.Scan(onionsToScan[count], reports)
count++
if *simpleReport {
report.GenerateSimpleReport(*reportFile, scanReport)
}
received := 0
for received < len(onionsToScan) {
scanReport := <-reports
// After the initial batch, it's one in one out to prevent proxy overload.
if count < len(onionsToScan) {
go onionScan.Scan(onionsToScan[count], reports)
count++
}
received++
if scanReport.TimedOut {
onionScan.Config.LogError(errors.New(scanReport.HiddenService + " timed out"))
}
file := *reportFile
if file != "" {
file = scanReport.HiddenService + "." + *reportFile
}
if *jsonReport {
report.GenerateJsonReport(file, scanReport)
} else if *simpleReport {
report.GenerateSimpleReport(file, scanReport)
}
if !*jsonReport && err != nil {
log.Fatalf("Error running scanner: %s", err)
}
}

View File

@ -1,72 +1,20 @@
package main
import (
"errors"
"github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/protocol"
"github.com/s-rah/onionscan/report"
"github.com/s-rah/onionscan/utils"
"log"
"strings"
"time"
)
type OnionScan struct {
Config *config.OnionscanConfig
}
func (os *OnionScan) PerformNextAction(report *report.OnionScanReport) {
switch report.NextAction {
case "web":
wps := new(protocol.HTTPProtocolScanner)
wps.ScanProtocol(report.HiddenService, os.Config, report)
report.NextAction = "tls"
case "tls":
tps := new(protocol.TLSProtocolScanner)
tps.ScanProtocol(report.HiddenService, os.Config, report)
report.NextAction = "ssh"
case "ssh":
sps := new(protocol.SSHProtocolScanner)
sps.ScanProtocol(report.HiddenService, os.Config, report)
report.NextAction = "irc"
case "irc":
ips := new(protocol.IRCProtocolScanner)
ips.ScanProtocol(report.HiddenService, os.Config, report)
report.NextAction = "ricochet"
case "ricochet":
rps := new(protocol.RicochetProtocolScanner)
rps.ScanProtocol(report.HiddenService, os.Config, report)
report.NextAction = "ftp"
case "ftp":
fps := new(protocol.FTPProtocolScanner)
fps.ScanProtocol(report.HiddenService, os.Config, report)
report.NextAction = "smtp"
case "smtp":
smps := new(protocol.SMTPProtocolScanner)
smps.ScanProtocol(report.HiddenService, os.Config, report)
report.NextAction = "mongodb"
case "mongodb":
mdbps := new(protocol.MongoDBProtocolScanner)
mdbps.ScanProtocol(report.HiddenService, os.Config, report)
report.NextAction = "vnc"
case "vnc":
vncps := new(protocol.VNCProtocolScanner)
vncps.ScanProtocol(report.HiddenService, os.Config, report)
report.NextAction = "xmpp"
case "xmpp":
xmppps := new(protocol.XMPPProtocolScanner)
xmppps.ScanProtocol(report.HiddenService, os.Config, report)
report.NextAction = "bitcoin"
case "bitcoin":
bps := new(protocol.BitcoinProtocolScanner)
bps.ScanProtocol(report.HiddenService, os.Config, report)
report.NextAction = "none"
case "none":
return
default:
report.NextAction = "web"
}
}
func (os *OnionScan) Scan(hiddenService string, out chan *report.OnionScanReport) {
func (os *OnionScan) Scan(hiddenService string) (*report.OnionScanReport, error) {
// Remove Extra Prefix
hiddenService = utils.WithoutProtocol(hiddenService)
@ -77,13 +25,46 @@ func (os *OnionScan) Scan(hiddenService string, out chan *report.OnionScanReport
report := report.NewOnionScanReport(hiddenService)
for report.NextAction != "none" {
os.PerformNextAction(report)
if time.Now().Sub(report.DateScanned).Seconds() > os.Config.Timeout.Seconds() {
report.TimedOut = true
report.NextAction = "none"
}
// HTTP
hps := new(protocol.HTTPProtocolScanner)
hps.ScanProtocol(hiddenService, os.Config, report)
// SSH
sps := new(protocol.SSHProtocolScanner)
sps.ScanProtocol(hiddenService, os.Config, report)
// Ricochet
rps := new(protocol.RicochetProtocolScanner)
rps.ScanProtocol(hiddenService, os.Config, report)
// Bitcoin
bps := new(protocol.BitcoinProtocolScanner)
bps.ScanProtocol(hiddenService, os.Config, report)
//IRC
ips := new(protocol.IRCProtocolScanner)
ips.ScanProtocol(hiddenService, os.Config, report)
//FTP
fps := new(protocol.FTPProtocolScanner)
fps.ScanProtocol(hiddenService, os.Config, report)
//SMTP
smps := new(protocol.SMTPProtocolScanner)
smps.ScanProtocol(hiddenService, os.Config, report)
//MongoDb
mdbps := new(protocol.MongoDBProtocolScanner)
mdbps.ScanProtocol(hiddenService, os.Config, report)
//VNC
vncps := new(protocol.VNCProtocolScanner)
vncps.ScanProtocol(hiddenService, os.Config, report)
if !report.WebDetected && !report.SSHDetected && !report.RicochetDetected && !report.BitcoinDetected && !report.IRCDetected && !report.FTPDetected && !report.SMTPDetected && !report.MongoDBDetected {
log.Printf("Unable to connect to this Tor Hidden Service on any known protocol.\n")
return nil, errors.New("Unable to connect to this Tor Hidden Service on any known protocol.")
}
out <- report
return report, nil
}

View File

@ -1,28 +1,26 @@
package protocol
import (
"fmt"
"github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report"
"github.com/s-rah/onionscan/utils"
"h12.me/socks"
"log"
)
type BitcoinProtocolScanner struct {
}
func (rps *BitcoinProtocolScanner) ScanProtocol(hiddenService string, osc *config.OnionscanConfig, report *report.OnionScanReport) {
func (rps *BitcoinProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) {
// Bitcoin
osc.LogInfo(fmt.Sprintf("Checking %s Bitcoin(8333)\n", hiddenService))
conn, err := utils.GetNetworkConnection(hiddenService, 8333, osc.TorProxyAddress, osc.Timeout)
log.Printf("Checking %s Bitcoin(8333)\n", hiddenService)
_, err := socks.DialSocksProxy(socks.SOCKS5, onionscanConfig.TorProxyAddress)("", hiddenService+":8333")
if err != nil {
osc.LogInfo("Failed to connect to service on port 8333\n")
log.Printf("Failed to connect to service on port 8333\n")
report.BitcoinDetected = false
} else {
osc.LogInfo("Detected possible Bitcoin instance\n")
log.Printf("Detected possible Bitcoin instance\n")
// TODO: Actual Analysis
report.BitcoinDetected = true
}
if conn != nil {
conn.Close()
}
}

View File

@ -4,23 +4,24 @@ import (
"bufio"
"crypto/sha1"
"encoding/hex"
"fmt"
"github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report"
"github.com/s-rah/onionscan/utils"
"h12.me/socks"
"log"
)
type FTPProtocolScanner struct {
}
func (sps *FTPProtocolScanner) ScanProtocol(hiddenService string, osc *config.OnionscanConfig, report *report.OnionScanReport) {
func (sps *FTPProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) {
// FTP
osc.LogInfo(fmt.Sprintf("Checking %s FTP(21)\n", hiddenService))
conn, err := utils.GetNetworkConnection(hiddenService, 21, osc.TorProxyAddress, osc.Timeout)
log.Printf("Checking %s FTP(21)\n", hiddenService)
conn, err := socks.DialSocksProxy(socks.SOCKS5, onionscanConfig.TorProxyAddress)("", hiddenService+":21")
if err != nil {
osc.LogInfo("Failed to connect to service on port 21\n")
log.Printf("Failed to connect to service on port 21\n")
report.FTPDetected = false
} else {
// TODO FTP Checking
report.FTPDetected = true
reader := bufio.NewReader(conn)
banner, err := reader.ReadString('\n')
@ -28,10 +29,8 @@ func (sps *FTPProtocolScanner) ScanProtocol(hiddenService string, osc *config.On
report.FTPBanner = banner
hash := sha1.Sum([]byte(banner))
report.FTPFingerprint = hex.EncodeToString(hash[:])
osc.LogInfo(fmt.Sprintf("Found FTP Banner: %s (%s)", banner, report.FTPFingerprint))
log.Printf("Found FTP Banner: %s (%s)", banner, report.FTPFingerprint)
}
}
if conn != nil {
conn.Close()
}
}

View File

@ -1,14 +1,13 @@
package protocol
import (
"crypto/tls"
"fmt"
"github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report"
"github.com/s-rah/onionscan/scans"
"github.com/s-rah/onionscan/utils"
"h12.me/socks"
"io/ioutil"
"log"
"net/http"
"strings"
)
@ -25,72 +24,63 @@ var (
"/products", "/products/cat"}
)
func (hps *HTTPProtocolScanner) ScanProtocol(hiddenService string, osc *config.OnionscanConfig, report *report.OnionScanReport) {
func (hps *HTTPProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) {
// HTTP
osc.LogInfo(fmt.Sprintf("Checking %s http(80)\n", hiddenService))
conn, err := utils.GetNetworkConnection(hiddenService, 80, osc.TorProxyAddress, osc.Timeout)
log.Printf("Checking %s http(80)\n", hiddenService)
_, err := socks.DialSocksProxy(socks.SOCKS5, onionscanConfig.TorProxyAddress)("", hiddenService+":80")
if err != nil {
osc.LogInfo("Failed to connect to service on port 80\n")
log.Printf("Failed to connect to service on port 80\n")
report.WebDetected = false
if conn != nil {
conn.Close()
}
return
} else {
osc.LogInfo("Found potential service on http(80)\n")
log.Printf("Found potential service on http(80)\n")
report.WebDetected = true
conn.Close()
dialSocksProxy := socks.DialSocksProxy(socks.SOCKS5, osc.TorProxyAddress)
dialSocksProxy := socks.DialSocksProxy(socks.SOCKS5, onionscanConfig.TorProxyAddress)
transportConfig := &http.Transport{
Dial: dialSocksProxy,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
hps.Client = &http.Client{
Transport: transportConfig,
Dial: dialSocksProxy,
}
hps.Client = &http.Client{Transport: transportConfig}
// FIXME This should probably be moved to it's own file now.
response, err := hps.Client.Get("http://" + hiddenService)
if err == nil {
// Reading all http headers
osc.LogInfo(fmt.Sprintf("HTTP response headers: %s\n", report.ServerVersion))
responseHeaders := response.Header
for key := range responseHeaders {
value := responseHeaders.Get(key)
// normalize by strings.ToUpper(key) to avoid case sensitive checking
report.AddResponseHeader(strings.ToUpper(key), value)
}
report.ServerVersion = responseHeaders.Get("Server")
response.Body.Close()
} else {
osc.LogError(err)
if err != nil {
log.Printf("Failed to connect to service on port 80\n")
return
}
// Apache mod-status Check
hps.ScanPage(hiddenService, "/", report, osc, scans.StandardPageScan)
hps.ScanPage(hiddenService, "/server-status", report, osc, scans.ApacheModStatus)
hps.ScanPage(hiddenService, "/private_key", report, osc, scans.PrivateKeyScan)
// Reading all http headers
log.Printf("HTTP response headers: %s\n", report.ServerVersion)
responseHeaders := response.Header
for key := range responseHeaders {
value := responseHeaders.Get(key)
// normalize by strings.ToUpper(key) to avoid case sensitive checking
report.AddResponseHeader(strings.ToUpper(key), value)
log.Printf("\t%s : %s\n", strings.ToUpper(key), value)
}
if osc.Fingerprint == false {
osc.LogInfo("\tScanning Common and Referenced Directories\n")
report.ServerVersion = responseHeaders.Get("Server")
// Apache mod-status Check
hps.ScanPage(hiddenService, "/server-status", report, scans.ApacheModStatus)
hps.ScanPage(hiddenService, "/", report, scans.StandardPageScan)
if onionscanConfig.Fingerprint == false {
log.Printf("\tScanning Common and Referenced Directories\n")
directories := append(CommonDirectories, report.PageReferencedDirectories...)
utils.RemoveDuplicates(&directories)
for _, directory := range directories {
hps.ScanPage(hiddenService, directory, report, osc, scans.CheckDirectoryListing(osc.DirectoryDepth))
hps.ScanPage(hiddenService, directory, report, scans.CheckDirectoryListing(onionscanConfig.DirectoryDepth))
}
}
}
log.Printf("\n")
}
func (hps *HTTPProtocolScanner) ScanPage(hiddenService string, page string, report *report.OnionScanReport, osc *config.OnionscanConfig, f func(scans.Scanner, string, int, string, *report.OnionScanReport, *config.OnionscanConfig)) {
err, contents, responseCode := hps.ScrapePage(hiddenService, page)
if err == nil {
f(hps, page, responseCode, string(contents), report, osc)
return
} else {
osc.LogError(err)
}
func (hps *HTTPProtocolScanner) ScanPage(hiddenService string, page string, report *report.OnionScanReport, f func(scans.Scanner, string, int, string, *report.OnionScanReport)) {
_, contents, responseCode := hps.ScrapePage(hiddenService, page)
f(hps, page, responseCode, string(contents), report)
}
func (hps *HTTPProtocolScanner) ScrapePage(hiddenService string, page string) (error, []byte, int) {
@ -102,6 +92,7 @@ func (hps *HTTPProtocolScanner) ScrapePage(hiddenService string, page string) (e
}
response, err := hps.Client.Get("http://" + page)
if err != nil {
log.Printf("Error connecting to http://%s %s\n", page, err)
return err, nil, -1
}
defer response.Body.Close()

View File

@ -1,42 +1,26 @@
package protocol
import (
"fmt"
"github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report"
"github.com/s-rah/onionscan/utils"
"h12.me/socks"
"log"
)
type IRCProtocolScanner struct {
}
func (rps *IRCProtocolScanner) ScanProtocol(hiddenService string, osc *config.OnionscanConfig, report *report.OnionScanReport) {
func (rps *IRCProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) {
// IRC
osc.LogInfo(fmt.Sprintf("Checking %s IRC(6667)\n", hiddenService))
conn, err := utils.GetNetworkConnection(hiddenService, 6667, osc.TorProxyAddress, osc.Timeout)
log.Printf("Checking %s IRC(6667)\n", hiddenService)
_, err := socks.DialSocksProxy(socks.SOCKS5, onionscanConfig.TorProxyAddress)("", hiddenService+":6667")
if err != nil {
osc.LogInfo("Failed to connect to service on port 6667\n")
log.Printf("Failed to connect to service on port 6667\n")
report.IRCDetected = false
} else {
osc.LogInfo("Detected possible IRC instance\n")
log.Printf("Detected possible IRC instance\n")
// TODO: Actual Analysis
report.IRCDetected = true
}
if conn != nil {
conn.Close()
}
// IRC
osc.LogInfo(fmt.Sprintf("Checking %s IRC(6697)\n", hiddenService))
conn, err = utils.GetNetworkConnection(hiddenService, 6697, osc.TorProxyAddress, osc.Timeout)
if err != nil {
osc.LogInfo("Failed to connect to service on port 6697\n")
} else {
osc.LogInfo("Detected possible IRC (secure) instance\n")
// TODO: Actual Analysis
report.IRCDetected = true
}
if conn != nil {
conn.Close()
}
}

View File

@ -1,29 +1,26 @@
package protocol
import (
"fmt"
"github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report"
"github.com/s-rah/onionscan/utils"
"h12.me/socks"
"log"
)
type MongoDBProtocolScanner struct {
}
func (rps *MongoDBProtocolScanner) ScanProtocol(hiddenService string, osc *config.OnionscanConfig, report *report.OnionScanReport) {
func (rps *MongoDBProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) {
// MongoDB
osc.LogInfo(fmt.Sprintf("Checking %s MongoDB(27017)\n", hiddenService))
conn, err := utils.GetNetworkConnection(hiddenService, 27017, osc.TorProxyAddress, osc.Timeout)
log.Printf("Checking %s MongoDB(27017)\n", hiddenService)
_, err := socks.DialSocksProxy(socks.SOCKS5, onionscanConfig.TorProxyAddress)("", hiddenService+":27017")
if err != nil {
osc.LogInfo("Failed to connect to service on port 27017\n")
log.Printf("Failed to connect to service on port 27017\n")
report.MongoDBDetected = false
} else {
osc.LogInfo("Detected possible MongoDB instance\n")
log.Printf("Detected possible MongoDB instance\n")
// TODO: Actual Analysis
report.MongoDBDetected = true
}
if conn != nil {
conn.Close()
}
}

View File

@ -1,28 +1,26 @@
package protocol
import (
"fmt"
"github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report"
"github.com/s-rah/onionscan/utils"
"h12.me/socks"
"log"
)
type RicochetProtocolScanner struct {
}
func (rps *RicochetProtocolScanner) ScanProtocol(hiddenService string, osc *config.OnionscanConfig, report *report.OnionScanReport) {
func (rps *RicochetProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) {
// Ricochet
osc.LogInfo(fmt.Sprintf("Checking %s ricochet(9878)\n", hiddenService))
conn, err := utils.GetNetworkConnection(hiddenService, 9878, osc.TorProxyAddress, osc.Timeout)
log.Printf("Checking %s ricochet(9878)\n", hiddenService)
_, err := socks.DialSocksProxy(socks.SOCKS5, onionscanConfig.TorProxyAddress)("", hiddenService+":9878")
if err != nil {
osc.LogInfo("Failed to connect to service on port 9878\n")
log.Printf("Failed to connect to service on port 9878\n")
report.RicochetDetected = false
} else {
osc.LogInfo("Detected possible ricochet instance\n")
log.Printf("Detected possible ricochet instance\n")
// TODO: Actual Analysis
report.RicochetDetected = true
}
if conn != nil {
conn.Close()
}
}

View File

@ -4,21 +4,21 @@ import (
"bufio"
"crypto/sha1"
"encoding/hex"
"fmt"
"github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report"
"github.com/s-rah/onionscan/utils"
"h12.me/socks"
"log"
)
type SMTPProtocolScanner struct {
}
func (sps *SMTPProtocolScanner) ScanProtocol(hiddenService string, osc *config.OnionscanConfig, report *report.OnionScanReport) {
func (sps *SMTPProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) {
// SMTP
osc.LogInfo(fmt.Sprintf("Checking %s SMTP(25)\n", hiddenService))
conn, err := utils.GetNetworkConnection(hiddenService, 25, osc.TorProxyAddress, osc.Timeout)
log.Printf("Checking %s SMTP(25)\n", hiddenService)
conn, err := socks.DialSocksProxy(socks.SOCKS5, onionscanConfig.TorProxyAddress)("", hiddenService+":25")
if err != nil {
osc.LogInfo("Failed to connect to service on port 25\n")
log.Printf("Failed to connect to service on port 25\n")
report.SMTPDetected = false
} else {
// TODO SMTP Checking
@ -29,10 +29,8 @@ func (sps *SMTPProtocolScanner) ScanProtocol(hiddenService string, osc *config.O
report.SMTPBanner = banner
hash := sha1.Sum([]byte(banner))
report.SMTPFingerprint = hex.EncodeToString(hash[:])
osc.LogInfo(fmt.Sprintf("Found SMTP Banner: %s (%s)", banner, report.SMTPFingerprint))
log.Printf("Found SMTP Banner: %s (%s)", banner, report.SMTPFingerprint)
}
}
if conn != nil {
conn.Close()
}
}

View File

@ -1,30 +1,27 @@
package protocol
import (
"bufio"
"crypto/md5"
"errors"
"fmt"
"github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report"
"github.com/s-rah/onionscan/utils"
"golang.org/x/crypto/ssh"
"h12.me/socks"
"log"
"net"
)
type SSHProtocolScanner struct {
}
func (sps *SSHProtocolScanner) ScanProtocol(hiddenService string, osc *config.OnionscanConfig, report *report.OnionScanReport) {
func (sps *SSHProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) {
// SSH
osc.LogInfo(fmt.Sprintf("Checking %s ssh(22)\n", hiddenService))
conn, err := utils.GetNetworkConnection(hiddenService, 22, osc.TorProxyAddress, osc.Timeout)
log.Printf("Checking %s ssh(22)\n", hiddenService)
conn, err := socks.DialSocksProxy(socks.SOCKS5, onionscanConfig.TorProxyAddress)("", hiddenService+":22")
if err != nil {
osc.LogInfo("Failed to connect to service on port 22\n")
log.Printf("Failed to connect to service on port 22\n")
report.SSHDetected = false
if conn != nil {
conn.Close()
}
} else {
// TODO SSH Checking
report.SSHDetected = true
@ -44,26 +41,13 @@ func (sps *SSHProtocolScanner) ScanProtocol(hiddenService string, osc *config.On
}
}
report.SSHKey = fingerprint
osc.LogInfo(fmt.Sprintf("Found SSH Key %s\n", fingerprint))
log.Printf("Found SSH Key %s\n", fingerprint)
// We don't want to continue
return errors.New("error")
},
}
ssh.NewClientConn(conn, hiddenService+":22", config)
if conn != nil {
conn.Close()
}
conn, err = utils.GetNetworkConnection(hiddenService, 22, osc.TorProxyAddress, osc.Timeout)
if err == nil {
reader := bufio.NewReader(conn)
banner, err := reader.ReadString('\n')
if err == nil {
report.SSHBanner = banner
osc.LogInfo(fmt.Sprintf("Found SSH Banner: %s (%s)", banner))
}
}
if conn != nil {
conn.Close()
}
}
}

View File

@ -1,37 +0,0 @@
package protocol
import (
"crypto/tls"
"fmt"
"github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report"
"github.com/s-rah/onionscan/utils"
)
type TLSProtocolScanner struct {
}
func (sps *TLSProtocolScanner) ScanProtocol(hiddenService string, osc *config.OnionscanConfig, report *report.OnionScanReport) {
osc.LogInfo(fmt.Sprintf("Checking %s TLS(443)\n", hiddenService))
conn, err := utils.GetNetworkConnection(hiddenService, 443, osc.TorProxyAddress, osc.Timeout)
if err != nil {
osc.LogInfo("Failed to connect to service on port 443\n")
report.TLSDetected = false
} else {
osc.LogInfo("Found TLS Endpoint\n")
report.TLSDetected = true
config := &tls.Config{
InsecureSkipVerify: true,
}
tlsConn := tls.Client(conn, config)
tlsConn.Write([]byte("GET / HTTP/1.1\r\n\r\n"))
for _, certificate := range tlsConn.ConnectionState().PeerCertificates {
osc.LogInfo(fmt.Sprintf("Found Certificate %v \n", certificate))
report.Certificates = append(report.Certificates, *certificate)
}
tlsConn.Close()
}
if conn != nil {
conn.Close()
}
}

View File

@ -1,28 +1,26 @@
package protocol
import (
"fmt"
"github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report"
"github.com/s-rah/onionscan/utils"
"h12.me/socks"
"log"
)
type VNCProtocolScanner struct {
}
func (vncps *VNCProtocolScanner) ScanProtocol(hiddenService string, osc *config.OnionscanConfig, report *report.OnionScanReport) {
func (vncps *VNCProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) {
// MongoDB
osc.LogInfo(fmt.Sprintf("Checking %s VNC(5900)\n", hiddenService))
conn, err := utils.GetNetworkConnection(hiddenService, 5900, osc.TorProxyAddress, osc.Timeout)
log.Printf("Checking %s VNC(5900)\n", hiddenService)
_, err := socks.DialSocksProxy(socks.SOCKS5, onionscanConfig.TorProxyAddress)("", hiddenService+":5900")
if err != nil {
osc.LogInfo("Failed to connect to service on port 5900\n")
log.Printf("Failed to connect to service on port 5900\n")
report.VNCDetected = false
} else {
osc.LogInfo("Detected possible VNC instance\n")
log.Printf("Detected possible VNC instance\n")
// TODO: Actual Analysis
report.VNCDetected = true
}
if conn != nil {
conn.Close()
}
}

View File

@ -1,41 +0,0 @@
package protocol
import (
"fmt"
"github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report"
"github.com/s-rah/onionscan/utils"
)
type XMPPProtocolScanner struct {
}
func (rps *XMPPProtocolScanner) ScanProtocol(hiddenService string, osc *config.OnionscanConfig, report *report.OnionScanReport) {
// XMPP
osc.LogInfo(fmt.Sprintf("Checking %s XMPP(5222)\n", hiddenService))
conn, err := utils.GetNetworkConnection(hiddenService, 5222, osc.TorProxyAddress, osc.Timeout)
if err != nil {
osc.LogInfo("Failed to connect to service on port 5222\n")
report.XMPPDetected = false
} else {
osc.LogInfo("Detected possible XMPP instance\n")
// TODO: Actual Analysis
report.XMPPDetected = true
}
if conn != nil {
conn.Close()
}
// XMPP
osc.LogInfo(fmt.Sprintf("Checking %s XMPP(5223)\n", hiddenService))
conn, err = utils.GetNetworkConnection(hiddenService, 5223, osc.TorProxyAddress, osc.Timeout)
if err != nil {
osc.LogInfo("Failed to connect to service on port 5223\n")
} else {
osc.LogInfo("Detected possible XMPP (secure) instance\n")
// TODO: Actual Analysis
report.XMPPDetected = true
}
if conn != nil {
conn.Close()
}
}

View File

@ -1,11 +1,9 @@
package report
import (
"crypto/x509"
"encoding/json"
"github.com/s-rah/onionscan/utils"
"io/ioutil"
"time"
)
type ExifTag struct {
@ -19,29 +17,24 @@ type ExifImage struct {
}
type PGPKey struct {
ArmoredKey string `json:"armoredKey"`
Identity string `json:"identity"`
FingerPrint string `json:"fingerprint"`
ArmoredKey string `json:"armoredKey"`
Identity string `json:"identity"`
FingerPrint string `json:"fingerprint"`
}
type OnionScanReport struct {
HiddenService string `json:"hiddenService"`
DateScanned time.Time `json:"dateScanned"`
HiddenService string `json:"hiddenService"`
// Summary
WebDetected bool `json:"webDetected"`
TLSDetected bool `json:"tlsDetected"`
SSHDetected bool `json:"sshDetected"`
RicochetDetected bool `json:"ricochetDetected"`
IRCDetected bool `json:"ircDetected"`
FTPDetected bool `json:"ftpDetected"`
SMTPDetected bool `json:"smtpDetected"`
BitcoinDetected bool `json:"bitcoinDetected"`
MongoDBDetected bool `json:"mongodbDetected"`
VNCDetected bool `json:"vncDetected"`
XMPPDetected bool `json:"xmppDetected"`
SkynetDetected bool `json:"skynetDetected"`
PrivateKeyDetected bool `json:"privateKeyDetected"`
WebDetected bool `json:"webDetected"`
SSHDetected bool `json:"sshDetected"`
RicochetDetected bool `json:"ricochetDetected"`
IRCDetected bool `json:"ircDetected"`
FTPDetected bool `json:"ftpDetected"`
SMTPDetected bool `json:"smtpDetected"`
BitcoinDetected bool `json:"bitcoinDetected"`
MongoDBDetected bool `json:"mongodbDetected"`
VNCDetected bool `json:"vncDetected"`
// Web Specific
ServerPoweredBy string `json:"serverPoweredBy"`
@ -56,21 +49,14 @@ type OnionScanReport struct {
ExifImages []ExifImage `json:"exifImages"`
InterestingFiles []string `json:"interestingFiles"`
PageReferencedDirectories []string `json:"pageReferencedDirectories"`
PGPKeys []PGPKey `json:"pgpKeys"`
PGPKeys []PGPKey `json:"pgpKeys"`
Hashes []string `json:"hashes"`
Snapshot string `json:"snapshot"`
PageTitle string `json:"pageTitle"`
ResponseHeaders map[string]string `json:"responseHeaders"`
// TLS
Certificates []x509.Certificate `json:"certificates"`
//Bitcoin
BitcoinAddresses []string `json:"bitcoinAddresses"`
// SSH
SSHKey string `json:"sshKey"`
SSHBanner string `json:"sshBanner"`
SSHKey string `json:"sshKey"`
// FTP
FTPFingerprint string `json:"ftpFingerprint"`
@ -79,9 +65,6 @@ type OnionScanReport struct {
// SMTP
SMTPFingerprint string `json:"smtpFingerprint"`
SMTPBanner string `json:"smtpBanner"`
NextAction string `json:"lastAction"`
TimedOut bool
}
func LoadReportFromFile(filename string) (OnionScanReport, error) {
@ -95,11 +78,7 @@ func LoadReportFromFile(filename string) (OnionScanReport, error) {
}
func NewOnionScanReport(hiddenService string) *OnionScanReport {
report := new(OnionScanReport)
report.HiddenService = hiddenService
report.ResponseHeaders = make(map[string]string)
report.DateScanned = time.Now()
return report
return &OnionScanReport{HiddenService: hiddenService, ResponseHeaders: make(map[string]string)}
}
func (osr *OnionScanReport) AddOpenDirectory(dir string) {

View File

@ -5,7 +5,6 @@ import (
"fmt"
"log"
"os"
"time"
)
func GenerateJsonReport(reportFile string, report *OnionScanReport) {
@ -16,11 +15,9 @@ func GenerateJsonReport(reportFile string, report *OnionScanReport) {
if len(reportFile) > 0 {
f, err := os.Create(reportFile)
for err != nil {
log.Printf("Cannot create report file: %s...trying again in 5 seconds...", err)
time.Sleep(time.Second * 5)
f, err = os.Create(reportFile)
if err != nil {
log.Fatalf("Cannot create report file: %s", err)
panic(err)
}
defer f.Close()
@ -176,11 +173,9 @@ func GenerateSimpleReport(reportFile string, report *OnionScanReport) {
if len(reportFile) > 0 {
f, err := os.Create(reportFile)
for err != nil {
log.Printf("Cannot create report file: %s...trying again in 5 seconds...", err)
time.Sleep(time.Second * 5)
f, err = os.Create(reportFile)
if err != nil {
log.Fatalf("Cannot create report file: %s", err)
panic(err)
}
defer f.Close()

View File

@ -1,59 +1,58 @@
package scans
import (
"fmt"
"github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report"
"github.com/s-rah/onionscan/utils"
"log"
"regexp"
"strings"
)
func ApacheModStatus(scan Scanner, page string, status int, contents string, report *report.OnionScanReport, osc *config.OnionscanConfig) {
func ApacheModStatus(scan Scanner, page string, status int, contents string, report *report.OnionScanReport) {
if status == 200 {
r := regexp.MustCompile(`Server Version: (.*)</dt>`)
serverVersion := r.FindStringSubmatch(string(contents))
// Check if this looks like a mod_status page. Sometimes sites simply load their index.
if len(serverVersion) > 1 {
osc.LogInfo("Detected Apache mod_status Exposed...\033[091mAlert!\033[0m\n")
log.Printf("Detected Apache mod_status Exposed...\033[091mAlert!\033[0m\n")
report.FoundApacheModStatus = true
osc.LogInfo(fmt.Sprintf("\t Using mod_status Server Version: %s\n", serverVersion[1]))
log.Printf("\t Using mod_status Server Version: %s\n", serverVersion[1])
report.ServerVersion = serverVersion[1]
// Check for co-hosted onion services.
osc.LogInfo("Scanning for Co-Hosted Onions\n")
log.Printf("Scanning for Co-Hosted Onions\n")
r = regexp.MustCompile(`[a-z0-9]+.onion(:[0-9]{0-5})?`)
foundServices := r.FindAllString(string(contents), -1)
utils.RemoveDuplicates(&foundServices)
for _, onion := range foundServices {
if onion != report.HiddenService {
osc.LogInfo(fmt.Sprintf("\t \033[091mAlert!\033[0m Found Co-Hosted Onions: %s\n", onion))
log.Printf("\t \033[091mAlert!\033[0m Found Co-Hosted Onions: %s\n", onion)
report.AddRelatedOnionService(onion)
}
}
// Check for co-hosted onion services.
osc.LogInfo("Scanning for Co-Hosted Clearnet Domains\n")
log.Printf("Scanning for Co-Hosted Clearnet Domains\n")
r = regexp.MustCompile(`>(([a-zA-Z]{1})|([a-zA-Z]{1}[a-zA-Z]{1})|([a-zA-Z]{1}[0-9]{1})|([0-9]{1}[a-zA-Z]{1})|([a-zA-Z0-9][a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]))\.([a-zA-Z]{2,6}|[a-zA-Z0-9-]{2,30}\.[a-zA-Z]{2,3})`)
foundServices = r.FindAllString(string(contents), -1)
utils.RemoveDuplicates(&foundServices)
for _, domain := range foundServices {
if strings.Contains(domain, ".onion") == false {
osc.LogInfo(fmt.Sprintf("\t \033[091mAlert!\033[0m Found Co-Hosted Service: %s\n", domain[1:]))
log.Printf("\t \033[091mAlert!\033[0m Found Co-Hosted Service: %s\n", domain[1:])
report.AddRelatedClearnetDomain(domain[4:])
}
}
// Check for IP Addresses
osc.LogInfo("Scanning for IP Addresses (clearweb clients, and servers)\n")
log.Printf("Scanning for IP Addresses (clearweb clients, and servers)\n")
r = regexp.MustCompile(`(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)`)
foundIPs := r.FindAllString(string(contents), -1)
utils.RemoveDuplicates(&foundIPs)
for _, ip := range foundIPs {
if ip != "127.0.0.1" {
osc.LogInfo(fmt.Sprintf("\t \033[091mAlert!\033[0m Found IP Address : %s\n", ip))
log.Printf("\t \033[091mAlert!\033[0m Found IP Address : %s\n", ip)
report.AddIPAddress(ip)
}
}
@ -61,7 +60,7 @@ func ApacheModStatus(scan Scanner, page string, status int, contents string, rep
}
}
if !report.FoundApacheModStatus {
osc.LogInfo("\tApache mod_status Not Exposed...\033[92mGood!\033[0m\n")
log.Printf("\tApache mod_status Not Exposed...\033[92mGood!\033[0m\n")
report.FoundApacheModStatus = false
}
}

View File

@ -1,20 +0,0 @@
package scans
import (
"github.com/s-rah/onionscan/report"
"log"
"regexp"
)
type BitcoinContentScan struct {
}
func (cs *BitcoinContentScan) ScanContent(content string, report *report.OnionScanReport) {
log.Printf("Scanning for Bitcoin Address\n")
bitcoinAddressRegexp := regexp.MustCompile("[1|3][A-Za-z0-9]{25,34}")
foundBitcoinAddress := bitcoinAddressRegexp.FindAllString(content, -1)
for _, ba := range foundBitcoinAddress {
log.Printf("Found Bitcoin Address: %s", ba)
report.BitcoinAddresses = append(report.BitcoinAddresses, ba)
}
}

View File

@ -1,36 +1,35 @@
package scans
import (
"fmt"
"github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report"
"log"
"regexp"
"strings"
)
func CheckDirectoryListing(depth int) func(Scanner, string, int, string, *report.OnionScanReport, *config.OnionscanConfig) {
return func(scan Scanner, dir string, status int, contents string, report *report.OnionScanReport, osc *config.OnionscanConfig) {
CheckDirectoryListingDepth(scan, dir, status, depth, contents, report, osc)
func CheckDirectoryListing(depth int) func(Scanner, string, int, string, *report.OnionScanReport) {
return func(scan Scanner, dir string, status int, contents string, report *report.OnionScanReport) {
CheckDirectoryListingDepth(scan, dir, status, depth, contents, report)
}
}
func CheckDirectoryListingDepth(scan Scanner, dir string, status int, depth int, contents string, report *report.OnionScanReport, osc *config.OnionscanConfig) {
func CheckDirectoryListingDepth(scan Scanner, dir string, status int, depth int, contents string, report *report.OnionScanReport) {
if status == 200 && strings.Contains(string(contents), "Index of "+dir) {
osc.LogInfo(fmt.Sprintf("Detected Open Directory %s...\033[091mAlert!\033[0m\n", dir))
log.Printf("Detected Open Directory %s...\033[091mAlert!\033[0m\n", dir)
report.AddOpenDirectory(dir)
r := regexp.MustCompile(`href="((.*?\.jpg)|(.*?\.png)|(.*?\.jpeg)|(.*?\.gif))"`)
foundImages := r.FindAllStringSubmatch(string(contents), -1)
for _, image := range foundImages {
osc.LogInfo(fmt.Sprintf("\t Found image %s/%s\n", dir, image[1]))
scan.ScanPage(report.HiddenService, dir+"/"+image[1], report, osc, CheckExif)
log.Printf("\t Found image %s/%s\n", dir, image[1])
scan.ScanPage(report.HiddenService, dir+"/"+image[1], report, CheckExif)
}
r = regexp.MustCompile(`href="((.*\.zip)|(.*\.tar)|(.*\.gz)|(.*\.pst)|(.*\.txt))"`)
interestingFiles := r.FindAllStringSubmatch(string(contents), -1)
for _, file := range interestingFiles {
osc.LogInfo(fmt.Sprintf("\t Found interesting file %s/%s\n", dir, file[1]))
log.Printf("\t Found interesting file %s/%s\n", dir, file[1])
//TODO: We can do further analysis here, for now, just report them.
report.AddInterestingFile(dir + "/" + file[1])
}
@ -38,14 +37,14 @@ func CheckDirectoryListingDepth(scan Scanner, dir string, status int, depth int,
r = regexp.MustCompile(`href="([^/](.*?))/"`)
subDir := r.FindAllStringSubmatch(string(contents), -1)
for _, file := range subDir {
osc.LogInfo(fmt.Sprintf("\t Found subdir %s/%s\n", dir, file[1]))
log.Printf("\t Found subdir %s/%s\n", dir, file[1])
//TODO: We can do further analysis here, for now, just report them.
if depth > 0 {
scan.ScanPage(report.HiddenService, dir+"/"+file[1], report, osc, CheckDirectoryListing(depth-1))
scan.ScanPage(report.HiddenService, dir+"/"+file[1], report, CheckDirectoryListing(depth-1))
}
}
} else {
osc.LogInfo(fmt.Sprintf("Directory %s either doesn't exist or is not readable\n", dir))
log.Printf("Directory %s either doesn't exist or is not readable\n", dir)
}
}

View File

@ -1,15 +1,14 @@
package scans
import (
"fmt"
"github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report"
"github.com/xiam/exif"
"io"
"log"
"strings"
)
func CheckExif(scan Scanner, page string, status int, contents string, report *report.OnionScanReport, osc *config.OnionscanConfig) {
func CheckExif(scan Scanner, page string, status int, contents string, report *report.OnionScanReport) {
if status == 200 {
reader := exif.New()
_, err := io.Copy(reader, strings.NewReader(contents))
@ -32,7 +31,7 @@ func CheckExif(scan Scanner, page string, status int, contents string, report *r
report.AddExifImage(page)
for name, val := range reader.Tags {
osc.LogInfo(fmt.Sprintf("\t \033[091mAlert!\033[0m Found Exif Tag%s: %s\n", name, val))
log.Printf("\t \033[091mAlert!\033[0m Found Exif Tag%s: %s\n", name, val)
report.AddExifTag(name, val)
}
}

View File

@ -3,34 +3,38 @@ package scans
import (
"github.com/s-rah/onionscan/report"
"golang.org/x/crypto/openpgp"
"log"
"regexp"
"strings"
"fmt"
)
type PGPContentScan struct {
}
func (cs *PGPContentScan) ScanContent(content string, report *report.OnionScanReport) {
//log.Printf("Scanning for PGP Key\n")
log.Printf("Scanning for PGP Key\n")
pgpRegexp := regexp.MustCompile("-----BEGIN PGP PUBLIC KEY BLOCK-----((?s).*)-----END PGP PUBLIC KEY BLOCK-----")
foundPGP := pgpRegexp.FindAllString(content, -1)
for _, keyString := range foundPGP {
keys, err := openpgp.ReadArmoredKeyRing(strings.NewReader(keyString))
keys, err := openpgp.ReadArmoredKeyRing(strings.NewReader(keyString));
if err != nil {
// log.Printf("ERROR: %s\n", err)
log.Printf("ERROR: %s\n", err)
continue
}
if len(keys) < 1 || len(keys[0].Subkeys) < 1 || len(keys[0].Identities) < 1 {
// log.Printf("ERROR: failed to accept key\n")
if len(keys) < 1 || len(keys[0].Subkeys) < 1 || len(keys[0].Identities) < 1{
log.Printf("ERROR: failed to accept key\n")
continue
}
var identity string
for identity = range keys[0].Identities {
for identity, _ = range keys[0].Identities {
break
}
// log.Printf("\tFound PGP Key fingerprint: %s belonging to %s", keys[0].Subkeys[0].PublicKey.KeyIdShortString(), identity)
var fingerprint string
fingerprint = fmt.Sprintf("%X", keys[0].Subkeys[0].PublicKey.Fingerprint)
log.Printf("\tFound PGP Key fingerprint: %s belonging to %s", fingerprint, identity)
report.AddPGPKey(keyString, identity, keys[0].Subkeys[0].PublicKey.KeyIdShortString())
report.AddPGPKey(keyString, identity, fingerprint)
}
}

View File

@ -1,15 +0,0 @@
package scans
import (
"fmt"
"github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report"
)
func PrivateKeyScan(scan Scanner, page string, status int, contents string, report *report.OnionScanReport, osc *config.OnionscanConfig) {
osc.LogInfo(fmt.Sprintf("Scanning %s\n", page))
if status == 200 {
osc.LogInfo(fmt.Sprintf("\tPrivate Key %s is Accessible!!\n", page))
report.PrivateKeyDetected = true
}
}

View File

@ -1,11 +1,10 @@
package scans
import (
"github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report"
)
type Scanner interface {
ScanPage(string, string, *report.OnionScanReport, *config.OnionscanConfig, func(Scanner, string, int, string, *report.OnionScanReport, *config.OnionscanConfig))
ScanPage(string, string, *report.OnionScanReport, func(Scanner, string, int, string, *report.OnionScanReport))
ScrapePage(string, string) (error, []byte, int)
}

View File

@ -3,20 +3,19 @@ package scans
import (
"crypto/sha1"
"encoding/hex"
"fmt"
"github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report"
"github.com/s-rah/onionscan/utils"
"golang.org/x/net/html"
"log"
"net/url"
"regexp"
"strings"
)
func StandardPageScan(scan Scanner, page string, status int, contents string, report *report.OnionScanReport, osc *config.OnionscanConfig) {
osc.LogInfo(fmt.Sprintf("Scanning %s\n", page))
func StandardPageScan(scan Scanner, page string, status int, contents string, report *report.OnionScanReport) {
log.Printf("Scanning %s\n", page)
if status == 200 {
osc.LogInfo(fmt.Sprintf("\tPage %s is Accessible\n", page))
log.Printf("\tPage %s is Accessible\n", page)
hash := sha1.Sum([]byte(contents))
report.Hashes = append(report.Hashes, hex.EncodeToString(hash[:]))
@ -28,14 +27,13 @@ func StandardPageScan(scan Scanner, page string, status int, contents string, re
var startIndex = strings.Index(contents, "<title>")
var endIndex = strings.Index(contents, "</title>")
var pageTitle = contents[startIndex+len("<title>") : endIndex]
osc.LogInfo(fmt.Sprintf("\tPage Title: %s\n", pageTitle))
log.Printf("\tPage Title: %s\n", pageTitle)
report.PageTitle = pageTitle
}
new(PGPContentScan).ScanContent(contents, report)
//new(BitcoinContentScan).ScanContent(contents, report)
osc.LogInfo("\tScanning for Images\n")
log.Printf("\tScanning for Images\n")
var domains []string
var cssLinks []string
@ -70,48 +68,44 @@ func StandardPageScan(scan Scanner, page string, status int, contents string, re
if t.Data == "img" {
imageUrl := utils.GetAttribute(t, "src")
baseUrl, err := url.Parse(imageUrl)
if err == nil {
if utils.WithoutSubdomains(baseUrl.Host) == utils.WithoutSubdomains(report.HiddenService) {
scan.ScanPage(report.HiddenService, utils.WithoutProtocol(imageUrl), report, osc, CheckExif)
osc.LogInfo(fmt.Sprintf("\t Found internal image %s\n", imageUrl))
} else {
osc.LogInfo(fmt.Sprintf("\t Not scanning remote image %s\n", imageUrl))
}
baseUrl, _ := url.Parse(imageUrl)
if utils.WithoutSubdomains(baseUrl.Host) == utils.WithoutSubdomains(report.HiddenService) {
scan.ScanPage(report.HiddenService, utils.WithoutProtocol(imageUrl), report, CheckExif)
log.Printf("\t Found internal image %s\n", imageUrl)
} else {
log.Printf("\t Not scanning remote image %s\n", imageUrl)
}
}
}
osc.LogInfo("\tScanning for CSS Fonts and Background Images\n")
log.Printf("\tScanning for CSS Fonts and Background Images\n")
utils.RemoveDuplicates(&cssLinks)
for _, cssUrl := range cssLinks {
osc.LogInfo(fmt.Sprintf("\tScanning CSS file: %s\n", cssUrl))
log.Printf("\tScanning CSS file: %s\n", cssUrl)
_, cssContents, _ := scan.ScrapePage(report.HiddenService, utils.WithoutProtocol(cssUrl))
domains = append(domains, utils.ExtractDomains(string(cssContents))[:]...)
domains = append(domains, utils.ExtractDomains(string(cssContents))[0:]...)
}
osc.LogInfo("\tScanning for Links\n")
log.Printf("\tScanning for Links\n")
domains = append(domains, utils.ExtractDomains(contents)...)
utils.RemoveDuplicates(&domains)
for _, domain := range domains {
baseUrl, err := url.Parse(domain)
if err == nil {
if baseUrl.Host != "" && utils.WithoutSubdomains(baseUrl.Host) != utils.WithoutSubdomains(report.HiddenService) {
osc.LogInfo(fmt.Sprintf("Found Related URL %s\n", domain))
// TODO: Lots of information here which needs to be processed.
// * Links to standard sites - google / bitpay etc.
// * Links to other onion sites
// * Links to obscure clearnet sites.
report.AddLinkedSite(baseUrl.Host)
} else {
// * Process FQDN internal links
osc.LogInfo(fmt.Sprintf("Found Internal URL %s\n", domain))
report.AddInternalPage(baseUrl.Host)
}
baseUrl, _ := url.Parse(domain)
if baseUrl.Host != "" && utils.WithoutSubdomains(baseUrl.Host) != utils.WithoutSubdomains(report.HiddenService) {
log.Printf("Found Related URL %s\n", domain)
// TODO: Lots of information here which needs to be processed.
// * Links to standard sites - google / bitpay etc.
// * Links to other onion sites
// * Links to obscure clearnet sites.
report.AddLinkedSite(baseUrl.Host)
} else {
// * Process FQDN internal links
log.Printf("Found Internal URL %s\n", domain)
report.AddInternalPage(baseUrl.Host)
}
}
osc.LogInfo("\tScanning for Referenced Directories\n")
log.Printf("\tScanning for Referenced Directories\n")
r := regexp.MustCompile("(src|href)=\"([^\"]*)\"")
foundPaths := r.FindAllStringSubmatch(string(contents), -1)
for _, regexpResults := range foundPaths {
@ -122,13 +116,13 @@ func StandardPageScan(scan Scanner, page string, status int, contents string, re
term := strings.LastIndex(path, "/")
if term > 0 {
osc.LogInfo(fmt.Sprintf("\t Found Referenced Directory %s\n", path[:term]))
log.Printf("\t Found Referenced Directory %s\n", path[:term])
report.AddPageReferencedDirectory(utils.WithoutProtocol(path[:term]))
}
}
} else if status == 403 {
osc.LogInfo(fmt.Sprintf("\tPage %s%s is Forbidden\n", report.HiddenService, page))
log.Printf("\tPage %s%s is Forbidden\n", report.HiddenService, page)
} else if status == 404 {
osc.LogInfo(fmt.Sprintf("\tPage %s%s is Does Not Exist\n", report.HiddenService, page))
log.Printf("\tPage %s%s is Does Not Exist\n", report.HiddenService, page)
}
}

View File

@ -1,17 +0,0 @@
package utils
import (
"h12.me/socks"
"net"
"strconv"
"time"
)
func GetNetworkConnection(onionService string, port int, proxy string, timeout time.Duration) (net.Conn, error) {
portNumber := strconv.Itoa(port)
conn, err := socks.DialSocksProxy(socks.SOCKS5, proxy)("", onionService+":"+portNumber)
if err == nil {
conn.SetDeadline(time.Now().Add(timeout))
}
return conn, err
}