mirror of
https://github.com/jayateertha043/goshod.git
synced 2026-07-21 20:11:02 +00:00
Added all files
This commit is contained in:
parent
07699d6e37
commit
fa53e7b7a0
11 changed files with 815 additions and 0 deletions
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# If you prefer the allow list template instead of the deny list, see community template:
|
||||
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
||||
#
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
*.txt
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Go workspace file
|
||||
go.work
|
||||
BIN
GoShod.gif
Normal file
BIN
GoShod.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 MiB |
161
GoShod.go
Normal file
161
GoShod.go
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"mime"
|
||||
"net"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/jayateertha043/goshod/pkg/shodan_utils"
|
||||
"github.com/pkg/browser"
|
||||
)
|
||||
|
||||
var ApiKey string = ""
|
||||
|
||||
func main() {
|
||||
|
||||
printbanner()
|
||||
apiKey := flag.String("api", "", "Your Shodan API Key, One time Configure.")
|
||||
flag.Parse()
|
||||
if strings.TrimSpace(*apiKey) != "" {
|
||||
ApiKey = strings.TrimSpace(*apiKey)
|
||||
b_api := []byte(ApiKey)
|
||||
err := ioutil.WriteFile("./shodan_config.txt", b_api, 0666)
|
||||
if err != nil {
|
||||
log.Fatalln("[*] Error writing api to configuration file at ./shodan_config.txt")
|
||||
}
|
||||
log.Println("[*] Api Key Configured at ./shodan_config.txt")
|
||||
}
|
||||
|
||||
var server_wg = new(sync.WaitGroup)
|
||||
log.Println("[*] Looking for shodan_config.txt at current directory")
|
||||
b, err := ioutil.ReadFile("./shodan_config.txt")
|
||||
if err != nil {
|
||||
log.Fatalln("[*] Shodan_config.txt not found, Kindly configure Shodan api key.")
|
||||
}
|
||||
|
||||
ApiKey = strings.TrimSpace(string(b))
|
||||
uri := startServer(server_wg)
|
||||
log.Println("[*] Server started at: " + uri)
|
||||
browser.OpenURL(uri)
|
||||
server_wg.Wait()
|
||||
}
|
||||
func startServer(wg *sync.WaitGroup) string {
|
||||
wg.Add(1)
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
go func() {
|
||||
defer ln.Close()
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
path := r.URL.Path
|
||||
w.Header().Add("Access-Control-Allow-Origin", "*")
|
||||
if path == "" || path == "/" {
|
||||
path = "./html/index.html"
|
||||
w.Header().Add("Content-Type", mime.TypeByExtension(filepath.Ext(path)))
|
||||
bs, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
io.Copy(w, bytes.NewBuffer(bs))
|
||||
} else if path == "/shodanpagecount" && r.Method == "POST" {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
apikey := ApiKey
|
||||
//apikey := r.FormValue("apikey")
|
||||
search := r.FormValue("search")
|
||||
|
||||
if strings.TrimSpace(apikey) == "" || strings.TrimSpace(search) == "" {
|
||||
w.WriteHeader(401)
|
||||
w.Write([]byte("missing necessary params !"))
|
||||
|
||||
} else {
|
||||
params := make(map[string]string, 0)
|
||||
params["key"] = apikey
|
||||
params["query"] = search
|
||||
status_code, page_count, response_body := shodan_utils.ShodanSearchHostCount(params)
|
||||
if status_code == 200 && page_count > 0 && response_body != "" {
|
||||
w.WriteHeader(status_code)
|
||||
p_str := strconv.Itoa(page_count)
|
||||
w.Write([]byte(p_str))
|
||||
} else if page_count == -101 {
|
||||
w.WriteHeader(status_code)
|
||||
w.Write([]byte(response_body))
|
||||
} else {
|
||||
w.WriteHeader(status_code)
|
||||
w.Write([]byte(response_body))
|
||||
}
|
||||
}
|
||||
} else if path == "/shodansearch" && r.Method == "POST" {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
apikey := ApiKey
|
||||
//apikey := r.FormValue("apikey")
|
||||
search := r.FormValue("search")
|
||||
page := r.FormValue("page")
|
||||
_, err = strconv.Atoi(page)
|
||||
if err != nil || page == "" {
|
||||
page = "1"
|
||||
}
|
||||
|
||||
if strings.TrimSpace(apikey) == "" || strings.TrimSpace(search) == "" || strings.TrimSpace(page) == "" {
|
||||
w.WriteHeader(401)
|
||||
w.Write([]byte("missing necessary params !"))
|
||||
|
||||
} else {
|
||||
params := make(map[string]string, 0)
|
||||
params["key"] = apikey
|
||||
params["query"] = search
|
||||
params["page"] = page
|
||||
if params["page"] < "0" {
|
||||
params["page"] = "1"
|
||||
}
|
||||
|
||||
status_code, response_body := shodan_utils.GetShodanResultForPage(params)
|
||||
w.WriteHeader(status_code)
|
||||
w.Write([]byte(response_body))
|
||||
|
||||
}
|
||||
} else {
|
||||
path = "./html/" + path[1:]
|
||||
w.Header().Add("Content-Type", mime.TypeByExtension(filepath.Ext(path)))
|
||||
bs, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
io.Copy(w, bytes.NewBuffer(bs))
|
||||
}
|
||||
})
|
||||
log.Fatal(http.Serve(ln, nil))
|
||||
}()
|
||||
return "http://" + ln.Addr().String()
|
||||
}
|
||||
|
||||
func printbanner() {
|
||||
banner :=
|
||||
`
|
||||
|
||||
██████╗ ██████╗ ███████╗██╗ ██╗ ██████╗ ██████╗
|
||||
██╔════╝ ██╔═══██╗██╔════╝██║ ██║██╔═══██╗██╔══██╗
|
||||
██║ ███╗██║ ██║███████╗███████║██║ ██║██║ ██║
|
||||
██║ ██║██║ ██║╚════██║██╔══██║██║ ██║██║ ██║
|
||||
╚██████╔╝╚██████╔╝███████║██║ ██║╚██████╔╝██████╔╝
|
||||
╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝
|
||||
|
||||
`
|
||||
fmt.Println(banner)
|
||||
}
|
||||
8
go.mod
Normal file
8
go.mod
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
module github.com/jayateertha043/goshod
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/Jeffail/gabs v1.4.0
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8
|
||||
)
|
||||
6
go.sum
Normal file
6
go.sum
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo=
|
||||
github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71 h1:X/2sJAybVknnUnV7AD2HdT6rm2p5BP6eH2j+igduWgk=
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
3
html/css/style.css
Normal file
3
html/css/style.css
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#app {
|
||||
background-color: var(--v-background-base);
|
||||
}
|
||||
106
html/index.html
Normal file
106
html/index.html
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<link>
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet" />
|
||||
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@6.x/css/materialdesignicons.min.css" rel="stylesheet" />
|
||||
<link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet" />
|
||||
<link href="./css/style.css" rel="stylesheet">
|
||||
</link>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<v-app>
|
||||
<v-main>
|
||||
<template>
|
||||
<v-container full-width fluid>
|
||||
<v-card>
|
||||
<v-card-title primary-title>
|
||||
<p class="text-h3 font-weight-bold mx-auto px-auto">GoShoD</p>
|
||||
</v-card-title>
|
||||
<v-divider></v-divider>
|
||||
<v-card-text class="pa-3">
|
||||
<v-container d-flex>
|
||||
|
||||
<v-text-field label="Shodan Search" name="search" type="text" dense solo v-model="search">
|
||||
</v-text-field>
|
||||
|
||||
<v-btn raised color="primary" class="ml-3" @click="shodanHostSearch(search,-1,$event)">Search</v-btn>
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<div class="my-3 d-flex flex-row justify-center" v-if="showLoading">
|
||||
<v-progress-circular class="justify-center" indeterminate color="primary"></v-progress-circular>
|
||||
</div>
|
||||
|
||||
<v-card id="card_list" class="my-3" v-if="host_result.matches.length>0">
|
||||
<v-card-text>
|
||||
<v-simple-table>
|
||||
<template v-slot:default>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>IP</th>
|
||||
<th>Product</th>
|
||||
<th>Version</th>
|
||||
<th>Port</th>
|
||||
<th>Organisation</th>
|
||||
<th>Hostnames</th>
|
||||
<th>Country</th>
|
||||
<th>City</th>
|
||||
<th>Timestamp</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="result in host_result.matches">
|
||||
|
||||
<td><a :href='"https://shodan.io/host/"+result.ip_str' target="_blank" rel="noreferrer noopener">{{result.ip_str}}</a></td>
|
||||
|
||||
<td>{{result.product}}</td>
|
||||
<td>{{result.version}}</td>
|
||||
<td>{{result.port}}</td>
|
||||
<td>{{result.org}}</td>
|
||||
<td>{{result.hostnames.join(", ")}}</td>
|
||||
<td>{{result.location.country_name}}</td>
|
||||
<td>{{result.location.city}}</td>
|
||||
<td>{{result.timestamp.split(".")[0]}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
</template>
|
||||
</v-simple-table>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<template>
|
||||
<div class="my-3 d-flex flex-row justify-center" class="my-3" v-if="host_result.matches.length>0">
|
||||
<v-btn icon x-large @click="prevPage">
|
||||
<v-icon>mdi-chevron-left</v-icon>
|
||||
</v-btn>
|
||||
<v-btn icon x-large>
|
||||
{{curPage}}
|
||||
</v-btn>
|
||||
<v-btn icon x-large @click="nextPage">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
</v-container>
|
||||
</v-main>
|
||||
</v-app>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>
|
||||
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
||||
<script src="./js/app.js"></script>
|
||||
<script>
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
185
html/js/app.js
Normal file
185
html/js/app.js
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
const vuetify = new Vuetify({
|
||||
theme: {
|
||||
themes: {
|
||||
dark: {
|
||||
primary: '#620ee',
|
||||
secondary: '#03dac5',
|
||||
accent: '#82B1FF',
|
||||
error: '#FF5252',
|
||||
info: '#2196F3',
|
||||
success: '#4CAF50',
|
||||
warning: '#FFC107',
|
||||
background: '#121212',
|
||||
},
|
||||
|
||||
},
|
||||
options: {
|
||||
customProperties: true
|
||||
},
|
||||
},
|
||||
});
|
||||
const app = new Vue({
|
||||
el: "#app",
|
||||
vuetify: vuetify,
|
||||
data: () => ({
|
||||
search:"",
|
||||
host_result:null,
|
||||
maxPage:1,
|
||||
minPage:1,
|
||||
curPage:1,
|
||||
showLoading:false,
|
||||
|
||||
}),
|
||||
created(){
|
||||
this.$vuetify.theme.dark = true;
|
||||
},
|
||||
mounted () {
|
||||
this.host_result={matches:[]}
|
||||
},
|
||||
methods: {
|
||||
shodanHostSearch(search,page,event){
|
||||
event.preventDefault();
|
||||
this.host_result={matches:[]}
|
||||
this.showLoading=true;
|
||||
var params = new URLSearchParams();
|
||||
params.append("search",search);
|
||||
console.log(params.get("search"));
|
||||
console.log("Search param submitted: "+params.get("search"))
|
||||
|
||||
|
||||
if(page!=-1&&page<0){
|
||||
page=1;
|
||||
}
|
||||
|
||||
params.append("page",page);
|
||||
console.log("Page:",page);
|
||||
//If first time clicked on search, need page count
|
||||
if(page=="-1"){
|
||||
this.showLoading=true;
|
||||
axios({
|
||||
method: "post",
|
||||
url: "/shodanpagecount",
|
||||
data: params,
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
}).then( (response)=>{
|
||||
var tmp = parseInt(response.data);
|
||||
console.log("Pages:",tmp);
|
||||
if(tmp<=0){
|
||||
alert("No hosts found")
|
||||
}
|
||||
if(tmp!=NaN&&tmp>0){
|
||||
this.maxPage = tmp;
|
||||
this.minPage = 1;
|
||||
this.curPage = 1;
|
||||
params.set("page",this.curPage);
|
||||
this.showLoading=true;
|
||||
axios({
|
||||
method: "post",
|
||||
url: "/shodansearch",
|
||||
data: params,
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
}).then( (response)=>{
|
||||
this.host_result = response.data
|
||||
}).catch((e)=>{
|
||||
this.showLoading=false;
|
||||
console.log(e);
|
||||
if(e.response){
|
||||
console.log(e.response.data);
|
||||
var err = e.response.data.error;
|
||||
alert(err);
|
||||
}
|
||||
}).then(()=>{
|
||||
this.showLoading=false;
|
||||
});
|
||||
}
|
||||
}).catch((e)=>{
|
||||
this.showLoading=false;
|
||||
console.log(e)
|
||||
alert("Error, Try again later !!!");
|
||||
}).then(()=>{
|
||||
});
|
||||
|
||||
}else{
|
||||
axios({
|
||||
method: "post",
|
||||
url: "/shodansearch",
|
||||
data: params,
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
}).then( (response)=>{
|
||||
this.host_result = response.data
|
||||
console.log(response.data)
|
||||
}).catch((e)=>{
|
||||
this.showLoading=false;
|
||||
console.log(e)
|
||||
if(e.response){
|
||||
console.log(e.response.data);
|
||||
var err = e.response.data.error;
|
||||
alert(err);
|
||||
}
|
||||
}).then(()=>{
|
||||
this.showLoading=false;
|
||||
});
|
||||
}
|
||||
},
|
||||
nextPage(){
|
||||
if(this.curPage<this.maxPage){
|
||||
this.curPage++;
|
||||
var params = new URLSearchParams();
|
||||
params.append("search",this.search);
|
||||
params.append("page",this.curPage)
|
||||
axios({
|
||||
method: "post",
|
||||
url: "/shodansearch",
|
||||
data: params,
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
}).then( (response)=>{
|
||||
this.host_result = response.data
|
||||
}).catch((e)=>{
|
||||
this.curPage--;
|
||||
this.showLoading=false;
|
||||
console.log(e);
|
||||
if(e.response){
|
||||
console.log(e.response.data);
|
||||
var err = e.response.data.error;
|
||||
alert(err);
|
||||
}
|
||||
}).then(()=>{
|
||||
this.showLoading=false;
|
||||
});
|
||||
}else{
|
||||
alert("Max Pages Reached !!!");
|
||||
}
|
||||
|
||||
},
|
||||
prevPage(){
|
||||
if(this.curPage>this.minPage){
|
||||
this.curPage--;
|
||||
var params = new URLSearchParams();
|
||||
params.append("search",this.search);
|
||||
params.append("page",this.curPage)
|
||||
axios({
|
||||
method: "post",
|
||||
url: "/shodansearch",
|
||||
data: params,
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
}).then( (response)=>{
|
||||
this.host_result = response.data
|
||||
}).catch((e)=>{
|
||||
this.curPage++;
|
||||
this.showLoading=false;
|
||||
console.log(e);
|
||||
if(e.response){
|
||||
console.log(e.response.data);
|
||||
var err = e.response.data.error;
|
||||
alert(err);
|
||||
}
|
||||
}).then(()=>{
|
||||
this.showLoading=false;
|
||||
});
|
||||
}else{
|
||||
alert("Min Page Reached !!!");
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
});
|
||||
25
html/js/shodan_utils.js
Normal file
25
html/js/shodan_utils.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
function shodanSearch(){
|
||||
|
||||
searchbar = document.getElementById("search").value;
|
||||
search = document.getElementById("search").value;
|
||||
console.log("Executing shodanSearch ...")
|
||||
console.log(searchbar)
|
||||
|
||||
|
||||
var xhttp = new XMLHttpRequest();
|
||||
var url = '/shodansearch';
|
||||
|
||||
xhttp.open("POST", url, true);
|
||||
xhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||
var response_body="";
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
// Typical action to be performed when the document is ready:
|
||||
response_body = xhttp.responseText
|
||||
console.log(response_body);
|
||||
}
|
||||
};
|
||||
xhttp.send("search="+search);
|
||||
|
||||
|
||||
}
|
||||
248
pkg/httpclient/httpclient.go
Normal file
248
pkg/httpclient/httpclient.go
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
package httpclient
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var userAgents = []string{
|
||||
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Safari/604.1.38",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Safari/604.1.38",
|
||||
}
|
||||
|
||||
var mu = new(sync.Mutex)
|
||||
|
||||
//Build Default Headers sent with every request
|
||||
func BuildDefaultHeaders() map[string]string {
|
||||
return map[string]string{
|
||||
"User-Agent": "goshod by @jayateerthag", //RandomUA(),
|
||||
"Accept": "text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8",
|
||||
"Accept-Language": "en-US,en;q=0.5",
|
||||
// "Accept-Encoding": "gzip,deflate",
|
||||
"DNT": "1",
|
||||
//"Connection": "close",
|
||||
}
|
||||
}
|
||||
|
||||
//Get request with params
|
||||
func GetRequestP(url string, params map[string]string, headers map[string]string, timeoutP int) (*http.Response, error) {
|
||||
timeout := timeoutP
|
||||
if timeout <= 0 {
|
||||
timeout = 5
|
||||
}
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
|
||||
transport := &http.Transport{
|
||||
TLSClientConfig: tlsConfig,
|
||||
}
|
||||
|
||||
var client = new(http.Client)
|
||||
|
||||
client = &http.Client{Transport: transport, Timeout: time.Duration(timeout) * time.Second}
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Close = true
|
||||
|
||||
//params adding and encoding
|
||||
q := req.URL.Query()
|
||||
for name, value := range params {
|
||||
q.Add(name, value)
|
||||
}
|
||||
req.URL.RawQuery = q.Encode()
|
||||
|
||||
//Set Default Headers with Ramdom UA
|
||||
tmpHeaders := BuildDefaultHeaders()
|
||||
for key, value := range tmpHeaders {
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
if headers != nil {
|
||||
for key, value := range headers {
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
}
|
||||
mu.Unlock()
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
func GetRequest(uri string, headers map[string]string, timeoutP int, proxy string) (*http.Response, error) {
|
||||
h := CloneHeaders(headers)
|
||||
pu, err := url.Parse(proxy)
|
||||
|
||||
if proxy != "" {
|
||||
if err != nil {
|
||||
fmt.Println("Invalid proxy...")
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
timeout := timeoutP
|
||||
if timeout <= 0 {
|
||||
timeout = 5
|
||||
}
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
|
||||
transport := &http.Transport{
|
||||
TLSClientConfig: tlsConfig,
|
||||
}
|
||||
var client = new(http.Client)
|
||||
if proxy != "" {
|
||||
transport = &http.Transport{
|
||||
TLSClientConfig: tlsConfig,
|
||||
Proxy: http.ProxyURL(pu),
|
||||
}
|
||||
}
|
||||
client = &http.Client{Transport: transport, Timeout: time.Duration(timeout) * time.Second}
|
||||
|
||||
req, err := http.NewRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Close = true
|
||||
//Set Default Headers with Ramdom UA
|
||||
tmpHeaders := BuildDefaultHeaders()
|
||||
for key, value := range tmpHeaders {
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
mu.Lock()
|
||||
if h != nil {
|
||||
for key, value := range h {
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
}
|
||||
mu.Unlock()
|
||||
resp, err := client.Do(req)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
//Post Request supports normal and json body too
|
||||
func PostRequest(uri string, data string, headers map[string]string, timeoutP int, proxy string) (*http.Response, error) {
|
||||
h := CloneHeaders(headers)
|
||||
pu, err := url.Parse(proxy)
|
||||
|
||||
if proxy != "" {
|
||||
if err != nil {
|
||||
fmt.Println("Invalid proxy...")
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
var req *http.Request
|
||||
var resp *http.Response
|
||||
|
||||
timeout := timeoutP
|
||||
if timeout <= 0 {
|
||||
timeout = 5
|
||||
}
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
|
||||
transport := &http.Transport{
|
||||
TLSClientConfig: tlsConfig,
|
||||
}
|
||||
var client = new(http.Client)
|
||||
if proxy != "" {
|
||||
transport = &http.Transport{
|
||||
TLSClientConfig: tlsConfig,
|
||||
Proxy: http.ProxyURL(pu),
|
||||
}
|
||||
}
|
||||
client = &http.Client{Transport: transport, Timeout: time.Duration(timeout) * time.Second}
|
||||
req, err = http.NewRequest("POST", uri, strings.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Close = true
|
||||
|
||||
req.Header.Set("Content-Type", "application/x-www-form-uriencoded")
|
||||
|
||||
//Set Default Headers with Ramdom UA
|
||||
tmpHeaders := BuildDefaultHeaders()
|
||||
for key, value := range tmpHeaders {
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
if h != nil {
|
||||
for key, value := range h {
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
}
|
||||
mu.Unlock()
|
||||
resp, err = client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func RandomUA() string {
|
||||
rand.Seed(time.Now().Unix())
|
||||
choice := rand.Intn(len(userAgents))
|
||||
return userAgents[choice]
|
||||
}
|
||||
|
||||
//default json escapes html characters such as <> so custom marshal needed
|
||||
func JsonMarshal(params interface{}) ([]byte, error) {
|
||||
buffer := new(bytes.Buffer)
|
||||
enc := json.NewEncoder(buffer)
|
||||
enc.SetEscapeHTML(false)
|
||||
err := enc.Encode(¶ms)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
return buffer.Bytes(), err
|
||||
}
|
||||
|
||||
//default json escapes html characters such as <> so custom marshal needed
|
||||
func JsonMarshalIndent(params interface{}, prefix string, indent string) ([]byte, error) {
|
||||
buffer := new(bytes.Buffer)
|
||||
enc := json.NewEncoder(buffer)
|
||||
enc.SetEscapeHTML(false)
|
||||
enc.SetIndent(prefix, indent)
|
||||
err := enc.Encode(¶ms)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
return buffer.Bytes(), err
|
||||
}
|
||||
|
||||
func CloneHeaders(m map[string]string) map[string]string {
|
||||
cp := make(map[string]string)
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
for k, v := range m {
|
||||
cp[k] = v
|
||||
}
|
||||
return cp
|
||||
}
|
||||
52
pkg/shodan_utils/shodan_utils.go
Normal file
52
pkg/shodan_utils/shodan_utils.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package shodan_utils
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/Jeffail/gabs"
|
||||
"github.com/jayateertha043/goshod/pkg/httpclient"
|
||||
)
|
||||
|
||||
func ShodanSearchHostCount(params map[string]string) (statuscode int, hostcount int, responsebody string) {
|
||||
sres, err := httpclient.GetRequestP("https://api.shodan.io/shodan/host/count", params, nil, 25)
|
||||
|
||||
if err != nil {
|
||||
return 500, -100, "Error: Unable to make request to shodan"
|
||||
}
|
||||
|
||||
defer sres.Body.Close()
|
||||
status_code := sres.StatusCode
|
||||
sresbytes, _ := ioutil.ReadAll(sres.Body)
|
||||
response_body := string(sresbytes)
|
||||
if status_code == 200 {
|
||||
res, err := gabs.ParseJSON([]byte(sresbytes))
|
||||
if err != nil {
|
||||
response_body = "Error: Unable to parse result from shodan"
|
||||
return 500, -101, response_body
|
||||
}
|
||||
total_exist := res.ExistsP("total")
|
||||
if total_exist {
|
||||
total := res.Path("total").Data().(float64)
|
||||
pages := int(((total - 1) / 100)) + 1
|
||||
return 200, pages, response_body
|
||||
}
|
||||
} else {
|
||||
return 500, -100, "Error: Unknown"
|
||||
}
|
||||
|
||||
return 500, -100, "Error: Unknown"
|
||||
}
|
||||
|
||||
func GetShodanResultForPage(params map[string]string) (status_code int, response_body string) {
|
||||
|
||||
sres, err := httpclient.GetRequestP("https://api.shodan.io/shodan/host/search", params, nil, 25)
|
||||
if err != nil {
|
||||
return 500, `{"error": "Internal connection error with shodan"}`
|
||||
}
|
||||
|
||||
defer sres.Body.Close()
|
||||
statuscode := sres.StatusCode
|
||||
sresbytes, _ := ioutil.ReadAll(sres.Body)
|
||||
responsebody := string(sresbytes)
|
||||
return statuscode, responsebody
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue