@@ -11,6 +11,9 @@ import (
11
11
"github.com/caffix/pipeline"
12
12
"github.com/caffix/stringset"
13
13
"github.com/owasp-amass/amass/v4/requests"
14
+ "github.com/owasp-amass/asset-db/types"
15
+ oam "github.com/owasp-amass/open-asset-model"
16
+ "github.com/owasp-amass/open-asset-model/domain"
14
17
)
15
18
16
19
// subdomainTask handles newly discovered proper subdomain names in the enumeration.
@@ -20,6 +23,7 @@ type subdomainTask struct {
20
23
withinWildcards * stringset.Set
21
24
timesChan chan * timesReq
22
25
done chan struct {}
26
+ possibleApexes map [string ]struct {}
23
27
}
24
28
25
29
// newSubdomainTask returns an initialized SubdomainTask.
@@ -30,6 +34,7 @@ func newSubdomainTask(e *Enumeration) *subdomainTask {
30
34
withinWildcards : stringset .New (),
31
35
timesChan : make (chan * timesReq , 10 ),
32
36
done : make (chan struct {}, 2 ),
37
+ possibleApexes : make (map [string ]struct {}),
33
38
}
34
39
35
40
go r .timesManager ()
@@ -41,6 +46,7 @@ func (r *subdomainTask) Stop() {
41
46
close (r .done )
42
47
r .cnames .Close ()
43
48
r .withinWildcards .Close ()
49
+ r .linkNodesToApexes ()
44
50
}
45
51
46
52
// Process implements the pipeline Task interface.
@@ -112,6 +118,7 @@ func (r *subdomainTask) checkForSubdomains(ctx context.Context, req *requests.DN
112
118
113
119
r .enum .sendRequests (subreq )
114
120
if times == 1 {
121
+ r .possibleApexes [sub ] = struct {}{}
115
122
pipeline .SendData (ctx , "root" , subreq , tp )
116
123
}
117
124
return true
@@ -168,3 +175,46 @@ func (r *subdomainTask) timesManager() {
168
175
}
169
176
}
170
177
}
178
+
179
+ func (r * subdomainTask ) linkNodesToApexes () {
180
+ apexes := make (map [string ]* types.Asset )
181
+
182
+ for k := range r .possibleApexes {
183
+ res , err := r .enum .graph .DB .FindByContent (domain.FQDN {Name : k }, r .enum .Config .CollectionStartTime )
184
+ if err != nil || len (res ) == 0 {
185
+ continue
186
+ }
187
+ apex := res [0 ]
188
+
189
+ if rels , err := r .enum .graph .DB .OutgoingRelations (apex , r .enum .Config .CollectionStartTime , "ns_record" ); err == nil && len (rels ) > 0 {
190
+ apexes [k ] = apex
191
+ }
192
+ }
193
+
194
+ for _ , d := range r .enum .Config .Domains () {
195
+ names , err := r .enum .graph .DB .FindByScope ([]oam.Asset {domain.FQDN {Name : d }}, r .enum .Config .CollectionStartTime )
196
+ if err != nil || len (names ) == 0 {
197
+ continue
198
+ }
199
+
200
+ for _ , name := range names {
201
+ n , ok := name .Asset .(domain.FQDN )
202
+ if ! ok {
203
+ continue
204
+ }
205
+ // determine which domain apex this name is a node in
206
+ best := len (n .Name )
207
+ var apex * types.Asset
208
+ for fqdn , a := range apexes {
209
+ if idx := strings .Index (n .Name , fqdn ); idx != - 1 && idx != 0 && idx < best {
210
+ best = idx
211
+ apex = a
212
+ }
213
+ }
214
+
215
+ if apex != nil {
216
+ _ , _ = r .enum .graph .DB .Create (apex , "node" , n )
217
+ }
218
+ }
219
+ }
220
+ }
0 commit comments