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


浙公网安备 33010602011771号