zoukankan      html  css  js  c++  java
  • Go Pentester

    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
    Scan Credits: %d
    
    ",
    		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
    ", host.IPString, host.Port)
    	}
    }
    

    Run the Shodan search program.

    SHODAN_API_KEY=XXXX go run main.go tomcat

    相信未来 - 该面对的绝不逃避,该执著的永不怨悔,该舍弃的不再留念,该珍惜的好好把握。
  • 相关阅读:
    【网络游戏同步技术】帧同步的一致性
    【C++】STL常用容器总结之五:双端队列deque
    使 egg-multipart 同时支持 stream 和 file
    react + 图灵api 实现模拟客服
    egg 扩展上传文件白名单
    input[type=file] 样式美化,input上传按钮美化
    react-lazyload 实现图片懒加载
    useEffect 模拟 react 生命周期
    egg 实现下载数据,并保存成excel文件
    egg 实现上传excel,并解析保存到数据库
  • 原文地址:https://www.cnblogs.com/keepmoving1113/p/12353296.html
Copyright © 2011-2022 走看看