Files
osmedeus/execution/request.go
T
2023-09-07 21:21:14 +07:00

228 lines
5.7 KiB
Go

package execution
import (
"bufio"
"crypto/tls"
"encoding/base64"
"fmt"
"github.com/j3ssie/osmedeus/libs"
"github.com/j3ssie/osmedeus/utils"
"io"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"github.com/go-resty/resty/v2"
"github.com/sirupsen/logrus"
)
func SendGET(token string, url string) (libs.Response, error) {
client := BuildClient(token, 2)
res, err := JustSend(url, client)
return res, err
}
// BuildClient build base HTTP client
func BuildClient(token string, retry int) *resty.Client {
headers := map[string]string{
"UserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36",
"Content-Type": "application/json",
}
if token != "" {
headers["Authorization"] = fmt.Sprintf("Bearer %s", token)
}
timeout := 15
//if len(options.Headers) > 0 {
// for _, head := range options.Headers {
// if strings.Contains(head, ":") {
// data := strings.Split(head, ":")
// if len(data) < 2 {
// continue
// }
// headers[data[0]] = strings.Join(data[1:], "")
// }
// }
//}
// disable log when retry
logger := logrus.New()
logger.Out = io.Discard
client := resty.New()
client.SetLogger(logger)
client.SetTransport(&http.Transport{
MaxIdleConns: 100,
MaxConnsPerHost: 1000,
IdleConnTimeout: time.Duration(timeout) * time.Second,
ExpectContinueTimeout: time.Duration(timeout) * time.Second,
ResponseHeaderTimeout: time.Duration(timeout) * time.Second,
TLSHandshakeTimeout: time.Duration(timeout) * time.Second,
DisableCompression: true,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
})
client.SetHeaders(headers)
client.SetCloseConnection(true)
client.SetRetryCount(retry)
client.SetTimeout(time.Duration(timeout) * time.Second)
client.SetRetryWaitTime(time.Duration(timeout/2) * time.Second)
client.SetRetryMaxWaitTime(time.Duration(timeout) * time.Second)
return client
}
// JustSend just sending request
func JustSend(url string, client *resty.Client) (res libs.Response, err error) {
method := "GET"
// redirect policy
var resp *resty.Response
// really sending things here
method = strings.ToLower(strings.TrimSpace(method))
switch method {
case "get":
resp, err = client.R().
Get(url)
break
case "post":
resp, err = client.R().
Post(url)
break
}
// in case we want to get redirect stuff
if res.StatusCode != 0 {
return res, nil
}
if err != nil || resp == nil {
utils.WarnF("%v %v", url, err)
return libs.Response{}, err
}
return ParseResponse(*resp), nil
}
// ParseResponse field to Response
func ParseResponse(resp resty.Response) (res libs.Response) {
// var res libs.Response
resLength := len(string(resp.Body()))
// format the headers
var resHeaders []map[string]string
for k, v := range resp.RawResponse.Header {
if k == "Content-Type" {
res.ContentType = strings.Join(v[:], "")
}
if k == "Location" {
res.Location = strings.Join(v[:], "")
}
element := make(map[string]string)
element[k] = strings.Join(v[:], "")
resLength += len(fmt.Sprintf("%s: %s\n", k, strings.Join(v[:], "")))
resHeaders = append(resHeaders, element)
}
// response time in second
resTime := float64(resp.Time()) / float64(time.Second)
resHeaders = append(resHeaders,
map[string]string{"Total Length": strconv.Itoa(resLength)},
map[string]string{"Response Time": fmt.Sprintf("%f", resTime)},
)
// set some variable
res.Headers = resHeaders
res.StatusCode = resp.StatusCode()
res.Status = fmt.Sprintf("%v %v", resp.Status(), resp.RawResponse.Proto)
res.Body = string(resp.Body())
res.ResponseTime = resTime
res.Length = resLength
// beautify
res.Beautify = BeautifyResponse(res)
res.BeautifyHeader = BeautifyHeaders(res)
return res
}
// BeautifyRequest beautify request
func BeautifyRequest(req libs.Request) string {
var beautifyReq string
// hardcoded HTTP/1.1 for now
beautifyReq += fmt.Sprintf("%v %v HTTP/1.1\n", req.Method, req.URL)
for _, header := range req.Headers {
for key, value := range header {
if key != "" && value != "" {
beautifyReq += fmt.Sprintf("%v: %v\n", key, value)
}
}
}
if req.Body != "" {
beautifyReq += fmt.Sprintf("\n%v\n", req.Body)
}
return beautifyReq
}
// BeautifyHeaders beautify headers
func BeautifyHeaders(res libs.Response) string {
beautifyHeader := fmt.Sprintf("< %v \n", res.Status)
for _, header := range res.Headers {
for key, value := range header {
beautifyHeader += fmt.Sprintf("< %v: %v\n", key, value)
}
}
return beautifyHeader
}
// BeautifyResponse beautify response
func BeautifyResponse(res libs.Response) string {
var beautifyRes string
beautifyRes += fmt.Sprintf("%v \n", res.Status)
for _, header := range res.Headers {
for key, value := range header {
beautifyRes += fmt.Sprintf("%v: %v\n", key, value)
}
}
beautifyRes += fmt.Sprintf("\n%v\n", res.Body)
return beautifyRes
}
// ParseBurpRequest parse burp style request
func ParseBurpRequest(raw string) string {
rawDecoded, err := base64.StdEncoding.DecodeString(raw)
if err != nil {
return ""
}
var realReq libs.Request
reader := bufio.NewReader(strings.NewReader(string(rawDecoded)))
parsedReq, err := http.ReadRequest(reader)
if err != nil {
return ""
}
realReq.Method = parsedReq.Method
// URL part
if parsedReq.URL.Host == "" {
realReq.Host = parsedReq.Host
parsedReq.URL.Host = parsedReq.Host
}
if parsedReq.URL.Scheme == "" {
if parsedReq.Referer() == "" {
realReq.Scheme = "https"
parsedReq.URL.Scheme = "https"
} else {
u, err := url.Parse(parsedReq.Referer())
if err == nil {
realReq.Scheme = u.Scheme
parsedReq.URL.Scheme = u.Scheme
}
}
}
realReq.URL = parsedReq.URL.String()
realReq.Path = parsedReq.RequestURI
return realReq.URL
}