mirror of
https://github.com/owasp-amass/amass.git
synced 2026-10-12 02:20:44 +00:00
124 lines
2.8 KiB
Go
124 lines
2.8 KiB
Go
// Copyright © by Jeff Foley 2017-2026. All rights reserved.
|
|
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package scrape
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"time"
|
|
|
|
"github.com/owasp-amass/amass/v5/engine/plugins/support"
|
|
et "github.com/owasp-amass/amass/v5/engine/types"
|
|
"github.com/owasp-amass/amass/v5/internal/net/http"
|
|
dbt "github.com/owasp-amass/asset-db/types"
|
|
oam "github.com/owasp-amass/open-asset-model"
|
|
oamnet "github.com/owasp-amass/open-asset-model/network"
|
|
"golang.org/x/time/rate"
|
|
)
|
|
|
|
type ipverse struct {
|
|
name string
|
|
fmtstr string
|
|
log *slog.Logger
|
|
rlimit *rate.Limiter
|
|
source *et.Source
|
|
asns map[int]struct{}
|
|
}
|
|
|
|
func NewIPVerse() et.Plugin {
|
|
limit := rate.Every(2 * time.Second)
|
|
|
|
return &ipverse{
|
|
name: "GitHub-IPVerse",
|
|
fmtstr: "https://raw.githubusercontent.com/ipverse/asn-ip/master/as/%d/aggregated.json",
|
|
rlimit: rate.NewLimiter(limit, 1),
|
|
source: &et.Source{
|
|
Name: "GitHub-IPVerse",
|
|
Confidence: 90,
|
|
},
|
|
asns: make(map[int]struct{}),
|
|
}
|
|
}
|
|
|
|
func (v *ipverse) Name() string {
|
|
return v.name
|
|
}
|
|
|
|
func (v *ipverse) Start(r et.Registry) error {
|
|
v.log = r.Log().WithGroup("plugin").With("name", v.name)
|
|
|
|
if err := r.RegisterHandler(&et.Handler{
|
|
Plugin: v,
|
|
Name: v.name + "-Handler",
|
|
Position: 30,
|
|
Exclusive: true,
|
|
MaxInstances: support.MidHandlerInstances,
|
|
Transforms: []string{string(oam.Netblock)},
|
|
EventType: oam.AutonomousSystem,
|
|
Callback: v.check,
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
v.log.Info("Plugin started")
|
|
return nil
|
|
}
|
|
|
|
func (v *ipverse) Stop() {
|
|
v.log.Info("Plugin stopped")
|
|
}
|
|
|
|
func (v *ipverse) check(e *et.Event) error {
|
|
as, ok := e.Entity.Asset.(*oamnet.AutonomousSystem)
|
|
if !ok {
|
|
return errors.New("failed to extract the AutonomousSystem asset")
|
|
}
|
|
|
|
if _, found := v.asns[as.Number]; found {
|
|
return nil
|
|
}
|
|
|
|
rec := v.query(e.Session, e.Entity)
|
|
if rec == nil {
|
|
return nil
|
|
}
|
|
v.asns[as.Number] = struct{}{}
|
|
|
|
for _, cidr := range append(rec.CIDRs.IPv4, rec.CIDRs.IPv6...) {
|
|
_ = support.AddNetblock(e.Session, cidr, as.Number, v.source)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type record struct {
|
|
ASN int `json:"asn"`
|
|
CIDRs struct {
|
|
IPv4 []string `json:"ipv4"`
|
|
IPv6 []string `json:"ipv6"`
|
|
} `json:"subnets"`
|
|
}
|
|
|
|
func (v *ipverse) query(sess et.Session, asset *dbt.Entity) *record {
|
|
_ = v.rlimit.Wait(sess.Ctx())
|
|
|
|
ctx, cancel := context.WithTimeout(sess.Ctx(), 30*time.Second)
|
|
defer cancel()
|
|
|
|
as := asset.Asset.(*oamnet.AutonomousSystem)
|
|
resp, err := http.RequestWebPage(ctx, &http.Request{URL: fmt.Sprintf(v.fmtstr, as.Number)})
|
|
if err != nil || resp.Body == "" {
|
|
return nil
|
|
}
|
|
|
|
var result record
|
|
if err := json.Unmarshal([]byte(resp.Body), &result); err != nil {
|
|
return nil
|
|
}
|
|
return &result
|
|
}
|