Load Onions from a File

Fixes #21 - Also enforces timeouts and cleans up
some code.
This commit is contained in:
Sarah Jamie Lewis 2016-06-06 23:29:29 -07:00
parent fea4c84b0b
commit 35fd1d3830
14 changed files with 105 additions and 47 deletions

View File

@ -1,15 +1,21 @@
package config package config
import (
"time"
)
type OnionscanConfig struct { type OnionscanConfig struct {
TorProxyAddress string TorProxyAddress string
DirectoryDepth int DirectoryDepth int
Fingerprint bool Fingerprint bool
Timeout time.Duration
} }
func Configure(torProxyAddress string, directoryDepth int, fingerprint bool) *OnionscanConfig { func Configure(torProxyAddress string, directoryDepth int, fingerprint bool, timeout int) *OnionscanConfig {
onionScan := new(OnionscanConfig) onionScan := new(OnionscanConfig)
onionScan.TorProxyAddress = torProxyAddress onionScan.TorProxyAddress = torProxyAddress
onionScan.DirectoryDepth = directoryDepth onionScan.DirectoryDepth = directoryDepth
onionScan.Fingerprint = fingerprint onionScan.Fingerprint = fingerprint
onionScan.Timeout = time.Duration(time.Second * time.Duration(timeout))
return onionScan return onionScan
} }

68
main.go
View File

@ -8,54 +8,88 @@ import (
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
"strings"
) )
func main() { func main() {
flag.Usage = func() { flag.Usage = func() {
fmt.Printf("Usage of %s:\n", os.Args[0]) fmt.Printf("Usage of %s:\n", os.Args[0])
fmt.Printf(" onionscan [flags] hiddenservice\n") fmt.Printf(" onionscan [flags] hiddenservice | onionscan [flags] --list list\n")
flag.PrintDefaults() flag.PrintDefaults()
} }
torProxyAddress := flag.String("torProxyAddress", "127.0.0.1:9050", "the address of the tor proxy to use") 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") 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") 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")
jsonReport := flag.Bool("jsonReport", false, "print out a json report providing a detailed report of the scan.") 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") 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)") directoryDepth := flag.Int("depth", 100, "depth of directory scan recursion (default: 100)")
fingerprint := flag.Bool("fingerprint", true, "whether to conduct a full scan, or just fingerprint possible ports") 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")
flag.Parse() flag.Parse()
if len(flag.Args()) != 1 { if len(flag.Args()) != 1 && *list == "" {
flag.Usage() flag.Usage()
os.Exit(1) os.Exit(1)
} }
hiddenService := flag.Args()[0] if !*simpleReport && !*jsonReport {
log.Fatalf("You must set one of --simpleReport or --jsonReport")
}
log.Printf("Starting Scan of %s\n", hiddenService) 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")
onionsToScan = append(onionsToScan, onions...)
log.Printf("Starting Scan of %d onion services\n", len(onionsToScan)-1)
}
log.Printf("This might take a few minutes..\n\n") log.Printf("This might take a few minutes..\n\n")
onionScan := new(OnionScan)
onionScan.Config = config.Configure(*torProxyAddress, *directoryDepth, *fingerprint, *timeout)
reports := make(chan *report.OnionScanReport)
if !*verbose { if !*verbose {
log.SetOutput(ioutil.Discard) log.SetOutput(ioutil.Discard)
} }
onionScan := new(OnionScan) count := 0
onionScan.Config = config.Configure(*torProxyAddress, *directoryDepth, *fingerprint) max := 100
scanReport, err := onionScan.Scan(hiddenService) if max > len(onionsToScan)-1 {
max = len(onionsToScan) - 1
if *jsonReport {
report.GenerateJsonReport(*reportFile, scanReport)
} }
if *simpleReport { // Run an initial batch of 100 requests (or less...)
report.GenerateSimpleReport(*reportFile, scanReport) for count < max {
go onionScan.Scan(onionsToScan[count], reports)
count++
} }
if !*jsonReport && err != nil { received := 0
log.Fatalf("Error running scanner: %s", err) for received < len(onionsToScan)-1 {
} scanReport := <-reports
// After the initial batch, it's one in one out to prevent proxy overload.
if count < len(onionsToScan)-1 {
go onionScan.Scan(onionsToScan[count], reports)
count++
}
received++
if *jsonReport {
report.GenerateJsonReport(*reportFile, scanReport)
} else if *simpleReport {
report.GenerateSimpleReport(*reportFile, scanReport)
}
}
} }

