New Protocols Scans, SSH Fingerprinting
* SSH Fingerprint * Page Snapshot * A few new Protocol Tests (FTP, SMTP, Ricochet, IRC)
This commit is contained in:
parent
a0ae46ca31
commit
44e6d5c955
|
@ -84,7 +84,7 @@ or their users at risk of deanonymization.
|
||||||
## Server Fingerprint
|
## Server Fingerprint
|
||||||
|
|
||||||
Sometimes, even without mod_status we can determine if two sites are hosted on
|
Sometimes, even without mod_status we can determine if two sites are hosted on
|
||||||
the sam infrastructure. We can use the following attributes to make this distinction:
|
the same infrastructure. We can use the following attributes to make this distinction:
|
||||||
|
|
||||||
* Server HTTP Header
|
* Server HTTP Header
|
||||||
* Technology Stack (e.g. php, jquery version etc.)
|
* Technology Stack (e.g. php, jquery version etc.)
|
||||||
|
|
16
onionscan.go
16
onionscan.go
|
@ -42,5 +42,21 @@ func (os *OnionScan) Scan(hiddenService string) (*report.OnionScanReport, error)
|
||||||
rps := new(protocol.RicochetProtocolScanner)
|
rps := new(protocol.RicochetProtocolScanner)
|
||||||
rps.ScanProtocol(hiddenService, os.TorProxyAddress, report)
|
rps.ScanProtocol(hiddenService, os.TorProxyAddress, report)
|
||||||
|
|
||||||
|
// Bitcoin
|
||||||
|
bps := new(protocol.BitcoinProtocolScanner)
|
||||||
|
bps.ScanProtocol(hiddenService, os.TorProxyAddress, report)
|
||||||
|
|
||||||
|
//IRC
|
||||||
|
ips := new(protocol.IRCProtocolScanner)
|
||||||
|
ips.ScanProtocol(hiddenService, os.TorProxyAddress, report)
|
||||||
|
|
||||||
|
//FTP
|
||||||
|
fps := new(protocol.FTPProtocolScanner)
|
||||||
|
fps.ScanProtocol(hiddenService, os.TorProxyAddress, report)
|
||||||
|
|
||||||
|
//SMTP
|
||||||
|
smps := new(protocol.SMTPProtocolScanner)
|
||||||
|
smps.ScanProtocol(hiddenService, os.TorProxyAddress, report)
|
||||||
|
|
||||||
return report, nil
|
return report, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/s-rah/onionscan/report"
|
||||||
|
"h12.me/socks"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BitcoinProtocolScanner struct {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rps *BitcoinProtocolScanner) ScanProtocol(hiddenService string, proxyAddress string, report *report.OnionScanReport) {
|
||||||
|
// Bitcoin
|
||||||
|
log.Printf("Checking %s Bitcoin(8333)\n", hiddenService)
|
||||||
|
_, err := socks.DialSocksProxy(socks.SOCKS5, proxyAddress)("", hiddenService+":8333")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to connect to service on port 8333\n")
|
||||||
|
} else {
|
||||||
|
log.Printf("Detected possible Bitcoin instance\n")
|
||||||
|
// TODO: Actual Analysis
|
||||||
|
report.BitcoinDetected = true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/s-rah/onionscan/report"
|
||||||
|
"h12.me/socks"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FTPProtocolScanner struct {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sps *FTPProtocolScanner) ScanProtocol(hiddenService string, proxyAddress string, report *report.OnionScanReport) {
|
||||||
|
// FTP
|
||||||
|
log.Printf("Checking %s FTP(22)\n", hiddenService)
|
||||||
|
_, err := socks.DialSocksProxy(socks.SOCKS5, proxyAddress)("", hiddenService+":21")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to connect to service on port 21\n")
|
||||||
|
} else {
|
||||||
|
// TODO FTP Checking
|
||||||
|
report.FTPDetected = true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ func (hps * HTTPProtocolScanner) ScanProtocol(hiddenService string, proxyAddress
|
||||||
log.Printf("Failed to connect to service on port 80\n")
|
log.Printf("Failed to connect to service on port 80\n")
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Found potential service on http(80)\n")
|
log.Printf("Found potential service on http(80)\n")
|
||||||
|
report.WebDetected = true
|
||||||
dialSocksProxy := socks.DialSocksProxy(socks.SOCKS5, proxyAddress)
|
dialSocksProxy := socks.DialSocksProxy(socks.SOCKS5, proxyAddress)
|
||||||
transportConfig := &http.Transport{
|
transportConfig := &http.Transport{
|
||||||
Dial: dialSocksProxy,
|
Dial: dialSocksProxy,
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/s-rah/onionscan/report"
|
||||||
|
"h12.me/socks"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IRCProtocolScanner struct {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rps *IRCProtocolScanner) ScanProtocol(hiddenService string, proxyAddress string, report *report.OnionScanReport) {
|
||||||
|
// IRC
|
||||||
|
log.Printf("Checking %s IRC(6667)\n", hiddenService)
|
||||||
|
_, err := socks.DialSocksProxy(socks.SOCKS5, proxyAddress)("", hiddenService+":6667")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to connect to service on port 6667\n")
|
||||||
|
} else {
|
||||||
|
log.Printf("Detected possible IRC instance\n")
|
||||||
|
// TODO: Actual Analysis
|
||||||
|
report.IRCDetected = true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ func (rps *RicochetProtocolScanner) ScanProtocol(hiddenService string, proxyAddr
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Detected possible ricochet instance\n")
|
log.Printf("Detected possible ricochet instance\n")
|
||||||
// TODO: Actual Analysis
|
// TODO: Actual Analysis
|
||||||
|
report.RicochetDetected = true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/s-rah/onionscan/report"
|
||||||
|
"h12.me/socks"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SMTPProtocolScanner struct {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sps *SMTPProtocolScanner) ScanProtocol(hiddenService string, proxyAddress string, report *report.OnionScanReport) {
|
||||||
|
// SMTP
|
||||||
|
log.Printf("Checking %s SMTP(25)\n", hiddenService)
|
||||||
|
_, err := socks.DialSocksProxy(socks.SOCKS5, proxyAddress)("", hiddenService+":25")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to connect to service on port 25\n")
|
||||||
|
} else {
|
||||||
|
// TODO SMTP Checking
|
||||||
|
report.SMTPDetected = true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,6 +4,11 @@ import (
|
||||||
"github.com/s-rah/onionscan/report"
|
"github.com/s-rah/onionscan/report"
|
||||||
"h12.me/socks"
|
"h12.me/socks"
|
||||||
"log"
|
"log"
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
"net"
|
||||||
|
"errors"
|
||||||
|
"crypto/md5"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SSHProtocolScanner struct {
|
type SSHProtocolScanner struct {
|
||||||
|
@ -13,11 +18,35 @@ type SSHProtocolScanner struct {
|
||||||
func (sps *SSHProtocolScanner) ScanProtocol(hiddenService string, proxyAddress string, report *report.OnionScanReport) {
|
func (sps *SSHProtocolScanner) ScanProtocol(hiddenService string, proxyAddress string, report *report.OnionScanReport) {
|
||||||
// SSH
|
// SSH
|
||||||
log.Printf("Checking %s ssh(22)\n", hiddenService)
|
log.Printf("Checking %s ssh(22)\n", hiddenService)
|
||||||
_, err := socks.DialSocksProxy(socks.SOCKS5, proxyAddress)("", hiddenService+":22")
|
conn, err := socks.DialSocksProxy(socks.SOCKS5, proxyAddress)("", hiddenService+":22")
|
||||||
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")
|
||||||
} else {
|
} else {
|
||||||
// TODO SSH Checking
|
// TODO SSH Checking
|
||||||
|
report.SSHDetected = true
|
||||||
|
|
||||||
|
config := &ssh.ClientConfig {
|
||||||
|
HostKeyCallback : func (hostname string, addr net.Addr, key ssh.PublicKey) error {
|
||||||
|
h := md5.New()
|
||||||
|
h.Write(key.Marshal())
|
||||||
|
|
||||||
|
fBytes := h.Sum(nil)
|
||||||
|
fingerprint := string("")
|
||||||
|
for i := 0; i < len(fBytes); i++ {
|
||||||
|
if i+1 != len(fBytes) {
|
||||||
|
fingerprint = fmt.Sprintf("%s%0.2x:", fingerprint, fBytes[i])
|
||||||
|
} else {
|
||||||
|
fingerprint = fmt.Sprintf("%s%0.2x", fingerprint, fBytes[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
report.SSHKey = 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)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ package report
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"github.com/s-rah/onionscan/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ExifTag struct {
|
type ExifTag struct {
|
||||||
|
@ -15,18 +17,43 @@ type ExifImage struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type OnionScanReport struct {
|
type OnionScanReport struct {
|
||||||
|
|
||||||
|
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"`
|
||||||
|
|
||||||
HiddenService string `json:"hiddenService"`
|
HiddenService string `json:"hiddenService"`
|
||||||
ServerPoweredBy string `json:"serverPoweredBy"`
|
ServerPoweredBy string `json:"serverPoweredBy"`
|
||||||
ServerVersion string `json:"serverVersion"`
|
ServerVersion string `json:"serverVersion"`
|
||||||
FoundApacheModStatus bool `json:"foundApacheModStatus"`
|
FoundApacheModStatus bool `json:"foundApacheModStatus"`
|
||||||
RelatedOnionServices []string `json:"relatedOnionServices"`
|
RelatedOnionServices []string `json:"relatedOnionServices"`
|
||||||
RelatedClearnetDomains []string `json:"relatedOnionDomains"`
|
RelatedClearnetDomains []string `json:"relatedOnionDomains"`
|
||||||
|
LinkedSites []string `json:"linkedSites"`
|
||||||
IP []string `json:"ipAddresses"`
|
IP []string `json:"ipAddresses"`
|
||||||
OpenDirectories []string `json:"openDirectories"`
|
OpenDirectories []string `json:"openDirectories"`
|
||||||
ExifImages []ExifImage `json:"exifImages"`
|
ExifImages []ExifImage `json:"exifImages"`
|
||||||
InterestingFiles []string `json:"interestingFiles"`
|
InterestingFiles []string `json:"interestingFiles"`
|
||||||
|
Hashes []string `json:"hashes"`
|
||||||
|
SSHKey string `json:"sshKey"`
|
||||||
|
Snapshot string `json:"snapshot"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LoadReportFromFile(filename string) (OnionScanReport, error) {
|
||||||
|
dat, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return OnionScanReport{}, err
|
||||||
|
}
|
||||||
|
res := OnionScanReport{}
|
||||||
|
err = json.Unmarshal(dat, &res)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func NewOnionScanReport(hiddenService string) *OnionScanReport {
|
func NewOnionScanReport(hiddenService string) *OnionScanReport {
|
||||||
return &OnionScanReport{HiddenService: hiddenService}
|
return &OnionScanReport{HiddenService: hiddenService}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +78,11 @@ func (osr *OnionScanReport) AddIPAddress(ip string) {
|
||||||
osr.IP = append(osr.IP, ip)
|
osr.IP = append(osr.IP, ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (osr *OnionScanReport) AddLinkedSite(site string) {
|
||||||
|
osr.LinkedSites = append(osr.LinkedSites, site)
|
||||||
|
utils.RemoveDuplicates(&osr.LinkedSites)
|
||||||
|
}
|
||||||
|
|
||||||
func (osr *OnionScanReport) Serialize() (string, error) {
|
func (osr *OnionScanReport) Serialize() (string, error) {
|
||||||
report,err := json.Marshal(osr)
|
report,err := json.Marshal(osr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -3,9 +3,12 @@ package scans
|
||||||
import (
|
import (
|
||||||
"github.com/s-rah/onionscan/report"
|
"github.com/s-rah/onionscan/report"
|
||||||
"github.com/s-rah/onionscan/utils"
|
"github.com/s-rah/onionscan/utils"
|
||||||
|
"net/url"
|
||||||
"log"
|
"log"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/hex"
|
||||||
)
|
)
|
||||||
|
|
||||||
func StandardPageScan(scan Scanner, page string, status int, contents string, report *report.OnionScanReport) {
|
func StandardPageScan(scan Scanner, page string, status int, contents string, report *report.OnionScanReport) {
|
||||||
|
@ -13,6 +16,10 @@ func StandardPageScan(scan Scanner, page string, status int, contents string, re
|
||||||
if status == 200 {
|
if status == 200 {
|
||||||
log.Printf("\tPage %s%s is Accessible\n", report.HiddenService, page)
|
log.Printf("\tPage %s%s is Accessible\n", report.HiddenService, page)
|
||||||
|
|
||||||
|
hash := sha1.Sum([]byte(contents))
|
||||||
|
report.Hashes = append(report.Hashes, hex.EncodeToString(hash[:]))
|
||||||
|
report.Snapshot = contents
|
||||||
|
|
||||||
domains := utils.ExtractDomains(contents)
|
domains := utils.ExtractDomains(contents)
|
||||||
|
|
||||||
for _,domain := range domains {
|
for _,domain := range domains {
|
||||||
|
@ -22,8 +29,11 @@ func StandardPageScan(scan Scanner, page string, status int, contents string, re
|
||||||
// * Links to standard sites - google / bitpay etc.
|
// * Links to standard sites - google / bitpay etc.
|
||||||
// * Links to other onion sites
|
// * Links to other onion sites
|
||||||
// * Links to obscure clearnet sites.
|
// * Links to obscure clearnet sites.
|
||||||
|
baseUrl,_ := url.Parse(domain)
|
||||||
|
report.AddLinkedSite(baseUrl.Host)
|
||||||
} else {
|
} else {
|
||||||
// * Process Internal links
|
// * Process Internal links
|
||||||
|
log.Printf("Found Internal URL %s\n", domain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,3 +50,5 @@ func StandardPageScan(scan Scanner, page string, status int, contents string, re
|
||||||
log.Printf("\tPage %s%s is Does Not Exist\n", report.HiddenService, page)
|
log.Printf("\tPage %s%s is Does Not Exist\n", report.HiddenService, page)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue