Files
2025-02-19 21:10:27 +01:00

188 lines
4.0 KiB
Go
Executable File

/*
asnip: ASN target organization IP range attack surface mapping
by github.com/harleo — MIT Licence
*/
package main
import (
"bufio"
"flag"
"fmt"
"io"
"log"
"net"
"net/http"
"os"
"regexp"
"sort"
"strings"
)
type sliceVal []string
func (s sliceVal) String() string {
var str string
for _, i := range s {
str += fmt.Sprintf("%s\n", i)
}
return str
}
func writeLines(lines []string, path string) {
file, err := os.Create(path)
if err != nil {
log.Fatalf("[!] Couldn't create file: %s\n", err.Error())
}
defer func(file *os.File) {
err := file.Close()
if err != nil {
log.Fatalf("Failed to write file %s: %s", file.Name(), err)
}
}(file)
w := bufio.NewWriter(file)
for _, line := range lines {
_, err := fmt.Fprintln(w, line)
if err != nil {
log.Fatalf("Failed to write '%s' to file %s: %s", line, file.Name(), err)
}
}
flushErr := w.Flush()
if flushErr != nil {
log.Fatalf("Couldn't write file %s: %s", file.Name(), flushErr)
}
}
func httpRequest(URI string) string {
response, errGet := http.Get(URI)
if errGet != nil {
log.Fatalf("[!] Error sending request: %s\n", errGet.Error())
}
responseText, errRead := io.ReadAll(response.Body)
if errRead != nil {
log.Fatalf("[!] Error reading response: %s\n", errRead.Error())
}
defer func(Body io.ReadCloser) {
err := Body.Close()
if err != nil {
os.Exit(1)
}
}(response.Body)
return string(responseText)
}
func incrementIP(ip net.IP) {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++
if ip[j] > 0 {
break
}
}
}
func IsIPv6CIDR(cidr string) bool {
ip, _, _ := net.ParseCIDR(cidr)
return ip != nil && ip.To4() == nil
}
func CIDRToIP(cidr string) []string {
ip, ipnet, err := net.ParseCIDR(cidr)
if err != nil {
log.Fatalf("[!] Failed to convert CIDR to IP: %s\n", err.Error())
}
var ips []string
for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); incrementIP(ip) {
ips = append(ips, ip.String())
}
// Exclude network and broadcast addresses
if len(ips) >= 3 {
return ips[1 : len(ips)-1]
} else {
return ips
}
}
func getIP(ipDomain string) []net.IP {
ip, err := net.LookupIP(ipDomain)
if err != nil {
log.Fatalf("[!] Error looking up domain: %s\n", err.Error())
}
return ip
}
func parseResponse(response string) []string {
r := regexp.MustCompile(`[^\s"']+|"([^"]*)"|'([^']*)`)
arr := r.FindAllString(response, -1)
return arr
}
func checkAPIRateLimit(response string) {
if strings.Contains(response, "API") {
fmt.Println("[!] The HackerTarget API limit was reached, exiting...")
os.Exit(0)
}
}
func main() {
var (
target = flag.String("t", "", "Domain or IP address (Required)")
onlyPrint = flag.Bool("p", false, "Only print results to console")
onlyCidrs = flag.Bool("c", false, "Only download list of CIDRs")
)
flag.Parse()
ipAddress := getIP(*target)[0]
apiRequest := fmt.Sprintf("https://api.hackertarget.com/aslookup/?q=%s", ipAddress)
apiResponse := httpRequest(apiRequest)
apiResponseInfo := parseResponse(apiResponse)
checkAPIRateLimit(apiResponse)
fmt.Printf("[?] ASN: %s ORG: %s\n", apiResponseInfo[2], apiResponseInfo[6])
apiASRequest := fmt.Sprintf("https://api.hackertarget.com/aslookup/?q=AS%s", strings.Trim(apiResponseInfo[2], "\""))
apiASResponse := httpRequest(apiASRequest)
apiASResponseInfo := parseResponse(apiASResponse)
checkAPIRateLimit(apiASResponse)
var CIDRSv4 []string
for _, cidrV4 := range apiASResponseInfo[3:] {
if !IsIPv6CIDR(cidrV4) {
CIDRSv4 = append(CIDRSv4, cidrV4)
}
}
sort.Strings(CIDRSv4)
if *onlyPrint {
fmt.Print(sliceVal(CIDRSv4))
} else {
fmt.Printf("[:] Writing %d CIDRs to file...\n", len(CIDRSv4))
writeLines(CIDRSv4, "cidrs.txt")
}
if !*onlyCidrs {
var ips []string
fmt.Println("[:] Converting to IPs...")
for _, cidr := range CIDRSv4 {
ips = append(ips, CIDRToIP(cidr)...)
}
if *onlyPrint {
for _, ipsValue := range ips {
fmt.Println(ipsValue)
}
} else {
fmt.Printf("[:] Writing %d IPs to file...\n", len(ips))
writeLines(ips, "ips.txt")
}
}
fmt.Println("[!] Done.")
}