View File

@ -1,12 +1,10 @@
package main package main
import ( import (
"errors"
"github.com/s-rah/onionscan/config" "github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/protocol" "github.com/s-rah/onionscan/protocol"
"github.com/s-rah/onionscan/report" "github.com/s-rah/onionscan/report"
"github.com/s-rah/onionscan/utils" "github.com/s-rah/onionscan/utils"
"log"
"strings" "strings"
) )
@ -14,7 +12,7 @@ type OnionScan struct {
Config *config.OnionscanConfig Config *config.OnionscanConfig
} }
func (os *OnionScan) Scan(hiddenService string) (*report.OnionScanReport, error) { func (os *OnionScan) Scan(hiddenService string, out chan *report.OnionScanReport) {
// Remove Extra Prefix // Remove Extra Prefix
hiddenService = utils.WithoutProtocol(hiddenService) hiddenService = utils.WithoutProtocol(hiddenService)
@ -61,10 +59,5 @@ func (os *OnionScan) Scan(hiddenService string) (*report.OnionScanReport, error)
vncps := new(protocol.VNCProtocolScanner) vncps := new(protocol.VNCProtocolScanner)
vncps.ScanProtocol(hiddenService, os.Config, report) vncps.ScanProtocol(hiddenService, os.Config, report)
if !report.WebDetected && !report.SSHDetected && !report.RicochetDetected && !report.BitcoinDetected && !report.IRCDetected && !report.FTPDetected && !report.SMTPDetected && !report.MongoDBDetected { out <- report
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.")
}
return report, nil
} }

View File

