Go Pentester - HTTP CLIENTS(2)

Building an HTTP Client That Interacts with Shodan

Shadon(URL:https://www.shodan.io/)  is the world's first search engine for Internet-connected devices.

Register and get the API key from Shadon, then set it as an environment variable.

 

 

 

 Here is a high-level overview of the typical steps for preparing and building an API client:

1. Review the service's API documentation.

  https://developer.shodan.io/api

2. Design a logical structure for the code in order to reduce complexity and repetition.

Project Structure

 

 main.go: Use primarily to interact with your client implementation.

3. Define request or response types, as necessary, in GO.

Cleaning Up API Calls in shodan.go.

package shodan

const BaseURL = "https://api.shodan.io"

type Client struct {
	apiKey string
}

func New(apiKey string) *Client {
	return &Client{apiKey: apiKey}
}

 

4. Create helper functions and types to facilitate simple initialization, authentication, and communication to reduce verbose or repetitive logic.

 Querying your Shodan Subscription

       api.go

package shodan

import (
	"encoding/json"
	"fmt"
	"net/http"
)

// Ref to shadon API doc: Sample Response
//{
//"query_credits": 56,
//"scan_credits": 0,
//"telnet": true,
//"plan": "edu",
//"https": true,
//"unlocked": true,
//}
type APIInfo struct {
	QueryCredits int    `json:"query_credits"`
	ScanCredits  int    `json:"scan_credits"`
	Telnet       bool   `json:"telnet"`
	Plan         string `json:"plan"`
	HTTPS        bool   `json:"https"`
	Unlocked     bool   `json:"unlocked"`
}

// Making an HTTP GET request and decoding the response
func (s *Client) APIInfo()(*APIInfo, error) {
	// Ref to shodan API Doc: https://api.shodan.io/api-info?key={YOUR_API_KEY}
	res, err := http.Get(fmt.Sprintf("%s/api-info?key=%s", BaseURL, s.apiKey))
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	var ret APIInfo
	if err := json.NewDecoder(res.Body).Decode(&ret); err != nil {
		return nil, err
	}
	return &ret, nil
}

  host.go

package shodan

import (
	"encoding/json"
	"fmt"
	"net/http"
)

// Represents the location element within the host
type HostLocation struct {
	City         string   `json:"city"`
	RegionCode   string   `json:"region_code"`
	AreaCode     int      `json:"area_code"`
	Longitude    float32  `json:"longitude"`
	CountryCode3 string   `json:"country_code3"`
	CountryName  string   `json:"country_name"`
	PostalCode   string   `json:"postal_code"`
	DMACode      int      `json:"dma_code"`
	CountryCode  string   `json:"country_code"`
	Latitude     float32  `json:"latitude"`
}

// Represents a single matches element
type Host struct {
	OS        string         `json:"os"`
	Timestamp string         `json:"timestamp"`
	ISP       string         `json:"isp"`
	ASN       string         `json:"asn"`
	Hostnames []string       `json:"hostnames"`
	Location  HostLocation   `json:"location"`
	IP        int64          `json:"ip"`
	Domains   []string       `json:"domains"`
	Org       string         `json:"org"`
	Data      string         `json:"data"`
	Port      int            `json:"port"`
	IPString  string         `json:"ip_str"`
}

// Used for parsing the matches array
type HostSearch struct {
	Matches []Host `json:"matches"`
}

// Ref to shodan API Doc:  https://api.shodan.io/shodan/host/search?key={YOUR_API_KEY}&query={query}&facets={facets}
func (s *Client) HostSearch(q string) (*HostSearch, error) {
	res, err := http.Get(
		fmt.Sprintf("%s/shodan/host/search?key=%s&query=%s", BaseURL, s.apiKey, q),
		)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	var ret HostSearch
	if err := json.NewDecoder(res.Body).Decode(&ret); err != nil {
		return nil, err
	}

	return &ret, nil
}

  

5. Build the client that interacts with the API consumer functions and types.

 Create a Client- main.go

package main

import (
	"Shodan/src/shodan/shodan"
	"fmt"
	"log"
	"os"
)

func main() {
	if len(os.Args) != 2 {
		log.Fatalln("Usage: shodan searchterm")
	}
	apiKey := os.Getenv("SHODAN_API_KEY")
	s := shodan.New(apiKey)
	info, err := s.APIInfo()
	if err != nil {
		log.Panicln(err)
	}
	fmt.Printf(
		"Query Credits: %d\nScan Credits: %d\n\n",
		info.QueryCredits,
		info.ScanCredits)

	hostSearch, err := s.HostSearch(os.Args[1])
	if err != nil {
		log.Panicln(err)
	}

	for _, host := range hostSearch.Matches {
		fmt.Printf("%18s%8d\n", host.IPString, host.Port)
	}
}

Run the Shodan search program.

SHODAN_API_KEY=XXXX go run main.go tomcat

 

posted @ 2020-02-23 19:04  晨风_Eric  阅读(212)  评论(0编辑  收藏  举报