/
activecert.go
124 lines (111 loc) · 3.17 KB
/
activecert.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Copyright 2017 Jeff Foley. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
package amass
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"strconv"
"strings"
"time"
"github.com/caffix/amass/amass/internal/utils"
)
const (
defaultTLSConnectTimeout = 1 * time.Second
defaultHandshakeDeadline = 3 * time.Second
)
// pullCertificate - Attempts to pull a cert from several ports on an IP
func PullCertificateNames(addr string, ports []int) []*AmassRequest {
var requests []*AmassRequest
// Check hosts for certificates that contain subdomain names
for _, port := range ports {
cfg := &tls.Config{InsecureSkipVerify: true}
// Set the maximum time allowed for making the connection
ctx, cancel := context.WithTimeout(context.Background(), defaultTLSConnectTimeout)
defer cancel()
// Obtain the connection
conn, err := DialContext(ctx, "tcp", addr+":"+strconv.Itoa(port))
if err != nil {
continue
}
defer conn.Close()
c := tls.Client(conn, cfg)
// Attempt to acquire the certificate chain
errChan := make(chan error, 2)
// This goroutine will break us out of the handshake
time.AfterFunc(defaultHandshakeDeadline, func() {
errChan <- errors.New("Handshake timeout")
})
// Be sure we do not wait too long in this attempt
c.SetDeadline(time.Now().Add(defaultHandshakeDeadline))
// The handshake is performed in the goroutine
go func() {
errChan <- c.Handshake()
}()
// The error channel returns handshake or timeout error
if err = <-errChan; err != nil {
continue
}
// Get the correct certificate in the chain
certChain := c.ConnectionState().PeerCertificates
cert := certChain[0]
// Create the new requests from names found within the cert
requests = append(requests, reqFromNames(namesFromCert(cert))...)
}
return requests
}
func namesFromCert(cert *x509.Certificate) []string {
var cn string
for _, name := range cert.Subject.Names {
oid := name.Type
if len(oid) == 4 && oid[0] == 2 && oid[1] == 5 && oid[2] == 4 {
if oid[3] == 3 {
cn = fmt.Sprintf("%s", name.Value)
break
}
}
}
var subdomains []string
// Add the subject common name to the list of subdomain names
commonName := removeAsteriskLabel(cn)
if commonName != "" {
subdomains = append(subdomains, commonName)
}
// Add the cert DNS names to the list of subdomain names
for _, name := range cert.DNSNames {
n := removeAsteriskLabel(name)
if n != "" {
subdomains = utils.UniqueAppend(subdomains, n)
}
}
return subdomains
}
func removeAsteriskLabel(s string) string {
var index int
labels := strings.Split(s, ".")
for i := len(labels) - 1; i >= 0; i-- {
if strings.TrimSpace(labels[i]) == "*" {
break
}
index = i
}
if index == len(labels)-1 {
return ""
}
return strings.Join(labels[index:], ".")
}
func reqFromNames(subdomains []string) []*AmassRequest {
var requests []*AmassRequest
// For each subdomain name, attempt to make a new AmassRequest
for _, name := range subdomains {
requests = append(requests, &AmassRequest{
Name: name,
Domain: SubdomainToDomain(name),
Tag: "cert",
Source: "Active Cert",
})
}
return requests
}