@ -3,7 +3,7 @@ package protocol
import ( import (
"github.com/s-rah/onionscan/config" "github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report" "github.com/s-rah/onionscan/report"
"h12.me/socks" "github.com/s-rah/onionscan/utils"
"log" "log"
) )
@ -13,7 +13,7 @@ type BitcoinProtocolScanner struct {
func (rps *BitcoinProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) { func (rps *BitcoinProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) {
// Bitcoin // Bitcoin
log.Printf("Checking %s Bitcoin(8333)\n", hiddenService) log.Printf("Checking %s Bitcoin(8333)\n", hiddenService)
_, err := socks.DialSocksProxy(socks.SOCKS5, onionscanConfig.TorProxyAddress)("", hiddenService+":8333") _, err := utils.GetNetworkConnection(hiddenService, 8333, onionscanConfig.TorProxyAddress, onionscanConfig.Timeout)
if err != nil { if err != nil {
log.Printf("Failed to connect to service on port 8333\n") log.Printf("Failed to connect to service on port 8333\n")
report.BitcoinDetected = false report.BitcoinDetected = false

View File

@ -6,7 +6,7 @@ import (
"encoding/hex" "encoding/hex"
"github.com/s-rah/onionscan/config" "github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report" "github.com/s-rah/onionscan/report"
"h12.me/socks" "github.com/s-rah/onionscan/utils"
"log" "log"
) )
@ -16,7 +16,7 @@ type FTPProtocolScanner struct {
func (sps *FTPProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) { func (sps *FTPProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) {
// FTP // FTP
log.Printf("Checking %s FTP(21)\n", hiddenService) log.Printf("Checking %s FTP(21)\n", hiddenService)
conn, err := socks.DialSocksProxy(socks.SOCKS5, onionscanConfig.TorProxyAddress)("", hiddenService+":21") conn, err := utils.GetNetworkConnection(hiddenService, 21, onionscanConfig.TorProxyAddress, onionscanConfig.Timeout)
if err != nil { if err != nil {
log.Printf("Failed to connect to service on port 21\n") log.Printf("Failed to connect to service on port 21\n")
report.FTPDetected = false report.FTPDetected = false

View File

@ -28,7 +28,7 @@ func (hps *HTTPProtocolScanner) ScanProtocol(hiddenService string, onionscanConf
// HTTP // HTTP
log.Printf("Checking %s http(80)\n", hiddenService) log.Printf("Checking %s http(80)\n", hiddenService)
_, err := socks.DialSocksProxy(socks.SOCKS5, onionscanConfig.TorProxyAddress)("", hiddenService+":80") _, err := utils.GetNetworkConnection(hiddenService, 80, onionscanConfig.TorProxyAddress, onionscanConfig.Timeout)
if err != nil { if err != nil {
log.Printf("Failed to connect to service on port 80\n") log.Printf("Failed to connect to service on port 80\n")
report.WebDetected = false report.WebDetected = false
@ -40,7 +40,7 @@ func (hps *HTTPProtocolScanner) ScanProtocol(hiddenService string, onionscanConf
transportConfig := &http.Transport{ transportConfig := &http.Transport{
Dial: dialSocksProxy, Dial: dialSocksProxy,
} }
hps.Client = &http.Client{Transport: transportConfig} hps.Client = &http.Client{Transport: transportConfig, Timeout: onionscanConfig.Timeout}
// FIXME This should probably be moved to it's own file now. // FIXME This should probably be moved to it's own file now.
response, err := hps.Client.Get("http://" + hiddenService) response, err := hps.Client.Get("http://" + hiddenService)

View File

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

View File

@ -3,7 +3,7 @@ package protocol
import ( import (
"github.com/s-rah/onionscan/config" "github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report" "github.com/s-rah/onionscan/report"
"h12.me/socks" "github.com/s-rah/onionscan/utils"
"log" "log"
) )
@ -13,7 +13,7 @@ type MongoDBProtocolScanner struct {
func (rps *MongoDBProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) { func (rps *MongoDBProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) {
// MongoDB // MongoDB
log.Printf("Checking %s MongoDB(27017)\n", hiddenService) log.Printf("Checking %s MongoDB(27017)\n", hiddenService)
_, err := socks.DialSocksProxy(socks.SOCKS5, onionscanConfig.TorProxyAddress)("", hiddenService+":27017") _, err := utils.GetNetworkConnection(hiddenService, 27017, onionscanConfig.TorProxyAddress, onionscanConfig.Timeout)
if err != nil { if err != nil {
log.Printf("Failed to connect to service on port 27017\n") log.Printf("Failed to connect to service on port 27017\n")
report.MongoDBDetected = false report.MongoDBDetected = false

View File

@ -3,7 +3,7 @@ package protocol
import ( import (
"github.com/s-rah/onionscan/config" "github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report" "github.com/s-rah/onionscan/report"
"h12.me/socks" "github.com/s-rah/onionscan/utils"
"log" "log"
) )
@ -13,7 +13,7 @@ type RicochetProtocolScanner struct {
func (rps *RicochetProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) { func (rps *RicochetProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) {
// Ricochet // Ricochet
log.Printf("Checking %s ricochet(9878)\n", hiddenService) log.Printf("Checking %s ricochet(9878)\n", hiddenService)
_, err := socks.DialSocksProxy(socks.SOCKS5, onionscanConfig.TorProxyAddress)("", hiddenService+":9878") _, err := utils.GetNetworkConnection(hiddenService, 9878, onionscanConfig.TorProxyAddress, onionscanConfig.Timeout)
if err != nil { if err != nil {
log.Printf("Failed to connect to service on port 9878\n") log.Printf("Failed to connect to service on port 9878\n")
report.RicochetDetected = false report.RicochetDetected = false

View File

@ -6,7 +6,7 @@ import (
"encoding/hex" "encoding/hex"
"github.com/s-rah/onionscan/config" "github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report" "github.com/s-rah/onionscan/report"
"h12.me/socks" "github.com/s-rah/onionscan/utils"
"log" "log"
) )
@ -16,7 +16,7 @@ type SMTPProtocolScanner struct {
func (sps *SMTPProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) { func (sps *SMTPProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) {
// SMTP // SMTP
log.Printf("Checking %s SMTP(25)\n", hiddenService) log.Printf("Checking %s SMTP(25)\n", hiddenService)
conn, err := socks.DialSocksProxy(socks.SOCKS5, onionscanConfig.TorProxyAddress)("", hiddenService+":25") conn, err := utils.GetNetworkConnection(hiddenService, 25, onionscanConfig.TorProxyAddress, onionscanConfig.Timeout)
if err != nil { if err != nil {
log.Printf("Failed to connect to service on port 25\n") log.Printf("Failed to connect to service on port 25\n")
report.SMTPDetected = false report.SMTPDetected = false

View File

@ -6,8 +6,8 @@ import (
"fmt" "fmt"
"github.com/s-rah/onionscan/config" "github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report" "github.com/s-rah/onionscan/report"
"github.com/s-rah/onionscan/utils"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
"h12.me/socks"
"log" "log"
"net" "net"
) )
@ -18,7 +18,7 @@ type SSHProtocolScanner struct {
func (sps *SSHProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) { func (sps *SSHProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) {
// SSH // SSH
log.Printf("Checking %s ssh(22)\n", hiddenService) log.Printf("Checking %s ssh(22)\n", hiddenService)
conn, err := socks.DialSocksProxy(socks.SOCKS5, onionscanConfig.TorProxyAddress)("", hiddenService+":22") conn, err := utils.GetNetworkConnection(hiddenService, 22, onionscanConfig.TorProxyAddress, onionscanConfig.Timeout)
if err != nil { if err != nil {
log.Printf("Failed to connect to service on port 22\n") log.Printf("Failed to connect to service on port 22\n")
report.SSHDetected = false report.SSHDetected = false

View File

@ -3,7 +3,7 @@ package protocol
import ( import (
"github.com/s-rah/onionscan/config" "github.com/s-rah/onionscan/config"
"github.com/s-rah/onionscan/report" "github.com/s-rah/onionscan/report"
"h12.me/socks" "github.com/s-rah/onionscan/utils"
"log" "log"
) )
@ -13,7 +13,7 @@ type VNCProtocolScanner struct {
func (vncps *VNCProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) { func (vncps *VNCProtocolScanner) ScanProtocol(hiddenService string, onionscanConfig *config.OnionscanConfig, report *report.OnionScanReport) {
// MongoDB // MongoDB
log.Printf("Checking %s VNC(5900)\n", hiddenService) log.Printf("Checking %s VNC(5900)\n", hiddenService)
_, err := socks.DialSocksProxy(socks.SOCKS5, onionscanConfig.TorProxyAddress)("", hiddenService+":5900") _, err := utils.GetNetworkConnection(hiddenService, 5900, onionscanConfig.TorProxyAddress, onionscanConfig.Timeout)
if err != nil { if err != nil {
log.Printf("Failed to connect to service on port 5900\n") log.Printf("Failed to connect to service on port 5900\n")
report.VNCDetected = false report.VNCDetected = false

View File

@ -14,7 +14,7 @@ func GenerateJsonReport(reportFile string, report *OnionScanReport) {
buffer.WriteString(fmt.Sprintf("%s\n", jsonOut)) buffer.WriteString(fmt.Sprintf("%s\n", jsonOut))
if len(reportFile) > 0 { if len(reportFile) > 0 {
f, err := os.Create(reportFile) f, err := os.Create(report.HiddenService + "." + reportFile)
if err != nil { if err != nil {
log.Fatalf("Cannot create report file: %s", err) log.Fatalf("Cannot create report file: %s", err)
panic(err) panic(err)
@ -172,7 +172,7 @@ func GenerateSimpleReport(reportFile string, report *OnionScanReport) {
} }
if len(reportFile) > 0 { if len(reportFile) > 0 {
f, err := os.Create(reportFile) f, err := os.Create(report.HiddenService + "." + reportFile)
if err != nil { if err != nil {
log.Fatalf("Cannot create report file: %s", err) log.Fatalf("Cannot create report file: %s", err)
panic(err) panic(err)

15
utils/networking.go Normal file
View File

@ -0,0 +1,15 @@
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)
conn.SetDeadline(time.Now().Add(timeout))
return conn, err
}